Merge branch 'master' into MNG-7532
diff --git a/.asf.yaml b/.asf.yaml
index 7411fdc..ae0f2fc 100644
--- a/.asf.yaml
+++ b/.asf.yaml
@@ -12,6 +12,8 @@
     squash: true
     merge: false
     rebase: true
+  autolink_jira:
+    - MNG
 notifications:
   commits: commits@maven.apache.org
   issues: issues@maven.apache.org
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000..93ac858
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# Change maven code style
+de19cfcd2bc8e774818d87472e8e64dc37c0b93d
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index b4a4f83..bb2549a 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -6,9 +6,10 @@
        require a JIRA issue. Your pull request should address just this issue, without
        pulling in other changes.
  - [ ] Each commit in the pull request should have a meaningful subject line and body.
- - [ ] Format the pull request title like `[MNG-XXX] SUMMARY`, where you replace `MNG-XXX`
-       and `SUMMARY` with the appropriate JIRA issue. Best practice is to use the JIRA issue
-       title in the pull request title and in the first line of the commit message.
+ - [ ] Format the pull request title like `[MNG-XXX] SUMMARY`,
+       where you replace `MNG-XXX` and `SUMMARY` with the appropriate JIRA issue.
+ - [ ] Also format the first line of the commit message like `[MNG-XXX] SUMMARY`.
+       Best practice is to use the JIRA issue title in both the pull request title and in the first line of the commit message.
  - [ ] Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  - [ ] Run `mvn clean verify` to make sure basic checks pass. A more thorough check will
        be performed on your pull request automatically.
diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml
index 3b82ac1..1be8569 100644
--- a/.github/workflows/maven.yml
+++ b/.github/workflows/maven.yml
@@ -19,8 +19,15 @@
 
 on: [push, pull_request]
 
+# clear all permissions for GITHUB_TOKEN
+permissions: {}
+
 jobs:
   build:
+
+    # execute on any push or pull request from forked repo
+    if: github.event_name == 'push' || ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork )
+
     strategy:
       matrix:
         os: [ubuntu-latest, windows-latest, macOS-latest]
@@ -29,10 +36,13 @@
     runs-on: ${{ matrix.os }}
 
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-java@v2
+      - uses: actions/checkout@v3
         with:
-          java-version: 8
+          persist-credentials: false
+
+      - uses: actions/setup-java@v3
+        with:
+          java-version: 11
           distribution: 'temurin'
           cache: 'maven'
 
@@ -40,7 +50,7 @@
         run: mvn verify -e -B -V -DdistributionFileName=apache-maven
 
       - name: Upload built Maven
-        uses: actions/upload-artifact@v2
+        uses: actions/upload-artifact@v3
         if: ${{ matrix.os == 'ubuntu-latest' }}
         with:
           name: built-maven
@@ -51,7 +61,7 @@
     strategy:
       matrix:
         os: [ubuntu-latest, windows-latest, macOS-latest]
-        java: [8, 11, 17]
+        java: [11, 17, 21]
 
       fail-fast: false
     runs-on: ${{ matrix.os }}
@@ -89,33 +99,28 @@
           echo "REPO_USER=$target_user" >> $GITHUB_ENV
 
       - name: Checkout maven-integration-testing
-        uses: actions/checkout@v2
+        uses: actions/checkout@v3
         with:
           repository: ${{ env.REPO_USER }}/maven-integration-testing
           path: maven-integration-testing/
           ref: ${{ env.REPO_BRANCH }}
-
-      - name: Set up cache for ~/.m2/repository
-        uses: actions/cache@v2
-        with:
-          path: ~/.m2/repository
-          key: it-m2-repo-${{ matrix.os }}-${{ hashFiles('maven-integration-testing/**/pom.xml') }}
-          restore-keys: |
-            it-m2-repo-${{ matrix.os }}-
-
-      - name: Download built Maven
-        uses: actions/download-artifact@v2
-        with:
-          name: built-maven
-          path: built-maven/
+          persist-credentials: false
 
       - name: Set up JDK
-        uses: actions/setup-java@v2
+        uses: actions/setup-java@v3
         with:
           java-version: ${{ matrix.java }}
           distribution: 'temurin'
-          cache: 'maven'
+#          cache: 'maven' - don't use cache for integration tests
+
+      - uses: actions/checkout@v3
+        with:
+          path: maven/
+          persist-credentials: false
+
+      - name: Build Maven
+        run: mvn install -e -B -V -DdistributionFileName=apache-maven -DskipTests -f maven/pom.xml
 
       - name: Running integration tests
         shell: bash
-        run: mvn install -e -B -V -Prun-its,embedded -Dmaven.repo.local="$HOME/.m2/repository" -DmavenDistro="$GITHUB_WORKSPACE/built-maven/apache-maven-bin.zip" -f maven-integration-testing/pom.xml
+        run: mvn install -e -B -V -Prun-its,embedded -DmavenDistro="$GITHUB_WORKSPACE/maven/apache-maven/target/apache-maven-bin.zip" -f maven-integration-testing/pom.xml
diff --git a/.github/workflows/maven_build_itself.yml b/.github/workflows/maven_build_itself.yml
index c181d23..25198d6 100644
--- a/.github/workflows/maven_build_itself.yml
+++ b/.github/workflows/maven_build_itself.yml
@@ -19,26 +19,36 @@
 
 on: [push, pull_request]
 
+# clear all permissions for GITHUB_TOKEN
+permissions: {}
+
 jobs:
   build:
+
+    # execute on any push or pull request from forked repo
+    if: github.event_name == 'push' || ( github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork )
+
     strategy:
       matrix:
         os: [ubuntu-latest, windows-latest]
-        java: [8, 17]
+        java: [11, 17, 21]
       fail-fast: false
 
     runs-on: ${{ matrix.os }}
 
     steps:
-      - uses: actions/checkout@v2
-      - uses: actions/setup-java@v2
+      - uses: actions/checkout@v3
+        with:
+          persist-credentials: false
+
+      - uses: actions/setup-java@v3
         with:
           java-version: ${{ matrix.java }}
           distribution: 'temurin'
           cache: 'maven'
 
       - name: Build with Maven
-        run: mvn verify -e -B -V -DdistributionFileName=apache-maven
+        run: mvn install -e -B -V -DdistributionFileName=apache-maven
 
       - name: Extract tarball
         shell: bash
@@ -70,4 +80,4 @@
         run: |
           set +e
           export PATH=${{ env.TEMP_MAVEN_BIN_DIR }}:$PATH
-          mvn verify -e -B -V -DdistributionFileName=apache-maven
+          mvn verify site -e -B -V -DdistributionFileName=apache-maven -Preporting
diff --git a/.gitignore b/.gitignore
index 69c3758..b630410 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-target/
+**/target/**
 .project
 .classpath
 .settings/
@@ -14,3 +14,4 @@
 .checkstyle
 .factorypath
 .vscode/
+repo/
diff --git a/Jenkinsfile b/Jenkinsfile
index 1215dec..97be982 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -20,11 +20,11 @@
 properties([buildDiscarder(logRotator(artifactNumToKeepStr: '5', numToKeepStr: env.BRANCH_NAME=='master'?'5':'1'))])
 
 def buildOs = 'linux'
-def buildJdk = '8'
-def buildMvn = '3.6.3'
-def runITsOses = ['linux', 'windows']
-def runITsJdks = ['8', '11', '17']
-def runITsMvn = '3.6.3'
+def buildJdk = '11'
+def buildMvn = '3.8.x'
+def runITsOses = ['linux']
+def runITsJdks = ['11', '17', '21']
+def runITsMvn = '3.8.x'
 def runITscommand = "mvn clean install -Prun-its,embedded -B -U -V" // -DmavenDistro=... -Dmaven.test.failure.ignore=true
 def tests
 
@@ -49,23 +49,16 @@
         stage('Build / Unit Test') {
             String jdkName = jenkinsEnv.jdkFromVersion(buildOs, buildJdk)
             String mvnName = jenkinsEnv.mvnFromVersion(buildOs, buildMvn)
-            withMaven(jdk: jdkName, maven: mvnName, mavenLocalRepo:"${WORK_DIR}/.repository", options:[
-                artifactsPublisher(disabled: false),
-                junitPublisher(ignoreAttachments: false),
-                findbugsPublisher(disabled: true),
-                openTasksPublisher(disabled: true),
-                dependenciesFingerprintPublisher(disabled: false),
-                invokerPublisher(disabled: true),
-                pipelineGraphPublisher(disabled: false)
-            ], publisherStrategy: 'EXPLICIT') {
-                sh "mvn clean ${MAVEN_GOAL} -B -U -e -fae -V -Dmaven.test.failure.ignore -PversionlessMavenDist"
-            }
-            dir ('apache-maven/target') {
-                stash includes: 'apache-maven-bin.zip', name: 'maven-dist'
-            }
+            try {
+                withEnv(["JAVA_HOME=${ tool "$jdkName" }",
+                         "PATH+MAVEN=${ tool "$jdkName" }/bin:${tool "$mvnName"}/bin",
+                         "MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) {                   
+                    sh "mvn clean ${MAVEN_GOAL} -B -U -e -fae -V -Dmaven.test.failure.ignore -PversionlessMavenDist -Dmaven.repo.local=${WORK_DIR}/.repository"
+                }
+            } finally {
+                junit testResults: '**/target/surefire-reports/*.xml,**/target/failsafe-reports/*.xml', allowEmptyResults: true
+            }    
         }
-
-        tests = resolveScm source: [$class: 'GitSCMSource', credentialsId: '', id: '_', remote: 'https://gitbox.apache.org/repos/asf/maven-integration-testing.git', traits: [[$class: 'jenkins.plugins.git.traits.BranchDiscoveryTrait'], [$class: 'GitToolSCMSourceTrait', gitTool: 'Default']]], targets: [BRANCH_NAME, 'master']
     }
 }
 
@@ -88,33 +81,54 @@
                     // will not trample each other plus workaround for JENKINS-52657
                     dir(isUnix() ? 'test' : "c:\\mvn-it-${EXECUTOR_NUMBER}.tmp") {
                         def WORK_DIR=pwd()
-                        checkout tests
-                        if (isUnix()) {
-                            sh "rm -rvf $WORK_DIR/dists $WORK_DIR/it-local-repo"
-                        } else {
-                            bat "if exist it-local-repo rmdir /s /q it-local-repo"
-                            bat "if exist dists         rmdir /s /q dists"
-                        }
-                        dir('dists') {
-                          unstash 'maven-dist'
-                        }
                         try {
-                            withMaven(jdk: jdkName, maven: mvnName, mavenLocalRepo:"${WORK_DIR}/it-local-repo", options:[
-                                junitPublisher(ignoreAttachments: false)
-                            ]) {
-                                String cmd = "${runITscommand} -DmavenDistro=$WORK_DIR/dists/apache-maven-bin.zip -Dmaven.test.failure.ignore"
+                            dir ('maven') {
+                                checkout scm
+                                withEnv(["JAVA_HOME=${ tool "$jdkName" }",
+                                         "PATH+MAVEN=${ tool "$jdkName" }/bin:${tool "$mvnName"}/bin",
+                                         "MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) {
+                                    sh "mvn clean install -B -U -e -DskipTests -V -PversionlessMavenDist -Dmaven.repo.local=${WORK_DIR}/.repository"
+                                }
+                            }
+                            dir ('its') {
+                                def ITS_BRANCH = env.CHANGE_BRANCH != null ? env.CHANGE_BRANCH :  env.BRANCH_NAME;
+                                try {
+                                  echo "Checkout ITs from branch: ${ITS_BRANCH}"
+                                  checkout([$class: 'GitSCM',
+                                          branches: [[name: ITS_BRANCH]],
+                                          extensions: [[$class: 'CloneOption', depth: 1, noTags: true, shallow: true]],
+                                          userRemoteConfigs: [[url: 'https://github.com/apache/maven-integration-testing.git']]])
+                                } catch (Throwable e) {
+                                  echo "Failure checkout ITs branch: ${ITS_BRANCH} - fallback master branch"
+                                  checkout([$class: 'GitSCM',
+                                          branches: [[name: "*/master"]],
+                                          extensions: [[$class: 'CloneOption', depth: 1, noTags: true, shallow: true]],
+                                          userRemoteConfigs: [[url: 'https://github.com/apache/maven-integration-testing.git']]])
+                                }
 
-                                if (isUnix()) {
-                                    sh 'df -hT'
-                                    sh "${cmd}"
-                                } else {
-                                    bat 'wmic logicaldisk get size,freespace,caption'
-                                    bat "${cmd}"
+                                try {
+                                    withEnv(["JAVA_HOME=${ tool "$jdkName" }",
+                                                "PATH+MAVEN=${ tool "$jdkName" }/bin:${tool "$mvnName"}/bin",
+                                                "MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) {
+                                        String cmd = "${runITscommand} -Dmaven.repo.local=$WORK_DIR/.repository -DmavenDistro=$WORK_DIR/maven/apache-maven/target/apache-maven-bin.zip -Dmaven.test.failure.ignore"
+
+                                        if (isUnix()) {
+                                            sh 'df -hT'
+                                            sh "${cmd}"
+                                        } else {
+                                            bat 'wmic logicaldisk get size,freespace,caption'
+                                            bat "${cmd}"
+                                        }
+                                    }
+                                } finally {
+                                    // in ITs test we need only reports from test itself
+                                    // test projects can contain reports with tested failed builds
+                                    junit testResults: '**/core-it-suite/target/surefire-reports/*.xml,**/core-it-support/**/target/surefire-reports/*.xml', allowEmptyResults: true
+                                    archiveDirs(stageId, ['core-it-suite-logs':'core-it-suite/target/test-classes',
+                                                          'core-it-suite-reports':'core-it-suite/target/surefire-reports'])
                                 }
                             }
                         } finally {
-                            archiveDirs(stageId, ['core-it-suite-logs':'core-it-suite/target/test-classes',
-                                                  'core-it-suite-reports':'core-it-suite/target/surefire-reports'])
                             deleteDir() // clean up after ourselves to reduce disk space
                         }
                     }
diff --git a/Jenkinsfile.s390x b/Jenkinsfile.s390x
new file mode 100644
index 0000000..e760a62
--- /dev/null
+++ b/Jenkinsfile.s390x
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+properties([buildDiscarder(logRotator(artifactNumToKeepStr: '5', numToKeepStr: env.BRANCH_NAME=='master'?'5':'1'))])
+
+def buildOs = 'linux'
+def buildJdk = '11'
+def buildMvn = '3.8.x'
+def runITsOses = ['linux']
+def runITsJdks = ['11', '17']
+def runITsMvn = '3.8.x'
+def runITscommand = "mvn clean install -Prun-its,embedded -B -U -V" // -DmavenDistro=... -Dmaven.test.failure.ignore=true
+def tests
+
+try {
+
+def osNode = jenkinsEnv.labelForOS(buildOs)
+node('s390x') {
+    dir('build') {
+        stage('Checkout') {
+            checkout scm
+        }
+
+        def WORK_DIR=pwd()
+        def MAVEN_GOAL='verify'
+
+        stage('Build / Unit Test') {
+            String jdkName = jenkinsEnv.jdkFromVersion(buildOs, buildJdk)
+            String mvnName = jenkinsEnv.mvnFromVersion(buildOs, buildMvn)
+            try {
+                withEnv(["JAVA_HOME=${ tool "$jdkName" }",
+                         "PATH+MAVEN=${ tool "$jdkName" }/bin:${tool "$mvnName"}/bin",
+                         "MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) {                   
+                    sh "mvn clean ${MAVEN_GOAL} -B -U -e -fae -V -Dmaven.test.failure.ignore -PversionlessMavenDist -Dmaven.repo.local=${WORK_DIR}/.repository"
+                }
+            } finally {
+                junit testResults: '**/target/surefire-reports/*.xml,**/target/failsafe-reports/*.xml', allowEmptyResults: true
+            }    
+            dir ('apache-maven/target') {
+                stash includes: 'apache-maven-bin.zip', name: 'maven-dist-s390x'
+            }
+        }
+    }
+}
+
+Map runITsTasks = [:]
+for (String os in runITsOses) {
+    for (def jdk in runITsJdks) {
+        String osLabel = jenkinsEnv.labelForOS(os);
+        String jdkName = jenkinsEnv.jdkFromVersion(os, "${jdk}")
+        String mvnName = jenkinsEnv.mvnFromVersion(os, "${runITsMvn}")
+        echo "OS: ${os} JDK: ${jdk} => Label: ${osLabel} JDK: ${jdkName} Arch: s390x"
+
+        String stageId = "${os}-jdk${jdk}-s390x"
+        String stageLabel = "Run ITs ${os.capitalize()} Java ${jdk} on s390x"
+        runITsTasks[stageId] = {
+            node('s390x') {
+                stage("${stageLabel}") {
+                    echo "NODE_NAME = ${env.NODE_NAME}"
+                    // on Windows, need a short path or we hit 256 character limit for paths
+                    // using EXECUTOR_NUMBER guarantees that concurrent builds on same agent
+                    // will not trample each other plus workaround for JENKINS-52657
+                    dir(isUnix() ? 'test' : "c:\\mvn-it-${EXECUTOR_NUMBER}.tmp") {
+                        def WORK_DIR=pwd()
+                        def ITS_BRANCH = env.CHANGE_BRANCH != null ? env.CHANGE_BRANCH :  env.BRANCH_NAME;
+                        try {
+                          echo "Checkout ITs from branch: ${ITS_BRANCH}"
+                          checkout([$class: 'GitSCM',
+                                  branches: [[name: ITS_BRANCH]],
+                                  extensions: [[$class: 'CloneOption', depth: 1, noTags: true, shallow: true]],
+                                  userRemoteConfigs: [[url: 'https://github.com/apache/maven-integration-testing.git']]])
+                        } catch (Throwable e) {
+                          echo "Failure checkout ITs branch: ${ITS_BRANCH} - fallback master branch"
+                          checkout([$class: 'GitSCM',
+                                  branches: [[name: "*/master"]],
+                                  extensions: [[$class: 'CloneOption', depth: 1, noTags: true, shallow: true]],
+                                  userRemoteConfigs: [[url: 'https://github.com/apache/maven-integration-testing.git']]])
+                        }
+                        if (isUnix()) {
+                            sh "rm -rvf $WORK_DIR/dists $WORK_DIR/it-local-repo"
+                        } else {
+                            bat "if exist it-local-repo rmdir /s /q it-local-repo"
+                            bat "if exist dists         rmdir /s /q dists"
+                        }
+                        dir('dists') {
+                          unstash 'maven-dist-s390x'
+                        }
+                        try {
+                            withEnv(["JAVA_HOME=${ tool "$jdkName" }",
+                                        "PATH+MAVEN=${ tool "$jdkName" }/bin:${tool "$mvnName"}/bin",
+                                        "MAVEN_OPTS=-Xms2g -Xmx4g -Djava.awt.headless=true"]) {                                               
+                                String cmd = "${runITscommand} -Dmaven.repo.local=$WORK_DIR/it-local-repo -DmavenDistro=$WORK_DIR/dists/apache-maven-bin.zip -Dmaven.test.failure.ignore"
+
+                                if (isUnix()) {
+                                    sh 'df -hT'
+                                    sh "${cmd}"
+                                } else {
+                                    bat 'wmic logicaldisk get size,freespace,caption'
+                                    bat "${cmd}"
+                                }
+                            }
+                        } finally {
+                            // in ITs test we need only reports from test itself
+                            // test projects can contain reports with tested failed builds
+                            junit testResults: '**/core-it-suite/target/surefire-reports/*.xml,**/core-it-support/**/target/surefire-reports/*.xml', allowEmptyResults: true
+                            archiveDirs(stageId, ['core-it-suite-logs':'core-it-suite/target/test-classes',
+                                                  'core-it-suite-reports':'core-it-suite/target/surefire-reports'])
+                            deleteDir() // clean up after ourselves to reduce disk space
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+// run the parallel ITs
+parallel(runITsTasks)
+
+// JENKINS-34376 seems to make it hard to detect the aborted builds
+} catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
+    echo "[FAILURE-002] FlowInterruptedException ${e}"
+    // this ambiguous condition means a user probably aborted
+    if (e.causes.size() == 0) {
+        currentBuild.result = "ABORTED"
+    } else {
+        currentBuild.result = "FAILURE"
+    }
+    throw e
+} catch (hudson.AbortException e) {
+    echo "[FAILURE-003] AbortException ${e}"
+    // this ambiguous condition means during a shell step, user probably aborted
+    if (e.getMessage().contains('script returned exit code 143')) {
+        currentBuild.result = "ABORTED"
+    } else {
+        currentBuild.result = "FAILURE"
+    }
+    throw e
+} catch (InterruptedException e) {
+    echo "[FAILURE-004] ${e}"
+    currentBuild.result = "ABORTED"
+    throw e
+} catch (Throwable e) {
+    echo "[FAILURE-001] ${e}"
+    currentBuild.result = "FAILURE"
+    throw e
+}
+
+def archiveDirs(stageId, archives) {
+    archives.each { archivePrefix, pathToContent ->
+        if (fileExists(pathToContent)) {
+            zip(zipFile: "${archivePrefix}-${stageId}.zip", dir: pathToContent, archive: true)
+        }
+    }
+}
diff --git a/README.md b/README.md
index 39d5335..1cf5bc8 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,7 @@
 [![ASF Jira](https://img.shields.io/endpoint?url=https%3A%2F%2Fmaven.apache.org%2Fbadges%2Fasf_jira-MNG.json)][jira]
 [![Apache License, Version 2.0, January 2004](https://img.shields.io/github/license/apache/maven.svg?label=License)][license]
 [![Maven Central](https://img.shields.io/maven-central/v/org.apache.maven/apache-maven.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.apache.maven/apache-maven)
+[![Reproducible Builds](https://img.shields.io/badge/Reproducible_Builds-ok-green?labelColor=blue)](https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/org/apache/maven/maven/README.md)
 [![Jenkins Status](https://img.shields.io/jenkins/s/https/ci-maven.apache.org/job/Maven/job/maven-box/job/maven/job/master.svg?)][build]
 [![Jenkins tests](https://img.shields.io/jenkins/t/https/ci-maven.apache.org/job/Maven/job/maven-box/job/maven/job/master.svg?)][test-results]
 
@@ -64,8 +65,8 @@
 Quick Build
 -------
 If you want to bootstrap Maven, you'll need:
-- Java 8+
-- Maven 3.0.5 or later
+- Java 11+
+- Maven 3.6.3 or later
 - Run Maven, specifying a location into which the completed Maven distro should be installed:
     ```
     mvn -DdistributionTargetDir="$HOME/app/maven/apache-maven-4.0.x-SNAPSHOT" clean package
diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index 5207457..de432ee 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>apache-maven</artifactId>
@@ -82,13 +80,20 @@
       <groupId>org.apache.maven.resolver</groupId>
       <artifactId>maven-resolver-transport-file</artifactId>
     </dependency>
+    <!-- HTTP/1.1, lowest priority, Java8+ (still must as some ITs force it) -->
+    <dependency>
+      <groupId>org.apache.maven.resolver</groupId>
+      <artifactId>maven-resolver-transport-wagon</artifactId>
+    </dependency>
+    <!-- HTTP/1.1, medium priority, Java8+ -->
     <dependency>
       <groupId>org.apache.maven.resolver</groupId>
       <artifactId>maven-resolver-transport-http</artifactId>
     </dependency>
+    <!-- HTTP/1.1 and HTTP/2, high priority, Java11+ -->
     <dependency>
       <groupId>org.apache.maven.resolver</groupId>
-      <artifactId>maven-resolver-transport-wagon</artifactId>
+      <artifactId>maven-resolver-transport-jdk</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
@@ -98,8 +103,25 @@
       <groupId>org.fusesource.jansi</groupId>
       <artifactId>jansi</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.ow2.asm</groupId>
+      <artifactId>asm</artifactId>
+    </dependency>
   </dependencies>
 
+  <pluginRepositories>
+    <pluginRepository>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <snapshots>
+        <enabled>true</enabled>
+      </snapshots>
+      <id>apache.snapshots</id>
+      <url>https://repository.apache.org/snapshots/</url>
+    </pluginRepository>
+  </pluginRepositories>
+
   <build>
     <finalName>${distributionFileName}</finalName>
     <pluginManagement>
@@ -157,12 +179,9 @@
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-surefire-plugin</artifactId>
         <configuration>
-          <systemProperties>
-            <property>
-              <name>basedir</name>
-              <value>${basedir}</value>
-            </property>
-          </systemProperties>
+          <systemPropertyVariables>
+            <basedir>${basedir}</basedir>
+          </systemPropertyVariables>
         </configuration>
         <executions>
           <execution>
@@ -179,10 +198,10 @@
         <executions>
           <execution>
             <id>create-distro-packages</id>
-            <phase>package</phase>
             <goals>
               <goal>single</goal>
             </goals>
+            <phase>package</phase>
             <configuration>
               <descriptors>
                 <descriptor>src/assembly/bin.xml</descriptor>
@@ -194,19 +213,6 @@
     </plugins>
   </build>
 
-  <pluginRepositories>
-    <pluginRepository>
-      <id>apache.snapshots</id>
-      <url>https://repository.apache.org/snapshots/</url>
-      <snapshots>
-        <enabled>true</enabled>
-      </snapshots>
-      <releases>
-        <enabled>false</enabled>
-      </releases>
-    </pluginRepository>
-  </pluginRepositories>
-
   <profiles>
     <profile>
       <id>create-distribution-in-dir</id>
@@ -222,10 +228,10 @@
             <artifactId>maven-clean-plugin</artifactId>
             <executions>
               <execution>
+                <id>clean-target-dir</id>
                 <goals>
                   <goal>clean</goal>
                 </goals>
-                <id>clean-target-dir</id>
                 <phase>prepare-package</phase>
                 <configuration>
                   <excludeDefaultDirectories>true</excludeDefaultDirectories>
@@ -243,10 +249,10 @@
             <executions>
               <execution>
                 <id>create-distribution-dir</id>
-                <phase>package</phase>
                 <goals>
                   <goal>single</goal>
                 </goals>
+                <phase>package</phase>
                 <configuration>
                   <finalName>./</finalName>
                   <appendAssemblyId>false</appendAssemblyId>
@@ -271,10 +277,10 @@
             <executions>
               <execution>
                 <id>make-src-assembly</id>
-                <phase>package</phase>
                 <goals>
                   <goal>single</goal>
                 </goals>
+                <phase>package</phase>
                 <configuration>
                   <descriptors>
                     <descriptor>src/assembly/src.xml</descriptor>
@@ -288,28 +294,18 @@
           <plugin>
             <groupId>net.nicoulaj.maven.plugins</groupId>
             <artifactId>checksum-maven-plugin</artifactId>
+            <version>1.11</version>
             <executions>
               <execution>
                 <id>source-release-checksum</id>
                 <goals>
-                  <goal>files</goal>
+                  <goal>artifacts</goal>
                 </goals>
+                <configuration>
+                  <includeClassifiers>bin,src</includeClassifiers>
+                </configuration>
               </execution>
             </executions>
-            <configuration>
-              <fileSets>
-                <fileSet>
-                  <directory>${project.build.directory}</directory>
-                  <includes>
-                    <include>${project.artifactId}-${project.version}-src.zip</include>
-                    <include>${project.artifactId}-${project.version}-src.tar.gz</include>
-                    <include>${project.artifactId}-${project.version}-bin.zip</include>
-                    <include>${project.artifactId}-${project.version}-bin.tar.gz</include>
-                  </includes>
-                </fileSet>
-              </fileSets>
-              <failIfNoFiles>true</failIfNoFiles>
-            </configuration>
           </plugin>
         </plugins>
       </build>
diff --git a/apache-maven/src/assembly/maven/bin/m2.conf b/apache-maven/src/assembly/maven/bin/m2.conf
index c446568..15e0f5d 100644
--- a/apache-maven/src/assembly/maven/bin/m2.conf
+++ b/apache-maven/src/assembly/maven/bin/m2.conf
@@ -6,5 +6,7 @@
 load       ${maven.conf}/logging
 optionally ${maven.home}/lib/ext/redisson/*.jar
 optionally ${maven.home}/lib/ext/hazelcast/*.jar
+optionally ${user.home}/.m2/ext/*.jar
 optionally ${maven.home}/lib/ext/*.jar
+load       ${maven.home}/lib/maven-*.jar
 load       ${maven.home}/lib/*.jar
diff --git a/apache-maven/src/assembly/maven/conf/settings.xml b/apache-maven/src/assembly/maven/conf/settings.xml
index 2f18af3..1ffdca9 100644
--- a/apache-maven/src/assembly/maven/conf/settings.xml
+++ b/apache-maven/src/assembly/maven/conf/settings.xml
@@ -43,9 +43,9 @@
  | values (values used when the setting is not specified) are provided.
  |
  |-->
-<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
+<settings xmlns="http://maven.apache.org/SETTINGS/1.3.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0 https://maven.apache.org/xsd/settings-1.2.0.xsd">
+          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.3.0 https://maven.apache.org/xsd/settings-1.3.0.xsd">
   <!-- localRepository
    | The path to the local repository maven will use to store artifacts.
    |
@@ -82,6 +82,7 @@
     -->
   </pluginGroups>
 
+  <!-- TODO Since when can proxies be selected as depicted? -->
   <!-- proxies
    | This is a list of proxies which can be used on this machine to connect to the network.
    | Unless otherwise specified (by system property or command-line switch), the first proxy
@@ -165,6 +166,35 @@
     </mirror>
   </mirrors>
 
+  <!-- repositories
+   | Specifies the list of default remote repositories that maven will search artifacts for.
+  -->
+  <repositories>
+    <repository>
+      <id>central</id>
+      <name>Central Repository</name>
+      <url>https://repo.maven.apache.org/maven2</url>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+  </repositories>
+
+  <!-- plugin repositories
+   | Specifies the list of default remote repositories that maven will search plugins for.
+  -->
+  <pluginRepositories>
+    <pluginRepository>
+      <id>central</id>
+      <name>Central Repository</name>
+      <url>https://repo.maven.apache.org/maven2</url>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </pluginRepository>
+  </pluginRepositories>
+
+
   <!-- profiles
    | This is a list of profiles which can be activated in a variety of ways, and which can modify
    | the build process. Profiles provided in the settings.xml are intended to provide local machine-
@@ -176,7 +206,7 @@
    |
    | As noted above, profiles can be activated in a variety of ways. One way - the activeProfiles
    | section of this document (settings.xml) - will be discussed later. Another way essentially
-   | relies on the detection of a system property, either matching a particular value for the property,
+   | relies on the detection of a property, either matching a particular value for the property,
    | or merely testing its existence. Profiles can also be activated by JDK version prefix, where a
    | value of '1.4' might activate a profile when the build is executed on a JDK version of '1.4.2_07'.
    | Finally, the list of active profiles can be specified directly from the command line.
@@ -218,9 +248,9 @@
     -->
 
     <!--
-     | Here is another profile, activated by the system property 'target-env' with a value of 'dev',
-     | which provides a specific path to the Tomcat instance. To use this, your plugin configuration
-     | might hypothetically look like:
+     | Here is another profile, activated by the property 'target-env' with a value of 'dev', which
+     | provides a specific path to the Tomcat instance. To use this, your plugin configuration might
+     | hypothetically look like:
      |
      | ...
      | <plugin>
diff --git a/apache-maven/src/assembly/shared/init.cmd b/apache-maven/src/assembly/shared/init.cmd
index 019e4b8..e41e093 100755
--- a/apache-maven/src/assembly/shared/init.cmd
+++ b/apache-maven/src/assembly/shared/init.cmd
@@ -64,8 +64,9 @@
 
 :findBaseDir
 cd /d "%WDIR%"
+set "WDIR=%CD%"
 :findBaseDirLoop
-if exist "%WDIR%\.mvn" goto baseDirFound
+if exist ".mvn" goto baseDirFound
 cd ..
 IF "%WDIR%"=="%CD%" goto baseDirNotFound
 set "WDIR=%CD%"
diff --git a/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm b/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm
index b9a517e..dabe9f3 100644
--- a/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm
+++ b/apache-maven/src/main/appended-resources/META-INF/NOTICE.vm
@@ -18,9 +18,9 @@
 ##
 This software bundles the following NOTICE files from third party library providers:
 
-META-INF/NOTICE in archive lib/guice-4.2.1-no_aop.jar
+META-INF/NOTICE in archive lib/guice-5.1.0.jar
 Google Guice - Core Library
-Copyright 2006-2018 Google, Inc.
+Copyright 2006-2022 Google, Inc.
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
 
diff --git a/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.36.txt b/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.36.txt
index 712cd8c..1a3d053 100644
--- a/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.36.txt
+++ b/apache-maven/src/main/appended-resources/licenses/MIT-slf4j-api-1.7.36.txt
@@ -1,6 +1,4 @@
-https://raw.githubusercontent.com/qos-ch/slf4j/v_1.7.32/LICENSE.txt
-
-Copyright (c) 2004-2017 QOS.ch
+Copyright (c) 2004-2022 QOS.ch Sarl (Switzerland)
 All rights reserved.
 
 Permission is hereby granted, free  of charge, to any person obtaining
@@ -21,3 +19,6 @@
 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+
+
diff --git a/apache-maven/src/main/appended-resources/licenses/unrecognized-aopalliance-1.0.txt b/apache-maven/src/main/appended-resources/licenses/unrecognized-aopalliance-1.0.txt
new file mode 100644
index 0000000..a7a158b
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/unrecognized-aopalliance-1.0.txt
@@ -0,0 +1 @@
+Public Domain
\ No newline at end of file
diff --git a/apache-maven/src/main/appended-resources/licenses/unrecognized-asm-9.6.txt b/apache-maven/src/main/appended-resources/licenses/unrecognized-asm-9.6.txt
new file mode 100644
index 0000000..631ee53
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/unrecognized-asm-9.6.txt
@@ -0,0 +1,27 @@
+ASM: a very small and fast Java bytecode manipulation framework
+Copyright (c) 2000-2011 INRIA, France Telecom
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+  notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+  notice, this list of conditions and the following disclaimer in the
+  documentation and/or other materials provided with the distribution.
+3. Neither the name of the copyright holders nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/apache-maven/src/main/appended-resources/licenses/unrecognized-stax2-api-4.2.1.txt b/apache-maven/src/main/appended-resources/licenses/unrecognized-stax2-api-4.2.1.txt
new file mode 100644
index 0000000..df1288e
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/unrecognized-stax2-api-4.2.1.txt
@@ -0,0 +1,3 @@
+Copyright (c) 2008 FasterXML LLC info@fasterxml.com
+
+This source code is licensed under standard BSD license, which is compatible with all Free and Open Software (OSS) licenses.
\ No newline at end of file
diff --git a/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java b/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java
index 70a1115..cf1bf06 100644
--- a/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java
+++ b/apache-maven/src/test/java/org/apache/maven/settings/GlobalSettingsTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings;
 
 import java.io.File;
-import java.io.FileInputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
+import java.io.InputStream;
+import java.nio.file.Files;
 
-import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader;
+import org.apache.maven.api.settings.InputSource;
+import org.apache.maven.settings.v4.SettingsStaxReader;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -33,24 +31,18 @@
 /**
  * Tests that the global settings.xml shipped with the distribution is in good state.
  *
- * @author Benjamin Bentmann
  */
-public class GlobalSettingsTest
-{
+class GlobalSettingsTest {
 
     @Test
-    public void testValidGlobalSettings()
-        throws Exception
-    {
-        String basedir = System.getProperty( "basedir", System.getProperty( "user.dir" ) );
+    void testValidGlobalSettings() throws Exception {
+        String basedir = System.getProperty("basedir", System.getProperty("user.dir"));
 
-        File globalSettingsFile = new File( basedir, "src/assembly/maven/conf/settings.xml" );
-        assertTrue( globalSettingsFile.isFile(), globalSettingsFile.getAbsolutePath() );
+        File globalSettingsFile = new File(basedir, "src/assembly/maven/conf/settings.xml");
+        assertTrue(globalSettingsFile.isFile(), globalSettingsFile.getAbsolutePath());
 
-        try ( Reader reader = new InputStreamReader( new FileInputStream( globalSettingsFile ), StandardCharsets.UTF_8) )
-        {
-            new SettingsXpp3Reader().read( reader );
+        try (InputStream is = Files.newInputStream(globalSettingsFile.toPath())) {
+            new SettingsStaxReader().read(is, true, new InputSource(globalSettingsFile.getAbsolutePath()));
         }
     }
-
 }
diff --git a/api/maven-api-core/pom.xml b/api/maven-api-core/pom.xml
new file mode 100644
index 0000000..31002af
--- /dev/null
+++ b/api/maven-api-core/pom.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-core</artifactId>
+  <name>Maven 4 API :: Core</name>
+  <description>Maven 4 API - Maven Core API</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-meta</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-model</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-settings</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-toolchain</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-plugin</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>jakarta.inject</groupId>
+      <artifactId>jakarta.inject-api</artifactId>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java
new file mode 100644
index 0000000..b2d68f1
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Artifact.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * An artifact points to a resource such as a jar file or war application.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface Artifact {
+
+    /**
+     * Returns a unique identifier for this artifact.
+     * The identifier is composed of groupId, artifactId, extension, classifier, and version.
+     *
+     * @return the unique identifier
+     */
+    @Nonnull
+    default String key() {
+        return getGroupId()
+                + ':'
+                + getArtifactId()
+                + ':'
+                + getExtension()
+                + (getClassifier().isEmpty() ? "" : ":" + getClassifier())
+                + ':'
+                + getVersion();
+    }
+
+    /**
+     * The groupId of the artifact.
+     *
+     * @return the groupId
+     */
+    @Nonnull
+    String getGroupId();
+
+    /**
+     * The artifactId of the artifact.
+     *
+     * @return the artifactId
+     */
+    @Nonnull
+    String getArtifactId();
+
+    /**
+     * The version of the artifact.
+     *
+     * @return the version
+     */
+    @Nonnull
+    Version getVersion();
+
+    /**
+     * The classifier of the artifact.
+     *
+     * @return the classifier or an empty string if none, never {@code null}
+     */
+    @Nonnull
+    String getClassifier();
+
+    /**
+     * The file extension of the artifact.
+     *
+     * @return the extension
+     */
+    @Nonnull
+    String getExtension();
+
+    /**
+     * Determines whether this artifact uses a snapshot version.
+     *
+     * @return {@code true} if the artifact is a snapshot, {@code false} otherwise
+     * @see org.apache.maven.api.Session#isVersionSnapshot(String)
+     */
+    boolean isSnapshot();
+
+    /**
+     * Shortcut for {@code session.createArtifactCoordinate(artifact)}
+     *
+     * @return an {@link ArtifactCoordinate}
+     * @see org.apache.maven.api.Session#createArtifactCoordinate(Artifact)
+     */
+    @Nonnull
+    ArtifactCoordinate toCoordinate();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinate.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinate.java
new file mode 100644
index 0000000..553e60f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ArtifactCoordinate.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The {@code Coordinate} object is used to point to an {@link Artifact}
+ * but the version may be specified as a range instead of an exact version.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactCoordinate {
+
+    /**
+     * The groupId of the artifact.
+     *
+     * @return the groupId
+     */
+    @Nonnull
+    String getGroupId();
+
+    /**
+     * The artifactId of the artifact.
+     *
+     * @return the artifactId
+     */
+    @Nonnull
+    String getArtifactId();
+
+    /**
+     * The classifier of the artifact.
+     *
+     * @return the classifier or an empty string if none, never {@code null}
+     */
+    @Nonnull
+    String getClassifier();
+
+    /**
+     * The version of the artifact.
+     *
+     * @return the version
+     */
+    @Nonnull
+    VersionRange getVersion();
+
+    /**
+     * The extension of the artifact.
+     *
+     * @return the extension or an empty string if none, never {@code null}
+     */
+    @Nonnull
+    String getExtension();
+
+    /**
+     * Unique id identifying this artifact
+     */
+    @Nonnull
+    default String getId() {
+        return getGroupId()
+                + ":" + getArtifactId()
+                + ":" + getExtension()
+                + (getClassifier().isEmpty() ? "" : ":" + getClassifier())
+                + ":" + getVersion();
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java
new file mode 100644
index 0000000..efad141
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Dependency.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Nonnull;
+
+public interface Dependency extends Artifact {
+
+    /**
+     * The dependency type.
+     *
+     * @return the dependency type, never {@code null}
+     */
+    @Nonnull
+    Type getType();
+
+    /**
+     * The dependency properties.
+     *
+     * @return the dependency properties, never {@code null}
+     */
+    @Nonnull
+    DependencyProperties getDependencyProperties();
+
+    @Nonnull
+    Scope getScope();
+
+    boolean isOptional();
+
+    /**
+     * Creates a {@code DependencyCoordinate} based on this {@code Dependency}.
+     *
+     * @return a {@link DependencyCoordinate}
+     */
+    @Nonnull
+    DependencyCoordinate toCoordinate();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinate.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinate.java
new file mode 100644
index 0000000..7ba4bd1
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyCoordinate.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Collection;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface DependencyCoordinate extends ArtifactCoordinate {
+    /**
+     * The type of the artifact.
+     *
+     * @return the type
+     */
+    @Nonnull
+    Type getType();
+
+    @Nonnull
+    Scope getScope();
+
+    @Nullable
+    Boolean getOptional();
+
+    @Nonnull
+    Collection<Exclusion> getExclusions();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java
new file mode 100644
index 0000000..9f63416
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyProperties.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Map;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Dependency properties supported by Maven Core.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface DependencyProperties {
+    /**
+     * Boolean flag telling that dependency contains all of its dependencies. Value of this key should be parsed with
+     * {@link Boolean#parseBoolean(String)} to obtain value.
+     * <p>
+     * <em>Important: this flag must be kept in sync with resolver! (as is used during collection)</em>
+     */
+    String FLAG_INCLUDES_DEPENDENCIES = "includesDependencies";
+
+    /**
+     * Boolean flag telling that dependency is meant to be placed on class path. Value of this key should be parsed with
+     * {@link Boolean#parseBoolean(String)} to obtain value.
+     */
+    String FLAG_CLASS_PATH_CONSTITUENT = "classPathConstituent";
+
+    /**
+     * Returns immutable "map view" of all the properties.
+     */
+    @Nonnull
+    Map<String, String> asMap();
+
+    /**
+     * Returns {@code true} if given flag is {@code true}.
+     */
+    boolean checkFlag(@Nonnull String flag);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Event.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Event.java
new file mode 100644
index 0000000..0323abd
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Event.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Optional;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Event sent by maven during various phases of the build process.
+ * Such events can be listened to using {@link Listener}s objects
+ * registered in the {@link Session}.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface Event {
+
+    /**
+     * Gets the type of the event.
+     *
+     * @return the type of the event, never {@code null}
+     */
+    @Nonnull
+    EventType getType();
+
+    /**
+     * Gets the session from which this event originates.
+     *
+     * @return the current session, never {@code null}
+     */
+    @Nonnull
+    Session getSession();
+
+    /**
+     * Gets the current project (if any).
+     *
+     * @return the current project or {@code empty()} if not applicable
+     */
+    @Nonnull
+    Optional<Project> getProject();
+
+    /**
+     * Gets the current mojo execution (if any).
+     *
+     * @return the current mojo execution or {@code empty()} if not applicable
+     */
+    @Nonnull
+    Optional<MojoExecution> getMojoExecution();
+
+    /**
+     * Gets the exception that caused the event (if any).
+     *
+     * @return the exception or {@code empty()} if none
+     */
+    Optional<Exception> getException();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/EventType.java b/api/maven-api-core/src/main/java/org/apache/maven/api/EventType.java
new file mode 100644
index 0000000..63d3479
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/EventType.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The possible types of execution events.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public enum EventType {
+    PROJECT_DISCOVERY_STARTED,
+    SESSION_STARTED,
+    SESSION_ENDED,
+    PROJECT_SKIPPED,
+    PROJECT_STARTED,
+    PROJECT_SUCCEEDED,
+    PROJECT_FAILED,
+    MOJO_SKIPPED,
+    MOJO_STARTED,
+    MOJO_SUCCEEDED,
+    MOJO_FAILED,
+    FORK_STARTED,
+    FORK_SUCCEEDED,
+    FORK_FAILED,
+    FORKED_PROJECT_STARTED,
+    FORKED_PROJECT_SUCCEEDED,
+    FORKED_PROJECT_FAILED,
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Exclusion.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Exclusion.java
new file mode 100644
index 0000000..3c578c0
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Exclusion.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * A dependency exclusion.
+ *
+ * @since 4.0.0
+ * @see DependencyCoordinate#getExclusions()
+ */
+@Experimental
+public interface Exclusion {
+    @Nullable
+    String getGroupId();
+
+    @Nullable
+    String getArtifactId();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/JavaToolchain.java b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaToolchain.java
new file mode 100644
index 0000000..8420b65
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/JavaToolchain.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * A specific {@link Toolchain} dedicated for Java.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface JavaToolchain extends Toolchain {
+
+    String getJavaHome();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Listener.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Listener.java
new file mode 100644
index 0000000..dda744f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Listener.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A listener for session events.
+ * TODO: open this to other events like similar to {@code org.apache.maven.eventspy.EventSpy}
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@FunctionalInterface
+@Consumer
+public interface Listener {
+    void onEvent(@Nonnull Event event);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/LocalRepository.java b/api/maven-api-core/src/main/java/org/apache/maven/api/LocalRepository.java
new file mode 100644
index 0000000..5711e00
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/LocalRepository.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The local repository is used to cache artifacts downloaded from {@link RemoteRepository}
+ * and to hold artifacts that have been build locally.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface LocalRepository extends Repository {
+
+    @Nonnull
+    Path getPath();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/MetadataStorage.java b/api/maven-api-core/src/main/java/org/apache/maven/api/MetadataStorage.java
new file mode 100644
index 0000000..a7b8075
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/MetadataStorage.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Storage location for metadata
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public enum MetadataStorage {
+    GROUP,
+    ARTIFACT,
+    VERSION
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/MojoExecution.java b/api/maven-api-core/src/main/java/org/apache/maven/api/MojoExecution.java
new file mode 100644
index 0000000..2aa5d8a
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/MojoExecution.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Optional;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.api.xml.XmlNode;
+
+/**
+ * A {@code MojoExecution} represents a single execution of a Maven Plugin during a given build.
+ * An instance of this object is bound to the {@link org.apache.maven.api.di.MojoExecutionScoped}
+ * and available as {@code mojoExecution} within {@link org.apache.maven.api.plugin.annotations.Parameter}
+ * expressions.
+ */
+@Experimental
+public interface MojoExecution {
+
+    @Nonnull
+    Plugin getPlugin();
+
+    @Nonnull
+    PluginExecution getModel();
+
+    @Nonnull
+    MojoDescriptor getDescriptor();
+
+    @Nonnull
+    String getExecutionId();
+
+    @Nonnull
+    String getGoal();
+
+    @Nonnull
+    String getLifecyclePhase();
+
+    @Nonnull
+    Optional<XmlNode> getConfiguration();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Node.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Node.java
new file mode 100644
index 0000000..0d0e703
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Node.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Provider;
+
+/**
+ * Represents a dependency node within a Maven project's dependency collector.
+ *
+ * @since 4.0.0
+ * @see org.apache.maven.api.services.DependencyCollectorResult#getRoot()
+ */
+@Experimental
+@Immutable
+@Provider
+public interface Node {
+
+    /**
+     * @return dependency for this node
+     */
+    Dependency getDependency();
+
+    /**
+     * Gets the child nodes of this node.
+     *
+     * @return the child nodes of this node, never {@code null}
+     */
+    @Nonnull
+    List<Node> getChildren();
+
+    /**
+     * @return repositories of this node
+     */
+    @Nonnull
+    List<RemoteRepository> getRemoteRepositories();
+
+    /**
+     * The repository where this artifact has been downloaded from.
+     */
+    @Nonnull
+    Optional<RemoteRepository> getRepository();
+
+    /**
+     * Traverses this node and potentially its children using the specified visitor.
+     *
+     * @param visitor the visitor to call back, must not be {@code null}
+     * @return {@code true} to visit siblings nodes of this node as well, {@code false} to skip siblings
+     */
+    boolean accept(@Nonnull NodeVisitor visitor);
+
+    /**
+     * Returns a new tree starting at this node, filtering the children.
+     * Note that this node will not be filtered and only the children
+     * and its descendant will be checked.
+     *
+     * @param filter the filter to apply
+     * @return a new filtered graph
+     */
+    @Nonnull
+    Node filter(@Nonnull Predicate<Node> filter);
+
+    /**
+     * Returns a string representation of this dependency node.
+     *
+     * @return the string representation
+     */
+    @Nonnull
+    String asString();
+
+    /**
+     * Obtain a Stream containing this node and all its descendant.
+     *
+     * @return a stream containing this node and its descendant
+     */
+    @Nonnull
+    default Stream<Node> stream() {
+        return Stream.concat(Stream.of(this), getChildren().stream().flatMap(Node::stream));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/NodeVisitor.java b/api/maven-api-core/src/main/java/org/apache/maven/api/NodeVisitor.java
new file mode 100644
index 0000000..a09fc95
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/NodeVisitor.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Defines a hierarchical visitor for collecting dependency node trees.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Consumer
+public interface NodeVisitor {
+    /**
+     * Starts the visit to the specified dependency node.
+     *
+     * @param node the dependency node to visit
+     * @return <code>true</code> to visit the specified dependency node's children, <code>false</code> to skip the
+     *         specified dependency node's children and proceed to its next sibling
+     */
+    boolean enter(@Nonnull Node node);
+
+    /**
+     * Ends the visit to the specified dependency node.
+     *
+     * @param node the dependency node to visit
+     * @return <code>true</code> to visit the specified dependency node's next sibling, <code>false</code> to skip the
+     *         specified dependency node's next siblings and proceed to its parent
+     */
+    boolean leave(@Nonnull Node node);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Plugin.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Plugin.java
new file mode 100644
index 0000000..66f93d2
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Plugin.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.api.plugin.descriptor.lifecycle.Lifecycle;
+
+/**
+ * Represents a maven plugin runtime
+ */
+@Experimental
+public interface Plugin {
+
+    @Nonnull
+    org.apache.maven.api.model.Plugin getModel();
+
+    @Nonnull
+    PluginDescriptor getDescriptor();
+
+    @Nonnull
+    List<Lifecycle> getLifecycles();
+
+    @Nonnull
+    ClassLoader getClassLoader();
+
+    @Nonnull
+    Artifact getArtifact();
+
+    @Nonnull
+    default Collection<Dependency> getDependencies() {
+        return getDependenciesMap().values();
+    }
+
+    @Nonnull
+    Map<String, Dependency> getDependenciesMap();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java
new file mode 100644
index 0000000..256fe94
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Project.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Model;
+
+/**
+ * Interface representing a Maven project.
+ * Projects can be built using the {@link org.apache.maven.api.services.ProjectBuilder} service.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface Project {
+
+    @Nonnull
+    String getGroupId();
+
+    @Nonnull
+    String getArtifactId();
+
+    @Nonnull
+    String getVersion();
+
+    @Nonnull
+    String getPackaging();
+
+    @Nonnull
+    Artifact getArtifact();
+
+    @Nonnull
+    Model getModel();
+
+    @Nonnull
+    default Build getBuild() {
+        Build build = getModel().getBuild();
+        return build != null ? build : Build.newInstance();
+    }
+
+    /**
+     * Returns the path to the pom file for this project.
+     * A project is usually read from the file system and this will point to
+     * the file.  In some cases, a transient project can be created which
+     * will not point to an actual pom file.
+     * @return the path of the pom
+     */
+    @Nonnull
+    Optional<Path> getPomPath();
+
+    @Nonnull
+    default Optional<Path> getBasedir() {
+        return getPomPath().map(Path::getParent);
+    }
+
+    @Nonnull
+    List<DependencyCoordinate> getDependencies();
+
+    @Nonnull
+    List<DependencyCoordinate> getManagedDependencies();
+
+    @Nonnull
+    default String getId() {
+        return getModel().getId();
+    }
+
+    /**
+     * @deprecated use {@link #isTopProject()} instead
+     */
+    @Deprecated
+    boolean isExecutionRoot();
+
+    /**
+     * Returns a boolean indicating if the project is the top level project for
+     * this reactor build.  The top level project may be different from the
+     * {@code rootDirectory}, especially if a subtree of the project is being
+     * built, either because Maven has been launched in a subdirectory or using
+     * a {@code -f} option.
+     *
+     * @return {@code true} if the project is the top level project for this build
+     */
+    boolean isTopProject();
+
+    /**
+     * Returns a boolean indicating if the project is a root project,
+     * meaning that the {@link #getRootDirectory()} and {@link #getBasedir()}
+     * points to the same directory, and that either {@link Model#isRoot()}
+     * is {@code true} or that {@code basedir} contains a {@code .mvn} child
+     * directory.
+     *
+     * @return {@code true} if the project is the root project
+     * @see Model#isRoot()
+     */
+    boolean isRootProject();
+
+    /**
+     * Gets the root directory of the project, which is the parent directory
+     * containing the {@code .mvn} directory or flagged with {@code root="true"}.
+     *
+     * @throws IllegalStateException if the root directory could not be found
+     * @see Session#getRootDirectory()
+     */
+    @Nonnull
+    Path getRootDirectory();
+
+    @Nonnull
+    Optional<Project> getParent();
+
+    @Nonnull
+    List<RemoteRepository> getRemoteProjectRepositories();
+
+    @Nonnull
+    List<RemoteRepository> getRemotePluginRepositories();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/RemoteRepository.java b/api/maven-api-core/src/main/java/org/apache/maven/api/RemoteRepository.java
new file mode 100644
index 0000000..98dadef
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/RemoteRepository.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A remote repository that can be used to download or upload artifacts.
+ */
+@Experimental
+@Immutable
+public interface RemoteRepository extends Repository {
+
+    @Nonnull
+    String getUrl();
+
+    @Nonnull
+    String getProtocol();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Repository.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Repository.java
new file mode 100644
index 0000000..f437a6e
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Repository.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A repository holds artifacts.
+ *
+ * @since 4.0.0
+ * @see RemoteRepository
+ * @see LocalRepository
+ */
+@Experimental
+@Immutable
+public interface Repository {
+
+    /**
+     * The reserved id for Maven Central
+     */
+    String CENTRAL_ID = "central";
+
+    /**
+     * Gets the identifier of this repository.
+     *
+     * @return the (case-sensitive) identifier, never {@code null}
+     */
+    @Nonnull
+    String getId();
+
+    /**
+     * Gets the type of the repository, for example "default".
+     *
+     * @return the (case-sensitive) type of the repository, never {@code null}
+     */
+    @Nonnull
+    String getType();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/ResolutionScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/ResolutionScope.java
new file mode 100644
index 0000000..ee7eb78
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/ResolutionScope.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Dependencies resolution scopes available before
+ * <a href="/ref/current/maven-core/apidocs/org/apache/maven/lifecycle/internal/MojoExecutor.html">mojo execution</a>.
+ *
+ * Important note: The {@code id} values of this enum correspond to constants of
+ * {@code org.apache.maven.artifact.Artifact} class and MUST BE KEPT IN SYNC.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public enum ResolutionScope {
+    /**
+     * empty resolution scope
+     */
+    NONE(null),
+    /**
+     * <code>compile</code> resolution scope
+     * = <code>compile</code> + <code>system</code> + <code>provided</code> dependencies
+     */
+    COMPILE("compile", Scope.COMPILE, Scope.SYSTEM, Scope.PROVIDED),
+    /**
+     * <code>compile+runtime</code> resolution scope (Maven 3 only)
+     * = <code>compile</code> + <code>system</code> + <code>provided</code> + <code>runtime</code> dependencies
+     */
+    COMPILE_PLUS_RUNTIME("compile+runtime", Scope.COMPILE, Scope.SYSTEM, Scope.PROVIDED, Scope.RUNTIME),
+    /**
+     * <code>runtime</code> resolution scope
+     * = <code>compile</code> + <code>runtime</code> dependencies
+     */
+    RUNTIME("runtime", Scope.COMPILE, Scope.RUNTIME),
+    /**
+     * <code>runtime+system</code> resolution scope (Maven 3 only)
+     * = <code>compile</code> + <code>system</code> + <code>runtime</code> dependencies
+     */
+    RUNTIME_PLUS_SYSTEM("runtime+system", Scope.COMPILE, Scope.SYSTEM, Scope.RUNTIME),
+    /**
+     * <code>test</code> resolution scope
+     * = <code>compile</code> + <code>system</code> + <code>provided</code> + <code>runtime</code> + <code>test</code>
+     * dependencies
+     */
+    TEST("test", Scope.COMPILE, Scope.SYSTEM, Scope.PROVIDED, Scope.RUNTIME, Scope.TEST);
+
+    private static final Map<String, ResolutionScope> VALUES =
+            Stream.of(ResolutionScope.values()).collect(Collectors.toMap(ResolutionScope::id, s -> s));
+
+    public static ResolutionScope fromString(String id) {
+        return Optional.ofNullable(VALUES.get(id))
+                .orElseThrow(() -> new IllegalArgumentException("Unknown resolution scope " + id));
+    }
+
+    private final String id;
+    private final Set<Scope> scopes;
+
+    ResolutionScope(String id, Scope... scopes) {
+        this.id = id;
+        this.scopes = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(scopes)));
+    }
+
+    public String id() {
+        return this.id;
+    }
+
+    public Set<Scope> scopes() {
+        return scopes;
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java
new file mode 100644
index 0000000..dea7f29
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Scope.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Locale;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Scope for a dependency
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public enum Scope {
+    COMPILE("compile"),
+    PROVIDED("provided"),
+    SYSTEM("system"),
+    RUNTIME("runtime"),
+    TEST("test"),
+    IMPORT("import");
+
+    private final String id;
+
+    Scope(String id) {
+        this.id = id;
+    }
+
+    public String id() {
+        return this.id;
+    }
+
+    public static Scope get(String scope) {
+        return Enum.valueOf(Scope.class, scope.toUpperCase(Locale.ROOT));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Service.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Service.java
new file mode 100644
index 0000000..5f53c06
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Service.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.ThreadSafe;
+
+/**
+ * Marker interface for all services provided by the {@link Session}.
+ * <p>
+ * Services can be retrieved from the session using the
+ * {@link Session#getService(Class)} method.
+ *
+ * @see Session#getService(Class)
+ */
+@Experimental
+@ThreadSafe
+public interface Service {}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
new file mode 100644
index 0000000..ed396b8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Session.java
@@ -0,0 +1,368 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.nio.file.Path;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.ThreadSafe;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.api.services.DependencyCoordinateFactory;
+import org.apache.maven.api.settings.Settings;
+
+/**
+ * The session to install / deploy / resolve artifacts and dependencies.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@ThreadSafe
+public interface Session {
+
+    @Nonnull
+    Settings getSettings();
+
+    @Nonnull
+    LocalRepository getLocalRepository();
+
+    @Nonnull
+    List<RemoteRepository> getRemoteRepositories();
+
+    @Nonnull
+    SessionData getData();
+
+    /**
+     * Gets the user properties to use for interpolation. The user properties have been configured directly by the user,
+     * e.g. via the {@code -Dkey=value} parameter on the command line.
+     *
+     * @return the user properties, never {@code null}
+     */
+    @Nonnull
+    Map<String, String> getUserProperties();
+
+    /**
+     * Gets the system properties to use for interpolation. The system properties are collected from the runtime
+     * environment such as {@link System#getProperties()} and environment variables.
+     *
+     * @return the system properties, never {@code null}
+     */
+    @Nonnull
+    Map<String, String> getSystemProperties();
+
+    /**
+     * Returns the current maven version
+     * @return the maven version, never {@code null}
+     */
+    @Nonnull
+    String getMavenVersion();
+
+    int getDegreeOfConcurrency();
+
+    @Nonnull
+    Instant getStartTime();
+
+    /**
+     * Gets the directory of the topmost project being built, usually the current directory or the
+     * directory pointed at by the {@code -f/--file} command line argument.
+     */
+    @Nonnull
+    Path getTopDirectory();
+
+    /**
+     * Gets the root directory of the session, which is the root directory for the top directory project.
+     *
+     * @throws IllegalStateException if the root directory could not be found
+     * @see #getTopDirectory()
+     * @see Project#getRootDirectory()
+     */
+    @Nonnull
+    Path getRootDirectory();
+
+    @Nonnull
+    List<Project> getProjects();
+
+    /**
+     * Returns the plugin context for mojo being executed and the specified
+     * {@link Project}, never returns {@code null} as if context not present, creates it.
+     *
+     * <strong>Implementation note:</strong> while this method return type is {@link Map}, the
+     * returned map instance implements {@link java.util.concurrent.ConcurrentMap} as well.
+     *
+     * @throws org.apache.maven.api.services.MavenException if not called from the within a mojo execution
+     */
+    @Nonnull
+    Map<String, Object> getPluginContext(@Nonnull Project project);
+
+    /**
+     * Retrieves the service for the interface
+     *
+     * @throws NoSuchElementException if the service could not be found
+     */
+    @Nonnull
+    <T extends Service> T getService(@Nonnull Class<T> clazz);
+
+    /**
+     * Creates a derived session using the given local repository.
+     *
+     * @param localRepository the new local repository
+     * @return the derived session
+     * @throws NullPointerException if {@code localRepository} is null
+     */
+    @Nonnull
+    Session withLocalRepository(@Nonnull LocalRepository localRepository);
+
+    /**
+     * Creates a derived session using the given remote repositories.
+     *
+     * @param repositories the new list of remote repositories
+     * @return the derived session
+     * @throws NullPointerException if {@code repositories} is null
+     */
+    @Nonnull
+    Session withRemoteRepositories(@Nonnull List<RemoteRepository> repositories);
+
+    /**
+     * Register the given listener which will receive all events.
+     *
+     * @param listener the listener to register
+     * @throws NullPointerException if {@code listener} is null
+     */
+    void registerListener(@Nonnull Listener listener);
+
+    /**
+     * Unregisters a previously registered listener.
+     *
+     * @param listener the listener to unregister
+     * @throws NullPointerException if {@code listener} is null
+     */
+    void unregisterListener(@Nonnull Listener listener);
+
+    /**
+     * Returns the list of registered listeners.
+     *
+     * @return an immutable collection of listeners, never {@code null}
+     */
+    @Nonnull
+    Collection<Listener> getListeners();
+
+    /**
+     * Shortcut for <code>getService(RepositoryFactory.class).createLocal(...)</code>
+     * @see org.apache.maven.api.services.RepositoryFactory#createLocal(Path)
+     */
+    LocalRepository createLocalRepository(Path path);
+
+    /**
+     * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
+     * @see org.apache.maven.api.services.RepositoryFactory#createRemote(String, String)
+     */
+    @Nonnull
+    RemoteRepository createRemoteRepository(@Nonnull String id, @Nonnull String url);
+
+    /**
+     * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
+     * @see org.apache.maven.api.services.RepositoryFactory#createRemote(Repository)
+     */
+    @Nonnull
+    RemoteRepository createRemoteRepository(@Nonnull Repository repository);
+
+    /**
+     * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
+     * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String)
+     */
+    ArtifactCoordinate createArtifactCoordinate(String groupId, String artifactId, String version, String extension);
+
+    /**
+     * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
+     * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
+     */
+    ArtifactCoordinate createArtifactCoordinate(
+            String groupId, String artifactId, String version, String classifier, String extension, String type);
+
+    /**
+     * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
+     * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
+     */
+    ArtifactCoordinate createArtifactCoordinate(Artifact artifact);
+
+    /**
+     * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
+     * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate)
+     */
+    @Nonnull
+    DependencyCoordinate createDependencyCoordinate(@Nonnull ArtifactCoordinate coordinate);
+
+    /**
+     * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
+     * @see DependencyCoordinateFactory#create(Session, Dependency)
+     */
+    @Nonnull
+    DependencyCoordinate createDependencyCoordinate(@Nonnull Dependency dependency);
+
+    /**
+     * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
+     * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String)
+     */
+    Artifact createArtifact(String groupId, String artifactId, String version, String extension);
+
+    /**
+     * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
+     * @see org.apache.maven.api.services.ArtifactFactory#create(Session, String, String, String, String, String, String)
+     */
+    Artifact createArtifact(
+            String groupId, String artifactId, String version, String classifier, String extension, String type);
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+     */
+    Artifact resolveArtifact(ArtifactCoordinate coordinate);
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+     */
+    Collection<Artifact> resolveArtifacts(ArtifactCoordinate... coordinates);
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+     */
+    Collection<Artifact> resolveArtifacts(Collection<? extends ArtifactCoordinate> coordinates);
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+     */
+    Artifact resolveArtifact(Artifact artifact);
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     * @see org.apache.maven.api.services.ArtifactResolver#resolve(Session, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactResolverException if the artifact resolution failed
+     */
+    Collection<Artifact> resolveArtifacts(Artifact... artifacts);
+
+    /**
+     * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
+     * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed
+     */
+    void installArtifacts(Artifact... artifacts);
+
+    /**
+     * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
+     * @see org.apache.maven.api.services.ArtifactInstaller#install(Session, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactInstallerException if the artifacts installation failed
+     */
+    void installArtifacts(Collection<Artifact> artifacts);
+
+    /**
+     * Shortcut for <code>getService(ArtifactDeployer.class).deploy(...)</code>
+     * @see org.apache.maven.api.services.ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
+     *
+     * @throws org.apache.maven.api.services.ArtifactDeployerException if the artifacts deployment failed
+     */
+    void deployArtifact(RemoteRepository repository, Artifact... artifacts);
+
+    /**
+     * Shortcut for <code>getService(ArtifactManager.class).setPath(...)</code>
+     * @see org.apache.maven.api.services.ArtifactManager#setPath(Artifact, Path)
+     */
+    void setArtifactPath(@Nonnull Artifact artifact, @Nonnull Path path);
+
+    /**
+     * Shortcut for <code>getService(ArtifactManager.class).getPath(...)</code>
+     * @see org.apache.maven.api.services.ArtifactManager#getPath(Artifact)
+     */
+    @Nonnull
+    Optional<Path> getArtifactPath(@Nonnull Artifact artifact);
+
+    /**
+     * Shortcut for <code>getService(ArtifactManager.class).isSnapshot(...)</code>
+     * @see org.apache.maven.api.services.VersionParser#isSnapshot(String)
+     */
+    boolean isVersionSnapshot(@Nonnull String version);
+
+    /**
+     * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
+     * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Artifact)
+     *
+     * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
+     */
+    @Nonnull
+    Node collectDependencies(@Nonnull Artifact artifact);
+
+    /**
+     * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
+     * @see org.apache.maven.api.services.DependencyCollector#collect(Session, Project)
+     *
+     * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
+     */
+    @Nonnull
+    Node collectDependencies(@Nonnull Project project);
+
+    /**
+     * Shortcut for <code>getService(DependencyCollector.class).resolve(...)</code>
+     * @see org.apache.maven.api.services.DependencyCollector#collect(Session, DependencyCoordinate)
+     *
+     * @throws org.apache.maven.api.services.DependencyCollectorException if the dependency collection failed
+     */
+    @Nonnull
+    Node collectDependencies(@Nonnull DependencyCoordinate dependency);
+
+    Path getPathForLocalArtifact(@Nonnull Artifact artifact);
+
+    Path getPathForRemoteArtifact(RemoteRepository remote, Artifact artifact);
+
+    /**
+     * Shortcut for <code>getService(VersionParser.class).parseVersion(...)</code>
+     * @see org.apache.maven.api.services.VersionParser#parseVersion(String)
+     *
+     * @throws org.apache.maven.api.services.VersionParserException if the parsing failed
+     */
+    @Nonnull
+    Version parseVersion(@Nonnull String version);
+
+    /**
+     * Shortcut for <code>getService(VersionParser.class).parseVersionRange(...)</code>
+     * @see org.apache.maven.api.services.VersionParser#parseVersionRange(String)
+     *
+     * @throws org.apache.maven.api.services.VersionParserException if the parsing failed
+     */
+    @Nonnull
+    VersionRange parseVersionRange(@Nonnull String versionRange);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/SessionData.java b/api/maven-api-core/src/main/java/org/apache/maven/api/SessionData.java
new file mode 100644
index 0000000..134e44d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/SessionData.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.function.Supplier;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.annotations.Provider;
+import org.apache.maven.api.annotations.ThreadSafe;
+
+/**
+ * A container for data that is specific to a session.
+ * All components may use this storage to associate arbitrary data with a session.
+ * <p>
+ * Unlike a cache, this session data is not subject to purging. For this same reason, session data should also not be
+ * abused as a cache (i.e. for storing values that can be re-calculated) to avoid memory exhaustion.
+ * <p>
+ * <strong>Note:</strong> Actual implementations must be thread-safe.
+ *
+ * @see Session#getData()
+ * @since 4.0.0
+ */
+@Experimental
+@ThreadSafe
+@Provider
+public interface SessionData {
+
+    /**
+     * Associates the specified session data with the given key.
+     *
+     * @param key the key under which to store the session data, must not be {@code null}
+     * @param value the data to associate with the key, may be {@code null} to remove the mapping
+     */
+    void set(@Nonnull Object key, @Nullable Object value);
+
+    /**
+     * Associates the specified session data with the given key if the key is currently mapped to the given value. This
+     * method provides an atomic compare-and-update of some key's value.
+     *
+     * @param key the key under which to store the session data, must not be {@code null}
+     * @param oldValue the expected data currently associated with the key, may be {@code null}
+     * @param newValue the data to associate with the key, may be {@code null} to remove the mapping
+     * @return {@code true} if the key mapping was successfully updated from the old value to the new value,
+     *         {@code false} if the current key mapping didn't match the expected value and was not updated.
+     */
+    boolean set(@Nonnull Object key, @Nullable Object oldValue, @Nullable Object newValue);
+
+    /**
+     * Gets the session data associated with the specified key.
+     *
+     * @param key the key for which to retrieve the session data, must not be {@code null}
+     * @return the session data associated with the key or {@code null} if none
+     */
+    @Nullable
+    Object get(@Nonnull Object key);
+
+    /**
+     * Retrieve of compute the data associated with the specified key.
+     *
+     * @param key the key for which to retrieve the session data, must not be {@code null}
+     * @param supplier the supplier will compute the new value
+     * @return the session data associated with the key
+     */
+    @Nullable
+    Object computeIfAbsent(@Nonnull Object key, @Nonnull Supplier<Object> supplier);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
new file mode 100644
index 0000000..053f230
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Toolchain.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import java.util.Map;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Toolchain interface.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface Toolchain {
+    /**
+     * get the type of toolchain.
+     *
+     * @return the toolchain type
+     */
+    String getType();
+
+    /**
+     * Gets the platform tool executable.
+     *
+     * @param toolName the tool platform independent tool name
+     * @return file representing the tool executable, or null if the tool cannot be found
+     */
+    String findTool(String toolName);
+
+    /**
+     * Let the toolchain decide if it matches requirements defined
+     * in the toolchain plugin configuration.
+     * @param requirements Map&lt;String, String&gt; key value pair, may not be {@code null}
+     * @return {@code true} if the requirements match, otherwise {@code false}
+     */
+    boolean matchesRequirements(Map<String, String> requirements);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
new file mode 100644
index 0000000..4401c82
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Type.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.model.Dependency;
+
+/**
+ * A dependency's {@code Type} is uniquely identified by a {@code String},
+ * and semantically represents a known <i>kind</i> of dependency.
+ * <p>
+ * It provides information about the file type (or extension) of the associated artifact,
+ * its default classifier, and how the artifact will be used in the build when creating
+ * classpaths.
+ * <p>
+ * For example, the type {@code java-source} has a {@code jar} extension and a
+ * {@code sources} classifier. The artifact and its dependencies should be added
+ * to the classpath.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface Type {
+
+    String POM = "pom";
+    String JAR = "jar";
+    String JAVA_SOURCE = "java-source";
+    String JAVADOC = "javadoc";
+    String MAVEN_PLUGIN = "maven-plugin";
+    String TEST_JAR = "test-jar";
+
+    /**
+     * Returns the dependency type id.
+     * The id uniquely identifies this <i>dependency type</i>.
+     *
+     * @return the id of this type, never {@code null}.
+     */
+    @Nonnull
+    String getId();
+
+    /**
+     * Get the file extension of artifacts of this type.
+     *
+     * @return the file extension, never {@code null}.
+     */
+    @Nonnull
+    String getExtension();
+
+    /**
+     * Get the default classifier associated to the dependency type.
+     * The default classifier can be overridden when specifying
+     * the {@link Dependency#getClassifier()}.
+     *
+     * @return the default classifier, or {@code null}.
+     */
+    @Nullable
+    String getClassifier();
+
+    /**
+     * Specifies if the artifact contains java classes and should be
+     * added to the classpath.
+     *
+     * @return if the artifact should be added to the class path
+     */
+    default boolean isAddedToClassPath() {
+        return getDependencyProperties().checkFlag(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT);
+    }
+
+    /**
+     * Specifies if the artifact already embeds its own dependencies.
+     * This is the case for JEE packages or similar artifacts such as
+     * WARs, EARs, etc.
+     *
+     * @return if the artifact's dependencies are included in the artifact
+     */
+    default boolean isIncludesDependencies() {
+        return getDependencyProperties().checkFlag(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES);
+    }
+
+    /**
+     * Gets the default properties associated with this dependency type.
+     *
+     * @return the default properties, never {@code null}.
+     */
+    @Nonnull
+    DependencyProperties getDependencyProperties();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java b/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java
new file mode 100644
index 0000000..367385f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/Version.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A version usually parsed using the {@link org.apache.maven.api.services.VersionParser} service.
+ *
+ * @since 4.0.0
+ * @see org.apache.maven.api.services.VersionParser#parseVersion(String)
+ * @see org.apache.maven.api.Session#parseVersion(String)
+ */
+@Experimental
+public interface Version extends Comparable<Version> {
+
+    // TODO: add access to the version information
+
+    /**
+     * Returns a string representation of this version.
+     * @return the string representation of this version
+     */
+    @Nonnull
+    String asString();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java
new file mode 100644
index 0000000..375ac5f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/VersionRange.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A range of versions.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface VersionRange {
+
+    // TODO: v4: add access to the version information
+
+    /**
+     * Determines whether the specified version is contained within this range.
+     *
+     * @param version the version to test, must not be {@code null}
+     * @return {@code true} if this range contains the specified version, {@code false} otherwise
+     */
+    boolean contains(@Nonnull Version version);
+
+    /**
+     * Returns a string representation of this version range
+     * @return the string representation of this version range
+     */
+    @Nonnull
+    String asString();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/di/MojoExecutionScoped.java b/api/maven-api-core/src/main/java/org/apache/maven/api/di/MojoExecutionScoped.java
new file mode 100644
index 0000000..2fcbe07
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/di/MojoExecutionScoped.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.di;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import jakarta.inject.Scope;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Indicates that the annotated bean has a lifespan limited to a given mojo execution,
+ * which means each mojo execution will result in a different instance being injected.
+ *
+ * @since 4.0.0
+ */
+@Scope
+@Documented
+@Retention(RUNTIME)
+@Target({TYPE, METHOD})
+public @interface MojoExecutionScoped {}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/di/SessionScoped.java b/api/maven-api-core/src/main/java/org/apache/maven/api/di/SessionScoped.java
new file mode 100644
index 0000000..d5e9a0d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/di/SessionScoped.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.di;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import jakarta.inject.Scope;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+/**
+ * Indicates that annotated component should be instantiated before session execution starts
+ * and discarded after session execution completes.
+ *
+ * @since 4.0.0
+ */
+@Scope
+@Documented
+@Retention(RUNTIME)
+@Target({TYPE, METHOD})
+public @interface SessionScoped {}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/feature/Features.java b/api/maven-api-core/src/main/java/org/apache/maven/api/feature/Features.java
new file mode 100644
index 0000000..027591c
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/feature/Features.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.feature;
+
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Centralized class for Maven Core feature information.
+ * Features configured are supposed to be final in a given maven session.
+ *
+ * @since 4.0.0
+ */
+public final class Features {
+
+    /**
+     * Name of the Maven user property to enable or disable the build/consumer POM feature.
+     *
+     * TODO: v4: remove experimental bit
+     */
+    public static final String BUILDCONSUMER = "maven.experimental.buildconsumer";
+
+    private Features() {}
+
+    /**
+     * Check if the build/consumer POM feature is active.
+     */
+    public static boolean buildConsumer(@Nullable Properties userProperties) {
+        return doGet(userProperties, BUILDCONSUMER, true);
+    }
+
+    /**
+     * Check if the build/consumer POM feature is active.
+     */
+    public static boolean buildConsumer(@Nullable Map<String, String> userProperties) {
+        return doGet(userProperties, BUILDCONSUMER, true);
+    }
+
+    /**
+     * Check if the build/consumer POM feature is active.
+     */
+    public static boolean buildConsumer(@Nullable Session session) {
+        return buildConsumer(session != null ? session.getUserProperties() : null);
+    }
+
+    private static boolean doGet(Properties userProperties, String key, boolean def) {
+        return doGet(userProperties != null ? userProperties.get(key) : null, def);
+    }
+
+    private static boolean doGet(Map<String, ?> userProperties, String key, boolean def) {
+        return doGet(userProperties != null ? userProperties.get(key) : null, def);
+    }
+
+    private static boolean doGet(Object val, boolean def) {
+        if (val instanceof Boolean) {
+            return (Boolean) val;
+        } else if (val != null) {
+            return Boolean.parseBoolean(val.toString());
+        } else {
+            return def;
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/LifecycleProvider.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/LifecycleProvider.java
new file mode 100644
index 0000000..05046da
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/LifecycleProvider.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin;
+
+import java.util.List;
+
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.plugin.descriptor.lifecycle.Lifecycle;
+
+/**
+ * Interface that can be provided by the plugin to wire in custom lifecycles
+ * leveraged using the {@link org.apache.maven.api.plugin.annotations.Execute}
+ * annotation.  If a {@code META-INF/maven/lifecycle.xml} file is packaged
+ * in the plugin, Maven will provide a default implementation that will parse
+ * the file and return the contained lifecycle definitions.
+ */
+@Experimental
+@Consumer
+public interface LifecycleProvider {
+
+    List<Lifecycle> getLifecycles();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
new file mode 100644
index 0000000..2e28129
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Log.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin;
+
+import java.util.function.Supplier;
+
+import org.apache.maven.api.annotations.Provider;
+
+/**
+ * This interface supplies the API for providing feedback to the user from the <code>Mojo</code>, using standard
+ * <code>Maven</code> channels.<br>
+ * There should be no big surprises here, although you may notice that the methods accept
+ * <code>java.lang.CharSequence</code> rather than <code>java.lang.String</code>. This is provided mainly as a
+ * convenience, to enable developers to pass things like <code>java.lang.StringBuffer</code> directly into the logger,
+ * rather than formatting first by calling <code>toString()</code>.
+ *
+ * @since 4.0.0
+ */
+@Provider
+public interface Log {
+    /**
+     * @return true if the <b>debug</b> error level is enabled
+     */
+    boolean isDebugEnabled();
+
+    /**
+     * Send a message to the user in the <b>debug</b> error level.
+     *
+     * @param content
+     */
+    void debug(CharSequence content);
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>debug</b> error level.<br>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void debug(CharSequence content, Throwable error);
+
+    /**
+     * Send an exception to the user in the <b>debug</b> error level.<br>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void debug(Throwable error);
+
+    void debug(Supplier<String> content);
+
+    void debug(Supplier<String> content, Throwable error);
+
+    /**
+     * @return true if the <b>info</b> error level is enabled
+     */
+    boolean isInfoEnabled();
+
+    /**
+     * Send a message to the user in the <b>info</b> error level.
+     *
+     * @param content
+     */
+    void info(CharSequence content);
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>info</b> error level.<br>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void info(CharSequence content, Throwable error);
+
+    /**
+     * Send an exception to the user in the <b>info</b> error level.<br>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void info(Throwable error);
+
+    void info(Supplier<String> content);
+
+    void info(Supplier<String> content, Throwable error);
+
+    /**
+     * @return true if the <b>warn</b> error level is enabled
+     */
+    boolean isWarnEnabled();
+
+    /**
+     * Send a message to the user in the <b>warn</b> error level.
+     *
+     * @param content
+     */
+    void warn(CharSequence content);
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>warn</b> error level.<br>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void warn(CharSequence content, Throwable error);
+
+    /**
+     * Send an exception to the user in the <b>warn</b> error level.<br>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void warn(Throwable error);
+
+    void warn(Supplier<String> content);
+
+    void warn(Supplier<String> content, Throwable error);
+
+    /**
+     * @return true if the <b>error</b> error level is enabled
+     */
+    boolean isErrorEnabled();
+
+    /**
+     * Send a message to the user in the <b>error</b> error level.
+     *
+     * @param content
+     */
+    void error(CharSequence content);
+
+    /**
+     * Send a message (and accompanying exception) to the user in the <b>error</b> error level.<br>
+     * The error's stacktrace will be output when this error level is enabled.
+     *
+     * @param content
+     * @param error
+     */
+    void error(CharSequence content, Throwable error);
+
+    /**
+     * Send an exception to the user in the <b>error</b> error level.<br>
+     * The stack trace for this exception will be output when this error level is enabled.
+     *
+     * @param error
+     */
+    void error(Throwable error);
+
+    void error(Supplier<String> content);
+
+    void error(Supplier<String> content, Throwable error);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
new file mode 100644
index 0000000..7c9603b
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/Mojo.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin;
+
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * This interface forms the contract required for <code>Mojos</code> to interact with the <code>Maven</code>
+ * infrastructure.<br>
+ * It features an <code>execute()</code> method, which triggers the Mojo's build-process behavior, and can throw
+ * a MojoException if error conditions occur.<br>
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@FunctionalInterface
+@Consumer
+public interface Mojo {
+    /**
+     * Perform whatever build-process behavior this <code>Mojo</code> implements.<br>
+     * This is the main trigger for the <code>Mojo</code> inside the <code>Maven</code> system, and allows
+     * the <code>Mojo</code> to communicate errors.
+     *
+     * @throws MojoException if a problem occurs
+     */
+    void execute();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
new file mode 100644
index 0000000..b4faf31
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/MojoException.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.services.MavenException;
+
+/**
+ * An exception occurring during the execution of a plugin.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class MojoException extends MavenException {
+
+    protected Object source;
+
+    protected String longMessage;
+
+    /**
+     * Construct a new <code>MojoException</code> exception providing the source and a short and long message:
+     * these messages are used to improve the message written at the end of Maven build.
+     */
+    public MojoException(Object source, String shortMessage, String longMessage) {
+        super(shortMessage);
+        this.source = source;
+        this.longMessage = longMessage;
+    }
+
+    /**
+     * Construct a new <code>MojoExecutionException</code> exception wrapping an underlying <code>Throwable</code>
+     * and providing a <code>message</code>.
+     */
+    public MojoException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Construct a new <code>MojoExecutionException</code> exception providing a <code>message</code>.
+     */
+    public MojoException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new {@code MojoExecutionException} exception wrapping an underlying {@code Throwable}.
+     *
+     * @param cause the cause which is saved for later retrieval by the {@link #getCause()} method.
+     *              A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
+     */
+    public MojoException(Throwable cause) {
+        super(cause);
+    }
+
+    public String getLongMessage() {
+        return longMessage;
+    }
+
+    public Object getSource() {
+        return source;
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Execute.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Execute.java
new file mode 100644
index 0000000..1cfdfc6
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Execute.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Used if your Mojo needs to fork a <a href="/ref/3.0.4/maven-core/lifecycles.html">lifecycle</a>.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface Execute {
+    /**
+     * Lifecycle phase to fork. Note that specifying a phase overrides specifying a goal.
+     * For custom lifecycle phase ids use {@link #customPhase()} instead.
+     * Only one of {@link #customPhase()} and {@link #phase()} must be set.
+     * @return the phase
+     */
+    @Nonnull
+    LifecyclePhase phase() default LifecyclePhase.NONE;
+
+    /**
+     * Custom lifecycle phase to fork. Note that specifying a phase overrides specifying a goal.
+     * This element should only be used for non-standard phases. For standard phases rather use {@link #phase()}.
+     * Only one of {@link #customPhase()} and {@link #phase()} must be set.
+     * @return the custom phase id
+     */
+    @Nonnull
+    String customPhase() default "";
+
+    /**
+     * Goal to fork. Note that specifying a phase overrides specifying a goal. The specified <code>goal</code> must be
+     * another goal of the same plugin.
+     * @return the goal
+     */
+    @Nonnull
+    String goal() default "";
+
+    /**
+     * Lifecycle id of the lifecycle that defines {@link #phase()}. Only valid in combination with {@link #phase()}. If
+     * not specified, Maven will use the lifecycle of the current build.
+     *
+     * @see <a href="https://maven.apache.org/maven-plugin-api/lifecycle-mappings.html">Lifecycle Mappings</a>
+     * @return the lifecycle id
+     */
+    @Nonnull
+    String lifecycle() default "";
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/LifecyclePhase.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/LifecyclePhase.java
new file mode 100644
index 0000000..b3ddb72
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/LifecyclePhase.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin.annotations;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * <a href="/ref/3.0.4/maven-core/lifecycles.html">Lifecycle phases</a>.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public enum LifecyclePhase {
+    VALIDATE("validate"),
+    INITIALIZE("initialize"),
+    GENERATE_SOURCES("generate-sources"),
+    PROCESS_SOURCES("process-sources"),
+    GENERATE_RESOURCES("generate-resources"),
+    PROCESS_RESOURCES("process-resources"),
+    COMPILE("compile"),
+    PROCESS_CLASSES("process-classes"),
+    GENERATE_TEST_SOURCES("generate-test-sources"),
+    PROCESS_TEST_SOURCES("process-test-sources"),
+    GENERATE_TEST_RESOURCES("generate-test-resources"),
+    PROCESS_TEST_RESOURCES("process-test-resources"),
+    TEST_COMPILE("test-compile"),
+    PROCESS_TEST_CLASSES("process-test-classes"),
+    TEST("test"),
+    PREPARE_PACKAGE("prepare-package"),
+    PACKAGE("package"),
+    PRE_INTEGRATION_TEST("pre-integration-test"),
+    INTEGRATION_TEST("integration-test"),
+    POST_INTEGRATION_TEST("post-integration-test"),
+    VERIFY("verify"),
+    INSTALL("install"),
+    DEPLOY("deploy"),
+
+    PRE_CLEAN("pre-clean"),
+    CLEAN("clean"),
+    POST_CLEAN("post-clean"),
+
+    PRE_SITE("pre-site"),
+    SITE("site"),
+    POST_SITE("post-site"),
+    SITE_DEPLOY("site-deploy"),
+
+    NONE("");
+
+    private final String id;
+
+    LifecyclePhase(String id) {
+        this.id = id;
+    }
+
+    public String id() {
+        return this.id;
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Mojo.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Mojo.java
new file mode 100644
index 0000000..11245b5
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Mojo.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.maven.api.ResolutionScope;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * This annotation will mark your class as a Mojo (ie. goal in a Maven plugin).
+ * The mojo can be annotated with {@code jakarta.inject.*} annotations.
+ * The {@link Parameter} annotation can be added on fields to inject data
+ * from the plugin configuration or from other components.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+@Inherited
+public @interface Mojo {
+    /**
+     * goal name (required).
+     * @return the goal name
+     */
+    @Nonnull
+    String name();
+
+    /**
+     * default phase to bind your mojo.
+     * @return the default phase
+     */
+    @Nonnull
+    LifecyclePhase defaultPhase() default LifecyclePhase.NONE;
+
+    /**
+     * the required dependency resolution scope.
+     * @return the required dependency resolution scope
+     */
+    @Nonnull
+    ResolutionScope dependencyResolutionRequired() default ResolutionScope.NONE;
+
+    /**
+     * the required dependency collection scope.
+     * @return the required dependency collection scope
+     */
+    @Nonnull
+    ResolutionScope dependencyCollectionRequired() default ResolutionScope.NONE;
+
+    /**
+     * does your mojo requires a project to be executed?
+     * @return requires a project
+     */
+    boolean projectRequired() default true;
+
+    /**
+     * if the Mojo uses the Maven project and its child modules.
+     * @return uses the Maven project and its child modules
+     */
+    boolean aggregator() default false;
+
+    /**
+     * does this Mojo need to be online to be executed?
+     * @return need to be online
+     */
+    boolean onlineRequired() default false;
+
+    /**
+     * TODO: v4: add a SPI for the configurator
+     * configurator bean name.
+     * @return the configurator bean name
+     */
+    @Nonnull
+    String configurator() default "";
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Parameter.java b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Parameter.java
new file mode 100644
index 0000000..415f6a5
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/plugin/annotations/Parameter.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.plugin.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Used to configure your Mojo parameters to be injected by
+ * <a href="/ref/current/maven-core/apidocs/org/apache/maven/plugin/MavenPluginManager.html">
+ * <code>MavenPluginManager.getConfiguredMojo(...)</code></a>.
+ * <p>
+ * Beans injected into Mojo parameters are prepared by <a href="https://www.eclipse.org/sisu/">Sisu</a> JSR330-based
+ * container: this annotation is only effective on fields of the Mojo class itself, nested bean injection
+ * requires Sisu or JSR330 annotations.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.FIELD, ElementType.METHOD})
+@Inherited
+public @interface Parameter {
+    /**
+     * name of the bean property used to get/set the field: by default, field name is used.
+     * @return the name of the bean property
+     */
+    @Nonnull
+    String name() default "";
+
+    /**
+     * alias supported to get parameter value.
+     * @return the alias
+     */
+    @Nonnull
+    String alias() default "";
+
+    /**
+     * Property to use to retrieve a value. Can come from <code>-D</code> execution, setting properties or pom
+     * properties.
+     * @return property name
+     */
+    @Nonnull
+    String property() default "";
+
+    /**
+     * parameter default value, may contain <code>${...}</code> expressions which will be interpreted at
+     * inject time: see
+     * <a href="/ref/current/maven-core/apidocs/org/apache/maven/plugin/PluginParameterExpressionEvaluator.html">
+     * PluginParameterExpressionEvaluator</a>.
+     * @return the default value
+     */
+    @Nonnull
+    String defaultValue() default "";
+
+    /**
+     * is the parameter required?
+     * @return <code>true</code> if the Mojo should fail when the parameter cannot be injected
+     */
+    boolean required() default false;
+
+    /**
+     * Specifies that this parameter cannot be configured directly by the user (as in the case of POM-specified
+     * configuration). This is useful when you want to force the user to use common POM elements rather than plugin
+     * configurations, as in the case where you want to use the artifact's final name as a parameter. In this case, you
+     * want the user to modify <code>&lt;build&gt;&lt;finalName/&gt;&lt;/build&gt;</code> rather than specifying a value
+     * for finalName directly in the plugin configuration section. It is also useful to ensure that - for example - a
+     * List-typed parameter which expects items of type Artifact doesn't get a List full of Strings.
+     *
+     * @return <code>true</code> if the user should not be allowed to configure the parameter directly
+     */
+    boolean readonly() default false;
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactory.java
new file mode 100644
index 0000000..ef88499
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactory.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service used to create {@link ArtifactCoordinate} objects.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ArtifactCoordinateFactory extends Service {
+
+    /**
+     * Creates a coordinate.
+     *
+     * @param request the request holding coordinate creation parameters
+     * @return an {@code Artifact}, never {@code null}
+     * @throws IllegalArgumentException if {@code request} is null or {@code request.session} is null or invalid
+     */
+    @Nonnull
+    ArtifactCoordinate create(@Nonnull ArtifactCoordinateFactoryRequest request);
+
+    @Nonnull
+    default ArtifactCoordinate create(
+            @Nonnull Session session, String groupId, String artifactId, String version, String extension) {
+        return create(ArtifactCoordinateFactoryRequest.build(session, groupId, artifactId, version, extension));
+    }
+
+    @Nonnull
+    default ArtifactCoordinate create(
+            @Nonnull Session session,
+            String groupId,
+            String artifactId,
+            String version,
+            String classifier,
+            String extension,
+            String type) {
+        return create(ArtifactCoordinateFactoryRequest.build(
+                session, groupId, artifactId, version, classifier, extension, type));
+    }
+
+    @Nonnull
+    default ArtifactCoordinate create(@Nonnull Session session, Artifact artifact) {
+        return create(ArtifactCoordinateFactoryRequest.build(
+                session,
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getVersion().asString(),
+                artifact.getClassifier(),
+                artifact.getExtension(),
+                null));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactoryRequest.java
new file mode 100644
index 0000000..c81b453
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactCoordinateFactoryRequest.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * A request for creating a {@link ArtifactCoordinate} object.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactCoordinateFactoryRequest {
+
+    @Nonnull
+    Session getSession();
+
+    String getGroupId();
+
+    String getArtifactId();
+
+    String getVersion();
+
+    String getClassifier();
+
+    String getExtension();
+
+    String getType();
+
+    @Nonnull
+    static ArtifactCoordinateFactoryRequest build(
+            @Nonnull Session session, String groupId, String artifactId, String version, String extension) {
+        return ArtifactCoordinateFactoryRequest.builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(groupId)
+                .artifactId(artifactId)
+                .version(version)
+                .extension(extension)
+                .build();
+    }
+
+    @Nonnull
+    static ArtifactCoordinateFactoryRequest build(
+            @Nonnull Session session,
+            String groupId,
+            String artifactId,
+            String version,
+            String classifier,
+            String extension,
+            String type) {
+        return ArtifactCoordinateFactoryRequest.builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(groupId)
+                .artifactId(artifactId)
+                .version(version)
+                .classifier(classifier)
+                .extension(extension)
+                .type(type)
+                .build();
+    }
+
+    @Nonnull
+    static ArtifactCoordinateFactoryRequest build(@Nonnull Session session, @Nonnull ArtifactCoordinate coordinate) {
+        return ArtifactCoordinateFactoryRequest.builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(nonNull(coordinate, "coordinate cannot be null").getGroupId())
+                .artifactId(coordinate.getArtifactId())
+                .classifier(coordinate.getClassifier())
+                .version(coordinate.getVersion().asString())
+                .extension(coordinate.getExtension())
+                .build();
+    }
+
+    static ArtifactFactoryRequestBuilder builder() {
+        return new ArtifactFactoryRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class ArtifactFactoryRequestBuilder {
+        private Session session;
+        private String groupId;
+        private String artifactId;
+        private String version;
+        private String classifier;
+        private String extension;
+        private String type;
+
+        ArtifactFactoryRequestBuilder() {}
+
+        public ArtifactFactoryRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder groupId(String groupId) {
+            this.groupId = groupId;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder artifactId(String artifactId) {
+            this.artifactId = artifactId;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder version(String version) {
+            this.version = version;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder classifier(String classifier) {
+            this.classifier = classifier;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder extension(String extension) {
+            this.extension = extension;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder type(String type) {
+            this.type = type;
+            return this;
+        }
+
+        public ArtifactCoordinateFactoryRequest build() {
+            return new DefaultArtifactFactoryRequestArtifact(
+                    session, groupId, artifactId, version, classifier, extension, type);
+        }
+
+        private static class DefaultArtifactFactoryRequestArtifact extends BaseRequest
+                implements ArtifactCoordinateFactoryRequest {
+            private final String groupId;
+            private final String artifactId;
+            private final String version;
+            private final String classifier;
+            private final String extension;
+            private final String type;
+
+            DefaultArtifactFactoryRequestArtifact(
+                    @Nonnull Session session,
+                    String groupId,
+                    String artifactId,
+                    String version,
+                    String classifier,
+                    String extension,
+                    String type) {
+                super(session);
+                this.groupId = groupId;
+                this.artifactId = artifactId;
+                this.version = version;
+                this.classifier = classifier;
+                this.extension = extension;
+                this.type = type;
+            }
+
+            @Override
+            public String getGroupId() {
+                return groupId;
+            }
+
+            @Override
+            public String getArtifactId() {
+                return artifactId;
+            }
+
+            @Override
+            public String getVersion() {
+                return version;
+            }
+
+            @Override
+            public String getClassifier() {
+                return classifier;
+            }
+
+            @Override
+            public String getExtension() {
+                return extension;
+            }
+
+            @Override
+            public String getType() {
+                return type;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployer.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployer.java
new file mode 100644
index 0000000..fbe97fe
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployer.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.Collection;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Deploys {@link Artifact}s to a {@link RemoteRepository}.
+ *
+ * @since 4.0.0
+ * @see Session#deployArtifact(RemoteRepository, Artifact...)
+ */
+@Experimental
+public interface ArtifactDeployer extends Service {
+
+    /**
+     * @param request {@link ArtifactDeployerRequest}
+     * @throws ArtifactDeployerException if the deployment failed
+     */
+    void deploy(@Nonnull ArtifactDeployerRequest request);
+
+    /**
+     * @param session the repository session
+     * @param repository the repository to deploy to
+     * @param artifacts the collection of artifacts to deploy
+     * @throws ArtifactDeployerException if the deployment failed
+     * @throws IllegalArgumentException if an argument is {@code null} or invalid
+     */
+    default void deploy(
+            @Nonnull Session session, @Nonnull RemoteRepository repository, @Nonnull Collection<Artifact> artifacts) {
+        deploy(ArtifactDeployerRequest.build(session, repository, artifacts));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerException.java
new file mode 100644
index 0000000..8b5b4e2
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * An artifact could not correctly being deployed.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class ArtifactDeployerException extends MavenException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 7421964724059077698L;
+
+    /**
+     * @param message the message of the error
+     * @param e {@link Exception}
+     */
+    public ArtifactDeployerException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
new file mode 100644
index 0000000..f5146bf
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactDeployerRequest.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.Collection;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * A request for deploying one or more artifacts to a remote repository.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactDeployerRequest {
+
+    @Nonnull
+    Session getSession();
+
+    @Nonnull
+    RemoteRepository getRepository();
+
+    @Nonnull
+    Collection<Artifact> getArtifacts();
+
+    int getRetryFailedDeploymentCount();
+
+    @Nonnull
+    static ArtifactDeployerRequestBuilder builder() {
+        return new ArtifactDeployerRequestBuilder();
+    }
+
+    @Nonnull
+    static ArtifactDeployerRequest build(
+            @Nonnull Session session, @Nonnull RemoteRepository repository, @Nonnull Collection<Artifact> artifacts) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .repository(nonNull(repository, "repository cannot be null"))
+                .artifacts(nonNull(artifacts, "artifacts cannot be null"))
+                .build();
+    }
+
+    class ArtifactDeployerRequestBuilder {
+        Session session;
+        RemoteRepository repository;
+        Collection<Artifact> artifacts;
+        int retryFailedDeploymentCount;
+
+        ArtifactDeployerRequestBuilder() {}
+
+        @Nonnull
+        public ArtifactDeployerRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        @Nonnull
+        public ArtifactDeployerRequestBuilder repository(RemoteRepository repository) {
+            this.repository = repository;
+            return this;
+        }
+
+        public ArtifactDeployerRequestBuilder artifacts(Collection<Artifact> artifacts) {
+            this.artifacts = artifacts;
+            return this;
+        }
+
+        public ArtifactDeployerRequestBuilder retryFailedDeploymentCount(int retryFailedDeploymentCount) {
+            this.retryFailedDeploymentCount = retryFailedDeploymentCount;
+            return this;
+        }
+
+        @Nonnull
+        public ArtifactDeployerRequest build() {
+            return new DefaultArtifactDeployerRequest(session, repository, artifacts, retryFailedDeploymentCount);
+        }
+
+        private static class DefaultArtifactDeployerRequest extends BaseRequest implements ArtifactDeployerRequest {
+
+            private final RemoteRepository repository;
+            private final Collection<Artifact> artifacts;
+            private final int retryFailedDeploymentCount;
+
+            DefaultArtifactDeployerRequest(
+                    @Nonnull Session session,
+                    @Nonnull RemoteRepository repository,
+                    @Nonnull Collection<Artifact> artifacts,
+                    int retryFailedDeploymentCount) {
+                super(session);
+                this.repository = nonNull(repository, "repository cannot be null");
+                this.artifacts = unmodifiable(nonNull(artifacts, "artifacts cannot be null"));
+                this.retryFailedDeploymentCount = retryFailedDeploymentCount;
+            }
+
+            @Nonnull
+            @Override
+            public RemoteRepository getRepository() {
+                return repository;
+            }
+
+            @Nonnull
+            @Override
+            public Collection<Artifact> getArtifacts() {
+                return artifacts;
+            }
+
+            @Override
+            public int getRetryFailedDeploymentCount() {
+                return retryFailedDeploymentCount;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactory.java
new file mode 100644
index 0000000..97cb179
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactory.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service used to create {@link Artifact} objects.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ArtifactFactory extends Service {
+
+    /**
+     * Creates an artifact.
+     *
+     * @param request the request holding artifact creation parameters
+     * @return an {@code Artifact}, never {@code null}
+     * @throws IllegalArgumentException if {@code request} is null or {@code request.session} is null or invalid
+     */
+    @Nonnull
+    Artifact create(@Nonnull ArtifactFactoryRequest request);
+
+    @Nonnull
+    default Artifact create(
+            @Nonnull Session session, String groupId, String artifactId, String version, String extension) {
+        return create(ArtifactFactoryRequest.build(session, groupId, artifactId, version, extension));
+    }
+
+    @Nonnull
+    default Artifact create(
+            @Nonnull Session session,
+            String groupId,
+            String artifactId,
+            String version,
+            String classifier,
+            String extension,
+            String type) {
+        return create(ArtifactFactoryRequest.build(session, groupId, artifactId, version, classifier, extension, type));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
new file mode 100644
index 0000000..41f1944
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactFactoryRequest.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ *
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactFactoryRequest {
+
+    @Nonnull
+    Session getSession();
+
+    String getGroupId();
+
+    String getArtifactId();
+
+    String getVersion();
+
+    String getClassifier();
+
+    String getExtension();
+
+    String getType();
+
+    static ArtifactFactoryRequest build(
+            Session session, String groupId, String artifactId, String version, String extension) {
+        return ArtifactFactoryRequest.builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(groupId)
+                .artifactId(artifactId)
+                .version(version)
+                .extension(extension)
+                .build();
+    }
+
+    static ArtifactFactoryRequest build(
+            Session session,
+            String groupId,
+            String artifactId,
+            String version,
+            String classifier,
+            String extension,
+            String type) {
+        return ArtifactFactoryRequest.builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(groupId)
+                .artifactId(artifactId)
+                .version(version)
+                .classifier(classifier)
+                .extension(extension)
+                .type(type)
+                .build();
+    }
+
+    static ArtifactFactoryRequestBuilder builder() {
+        return new ArtifactFactoryRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class ArtifactFactoryRequestBuilder {
+        private Session session;
+        private String groupId;
+        private String artifactId;
+        private String version;
+        private String classifier;
+        private String extension;
+        private String type;
+
+        ArtifactFactoryRequestBuilder() {}
+
+        public ArtifactFactoryRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder groupId(String groupId) {
+            this.groupId = groupId;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder artifactId(String artifactId) {
+            this.artifactId = artifactId;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder version(String version) {
+            this.version = version;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder classifier(String classifier) {
+            this.classifier = classifier;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder extension(String extension) {
+            this.extension = extension;
+            return this;
+        }
+
+        public ArtifactFactoryRequestBuilder type(String type) {
+            this.type = type;
+            return this;
+        }
+
+        public ArtifactFactoryRequest build() {
+            return new DefaultArtifactFactoryRequest(
+                    session, groupId, artifactId, version, classifier, extension, type);
+        }
+
+        private static class DefaultArtifactFactoryRequest extends BaseRequest implements ArtifactFactoryRequest {
+            private final String groupId;
+            private final String artifactId;
+            private final String version;
+            private final String classifier;
+            private final String extension;
+            private final String type;
+
+            DefaultArtifactFactoryRequest(
+                    @Nonnull Session session,
+                    String groupId,
+                    String artifactId,
+                    String version,
+                    String classifier,
+                    String extension,
+                    String type) {
+                super(session);
+                this.groupId = groupId;
+                this.artifactId = artifactId;
+                this.version = version;
+                this.classifier = classifier;
+                this.extension = extension;
+                this.type = type;
+            }
+
+            @Override
+            public String getGroupId() {
+                return groupId;
+            }
+
+            @Override
+            public String getArtifactId() {
+                return artifactId;
+            }
+
+            @Override
+            public String getVersion() {
+                return version;
+            }
+
+            @Override
+            public String getClassifier() {
+                return classifier;
+            }
+
+            @Override
+            public String getExtension() {
+                return extension;
+            }
+
+            @Override
+            public String getType() {
+                return type;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstaller.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstaller.java
new file mode 100644
index 0000000..00500ab
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstaller.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Installs {@link Artifact}s to the local repository.
+ *
+ * @since 4.0.0
+ * @see Session#withLocalRepository(org.apache.maven.api.LocalRepository)
+ */
+@Experimental
+public interface ArtifactInstaller extends Service {
+    /**
+     * @param request {@link ArtifactInstallerRequest}
+     * @throws ArtifactInstallerException in case of an error
+     * @throws IllegalArgumentException in case {@code request} is {@code null}
+     */
+    void install(@Nonnull ArtifactInstallerRequest request);
+
+    /**
+     * @param session the repository session
+     * @param artifact the {@link Artifact} to install
+     * @throws ArtifactInstallerException In case of an error which can be the a given artifact cannot be found or the
+     *             installation has failed.
+     * @throws IllegalArgumentException in case of parameter {@code session} is {@code null} or
+     *          {@code artifact} is {@code null}.
+     */
+    default void install(Session session, Artifact artifact) {
+        install(session, Collections.singletonList(artifact));
+    }
+
+    /**
+     * @param session the repository session
+     * @param artifacts Collection of {@link Artifact MavenArtifacts}
+     * @throws ArtifactInstallerException In case of an error which can be the a given artifact cannot be found or the
+     *             installation has failed.
+     * @throws IllegalArgumentException in case of parameter {@code request} is {@code null} or parameter
+     *             {@code localRepository} is {@code null} or {@code localRepository} is not a directory
+     *             or parameter {@code mavenArtifacts} is {@code null} or
+     *             {@code mavenArtifacts.isEmpty()} is {@code true}.
+     */
+    default void install(Session session, Collection<Artifact> artifacts) {
+        install(ArtifactInstallerRequest.build(session, artifacts));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerException.java
new file mode 100644
index 0000000..a019273
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerException.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * @since 4.0.0
+ */
+@Experimental
+public class ArtifactInstallerException extends MavenException {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 3652561971360586373L;
+
+    /**
+     * @param message the message of the error
+     * @param e {@link Exception}
+     */
+    public ArtifactInstallerException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
new file mode 100644
index 0000000..4ac0142
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactInstallerRequest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * A request for installing one or more artifacts in the local repository.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactInstallerRequest {
+
+    @Nonnull
+    Session getSession();
+
+    @Nonnull
+    Collection<Artifact> getArtifacts();
+
+    @Nonnull
+    static ArtifactInstallerRequestBuilder builder() {
+        return new ArtifactInstallerRequestBuilder();
+    }
+
+    @Nonnull
+    static ArtifactInstallerRequest build(Session session, Collection<Artifact> artifacts) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .artifacts(nonNull(artifacts, "artifacts cannot be null"))
+                .build();
+    }
+
+    @NotThreadSafe
+    class ArtifactInstallerRequestBuilder {
+        Session session;
+        Collection<Artifact> artifacts = Collections.emptyList();
+
+        ArtifactInstallerRequestBuilder() {}
+
+        @Nonnull
+        public ArtifactInstallerRequestBuilder session(@Nonnull Session session) {
+            this.session = session;
+            return this;
+        }
+
+        @Nonnull
+        public ArtifactInstallerRequestBuilder artifacts(@Nullable Collection<Artifact> artifacts) {
+            this.artifacts = artifacts != null ? artifacts : Collections.emptyList();
+            return this;
+        }
+
+        @Nonnull
+        public ArtifactInstallerRequest build() {
+            return new DefaultArtifactInstallerRequest(session, artifacts);
+        }
+
+        static class DefaultArtifactInstallerRequest extends BaseRequest implements ArtifactInstallerRequest {
+
+            private final Collection<Artifact> artifacts;
+
+            DefaultArtifactInstallerRequest(@Nonnull Session session, @Nonnull Collection<Artifact> artifacts) {
+                super(session);
+                this.artifacts = unmodifiable(nonNull(artifacts, "artifacts cannot be null"));
+            }
+
+            @Nonnull
+            @Override
+            public Collection<Artifact> getArtifacts() {
+                return artifacts;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactManager.java
new file mode 100644
index 0000000..1777ded
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactManager.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ArtifactManager extends Service {
+
+    /**
+     * Returns the path of the file previously associated to this artifact
+     * or {@code Optional.empty()} if no path has been associated.
+     */
+    @Nonnull
+    Optional<Path> getPath(@Nonnull Artifact artifact);
+
+    /**
+     * Associates the given file path to the artifact.
+     */
+    void setPath(@Nonnull Artifact artifact, Path path);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolver.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolver.java
new file mode 100644
index 0000000..c9f36fb
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolver.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.Collection;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Resolves the artifact, i.e download the file when required and attach it to the artifact
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ArtifactResolver extends Service {
+
+    /**
+     * @param request {@link ArtifactResolverRequest}
+     * @return {@link ArtifactResolverResult}
+     * @throws ArtifactResolverException in case of an error
+     * @throws IllegalArgumentException in case of parameter {@code buildingRequest} is {@code null} or
+     *             parameter {@code mavenArtifact} is {@code null} or invalid
+     */
+    ArtifactResolverResult resolve(ArtifactResolverRequest request);
+
+    /**
+     * @param session {@link Session}
+     * @param coordinates array of {@link ArtifactCoordinate}
+     * @return {@link ArtifactResolverResult}
+     * @throws ArtifactResolverException in case of an error.
+     * @throws IllegalArgumentException in case of parameter {@code buildingRequest} is {@code null} or
+     *             parameter {@code coordinate} is {@code null} or invalid
+     */
+    default ArtifactResolverResult resolve(Session session, Collection<? extends ArtifactCoordinate> coordinates) {
+        return resolve(ArtifactResolverRequest.build(session, coordinates));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverException.java
new file mode 100644
index 0000000..3836ec2
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverException.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ *
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class ArtifactResolverException extends MavenException {
+
+    private static final long serialVersionUID = 7252294837746943917L;
+
+    /**
+     * @param message the message for the exception
+     * @param e the exception itself
+     */
+    public ArtifactResolverException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
new file mode 100644
index 0000000..caa5942
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverRequest.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.Collection;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * A request for resolving an artifact.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface ArtifactResolverRequest {
+    @Nonnull
+    Session getSession();
+
+    @Nonnull
+    Collection<? extends ArtifactCoordinate> getCoordinates();
+
+    @Nonnull
+    static ArtifactResolverRequestBuilder builder() {
+        return new ArtifactResolverRequestBuilder();
+    }
+
+    @Nonnull
+    static ArtifactResolverRequest build(
+            @Nonnull Session session, @Nonnull Collection<? extends ArtifactCoordinate> coordinates) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .coordinates(nonNull(coordinates, "coordinates cannot be null"))
+                .build();
+    }
+
+    @NotThreadSafe
+    class ArtifactResolverRequestBuilder {
+        Session session;
+        Collection<? extends ArtifactCoordinate> coordinates;
+
+        ArtifactResolverRequestBuilder() {}
+
+        @Nonnull
+        public ArtifactResolverRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        @Nonnull
+        public ArtifactResolverRequestBuilder coordinates(Collection<? extends ArtifactCoordinate> coordinates) {
+            this.coordinates = coordinates;
+            return this;
+        }
+
+        @Nonnull
+        public ArtifactResolverRequest build() {
+            return new DefaultArtifactResolverRequest(session, coordinates);
+        }
+
+        private static class DefaultArtifactResolverRequest extends BaseRequest implements ArtifactResolverRequest {
+            @Nonnull
+            private final Collection<? extends ArtifactCoordinate> coordinates;
+
+            DefaultArtifactResolverRequest(
+                    @Nonnull Session session, @Nonnull Collection<? extends ArtifactCoordinate> coordinates) {
+                super(session);
+                this.coordinates = unmodifiable(nonNull(coordinates, "coordinates cannot be null"));
+            }
+
+            @Nonnull
+            @Override
+            public Collection<? extends ArtifactCoordinate> getCoordinates() {
+                return coordinates;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
new file mode 100644
index 0000000..749f400
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ArtifactResolverResult.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+import java.util.Map;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The Artifact Result
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ArtifactResolverResult {
+    /**
+     * @return {@link Artifact}
+     */
+    @Nonnull
+    Map<Artifact, Path> getArtifacts();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
new file mode 100644
index 0000000..8b77720
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BaseRequest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Base class for requests.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+abstract class BaseRequest {
+
+    private final Session session;
+
+    protected BaseRequest(@Nonnull Session session) {
+        this.session = nonNull(session, "session cannot be null");
+    }
+
+    @Nonnull
+    public Session getSession() {
+        return session;
+    }
+
+    public static <T> T nonNull(T obj, String message) {
+        if (obj == null) {
+            throw new IllegalArgumentException(message);
+        }
+        return obj;
+    }
+
+    protected static <T> Collection<T> unmodifiable(Collection<T> obj) {
+        return obj != null && !obj.isEmpty()
+                ? Collections.unmodifiableCollection(new ArrayList<>(obj))
+                : Collections.emptyList();
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuilderProblem.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuilderProblem.java
new file mode 100644
index 0000000..9e4cb45
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/BuilderProblem.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Describes a problem that was encountered during project building. A problem can either be an exception that was
+ * thrown or a simple string message. In addition, a problem carries a hint about its source.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface BuilderProblem {
+
+    /**
+     * Gets the hint about the source of the problem. While the syntax of this hint is unspecified and depends on the
+     * creator of the problem, the general expectation is that the hint provides sufficient information to the user to
+     * track the problem back to its origin. A concrete example for such a source hint can be the file path or URL from
+     * which the settings were read.
+     *
+     * @return the hint about the source of the problem or an empty string if unknown, never {@code null}
+     */
+    @Nonnull
+    String getSource();
+
+    /**
+     * Gets the one-based index of the line containing the problem. The line number should refer to some text file that
+     * is given by {@link #getSource()}.
+     *
+     * @return the one-based index of the line containing the problem or a non-positive value if unknown
+     */
+    int getLineNumber();
+
+    /**
+     * Gets the one-based index of the column containing the problem. The column number should refer to some text file
+     * that is given by {@link #getSource()}.
+     *
+     * @return the one-based index of the column containing the problem or non-positive value if unknown
+     */
+    int getColumnNumber();
+
+    /**
+     * Gets the location of the problem. The location is a user-friendly combination of the values from
+     * {@link #getSource()}, {@link #getLineNumber()} and {@link #getColumnNumber()}. The exact syntax of the returned
+     * value is undefined.
+     *
+     * @return the location of the problem, never {@code null}
+     */
+    @Nonnull
+    String getLocation();
+
+    /**
+     * Gets the exception that caused this problem (if any).
+     *
+     * @return the exception that caused this problem or {@code null} if not applicable
+     */
+    @Nullable
+    Exception getException();
+
+    /**
+     * Gets the message that describes this problem.
+     *
+     * @return the message describing this problem, never {@code null}
+     */
+    @Nonnull
+    String getMessage();
+
+    /**
+     * Gets the severity level of this problem.
+     *
+     * @return the severity level of this problem, never {@code null}
+     */
+    @Nonnull
+    Severity getSeverity();
+
+    /**
+     * The different severity levels for a problem, in decreasing order.
+     *
+     * @since 4.0.0
+     */
+    @Experimental
+    enum Severity {
+        FATAL, //
+        ERROR, //
+        WARNING //
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java
new file mode 100644
index 0000000..788fd67
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollector.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * The DependencyCollector service can be used to collect dependencies
+ * for a given artifact and builds a graph of them.
+ * The dependencies collection mechanism will not download any artifacts,
+ * and only the pom files will be downloaded.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface DependencyCollector extends Service {
+
+    /**
+     * Collects the transitive dependencies and builds a dependency graph.
+     * Note that this operation is only concerned about determining the coordinates of the
+     * transitive dependencies and does not actually resolve the artifact files.
+     *
+     * @param request the dependency collection request, must not be {@code null}
+     * @return the collection result, never {@code null}
+     * @throws DependencyCollectorException if the dependency tree could not be built
+     * @throws IllegalArgumentException if an argument is null or invalid
+     *
+     * @see DependencyCollector#collect(Session, Project)
+     * @see DependencyCollector#collect(Session, DependencyCoordinate)
+     * @see DependencyCollector#collect(Session, Artifact)
+     */
+    @Nonnull
+    DependencyCollectorResult collect(@Nonnull DependencyCollectorRequest request);
+
+    /**
+     * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+     * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+     * artifact files.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param root the Maven Dependency, must not be {@code null}
+     * @return the collection result, never {@code null}
+     * @throws DependencyCollectorException if the dependency tree could not be built
+     * @throws IllegalArgumentException if an argument is null or invalid
+     * @see #collect(DependencyCollectorRequest)
+     */
+    @Nonnull
+    default DependencyCollectorResult collect(@Nonnull Session session, @Nonnull DependencyCoordinate root) {
+        return collect(DependencyCollectorRequest.build(session, root));
+    }
+
+    /**
+     * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+     * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+     * artifact files.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param project the {@link Project}, must not be {@code null}
+     * @return the collection result, never {@code null}
+     * @throws DependencyCollectorException if the dependency tree could not be built
+     * @throws IllegalArgumentException if an argument is null or invalid
+     * @see #collect(DependencyCollectorRequest)
+     */
+    @Nonnull
+    default DependencyCollectorResult collect(@Nonnull Session session, @Nonnull Project project) {
+        return collect(DependencyCollectorRequest.build(session, project));
+    }
+
+    /**
+     * Collects the transitive dependencies of some artifacts and builds a dependency graph. Note that this operation is
+     * only concerned about determining the coordinates of the transitive dependencies and does not actually resolve the
+     * artifact files.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param artifact the {@link Artifact}, must not be {@code null}
+     * @return the collection result, never {@code null}
+     * @throws DependencyCollectorException if the dependency tree could not be built
+     * @throws IllegalArgumentException if an argument is null or invalid
+     * @see #collect(DependencyCollectorRequest)
+     */
+    @Nonnull
+    default DependencyCollectorResult collect(@Nonnull Session session, @Nonnull Artifact artifact) {
+        return collect(DependencyCollectorRequest.build(session, artifact));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java
new file mode 100644
index 0000000..466c40e
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Thrown in case of bad artifact descriptors, version ranges or other
+ * issues encountered during calculation of the dependency graph.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class DependencyCollectorException extends MavenException {
+    /**
+     *
+     */
+    private static final long serialVersionUID = -3134726259840210686L;
+
+    /**
+     * @param message the message you would give for the exception
+     * @param cause the cause which is related to the message
+     */
+    public DependencyCollectorException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java
new file mode 100644
index 0000000..f7ebf23
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorRequest.java
@@ -0,0 +1,294 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * A request to collect the transitive dependencies and to build a dependency graph from them. There are three ways to
+ * create a dependency graph. First, only the root dependency can be given. Second, a root dependency and direct
+ * dependencies can be specified in which case the specified direct dependencies are merged with the direct dependencies
+ * retrieved from the artifact descriptor of the root dependency. And last, only direct dependencies can be specified in
+ * which case the root node of the resulting graph has no associated dependency.
+ *
+ * @since 4.0.0
+ * @see DependencyCollector#collect(DependencyCollectorRequest)
+ */
+@Experimental
+@Immutable
+public interface DependencyCollectorRequest {
+
+    @Nonnull
+    Session getSession();
+
+    @Nonnull
+    Optional<Artifact> getRootArtifact();
+
+    @Nonnull
+    Optional<DependencyCoordinate> getRoot();
+
+    @Nonnull
+    Collection<DependencyCoordinate> getDependencies();
+
+    @Nonnull
+    Collection<DependencyCoordinate> getManagedDependencies();
+
+    boolean getVerbose();
+
+    @Nonnull
+    static DependencyCollectorRequest build(@Nonnull Session session, Artifact root) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .rootArtifact(nonNull(root, "root cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static DependencyCollectorRequest build(@Nonnull Session session, @Nonnull DependencyCoordinate root) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .root(nonNull(root, "root cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static DependencyCollectorRequest build(@Nonnull Session session, @Nonnull Project project) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .rootArtifact(nonNull(project, "project cannot be null").getArtifact())
+                .dependencies(project.getDependencies())
+                .managedDependencies(project.getManagedDependencies())
+                .build();
+    }
+
+    @Nonnull
+    static DependencyCollectorRequestBuilder builder() {
+        return new DependencyCollectorRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class DependencyCollectorRequestBuilder {
+
+        Session session;
+        Artifact rootArtifact;
+        DependencyCoordinate root;
+        List<DependencyCoordinate> dependencies = Collections.emptyList();
+        List<DependencyCoordinate> managedDependencies = Collections.emptyList();
+        boolean verbose;
+
+        DependencyCollectorRequestBuilder() {}
+
+        @Nonnull
+        public DependencyCollectorRequestBuilder session(@Nonnull Session session) {
+            this.session = session;
+            return this;
+        }
+
+        /**
+         * Sets the root artifact for the dependency graph.
+         * This must not be confused with {@link #root(DependencyCoordinate)}: The root <em>dependency</em>, like any
+         * other specified dependency, will be subject to dependency collection/resolution, i.e. should have an artifact
+         * descriptor and a corresponding artifact file. The root <em>artifact</em> on the other hand is only used
+         * as a label for the root node of the graph in case no root dependency was specified. As such, the configured
+         * root artifact is ignored if {@link #root(DependencyCoordinate)} has been set.
+         *
+         * @param rootArtifact the root artifact for the dependency graph, may be {@code null}
+         * @return this request for chaining, never {@code null}
+         */
+        @Nonnull
+        public DependencyCollectorRequestBuilder rootArtifact(@Nullable Artifact rootArtifact) {
+            this.rootArtifact = rootArtifact;
+            return this;
+        }
+
+        /**
+         * @param root The root dependency
+         * @return this request for chaining, never {@code null}
+         */
+        @Nonnull
+        public DependencyCollectorRequestBuilder root(@Nonnull DependencyCoordinate root) {
+            this.root = root;
+            return this;
+        }
+
+        /**
+         * Sets the direct dependencies. If both a root dependency and direct dependencies are given in the request, the
+         * direct dependencies from the request will be merged with the direct dependencies from the root dependency's
+         * artifact descriptor, giving higher priority to the dependencies from the request.
+         *
+         * @param dependencies the direct dependencies, may be {@code null}
+         * @return this request for chaining, never {@code null}
+         */
+        @Nonnull
+        public DependencyCollectorRequestBuilder dependencies(@Nullable List<DependencyCoordinate> dependencies) {
+            this.dependencies = (dependencies != null) ? dependencies : Collections.emptyList();
+            return this;
+        }
+
+        /**
+         * Adds the specified direct dependency.
+         *
+         * @param dependency the dependency to add, may be {@code null}
+         * @return this request for chaining, never {@code null}
+         */
+        @Nonnull
+        public DependencyCollectorRequestBuilder dependency(@Nullable DependencyCoordinate dependency) {
+            if (dependency != null) {
+                if (this.dependencies.isEmpty()) {
+                    this.dependencies = new ArrayList<>();
+                }
+                this.dependencies.add(dependency);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the dependency management to apply to transitive dependencies. To clarify, this management does not
+         * apply to
+         * the direct dependencies of the root node.
+         *
+         * @param managedDependencies the dependency management, may be {@code null}
+         * @return this request for chaining, never {@code null}
+         */
+        @Nonnull
+        public DependencyCollectorRequestBuilder managedDependencies(
+                @Nullable List<DependencyCoordinate> managedDependencies) {
+            this.managedDependencies = (managedDependencies != null) ? managedDependencies : Collections.emptyList();
+            return this;
+        }
+
+        /**
+         * Adds the specified managed dependency.
+         *
+         * @param managedDependency The managed dependency to add, may be {@code null} in which case the call
+         *                          will have no effect.
+         * @return this request for chaining, never {@code null}
+         */
+        @Nonnull
+        public DependencyCollectorRequestBuilder managedDependency(@Nullable DependencyCoordinate managedDependency) {
+            if (managedDependency != null) {
+                if (this.managedDependencies.isEmpty()) {
+                    this.managedDependencies = new ArrayList<>();
+                }
+                this.managedDependencies.add(managedDependency);
+            }
+            return this;
+        }
+
+        /**
+         * Specifies that the collection should be verbose.
+         *
+         * @param verbose whether the collection should be verbose or not
+         * @return this request for chaining, never {@code null}
+         */
+        @Nonnull
+        public DependencyCollectorRequestBuilder verbose(boolean verbose) {
+            this.verbose = verbose;
+            return this;
+        }
+
+        @Nonnull
+        public DependencyCollectorRequest build() {
+            return new DefaultDependencyCollectorRequest(
+                    session, rootArtifact, root, dependencies, managedDependencies, verbose);
+        }
+
+        static class DefaultDependencyCollectorRequest extends BaseRequest implements DependencyCollectorRequest {
+            private final Artifact rootArtifact;
+            private final DependencyCoordinate root;
+            private final Collection<DependencyCoordinate> dependencies;
+            private final Collection<DependencyCoordinate> managedDependencies;
+            private final boolean verbose;
+
+            /**
+             * Creates a request with the specified properties.
+             *
+             * @param session      {@link Session}
+             * @param rootArtifact The root dependency whose transitive dependencies should be collected, may be {@code
+             *                     null}.
+             */
+            DefaultDependencyCollectorRequest(
+                    @Nonnull Session session,
+                    @Nullable Artifact rootArtifact,
+                    @Nullable DependencyCoordinate root,
+                    @Nonnull Collection<DependencyCoordinate> dependencies,
+                    @Nonnull Collection<DependencyCoordinate> managedDependencies,
+                    boolean verbose) {
+                super(session);
+                this.rootArtifact = rootArtifact;
+                this.root = root;
+                this.dependencies = unmodifiable(nonNull(dependencies, "dependencies cannot be null"));
+                this.managedDependencies =
+                        unmodifiable(nonNull(managedDependencies, "managedDependencies cannot be null"));
+                this.verbose = verbose;
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Artifact> getRootArtifact() {
+                return Optional.ofNullable(rootArtifact);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<DependencyCoordinate> getRoot() {
+                return Optional.ofNullable(root);
+            }
+
+            @Nonnull
+            @Override
+            public Collection<DependencyCoordinate> getDependencies() {
+                return dependencies;
+            }
+
+            @Nonnull
+            @Override
+            public Collection<DependencyCoordinate> getManagedDependencies() {
+                return managedDependencies;
+            }
+
+            @Override
+            public boolean getVerbose() {
+                return verbose;
+            }
+
+            @Nonnull
+            @Override
+            public String toString() {
+                return getRoot() + " -> " + getDependencies();
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java
new file mode 100644
index 0000000..9fb2179
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCollectorResult.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.List;
+
+import org.apache.maven.api.Node;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The result of a dependency collection request.
+ *
+ * @since 4.0.0
+ * @see DependencyCollector#collect(DependencyCollectorRequest)
+ */
+@Experimental
+public interface DependencyCollectorResult {
+    /**
+     * Gets the exceptions that occurred while building the dependency graph.
+     *
+     * @return the exceptions that occurred, never {@code null}
+     */
+    List<Exception> getExceptions();
+
+    /**
+     * Gets the root node of the dependency graph.
+     *
+     * @return the root node of the dependency graph or {@code null} if none
+     */
+    Node getRoot();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactory.java
new file mode 100644
index 0000000..f5fc736
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactory.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.ReportPlugin;
+
+/**
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface DependencyCoordinateFactory extends Service {
+
+    /**
+     * Creates a new {@link DependencyCoordinate} object from the request.
+     *
+     * @param request the request containing the various data
+     * @return a new {@link DependencyCoordinate} object
+     *
+     * @throws IllegalArgumentException if {@code request} is null or
+     *         if {@code request.getSession()} is null or invalid
+     */
+    @Nonnull
+    DependencyCoordinate create(@Nonnull DependencyCoordinateFactoryRequest request);
+
+    @Nonnull
+    default DependencyCoordinate create(@Nonnull Session session, @Nonnull ArtifactCoordinate coordinate) {
+        return create(DependencyCoordinateFactoryRequest.build(session, coordinate));
+    }
+
+    @Nonnull
+    default DependencyCoordinate create(@Nonnull Session session, @Nonnull org.apache.maven.api.Dependency dependency) {
+        return create(DependencyCoordinateFactoryRequest.build(session, dependency));
+    }
+
+    @Nonnull
+    default DependencyCoordinate create(@Nonnull Session session, Dependency dependency) {
+        return create(DependencyCoordinateFactoryRequest.build(
+                session,
+                dependency.getGroupId(),
+                dependency.getArtifactId(),
+                dependency.getVersion(),
+                dependency.getClassifier(),
+                null,
+                dependency.getType()));
+    }
+
+    @Nonnull
+    default DependencyCoordinate create(@Nonnull Session session, Plugin plugin) {
+        // TODO: hard coded string
+        return create(DependencyCoordinateFactoryRequest.build(
+                session, plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion(), null, null, "maven-plugin"));
+    }
+
+    @Nonnull
+    default DependencyCoordinate create(@Nonnull Session session, ReportPlugin reportPlugin) {
+        // TODO: hard coded string
+        return create(DependencyCoordinateFactoryRequest.build(
+                session,
+                reportPlugin.getGroupId(),
+                reportPlugin.getArtifactId(),
+                reportPlugin.getVersion(),
+                null,
+                null,
+                "maven-plugin"));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java
new file mode 100644
index 0000000..532d820
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/DependencyCoordinateFactoryRequest.java
@@ -0,0 +1,271 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.Exclusion;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface DependencyCoordinateFactoryRequest extends ArtifactCoordinateFactoryRequest {
+
+    String getScope();
+
+    boolean isOptional();
+
+    @Nonnull
+    Collection<Exclusion> getExclusions();
+
+    @Nonnull
+    static DependencyCoordinateFactoryRequest build(
+            @Nonnull Session session,
+            String groupId,
+            String artifactId,
+            String version,
+            String classifier,
+            String extension,
+            String type) {
+        return DependencyCoordinateFactoryRequest.builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(groupId)
+                .artifactId(artifactId)
+                .version(version)
+                .classifier(classifier)
+                .extension(extension)
+                .type(type)
+                .build();
+    }
+
+    @Nonnull
+    static DependencyCoordinateFactoryRequest build(@Nonnull Session session, @Nonnull ArtifactCoordinate coordinate) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(nonNull(coordinate, "coordinate cannot be null").getGroupId())
+                .artifactId(coordinate.getArtifactId())
+                .version(coordinate.getVersion().asString())
+                .classifier(coordinate.getClassifier())
+                .extension(coordinate.getExtension())
+                .build();
+    }
+
+    @Nonnull
+    static DependencyCoordinateFactoryRequest build(@Nonnull Session session, @Nonnull Dependency dependency) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .groupId(nonNull(dependency, "dependency").getGroupId())
+                .artifactId(dependency.getArtifactId())
+                .version(dependency.getVersion().asString())
+                .classifier(dependency.getClassifier())
+                .extension(dependency.getExtension())
+                .type(dependency.getType().getId())
+                .scope(dependency.getScope().id())
+                .optional(dependency.isOptional())
+                .build();
+    }
+
+    @Nonnull
+    static DependencyCoordinateFactoryRequestBuilder builder() {
+        return new DependencyCoordinateFactoryRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class DependencyCoordinateFactoryRequestBuilder {
+        private Session session;
+        private String groupId;
+        private String artifactId;
+        private String version;
+        private String classifier;
+        private String extension;
+        private String type;
+        private String scope;
+        private boolean optional;
+        private Collection<Exclusion> exclusions = Collections.emptyList();
+
+        DependencyCoordinateFactoryRequestBuilder() {}
+
+        public DependencyCoordinateFactoryRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder groupId(String groupId) {
+            this.groupId = groupId;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder artifactId(String artifactId) {
+            this.artifactId = artifactId;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder version(String version) {
+            this.version = version;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder classifier(String classifier) {
+            this.classifier = classifier;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder extension(String extension) {
+            this.extension = extension;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder type(String type) {
+            this.type = type;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder scope(String scope) {
+            this.scope = scope;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder optional(boolean optional) {
+            this.optional = optional;
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder exclusions(Collection<Exclusion> exclusions) {
+            if (exclusions != null) {
+                if (this.exclusions.isEmpty()) {
+                    this.exclusions = new ArrayList<>();
+                }
+                this.exclusions.addAll(exclusions);
+            }
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequestBuilder exclusion(Exclusion exclusion) {
+            if (exclusion != null) {
+                if (this.exclusions.isEmpty()) {
+                    this.exclusions = new ArrayList<>();
+                }
+                this.exclusions.add(exclusion);
+            }
+            return this;
+        }
+
+        public DependencyCoordinateFactoryRequest build() {
+            return new DefaultDependencyCoordinateFactoryRequest(
+                    session, groupId, artifactId, version, classifier, extension, type, scope, optional, exclusions);
+        }
+
+        private static class DefaultDependencyCoordinateFactoryRequest extends BaseRequest
+                implements DependencyCoordinateFactoryRequest {
+            private final String groupId;
+            private final String artifactId;
+            private final String version;
+            private final String classifier;
+            private final String extension;
+            private final String type;
+            private final String scope;
+            private final boolean optional;
+            private final Collection<Exclusion> exclusions;
+
+            @SuppressWarnings("checkstyle:ParameterNumber")
+            private DefaultDependencyCoordinateFactoryRequest(
+                    @Nonnull Session session,
+                    String groupId,
+                    String artifactId,
+                    String version,
+                    String classifier,
+                    String extension,
+                    String type,
+                    String scope,
+                    boolean optional,
+                    Collection<Exclusion> exclusions) {
+                super(session);
+                this.groupId = groupId;
+                this.artifactId = artifactId;
+                this.version = version;
+                this.classifier = classifier;
+                this.extension = extension;
+                this.type = type;
+                this.scope = scope;
+                this.optional = optional;
+                this.exclusions = exclusions;
+            }
+
+            @Override
+            public String getGroupId() {
+                return groupId;
+            }
+
+            @Override
+            public String getArtifactId() {
+                return artifactId;
+            }
+
+            @Override
+            public String getVersion() {
+                return version;
+            }
+
+            @Override
+            public String getClassifier() {
+                return classifier;
+            }
+
+            @Override
+            public String getExtension() {
+                return extension;
+            }
+
+            @Override
+            public String getType() {
+                return type;
+            }
+
+            @Override
+            public String getScope() {
+                return scope;
+            }
+
+            @Override
+            public boolean isOptional() {
+                return optional;
+            }
+
+            @Nonnull
+            @Override
+            public Collection<Exclusion> getExclusions() {
+                return exclusions;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/LocalRepositoryManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LocalRepositoryManager.java
new file mode 100644
index 0000000..2428db8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LocalRepositoryManager.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface LocalRepositoryManager extends Service {
+
+    Path getPathForLocalArtifact(Session session, LocalRepository local, Artifact artifact);
+
+    Path getPathForRemoteArtifact(Session session, LocalRepository local, RemoteRepository remote, Artifact artifact);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Lookup.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Lookup.java
new file mode 100644
index 0000000..07a0d4b
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Lookup.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.Service;
+
+public interface Lookup extends Service {
+
+    <T> T lookup(Class<T> type);
+
+    <T> T lookup(Class<T> type, String name);
+
+    <T> List<T> lookupList(Class<T> type);
+
+    <T> Map<String, T> lookupMap(Class<T> type);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/LookupException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LookupException.java
new file mode 100644
index 0000000..b72d04b
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/LookupException.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link Lookup} service.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class LookupException extends MavenException {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public LookupException(String message, Exception e) {
+        super(message, e);
+    }
+
+    /**
+     * @param e the {@link Exception}
+     */
+    public LookupException(Exception e) {
+        super(e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
new file mode 100644
index 0000000..a5ce695
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MavenException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * Base class for all maven exceptions.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class MavenException extends RuntimeException {
+    public MavenException() {}
+
+    public MavenException(String message) {
+        super(message);
+    }
+
+    public MavenException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public MavenException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilder.java
new file mode 100644
index 0000000..d00ad8d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilder.java
@@ -0,0 +1,216 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Message builder that supports configurable styling.
+ *
+ * @since 4.0.0
+ * @see MessageBuilderFactory
+ */
+public interface MessageBuilder {
+
+    /**
+     * Append message content in trace style.
+     * By default, bold magenta
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder trace(Object message);
+
+    /**
+     * Append message content in debug style.
+     * By default, bold cyan
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder debug(Object message);
+
+    /**
+     * Append message content in info style.
+     * By default, bold blue
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder info(Object message);
+
+    /**
+     * Append message content in warning style.
+     * By default, bold yellow
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder warning(Object message);
+
+    /**
+     * Append message content in error style.
+     * By default, bold red
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder error(Object message);
+
+    /**
+     * Append message content in success style.
+     * By default, bold green
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder success(Object message);
+
+    /**
+     * Append message content in failure style.
+     * By default, bold red
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder failure(Object message);
+
+    /**
+     * Append message content in strong style.
+     * By default, bold
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder strong(Object message);
+
+    /**
+     * Append message content in mojo style.
+     * By default, green
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder mojo(Object message);
+
+    /**
+     * Append message content in project style.
+     * By default, cyan
+     *
+     * @param message the message to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder project(Object message);
+
+    //
+    // message building methods modelled after Ansi methods
+    //
+    /**
+     * Append content to the message buffer.
+     *
+     * @param value the content to append
+     * @param offset the index of the first {@code char} to append
+     * @param len the number of {@code char}s to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder a(char[] value, int offset, int len);
+
+    /**
+     * Append content to the message buffer.
+     *
+     * @param value the content to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder a(char[] value);
+
+    /**
+     * Append content to the message buffer.
+     *
+     * @param value the content to append
+     * @param start the starting index of the subsequence to be appended
+     * @param end the end index of the subsequence to be appended
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder a(CharSequence value, int start, int end);
+
+    /**
+     * Append content to the message buffer.
+     *
+     * @param value the content to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder a(CharSequence value);
+
+    /**
+     * Append content to the message buffer.
+     *
+     * @param value the content to append
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder a(Object value);
+
+    /**
+     * Append newline to the message buffer.
+     *
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder newline();
+
+    /**
+     * Append formatted content to the buffer.
+     * @see String#format(String, Object...)
+     *
+     * @param pattern a <a href="../util/Formatter.html#syntax">format string</a>
+     * @param args arguments referenced by the format specifiers in the format string
+     * @return the current builder
+     */
+    @Nonnull
+    MessageBuilder format(String pattern, Object... args);
+
+    /**
+     * Return the built message.
+     *
+     * @return the message
+     */
+    @Nonnull
+    String build();
+
+    /**
+     * Set the buffer length.
+     *
+     * @param length the new length
+     */
+    void setLength(int length);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilderFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilderFactory.java
new file mode 100644
index 0000000..ac4691e
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/MessageBuilderFactory.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * A factory for {@link MessageBuilder}.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface MessageBuilderFactory extends Service {
+    /**
+     * Checks if the underlying output does support styling or not.
+     * @return whether color styling is supported or not
+     */
+    boolean isColorEnabled();
+
+    /**
+     * Returns the terminal width or <code>-1</code> if not supported.
+     * @return the terminal width
+     */
+    int getTerminalWidth();
+
+    /**
+     * Creates a new message builder.
+     * @return a new message builder
+     */
+    @Nonnull
+    MessageBuilder builder();
+
+    /**
+     * Creates a new message builder backed by the given string builder.
+     * @param stringBuilder a string builder
+     * @return a new message builder
+     */
+    @Nonnull
+    MessageBuilder builder(@Nonnull StringBuilder stringBuilder);
+
+    /**
+     * Creates a new message builder of the specified size.
+     * @param size the initial size of the message builder buffer
+     * @return a new message builder
+     */
+    @Nonnull
+    default MessageBuilder builder(int size) {
+        return builder(new StringBuilder(size));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java
new file mode 100644
index 0000000..c9212fe
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilder.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * @since 4.0.0
+ */
+@Experimental
+public interface ProjectBuilder extends Service {
+
+    /**
+     * Creates a {@link org.apache.maven.api.Project} from a POM file.
+     *
+     * @param request {@link ProjectBuilderRequest}
+     * @return the {@link ProjectBuilderResult} containing the built project and possible errors
+     * @throws ProjectBuilderException if the project cannot be created
+     * @throws IllegalArgumentException if an argument is {@code null} or invalid
+     */
+    @Nonnull
+    ProjectBuilderResult build(ProjectBuilderRequest request);
+
+    /**
+     * Creates a {@link org.apache.maven.api.Project} from a POM file.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param source The {@link Source}, must not be {@code null}
+     * @throws ProjectBuilderException if the project cannot be created
+     * @throws IllegalArgumentException if an argument is {@code null} or invalid
+     * @see #build(ProjectBuilderRequest)
+     */
+    @Nonnull
+    default ProjectBuilderResult build(@Nonnull Session session, @Nonnull Source source) {
+        return build(ProjectBuilderRequest.build(session, source));
+    }
+
+    /**
+     * Creates a {@link org.apache.maven.api.Project} from a POM file.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param path the {@link Path}, must not be {@code null}
+     * @throws ProjectBuilderException if the project cannot be created
+     * @throws IllegalArgumentException if an argument is {@code null} or invalid
+     * @see #build(ProjectBuilderRequest)
+     */
+    @Nonnull
+    default ProjectBuilderResult build(@Nonnull Session session, @Nonnull Path path) {
+        return build(ProjectBuilderRequest.build(session, path));
+    }
+
+    /**
+     * Creates a {@link org.apache.maven.api.Project} from an artifact.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param artifact the {@link Artifact}, must not be {@code null}
+     * @throws ProjectBuilderException if the project cannot be created
+     * @throws IllegalArgumentException if an argument is {@code null} or invalid
+     * @see #build(ProjectBuilderRequest)
+     */
+    @Nonnull
+    default ProjectBuilderResult build(@Nonnull Session session, @Nonnull Artifact artifact) {
+        return build(ProjectBuilderRequest.build(session, artifact));
+    }
+
+    /**
+     * Creates a {@link org.apache.maven.api.Project} from a coordinate.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param coordinate the {@link ArtifactCoordinate}, must not be {@code null}
+     * @throws ProjectBuilderException if the project cannot be created
+     * @throws IllegalArgumentException if an argument is {@code null} or invalid
+     * @see #build(ProjectBuilderRequest)
+     */
+    @Nonnull
+    default ProjectBuilderResult build(@Nonnull Session session, @Nonnull ArtifactCoordinate coordinate) {
+        return build(ProjectBuilderRequest.build(session, coordinate));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderException.java
new file mode 100644
index 0000000..b86d6ce
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderException.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link ProjectBuilder} service.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class ProjectBuilderException extends MavenException {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public ProjectBuilderException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
new file mode 100644
index 0000000..9cac473
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderRequest.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * Request used to build a {@link org.apache.maven.api.Project} using
+ * the {@link ProjectBuilder} service.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface ProjectBuilderRequest {
+
+    @Nonnull
+    Session getSession();
+
+    @Nonnull
+    Optional<Path> getPath();
+
+    @Nonnull
+    Optional<Source> getSource();
+
+    @Nonnull
+    Optional<Artifact> getArtifact();
+
+    @Nonnull
+    Optional<ArtifactCoordinate> getCoordinate();
+
+    boolean isAllowStubModel();
+
+    boolean isRecursive();
+
+    boolean isProcessPlugins();
+
+    boolean isResolveDependencies();
+
+    @Nonnull
+    static ProjectBuilderRequest build(@Nonnull Session session, @Nonnull Source source) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .source(nonNull(source, "source cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static ProjectBuilderRequest build(@Nonnull Session session, @Nonnull Path path) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .path(nonNull(path, "path cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static ProjectBuilderRequest build(@Nonnull Session session, @Nonnull Artifact artifact) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .artifact(nonNull(artifact, "artifact cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static ProjectBuilderRequest build(@Nonnull Session session, @Nonnull ArtifactCoordinate coordinate) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .coordinate(nonNull(coordinate, "coordinate cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static ProjectBuilderRequestBuilder builder() {
+        return new ProjectBuilderRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class ProjectBuilderRequestBuilder {
+        Session session;
+        Path path;
+        Source source;
+        Artifact artifact;
+        ArtifactCoordinate coordinate;
+        boolean allowStubModel;
+        boolean recursive;
+        boolean processPlugins = true;
+        boolean resolveDependencies = true;
+
+        ProjectBuilderRequestBuilder() {}
+
+        public ProjectBuilderRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        public ProjectBuilderRequestBuilder path(Path path) {
+            this.path = path;
+            return this;
+        }
+
+        public ProjectBuilderRequestBuilder source(Source source) {
+            this.source = source;
+            return this;
+        }
+
+        public ProjectBuilderRequestBuilder artifact(Artifact artifact) {
+            this.artifact = artifact;
+            return this;
+        }
+
+        public ProjectBuilderRequestBuilder coordinate(ArtifactCoordinate coordinate) {
+            this.coordinate = coordinate;
+            return this;
+        }
+
+        public ProjectBuilderRequestBuilder processPlugins(boolean processPlugins) {
+            this.processPlugins = processPlugins;
+            return this;
+        }
+
+        public ProjectBuilderRequestBuilder resolveDependencies(boolean resolveDependencies) {
+            this.resolveDependencies = resolveDependencies;
+            return this;
+        }
+
+        public ProjectBuilderRequest build() {
+            return new DefaultProjectBuilderRequest(
+                    session,
+                    path,
+                    source,
+                    artifact,
+                    coordinate,
+                    allowStubModel,
+                    recursive,
+                    processPlugins,
+                    resolveDependencies);
+        }
+
+        private static class DefaultProjectBuilderRequest extends BaseRequest implements ProjectBuilderRequest {
+            private final Path path;
+            private final Source source;
+            private final Artifact artifact;
+            private final ArtifactCoordinate coordinate;
+            private final boolean allowStubModel;
+            private final boolean recursive;
+            private final boolean processPlugins;
+            private final boolean resolveDependencies;
+
+            @SuppressWarnings("checkstyle:ParameterNumber")
+            DefaultProjectBuilderRequest(
+                    @Nonnull Session session,
+                    @Nullable Path path,
+                    @Nullable Source source,
+                    @Nullable Artifact artifact,
+                    @Nullable ArtifactCoordinate coordinate,
+                    boolean allowStubModel,
+                    boolean recursive,
+                    boolean processPlugins,
+                    boolean resolveDependencies) {
+                super(session);
+                this.path = path;
+                this.source = source;
+                this.artifact = artifact;
+                this.coordinate = coordinate;
+                this.allowStubModel = allowStubModel;
+                this.recursive = recursive;
+                this.processPlugins = processPlugins;
+                this.resolveDependencies = resolveDependencies;
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getPath() {
+                return Optional.ofNullable(path);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getSource() {
+                return Optional.ofNullable(source);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Artifact> getArtifact() {
+                return Optional.ofNullable(artifact);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<ArtifactCoordinate> getCoordinate() {
+                return Optional.ofNullable(coordinate);
+            }
+
+            @Override
+            public boolean isAllowStubModel() {
+                return allowStubModel;
+            }
+
+            @Override
+            public boolean isRecursive() {
+                return recursive;
+            }
+
+            @Override
+            public boolean isProcessPlugins() {
+                return processPlugins;
+            }
+
+            @Override
+            public boolean isResolveDependencies() {
+                return resolveDependencies;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
new file mode 100644
index 0000000..348be61
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectBuilderResult.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Optional;
+
+import org.apache.maven.api.Project;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Result of a project build call.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ProjectBuilderResult {
+
+    /**
+     * Gets the identifier of the project that could not be built. The general format of the identifier is {@code
+     * <groupId>:<artifactId>:<version>} but some of these coordinates may still be unknown at the point the exception
+     * is thrown so this information is merely meant to assist the user.
+     *
+     * @return the identifier of the project or an empty string if not known, never {@code null}
+     */
+    @Nonnull
+    String getProjectId();
+
+    /**
+     * Gets the POM file from which the project was built.
+     *
+     * @return the optional POM file
+     */
+    @Nonnull
+    Optional<Path> getPomFile();
+
+    /**
+     * Gets the project that was built.
+     *
+     * @return The project that was built or {@code null} if an error occurred and this result accompanies a
+     *         {@link ProjectBuilderException}.
+     */
+    @Nonnull
+    Optional<Project> getProject();
+
+    /**
+     * Gets the problems that were encountered during the project building.
+     *
+     * @return the problems that were encountered during the project building, can be empty but never {@code null}
+     */
+    @Nonnull
+    Collection<BuilderProblem> getProblems();
+
+    /**
+     * Gets the result of the dependency resolution for the project.
+     *
+     * @return the result of the dependency resolution for the project
+     */
+    @Nonnull
+    Optional<DependencyCollectorResult> getDependencyResolverResult();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectManager.java
new file mode 100644
index 0000000..13a09ad
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ProjectManager.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.ResolutionScope;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Interface to manage the project during its lifecycle.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ProjectManager extends Service {
+    /**
+     * Returns the path to the resolved file in the local repository
+     * if the artifact has been resolved.
+     *
+     * @return the path of the resolved artifact
+     */
+    @Nonnull
+    Optional<Path> getPath(Project project);
+
+    @Nonnull
+    Collection<Artifact> getAttachedArtifacts(Project project);
+
+    default void attachArtifact(Session session, Project project, Path path) {
+        String name = path.getFileName().toString();
+        int dot = name.lastIndexOf('.');
+        String ext = dot >= 1 ? name.substring(dot + 1) : "";
+        Artifact artifact =
+                session.createArtifact(project.getGroupId(), project.getArtifactId(), project.getVersion(), ext);
+        attachArtifact(project, artifact, path);
+    }
+
+    default void attachArtifact(Session session, Project project, String type, Path path) {
+        Artifact artifact = session.createArtifact(
+                project.getGroupId(), project.getArtifactId(), project.getVersion(), null, null, type);
+        attachArtifact(project, artifact, path);
+    }
+
+    void attachArtifact(Project project, Artifact artifact, Path path);
+
+    List<String> getCompileSourceRoots(Project project);
+
+    void addCompileSourceRoot(Project project, String sourceRoot);
+
+    List<String> getTestCompileSourceRoots(Project project);
+
+    void addTestCompileSourceRoot(Project project, String sourceRoot);
+
+    List<RemoteRepository> getRepositories(Project project);
+
+    List<Artifact> getResolvedDependencies(Project project, ResolutionScope scope);
+
+    Node getCollectedDependencies(Project project, ResolutionScope scope);
+
+    void setProperty(Project project, String key, String value);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Prompter.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Prompter.java
new file mode 100644
index 0000000..29f2a75
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Prompter.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.List;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Service used to interact with the end user.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface Prompter extends Service {
+    /**
+     * Prompts the user for a string.
+     *
+     * @param message the message to display to the user
+     * @return the string entered by the user
+     * @throws PrompterException if an exception occurs
+     */
+    @Nonnull
+    default String prompt(@Nullable String message) throws PrompterException {
+        return prompt(message, null, null);
+    }
+
+    /**
+     * Prompts the user for a string using a default value.
+     *
+     * @param message the message to display
+     * @param defaultReply the default reply value
+     * @return the string entered by the user
+     * @throws PrompterException if an exception occurs
+     */
+    @Nonnull
+    default String prompt(@Nullable String message, @Nullable String defaultReply) throws PrompterException {
+        return prompt(message, null, defaultReply);
+    }
+
+    /**
+     * Prompts the user for a string using a list of possible values.
+     *
+     * @param message the message to display
+     * @param possibleValues the list of possible values
+     * @return the string entered by the user
+     * @throws PrompterException if an exception occurs
+     */
+    @Nonnull
+    default String prompt(@Nullable String message, @Nullable List<String> possibleValues) throws PrompterException {
+        return prompt(message, possibleValues, null);
+    }
+
+    /**
+     * Prompts the user for a string using a list of possible values and a default reply.
+     *
+     * @param message the message to display
+     * @param possibleValues the list of possible values
+     * @param defaultReply the default reply value
+     * @return the string entered by the user
+     * @throws PrompterException if an exception occurs
+     */
+    @Nonnull
+    String prompt(@Nullable String message, @Nullable List<String> possibleValues, @Nullable String defaultReply)
+            throws PrompterException;
+
+    /**
+     * Prompts the user for a password.
+     *
+     * @param message the message to display
+     * @return the password entered by the user
+     * @throws PrompterException if an exception occurs
+     */
+    @Nonnull
+    String promptForPassword(@Nullable String message) throws PrompterException;
+
+    /**
+     * Displays a message to the user.
+     *
+     * @param message the message to display
+     * @throws PrompterException if an exception occurs
+     */
+    void showMessage(@Nullable String message) throws PrompterException;
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/PrompterException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PrompterException.java
new file mode 100644
index 0000000..8b76f6e
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/PrompterException.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link Prompter} service.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class PrompterException extends MavenException {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public PrompterException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryFactory.java
new file mode 100644
index 0000000..c04728f
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/RepositoryFactory.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.Repository;
+
+/**
+ * Factory service to create {@link LocalRepository} or {@link RemoteRepository} objects.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface RepositoryFactory extends Service {
+
+    @Nonnull
+    LocalRepository createLocal(@Nonnull Path path);
+
+    @Nonnull
+    RemoteRepository createRemote(@Nonnull String id, @Nonnull String url);
+
+    @Nonnull
+    RemoteRepository createRemote(@Nonnull Repository repository);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
new file mode 100644
index 0000000..bc216c9
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilder.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Builds the effective settings from a user settings file and/or a global settings file.
+ */
+public interface SettingsBuilder extends Service {
+
+    /**
+     * Builds the effective settings of the specified settings files.
+     *
+     * @param request the settings building request that holds the parameters, must not be {@code null}
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    SettingsBuilderResult build(@Nonnull SettingsBuilderRequest request);
+
+    /**
+     * Builds the effective settings of the specified settings sources.
+     *
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    default SettingsBuilderResult build(
+            @Nonnull Session session, @Nonnull Source globalSettingsSource, @Nonnull Source userSettingsSource) {
+        return build(session, globalSettingsSource, null, userSettingsSource);
+    }
+
+    /**
+     * Builds the effective settings of the specified settings paths.
+     *
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    default SettingsBuilderResult build(
+            @Nonnull Session session, @Nonnull Path globalSettingsPath, @Nonnull Path userSettingsPath) {
+        return build(session, globalSettingsPath, null, userSettingsPath);
+    }
+
+    /**
+     * Builds the effective settings of the specified settings sources.
+     *
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    default SettingsBuilderResult build(
+            @Nonnull Session session,
+            @Nonnull Source globalSettingsSource,
+            @Nonnull Source projectSettingsSource,
+            @Nonnull Source userSettingsSource) {
+        return build(
+                SettingsBuilderRequest.build(session, globalSettingsSource, projectSettingsSource, userSettingsSource));
+    }
+
+    /**
+     * Builds the effective settings of the specified settings paths.
+     *
+     * @return the result of the settings building, never {@code null}
+     * @throws SettingsBuilderException if the effective settings could not be built
+     */
+    @Nonnull
+    default SettingsBuilderResult build(
+            @Nonnull Session session,
+            @Nonnull Path globalSettingsPath,
+            @Nonnull Path projectSettingsPath,
+            @Nonnull Path userSettingsPath) {
+        return build(SettingsBuilderRequest.build(session, globalSettingsPath, projectSettingsPath, userSettingsPath));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
new file mode 100644
index 0000000..c22fed1
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderException.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link SettingsBuilder}.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class SettingsBuilderException extends MavenException {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public SettingsBuilderException(String message, Exception e) {
+        super(message, e);
+    }
+
+    // TODO: add SettingsBuilderResult
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
new file mode 100644
index 0000000..ee7692d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderRequest.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+/**
+ * Collects settings that control the building of effective settings.
+ */
+@Experimental
+@Immutable
+public interface SettingsBuilderRequest {
+
+    @Nonnull
+    Session getSession();
+
+    /**
+     * Gets the global settings path.
+     *
+     * @return the global settings path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getGlobalSettingsPath();
+
+    /**
+     * Gets the global settings source.
+     *
+     * @return the global settings source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getGlobalSettingsSource();
+
+    /**
+     * Gets the project settings source.
+     *
+     * @return the project settings source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getProjectSettingsSource();
+
+    /**
+     * Gets the project settings path.
+     *
+     * @return the project settings path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getProjectSettingsPath();
+
+    /**
+     * Gets the user settings path.
+     *
+     * @return the user settings path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getUserSettingsPath();
+
+    /**
+     * Gets the user settings source.
+     *
+     * @return the user settings source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getUserSettingsSource();
+
+    @Nonnull
+    static SettingsBuilderRequest build(
+            @Nonnull Session session, @Nonnull Source globalSettingsSource, @Nonnull Source userSettingsSource) {
+        return build(session, globalSettingsSource, null, userSettingsSource);
+    }
+
+    @Nonnull
+    static SettingsBuilderRequest build(
+            @Nonnull Session session, @Nonnull Path globalSettingsPath, @Nonnull Path userSettingsPath) {
+        return build(session, globalSettingsPath, null, userSettingsPath);
+    }
+
+    @Nonnull
+    static SettingsBuilderRequest build(
+            @Nonnull Session session,
+            @Nonnull Source globalSettingsSource,
+            @Nonnull Source projectSettingsSource,
+            @Nonnull Source userSettingsSource) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .globalSettingsSource(nonNull(globalSettingsSource, "globalSettingsSource cannot be null"))
+                .projectSettingsSource(nonNull(projectSettingsSource, "projectSettingsSource cannot be null"))
+                .userSettingsSource(nonNull(userSettingsSource, "userSettingsSource cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static SettingsBuilderRequest build(
+            @Nonnull Session session,
+            @Nonnull Path globalSettingsPath,
+            @Nonnull Path projectSettingsPath,
+            @Nonnull Path userSettingsPath) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .globalSettingsPath(nonNull(globalSettingsPath, "globalSettingsPath cannot be null"))
+                .projectSettingsPath(nonNull(projectSettingsPath, "projectSettingsPath cannot be null"))
+                .userSettingsPath(nonNull(userSettingsPath, "userSettingsPath cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static SettingsBuilderRequestBuilder builder() {
+        return new SettingsBuilderRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class SettingsBuilderRequestBuilder {
+        Session session;
+        Path globalSettingsPath;
+        Source globalSettingsSource;
+        Path projectSettingsPath;
+        Source projectSettingsSource;
+        Path userSettingsPath;
+        Source userSettingsSource;
+
+        public SettingsBuilderRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder globalSettingsPath(Path globalSettingsPath) {
+            this.globalSettingsPath = globalSettingsPath;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder globalSettingsSource(Source globalSettingsSource) {
+            this.globalSettingsSource = globalSettingsSource;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder projectSettingsPath(Path projectSettingsPath) {
+            this.projectSettingsPath = projectSettingsPath;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder projectSettingsSource(Source projectSettingsSource) {
+            this.projectSettingsSource = projectSettingsSource;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder userSettingsPath(Path userSettingsPath) {
+            this.userSettingsPath = userSettingsPath;
+            return this;
+        }
+
+        public SettingsBuilderRequestBuilder userSettingsSource(Source userSettingsSource) {
+            this.userSettingsSource = userSettingsSource;
+            return this;
+        }
+
+        public SettingsBuilderRequest build() {
+            return new DefaultSettingsBuilderRequest(
+                    session,
+                    globalSettingsPath,
+                    globalSettingsSource,
+                    projectSettingsPath,
+                    projectSettingsSource,
+                    userSettingsPath,
+                    userSettingsSource);
+        }
+
+        private static class DefaultSettingsBuilderRequest extends BaseRequest implements SettingsBuilderRequest {
+            private final Path globalSettingsPath;
+            private final Source globalSettingsSource;
+            private final Path projectSettingsPath;
+            private final Source projectSettingsSource;
+            private final Path userSettingsPath;
+            private final Source userSettingsSource;
+
+            @SuppressWarnings("checkstyle:ParameterNumber")
+            DefaultSettingsBuilderRequest(
+                    @Nonnull Session session,
+                    @Nullable Path globalSettingsPath,
+                    @Nullable Source globalSettingsSource,
+                    @Nullable Path projectSettingsPath,
+                    @Nullable Source projectSettingsSource,
+                    @Nullable Path userSettingsPath,
+                    @Nullable Source userSettingsSource) {
+                super(session);
+                this.globalSettingsPath = globalSettingsPath;
+                this.globalSettingsSource = globalSettingsSource;
+                this.projectSettingsPath = projectSettingsPath;
+                this.projectSettingsSource = projectSettingsSource;
+                this.userSettingsPath = userSettingsPath;
+                this.userSettingsSource = userSettingsSource;
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getGlobalSettingsPath() {
+                return Optional.ofNullable(globalSettingsPath);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getGlobalSettingsSource() {
+                return Optional.ofNullable(globalSettingsSource);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getProjectSettingsPath() {
+                return Optional.ofNullable(projectSettingsPath);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getProjectSettingsSource() {
+                return Optional.ofNullable(projectSettingsSource);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getUserSettingsPath() {
+                return Optional.ofNullable(userSettingsPath);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getUserSettingsSource() {
+                return Optional.ofNullable(userSettingsSource);
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
new file mode 100644
index 0000000..201501e
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SettingsBuilderResult.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.List;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.settings.Settings;
+
+public interface SettingsBuilderResult {
+
+    /**
+     * Gets the assembled settings.
+     *
+     * @return the assembled settings, never {@code null}
+     */
+    @Nonnull
+    Settings getEffectiveSettings();
+
+    /**
+     * Gets the problems that were encountered during the settings building. Note that only problems of severity
+     * {@link BuilderProblem.Severity#WARNING} and below are reported here. Problems with a higher severity level cause
+     * the settings builder to fail with a {@link SettingsBuilderException}.
+     *
+     * @return the problems that were encountered during the settings building, can be empty but never {@code null}
+     */
+    @Nonnull
+    List<BuilderProblem> getProblems();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java
new file mode 100644
index 0000000..9b393d6
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Source.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Provides access to the contents of a source independently of the
+ * backing store (e.g. file system, database, memory).
+ * <p>
+ * This is mainly used to parse files into objects such as
+ * {@link org.apache.maven.api.Project},
+ * {@link org.apache.maven.api.model.Model},
+ * {@link org.apache.maven.api.settings.Settings}, or
+ * {@link org.apache.maven.api.toolchain.PersistedToolchains}.
+ *
+ * @since 4.0.0
+ * @see org.apache.maven.api.services.ProjectBuilder#build(Session, Source)
+ * @see org.apache.maven.api.services.SettingsBuilder#build(Session, Source, Source, Source)
+ * @see org.apache.maven.api.services.ToolchainsBuilder#build(Session, Source, Source)
+ */
+@Experimental
+public interface Source {
+
+    /**
+     * Provides access the file to be parsed, if this source is backed by a file.
+     *
+     * @return the underlying {@code Path}, or {@code null} if this source is not backed by a file
+     */
+    @Nullable
+    Path getPath();
+
+    /**
+     * Creates a new byte stream to the source contents.
+     * Closing the returned stream is the responsibility of the caller.
+     *
+     * @return a byte stream to the source contents, never {@code null}
+     * @throws IOException in case of IO issue
+     */
+    @Nonnull
+    InputStream openStream() throws IOException;
+
+    /**
+     * Provides a user-friendly hint about the location of the source.
+     * This could be a local file path, a URI or just an empty string.
+     * The intention is to assist users during error reporting.
+     *
+     * @return a user-friendly hint about the location of the source, never {@code null}
+     */
+    @Nonnull
+    String getLocation();
+
+    /**
+     * Returns a new source identified by a relative path. Implementation <strong>MUST</strong>
+     * be able to accept <code>relative</code> parameter values that
+     * <ul>
+     * <li>use either / or \ file path separator,</li>
+     * <li>have .. parent directory references,</li>
+     * <li>point either at file or directory.</li>
+     * </ul>
+     *
+     * @param relative is the path of the requested source relative to this source
+     * @return related source or <code>null</code> if no such source
+     */
+    Source resolve(String relative);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SuperPomProvider.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SuperPomProvider.java
new file mode 100644
index 0000000..8b94ab8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SuperPomProvider.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.Model;
+
+/**
+ * Provides the super POM that all models implicitly inherit from.
+ */
+@Experimental
+public interface SuperPomProvider extends Service {
+
+    /**
+     * Gets the super POM for the specified model version.
+     *
+     * @param version The model version to retrieve the super POM for (e.g. "4.0.0"), must not be {@code null}.
+     * @return The super POM, never {@code null}.
+     * @throws SuperPomProviderException if the super POM could not be retrieved
+     */
+    @Nonnull
+    Model getSuperPom(@Nonnull String version);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/SuperPomProviderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SuperPomProviderException.java
new file mode 100644
index 0000000..4aa6890
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/SuperPomProviderException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+/**
+ * Exceptions thrown by the {@link SuperPomProvider} service.
+ *
+ * @since 4.0.0
+ */
+public class SuperPomProviderException extends MavenException {
+
+    public SuperPomProviderException() {
+        super();
+    }
+
+    public SuperPomProviderException(String message) {
+        super(message);
+    }
+
+    public SuperPomProviderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public SuperPomProviderException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainFactory.java
new file mode 100644
index 0000000..1a9baa3
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * @since 4.0.0
+ */
+@Experimental
+@Consumer
+public interface ToolchainFactory {
+    // TODO: implement ToolchainFactory
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
new file mode 100644
index 0000000..e428f81
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManager.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Toolchain;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service to manage {@link Toolchain}s.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ToolchainManager extends Service {
+
+    /**
+     *
+     * @param session
+     * @param type
+     * @param requirements
+     * @return the selected {@link Toolchain}s
+     * @throws ToolchainManagerException if an exception occurs
+     */
+    @Nonnull
+    List<Toolchain> getToolchains(@Nonnull Session session, String type, Map<String, String> requirements);
+
+    /**
+     *
+     * @param session
+     * @param type
+     * @return the selected {@link Toolchain}
+     * @throws ToolchainManagerException if an exception occurs
+     */
+    @Nonnull
+    Optional<Toolchain> getToolchainFromBuildContext(@Nonnull Session session, String type)
+            throws ToolchainManagerException;
+
+    /**
+     *
+     * @param session
+     * @param type
+     * @return the selected {@link Toolchain}s
+     * @throws ToolchainManagerException if an exception occurs
+     */
+    @Nonnull
+    List<Toolchain> getToolchainsForType(@Nonnull Session session, String type) throws ToolchainManagerException;
+
+    /**
+     *
+     * @param session
+     * @param toolchain
+     * @throws ToolchainManagerException if an exception occurs
+     */
+    void storeToolchainToBuildContext(@Nonnull Session session, Toolchain toolchain) throws ToolchainManagerException;
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
new file mode 100644
index 0000000..16c93c3
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainManagerException.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link ToolchainManager}.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class ToolchainManagerException extends MavenException {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public ToolchainManagerException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilder.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilder.java
new file mode 100644
index 0000000..8de4a64
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilder.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Builds the effective toolchains from a user toolchains file and/or a global toolchains file.
+ */
+@Experimental
+public interface ToolchainsBuilder extends Service {
+
+    /**
+     * Builds the effective toolchains for the specified toolchains files.
+     *
+     * @param request the toolchains building request that holds the parameters, must not be {@code null}
+     * @return the result of the toolchains building, never {@code null}
+     * @throws ToolchainsBuilderException if the effective toolchains could not be built
+     */
+    ToolchainsBuilderResult build(ToolchainsBuilderRequest request);
+
+    /**
+     * Builds the effective toolchains for the specified toolchains sources.
+     *
+     * @param session the {@link Session}, must not be {@code null}
+     * @param globalToolchainsSource The {@link Source} pointing to the global toolchains, must not be {@code null}
+     * @param userToolchainsSource The {@link Source} pointing to the user toolchains, must not be {@code null}
+     * @throws ToolchainsBuilderException if the project cannot be created
+     * @throws IllegalArgumentException if an argument is {@code null} or invalid
+     * @see #build(ToolchainsBuilderRequest)
+     */
+    @Nonnull
+    default ToolchainsBuilderResult build(
+            @Nonnull Session session, @Nonnull Source globalToolchainsSource, @Nonnull Source userToolchainsSource) {
+        return build(ToolchainsBuilderRequest.build(session, globalToolchainsSource, userToolchainsSource));
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
new file mode 100644
index 0000000..c6f5ca8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderException.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class throw by the {@link ToolchainsBuilder}.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class ToolchainsBuilderException extends MavenException {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public ToolchainsBuilderException(String message, Exception e) {
+        super(message, e);
+    }
+
+    // TODO: add ToolchainsBuilderResult
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
new file mode 100644
index 0000000..7999fe1
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderRequest.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+import static org.apache.maven.api.services.BaseRequest.nonNull;
+
+public interface ToolchainsBuilderRequest {
+    @Nonnull
+    Session getSession();
+
+    /**
+     * Gets the global Toolchains path.
+     *
+     * @return the global Toolchains path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getGlobalToolchainsPath();
+
+    /**
+     * Gets the global Toolchains source.
+     *
+     * @return the global Toolchains source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getGlobalToolchainsSource();
+
+    /**
+     * Gets the user Toolchains path.
+     *
+     * @return the user Toolchains path or {@code null} if none
+     */
+    @Nonnull
+    Optional<Path> getUserToolchainsPath();
+
+    /**
+     * Gets the user Toolchains source.
+     *
+     * @return the user Toolchains source or {@code null} if none
+     */
+    @Nonnull
+    Optional<Source> getUserToolchainsSource();
+
+    @Nonnull
+    static ToolchainsBuilderRequest build(
+            @Nonnull Session session, @Nonnull Source globalToolchainsSource, @Nonnull Source userToolchainsSource) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .globalToolchainsSource(nonNull(globalToolchainsSource, "globalToolchainsSource cannot be null"))
+                .userToolchainsSource(nonNull(userToolchainsSource, "userToolchainsSource cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static ToolchainsBuilderRequest build(
+            @Nonnull Session session, @Nonnull Path globalToolchainsPath, @Nonnull Path userToolchainsPath) {
+        return builder()
+                .session(nonNull(session, "session cannot be null"))
+                .globalToolchainsPath(nonNull(globalToolchainsPath, "globalToolchainsPath cannot be null"))
+                .userToolchainsPath(nonNull(userToolchainsPath, "userToolchainsPath cannot be null"))
+                .build();
+    }
+
+    @Nonnull
+    static ToolchainsBuilderRequestBuilder builder() {
+        return new ToolchainsBuilderRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class ToolchainsBuilderRequestBuilder {
+        Session session;
+        Path globalToolchainsPath;
+        Source globalToolchainsSource;
+        Path userToolchainsPath;
+        Source userToolchainsSource;
+
+        public ToolchainsBuilderRequestBuilder session(Session session) {
+            this.session = session;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder globalToolchainsPath(Path globalToolchainsPath) {
+            this.globalToolchainsPath = globalToolchainsPath;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder globalToolchainsSource(Source globalToolchainsSource) {
+            this.globalToolchainsSource = globalToolchainsSource;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder userToolchainsPath(Path userToolchainsPath) {
+            this.userToolchainsPath = userToolchainsPath;
+            return this;
+        }
+
+        public ToolchainsBuilderRequestBuilder userToolchainsSource(Source userToolchainsSource) {
+            this.userToolchainsSource = userToolchainsSource;
+            return this;
+        }
+
+        public ToolchainsBuilderRequest build() {
+            return new ToolchainsBuilderRequestBuilder.DefaultToolchainsBuilderRequest(
+                    session, globalToolchainsPath, globalToolchainsSource, userToolchainsPath, userToolchainsSource);
+        }
+
+        private static class DefaultToolchainsBuilderRequest extends BaseRequest implements ToolchainsBuilderRequest {
+            private final Path globalToolchainsPath;
+            private final Source globalToolchainsSource;
+            private final Path userToolchainsPath;
+            private final Source userToolchainsSource;
+
+            @SuppressWarnings("checkstyle:ParameterNumber")
+            DefaultToolchainsBuilderRequest(
+                    @Nonnull Session session,
+                    @Nullable Path globalToolchainsPath,
+                    @Nullable Source globalToolchainsSource,
+                    @Nullable Path userToolchainsPath,
+                    @Nullable Source userToolchainsSource) {
+                super(session);
+                this.globalToolchainsPath = globalToolchainsPath;
+                this.globalToolchainsSource = globalToolchainsSource;
+                this.userToolchainsPath = userToolchainsPath;
+                this.userToolchainsSource = userToolchainsSource;
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getGlobalToolchainsPath() {
+                return Optional.ofNullable(globalToolchainsPath);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getGlobalToolchainsSource() {
+                return Optional.ofNullable(globalToolchainsSource);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Path> getUserToolchainsPath() {
+                return Optional.ofNullable(userToolchainsPath);
+            }
+
+            @Nonnull
+            @Override
+            public Optional<Source> getUserToolchainsSource() {
+                return Optional.ofNullable(userToolchainsSource);
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
new file mode 100644
index 0000000..30ac872
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/ToolchainsBuilderResult.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.util.List;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.toolchain.PersistedToolchains;
+
+public interface ToolchainsBuilderResult {
+    /**
+     * Gets the assembled toolchains.
+     *
+     * @return the assembled toolchains, never {@code null}
+     */
+    @Nonnull
+    PersistedToolchains getEffectiveToolchains();
+
+    /**
+     * Gets the problems that were encountered during the settings building. Note that only problems of severity
+     * {@link BuilderProblem.Severity#WARNING} and below are reported here. Problems with a higher severity level cause
+     * the settings builder to fail with a {@link ToolchainsBuilderException}.
+     *
+     * @return the problems that were encountered during the settings building, can be empty but never {@code null}
+     */
+    @Nonnull
+    List<BuilderProblem> getProblems();
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/Transport.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Transport.java
new file mode 100644
index 0000000..a74c399
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/Transport.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import java.io.Closeable;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Transport for specified remote repository (using provided remote repository base URI as root). Must be treated as a
+ * resource, best in try-with-resource block.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Consumer
+public interface Transport extends Closeable {
+    /**
+     * GETs the source URI content into target (does not have to exist, or will be overwritten if exist). The
+     * source MUST BE relative from the {@link RemoteRepository#getUrl()} root.
+     *
+     * @return {@code true} if operation succeeded, {@code false} if source does not exist.
+     * @throws RuntimeException If failed (and not due source not exists).
+     */
+    boolean get(@Nonnull URI relativeSource, @Nonnull Path target);
+
+    /**
+     * GETs the source URI content as byte array. The source MUST BE relative from the {@link RemoteRepository#getUrl()}
+     * root.
+     *
+     * @return the byte array if operation succeeded, {@code null} if source does not exist.
+     * @throws RuntimeException If failed (and not due source not exists).
+     */
+    @Nonnull
+    Optional<byte[]> getBytes(@Nonnull URI relativeSource);
+
+    /**
+     * GETs the source URI content as string. The source MUST BE relative from the {@link RemoteRepository#getUrl()}
+     * root.
+     *
+     * @return the string if operation succeeded, {@code null} if source does not exist.
+     * @throws RuntimeException If failed (and not due source not exists).
+     */
+    @Nonnull
+    Optional<String> getString(@Nonnull URI relativeSource, @Nonnull Charset charset);
+
+    /**
+     * GETs the source URI content as string using UTF8 charset. The source MUST BE relative from the
+     * {@link RemoteRepository#getUrl()} root.
+     *
+     * @return the string if operation succeeded, {@code null} if source does not exist.
+     * @throws RuntimeException If failed (and not due source not exists).
+     */
+    @Nonnull
+    default Optional<String> getString(@Nonnull URI relativeSource) {
+        return getString(relativeSource, StandardCharsets.UTF_8);
+    }
+
+    /**
+     * PUTs the source file (must exist as file) to target URI. The target MUST BE relative from the
+     * {@link RemoteRepository#getUrl()} root.
+     *
+     * @throws RuntimeException If PUT fails for any reason.
+     */
+    void put(@Nonnull Path source, @Nonnull URI relativeTarget);
+
+    /**
+     * PUTs the source byte array to target URI. The target MUST BE relative from the
+     * {@link RemoteRepository#getUrl()} root.
+     *
+     * @throws RuntimeException If PUT fails for any reason.
+     */
+    void putBytes(@Nonnull byte[] source, @Nonnull URI relativeTarget);
+
+    /**
+     * PUTs the source string to target URI. The target MUST BE relative from the
+     * {@link RemoteRepository#getUrl()} root.
+     *
+     * @throws RuntimeException If PUT fails for any reason.
+     */
+    void putString(@Nonnull String source, @Nonnull Charset charset, @Nonnull URI relativeTarget);
+
+    /**
+     * PUTs the source string using UTF8 charset to target URI. The target MUST BE relative from the
+     * {@link RemoteRepository#getUrl()} root.
+     *
+     * @throws RuntimeException If PUT fails for any reason.
+     */
+    default void putString(@Nonnull String source, @Nonnull URI relativeTarget) {
+        putString(source, StandardCharsets.UTF_8, relativeTarget);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/TransportProvider.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TransportProvider.java
new file mode 100644
index 0000000..7bf6bd9
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TransportProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Transporter provider is a service that provides somewhat trivial transport capabilities backed by Maven internals.
+ * This API does not try to cover all the requirements out there, just the basic ones, and is intentionally simple.
+ * If plugin or extension needs anything more complex feature wise (i.e. HTTP range support or alike) it should
+ * probably roll its own.
+ * <p>
+ * This implementation is backed by Maven Resolver API, supported protocols and transport selection depends on it. If
+ * resolver preference regarding transport is altered, it will affect this service as well.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Consumer
+public interface TransportProvider extends Service {
+    /**
+     * Provides new {@link Transport} instance for given {@link RemoteRepository}, if possible.
+     *
+     * @throws TransportProviderException if passed in remote repository has invalid remote URL or unsupported protocol.
+     */
+    @Nonnull
+    Transport transport(@Nonnull Session session, @Nonnull RemoteRepository repository);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/TransportProviderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TransportProviderException.java
new file mode 100644
index 0000000..2da5020
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TransportProviderException.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Consumer;
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * @since 4.0.0
+ */
+@Experimental
+@Consumer
+public class TransportProviderException extends MavenException {
+    public TransportProviderException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java
new file mode 100644
index 0000000..c484df4
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/TypeRegistry.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Type;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Access to {@link Type} registry.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface TypeRegistry extends Service {
+
+    /**
+     * Obtain the {@link Type} from the specified {@code id}.
+     * If no type is known for {@code id}, the registry will
+     * create a custom {@code Type} for it.
+     *
+     * @param id the id of the type to retrieve
+     * @return the type
+     */
+    @Nonnull
+    Type getType(@Nonnull String id);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java
new file mode 100644
index 0000000..49c3738
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParser.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Version;
+import org.apache.maven.api.VersionRange;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Service interface to parse {@link Version} and {@link VersionRange}.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface VersionParser extends Service {
+    /**
+     * Parses the specified version string, for example "1.0".
+     *
+     * @param version the version string to parse, must not be {@code null}
+     * @return the parsed version, never {@code null}
+     * @throws VersionParserException if the string violates the syntax rules of this scheme
+     * @see org.apache.maven.api.Session#parseVersion(String)
+     */
+    @Nonnull
+    Version parseVersion(@Nonnull String version);
+
+    /**
+     * Parses the specified version range specification, for example "[1.0,2.0)".
+     *
+     * @param range the range specification to parse, must not be {@code null}
+     * @return the parsed version range, never {@code null}
+     * @throws VersionParserException if the range specification violates the syntax rules of this scheme
+     */
+    @Nonnull
+    VersionRange parseVersionRange(@Nonnull String range);
+
+    /**
+     * Checks whether a given artifact version is considered a {@code SNAPSHOT} or not.
+     */
+    boolean isSnapshot(@Nonnull String version);
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParserException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParserException.java
new file mode 100644
index 0000000..9982db8
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/VersionParserException.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services;
+
+import org.apache.maven.api.annotations.Experimental;
+
+/**
+ * The Exception class thrown by {@link VersionParser}.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class VersionParserException extends MavenException {
+    /**
+     * @param message the message to give
+     * @param e the {@link Exception}
+     */
+    public VersionParserException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ModelXmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ModelXmlFactory.java
new file mode 100644
index 0000000..f02e4e5
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ModelXmlFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.model.Model;
+
+/**
+ * Reads or writes a {@link Model} using XML.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ModelXmlFactory extends XmlFactory<Model> {}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/SettingsXmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/SettingsXmlFactory.java
new file mode 100644
index 0000000..9010dfa
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/SettingsXmlFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.settings.Settings;
+
+/**
+ * Reads and writes a {@link Settings} object to/from XML.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface SettingsXmlFactory extends XmlFactory<Settings> {}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ToolchainsXmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ToolchainsXmlFactory.java
new file mode 100644
index 0000000..ec90299
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/ToolchainsXmlFactory.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.toolchain.PersistedToolchains;
+
+/**
+ * Reads and writes a {@link PersistedToolchains} object to/from XML.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public interface ToolchainsXmlFactory extends XmlFactory<PersistedToolchains> {}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlFactory.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlFactory.java
new file mode 100644
index 0000000..6fae7f9
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlFactory.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.file.Path;
+
+import org.apache.maven.api.Service;
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+
+/**
+ * Generic interface to read/write objects to/from XML.
+ *
+ * @param <T> the object type to read/write
+ * @since 4.0.0
+ */
+@Experimental
+public interface XmlFactory<T> extends Service {
+
+    @Nonnull
+    default T read(@Nonnull Path path) throws XmlReaderException {
+        return read(path, true);
+    }
+
+    @Nonnull
+    default T read(@Nonnull Path path, boolean strict) throws XmlReaderException {
+        return read(XmlReaderRequest.builder().path(path).strict(strict).build());
+    }
+
+    @Nonnull
+    default T read(@Nonnull InputStream input) throws XmlReaderException {
+        return read(input, true);
+    }
+
+    @Nonnull
+    default T read(@Nonnull InputStream input, boolean strict) throws XmlReaderException {
+        return read(XmlReaderRequest.builder().inputStream(input).strict(strict).build());
+    }
+
+    @Nonnull
+    default T read(@Nonnull Reader reader) throws XmlReaderException {
+        return read(reader, true);
+    }
+
+    @Nonnull
+    default T read(@Nonnull Reader reader, boolean strict) throws XmlReaderException {
+        return read(XmlReaderRequest.builder().reader(reader).strict(strict).build());
+    }
+
+    @Nonnull
+    T read(@Nonnull XmlReaderRequest request) throws XmlReaderException;
+
+    default void write(@Nonnull T content, @Nonnull Path path) throws XmlWriterException {
+        write(XmlWriterRequest.<T>builder().content(content).path(path).build());
+    }
+
+    default void write(@Nonnull T content, @Nonnull OutputStream outputStream) throws XmlWriterException {
+        write(XmlWriterRequest.<T>builder()
+                .content(content)
+                .outputStream(outputStream)
+                .build());
+    }
+
+    default void write(@Nonnull T content, @Nonnull Writer writer) throws XmlWriterException {
+        write(XmlWriterRequest.<T>builder().content(content).writer(writer).build());
+    }
+
+    void write(@Nonnull XmlWriterRequest<T> request) throws XmlWriterException;
+
+    /**
+     * Simply parse the given xml string.
+     *
+     * @param xml the input xml string
+     * @return the parsed object
+     * @throws XmlReaderException if an error occurs during the parsing
+     * @see #toXmlString(Object)
+     */
+    @Nonnull
+    default T fromXmlString(@Nonnull String xml) throws XmlReaderException {
+        return read(new StringReader(xml));
+    }
+
+    /**
+     * Simply converts the given content to an xml string.
+     *
+     * @param content the object to convert
+     * @return the xml string representation
+     * @throws XmlWriterException if an error occurs during the transformation
+     * @see #fromXmlString(String)
+     */
+    @Nonnull
+    default String toXmlString(@Nonnull T content) throws XmlWriterException {
+        StringWriter sw = new StringWriter();
+        write(content, sw);
+        return sw.toString();
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java
new file mode 100644
index 0000000..a666c74
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderException.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.services.MavenException;
+
+/**
+ * An exception thrown during the reading of an xml file.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class XmlReaderException extends MavenException {
+
+    /**
+     * @param message the message for the exception
+     * @param e the exception itself
+     */
+    public XmlReaderException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
new file mode 100644
index 0000000..3087e3a
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlReaderRequest.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.net.URL;
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.NotThreadSafe;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * An XML reader request.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Immutable
+public interface XmlReaderRequest {
+
+    @Nullable
+    Path getPath();
+
+    @Nullable
+    URL getURL();
+
+    @Nullable
+    InputStream getInputStream();
+
+    @Nullable
+    Reader getReader();
+
+    @Nullable
+    Transformer getTransformer();
+
+    boolean isStrict();
+
+    @Nullable
+    String getModelId();
+
+    @Nullable
+    String getLocation();
+
+    boolean isAddDefaultEntities();
+
+    interface Transformer {
+        /**
+         * Interpolate the value read from the xml document
+         *
+         * @param source    The source value
+         * @param fieldName A description of the field being interpolated. The implementation may use this to
+         *                  log stuff.
+         * @return the interpolated value
+         */
+        String transform(String source, String fieldName);
+    }
+
+    @Nonnull
+    static XmlReaderRequestBuilder builder() {
+        return new XmlReaderRequestBuilder();
+    }
+
+    @NotThreadSafe
+    class XmlReaderRequestBuilder {
+        Path path;
+        URL url;
+        InputStream inputStream;
+        Reader reader;
+        Transformer transformer;
+        boolean strict;
+        String modelId;
+        String location;
+        boolean addDefaultEntities = true;
+
+        public XmlReaderRequestBuilder path(Path path) {
+            this.path = path;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder url(URL url) {
+            this.url = url;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder inputStream(InputStream inputStream) {
+            this.inputStream = inputStream;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder reader(Reader reader) {
+            this.reader = reader;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder transformer(Transformer transformer) {
+            this.transformer = transformer;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder strict(boolean strict) {
+            this.strict = strict;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder modelId(String modelId) {
+            this.modelId = modelId;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder location(String location) {
+            this.location = location;
+            return this;
+        }
+
+        public XmlReaderRequestBuilder addDefaultEntities(boolean addDefaultEntities) {
+            this.addDefaultEntities = addDefaultEntities;
+            return this;
+        }
+
+        public XmlReaderRequest build() {
+            return new DefaultXmlReaderRequest(
+                    path, url, inputStream, reader, transformer, strict, modelId, location, addDefaultEntities);
+        }
+
+        private static class DefaultXmlReaderRequest implements XmlReaderRequest {
+            final Path path;
+            final URL url;
+            final InputStream inputStream;
+            final Reader reader;
+            final Transformer transformer;
+            final boolean strict;
+            final String modelId;
+            final String location;
+            final boolean addDefaultEntities;
+
+            @SuppressWarnings("checkstyle:ParameterNumber")
+            DefaultXmlReaderRequest(
+                    Path path,
+                    URL url,
+                    InputStream inputStream,
+                    Reader reader,
+                    Transformer transformer,
+                    boolean strict,
+                    String modelId,
+                    String location,
+                    boolean addDefaultEntities) {
+                this.path = path;
+                this.url = url;
+                this.inputStream = inputStream;
+                this.reader = reader;
+                this.transformer = transformer;
+                this.strict = strict;
+                this.modelId = modelId;
+                this.location = location;
+                this.addDefaultEntities = addDefaultEntities;
+            }
+
+            @Override
+            public Path getPath() {
+                return path;
+            }
+
+            @Override
+            public URL getURL() {
+                return null;
+            }
+
+            @Override
+            public InputStream getInputStream() {
+                return inputStream;
+            }
+
+            public Reader getReader() {
+                return reader;
+            }
+
+            @Override
+            public Transformer getTransformer() {
+                return transformer;
+            }
+
+            @Override
+            public boolean isStrict() {
+                return strict;
+            }
+
+            @Override
+            public String getModelId() {
+                return modelId;
+            }
+
+            @Override
+            public String getLocation() {
+                return location;
+            }
+
+            @Override
+            public boolean isAddDefaultEntities() {
+                return addDefaultEntities;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java
new file mode 100644
index 0000000..491a1f0
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterException.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.services.MavenException;
+
+/**
+ * An exception thrown during the writing of an xml file.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+public class XmlWriterException extends MavenException {
+
+    /**
+     * @param message the message for the exception
+     * @param e the exception itself
+     */
+    public XmlWriterException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
new file mode 100644
index 0000000..f9a305d
--- /dev/null
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/services/xml/XmlWriterRequest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.services.xml;
+
+import java.io.OutputStream;
+import java.io.Writer;
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * An XML writer request.
+ *
+ * @since 4.0.0
+ * @param <T> the object type to read
+ */
+@Experimental
+public interface XmlWriterRequest<T> {
+
+    @Nullable
+    Path getPath();
+
+    @Nullable
+    OutputStream getOutputStream();
+
+    @Nullable
+    Writer getWriter();
+
+    @Nonnull
+    T getContent();
+
+    static <T> XmlWriterRequestBuilder<T> builder() {
+        return new XmlWriterRequestBuilder<>();
+    }
+
+    class XmlWriterRequestBuilder<T> {
+        Path path;
+        OutputStream outputStream;
+        Writer writer;
+        T content;
+
+        public XmlWriterRequestBuilder<T> path(Path path) {
+            this.path = path;
+            return this;
+        }
+
+        public XmlWriterRequestBuilder<T> outputStream(OutputStream outputStream) {
+            this.outputStream = outputStream;
+            return this;
+        }
+
+        public XmlWriterRequestBuilder<T> writer(Writer writer) {
+            this.writer = writer;
+            return this;
+        }
+
+        public XmlWriterRequestBuilder<T> content(T content) {
+            this.content = content;
+            return this;
+        }
+
+        public XmlWriterRequest<T> build() {
+            return new DefaultXmlWriterRequest<>(path, outputStream, writer, content);
+        }
+
+        private static class DefaultXmlWriterRequest<T> implements XmlWriterRequest<T> {
+            final Path path;
+            final OutputStream outputStream;
+            final Writer writer;
+            final T content;
+
+            DefaultXmlWriterRequest(Path path, OutputStream outputStream, Writer writer, T content) {
+                this.path = path;
+                this.outputStream = outputStream;
+                this.writer = writer;
+                this.content = content;
+            }
+
+            @Override
+            public Path getPath() {
+                return path;
+            }
+
+            @Override
+            public OutputStream getOutputStream() {
+                return outputStream;
+            }
+
+            @Override
+            public Writer getWriter() {
+                return writer;
+            }
+
+            @Override
+            public T getContent() {
+                return content;
+            }
+        }
+    }
+}
diff --git a/api/maven-api-core/src/site/site.xml b/api/maven-api-core/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/maven-api-core/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/api/maven-api-meta/pom.xml b/api/maven-api-meta/pom.xml
new file mode 100644
index 0000000..820af57
--- /dev/null
+++ b/api/maven-api-meta/pom.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-meta</artifactId>
+  <name>Maven 4 API :: Meta annotations</name>
+  <description>Maven 4 API - Java meta annotations.</description>
+
+</project>
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Consumer.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Consumer.java
new file mode 100644
index 0000000..8130023
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Consumer.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A type implemented by, or extended by maven plugins or extensions.
+ * Maven plugins or extensions may provide implementations of those types which will be used by maven.
+ * <p>
+ * A type can be marked {@link Consumer} or {@link Provider} but not both. A type is assumed to be
+ * {@link Consumer} if it is not marked either {@link Consumer} or {@link Provider}.
+ * <p>
+ * A package can be marked {@link Provider}. In this case, all types in the package are considered
+ * to be a provider type regardless of whether they are marked {@link Consumer} or {@link Provider}.
+ *
+ * @see Provider
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE, ElementType.PACKAGE})
+public @interface Consumer {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Experimental.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Experimental.java
new file mode 100644
index 0000000..6554cea
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Experimental.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This annotation tags types that are part of an experimental API.
+ * Classes or methods annotated with this annotation may be changed / removed without notice.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+public @interface Experimental {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Generated.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Generated.java
new file mode 100644
index 0000000..d41ba1c
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Generated.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation indicates that a type is automatically generated.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface Generated {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Immutable.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Immutable.java
new file mode 100644
index 0000000..e86d17f
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Immutable.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The {@code Immutable} annotation indicates that the object is immutable, i.e.
+ * none of its field can be changed.  This also ensures that the type is
+ * {@link ThreadSafe}.
+ *
+ * @see ThreadSafe
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@ThreadSafe
+@Target(ElementType.TYPE)
+public @interface Immutable {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nonnull.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nonnull.java
new file mode 100644
index 0000000..ada5c0d
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nonnull.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The annotated element must not be null.
+ * <p>
+ * Annotated fields must not be null after construction has completed.
+ * <p>
+ * When this annotation is applied to a method it applies to the method return value.
+ *
+ * @see Nullable
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
+public @interface Nonnull {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/NotThreadSafe.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/NotThreadSafe.java
new file mode 100644
index 0000000..348ca77
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/NotThreadSafe.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation indicates that the annotated type is <strong>not</strong> threadsafe
+ * and should only be used by a single thread.
+ *
+ * @see ThreadSafe
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface NotThreadSafe {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nullable.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nullable.java
new file mode 100644
index 0000000..32e4bd7
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Nullable.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * The annotated element can be {@code null}.
+ *
+ * @see Nonnull
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+public @interface Nullable {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Provider.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Provider.java
new file mode 100644
index 0000000..69d73db
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/Provider.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * A type implemented by, or extended by maven itself.
+ * Maven provides implementations of those types and may inject them in plugins.
+ * <p>
+ * A type can be marked {@link Consumer} or {@link Provider} but not both. A type is assumed to be
+ * {@link Consumer} if it is not marked either {@link Consumer} or {@link Provider}.
+ * <p>
+ * A package can be marked {@link Provider}. In this case, all types in the package are considered
+ * to be a provider type regardless of whether they are marked {@link Consumer} or {@link Provider}.
+ *
+ * @see Consumer
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.TYPE, ElementType.PACKAGE})
+public @interface Provider {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/ThreadSafe.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/ThreadSafe.java
new file mode 100644
index 0000000..9b500c2
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/ThreadSafe.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * The {@code ThreadSafe} annotation can be used to indicate a given type
+ * is thread safe.  {@link Immutable} objects are automatically thread safe.
+ *
+ * @see Immutable
+ * @see NotThreadSafe
+ * @since 4.0.0
+ */
+@Experimental
+@Documented
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.TYPE)
+public @interface ThreadSafe {}
diff --git a/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/package-info.java b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/package-info.java
new file mode 100644
index 0000000..220a5c3
--- /dev/null
+++ b/api/maven-api-meta/src/main/java/org/apache/maven/api/annotations/package-info.java
@@ -0,0 +1,10 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/**
+ * This package contains non-functional annotations which are
+ * used to tag various elements and help users understanding
+ * how those types should be used.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+package org.apache.maven.api.annotations;
diff --git a/api/maven-api-meta/src/site/site.xml b/api/maven-api-meta/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/maven-api-meta/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/api/maven-api-model/pom.xml b/api/maven-api-model/pom.xml
new file mode 100644
index 0000000..559c839
--- /dev/null
+++ b/api/maven-api-model/pom.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-model</artifactId>
+
+  <name>Maven 4 API :: Model</name>
+  <description>Maven 4 API - Immutable Model for Maven POM (Project Object Model).</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-xml</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.modello</groupId>
+        <artifactId>modello-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>velocity</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <configuration>
+              <version>4.1.0</version>
+              <velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
+              <models>
+                <model>src/main/mdo/maven.mdo</model>
+              </models>
+              <templates>
+                <template>model.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV4=org.apache.maven.api.model</param>
+                <param>isMavenModel=true</param>
+              </params>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/package-info.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>3.4.0</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${basedir}/src/main/mdo/maven.mdo</file>
+                  <type>mdo</type>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java
new file mode 100644
index 0000000..28bd415
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocation.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.model;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Class InputLocation.
+ */
+public class InputLocation implements Serializable, InputLocationTracker {
+    private final int lineNumber;
+    private final int columnNumber;
+    private final InputSource source;
+    private final Map<Object, InputLocation> locations;
+
+    public InputLocation(InputSource source) {
+        this.lineNumber = -1;
+        this.columnNumber = -1;
+        this.source = source;
+        this.locations = Collections.singletonMap(0, this);
+    }
+
+    public InputLocation(int lineNumber, int columnNumber) {
+        this(lineNumber, columnNumber, null, null);
+    }
+
+    public InputLocation(int lineNumber, int columnNumber, InputSource source) {
+        this(lineNumber, columnNumber, source, null);
+    }
+
+    public InputLocation(int lineNumber, int columnNumber, InputSource source, Object selfLocationKey) {
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+        this.source = source;
+        this.locations =
+                selfLocationKey != null ? Collections.singletonMap(selfLocationKey, this) : Collections.emptyMap();
+    }
+
+    public InputLocation(int lineNumber, int columnNumber, InputSource source, Map<Object, InputLocation> locations) {
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+        this.source = source;
+        this.locations = ImmutableCollections.copy(locations);
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    public InputSource getSource() {
+        return source;
+    }
+
+    public InputLocation getLocation(Object key) {
+        return locations != null ? locations.get(key) : null;
+    }
+
+    public Map<Object, InputLocation> getLocations() {
+        return locations;
+    }
+
+    /**
+     * Merges the {@code source} location into the {@code target} location.
+     *
+     * @param target the target location
+     * @param source the source location
+     * @param sourceDominant the boolean indicating of {@code source} is dominant compared to {@code target}
+     * @return the merged location
+     */
+    public static InputLocation merge(InputLocation target, InputLocation source, boolean sourceDominant) {
+        if (source == null) {
+            return target;
+        } else if (target == null) {
+            return source;
+        }
+
+        Map<Object, InputLocation> locations;
+        Map<Object, InputLocation> sourceLocations = source.locations;
+        Map<Object, InputLocation> targetLocations = target.locations;
+        if (sourceLocations == null) {
+            locations = targetLocations;
+        } else if (targetLocations == null) {
+            locations = sourceLocations;
+        } else {
+            locations = new LinkedHashMap<>();
+            locations.putAll(sourceDominant ? targetLocations : sourceLocations);
+            locations.putAll(sourceDominant ? sourceLocations : targetLocations);
+        }
+
+        return new InputLocation(-1, -1, InputSource.merge(source.getSource(), target.getSource()), locations);
+    } // -- InputLocation merge( InputLocation, InputLocation, boolean )
+
+    /**
+     * Merges the {@code source} location into the {@code target} location.
+     * This method is used when the locations refer to lists and also merges the indices.
+     *
+     * @param target the target location
+     * @param source the source location
+     * @param indices the list of integers for the indices
+     * @return the merged location
+     */
+    public static InputLocation merge(InputLocation target, InputLocation source, Collection<Integer> indices) {
+        if (source == null) {
+            return target;
+        } else if (target == null) {
+            return source;
+        }
+
+        Map<Object, InputLocation> locations;
+        Map<Object, InputLocation> sourceLocations = source.locations;
+        Map<Object, InputLocation> targetLocations = target.locations;
+        if (sourceLocations == null) {
+            locations = targetLocations;
+        } else if (targetLocations == null) {
+            locations = sourceLocations;
+        } else {
+            locations = new LinkedHashMap<>();
+            for (int index : indices) {
+                InputLocation location;
+                if (index < 0) {
+                    location = sourceLocations.get(~index);
+                } else {
+                    location = targetLocations.get(index);
+                }
+                locations.put(locations.size(), location);
+            }
+        }
+
+        return new InputLocation(-1, -1, InputSource.merge(source.getSource(), target.getSource()), locations);
+    } // -- InputLocation merge( InputLocation, InputLocation, java.util.Collection )
+
+    /**
+     * Class StringFormatter.
+     *
+     * @version $Revision$ $Date$
+     */
+    public interface StringFormatter {
+
+        // -----------/
+        // - Methods -/
+        // -----------/
+
+        /**
+         * Method toString.
+         */
+        String toString(InputLocation location);
+    }
+}
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java
new file mode 100644
index 0000000..ce4240e
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputLocationTracker.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.model;
+
+public interface InputLocationTracker {
+    InputLocation getLocation(Object field);
+}
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java
new file mode 100644
index 0000000..d5dc895
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/InputSource.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.model;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Class InputSource.
+ */
+public class InputSource implements Serializable {
+
+    private final String modelId;
+    private final String location;
+    private final List<InputSource> inputs;
+
+    public InputSource(String modelId, String location) {
+        this.modelId = modelId;
+        this.location = location;
+        this.inputs = null;
+    }
+
+    public InputSource(Collection<InputSource> inputs) {
+        this.modelId = null;
+        this.location = null;
+        this.inputs = ImmutableCollections.copy(inputs);
+    }
+
+    /**
+     * Get the path/URL of the POM or {@code null} if unknown.
+     *
+     * @return the location
+     */
+    public String getLocation() {
+        return this.location;
+    }
+
+    /**
+     * Get the identifier of the POM in the format {@code <groupId>:<artifactId>:<version>}.
+     *
+     * @return the model id
+     */
+    public String getModelId() {
+        return this.modelId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        InputSource that = (InputSource) o;
+        return Objects.equals(modelId, that.modelId)
+                && Objects.equals(location, that.location)
+                && Objects.equals(inputs, that.inputs);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(modelId, location, inputs);
+    }
+
+    Stream<InputSource> sources() {
+        return inputs != null ? inputs.stream() : Stream.of(this);
+    }
+
+    @Override
+    public String toString() {
+        if (inputs != null) {
+            return inputs.stream().map(InputSource::toString).collect(Collectors.joining(", ", "merged[", "]"));
+        }
+        return getModelId() + " " + getLocation();
+    }
+
+    public static InputSource merge(InputSource src1, InputSource src2) {
+        return new InputSource(Stream.concat(src1.sources(), src2.sources()).collect(Collectors.toSet()));
+    }
+}
diff --git a/api/maven-api-model/src/main/java/org/apache/maven/api/model/package-info.java b/api/maven-api-model/src/main/java/org/apache/maven/api/model/package-info.java
new file mode 100644
index 0000000..3c1c61e
--- /dev/null
+++ b/api/maven-api-model/src/main/java/org/apache/maven/api/model/package-info.java
@@ -0,0 +1,6 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/**
+ * Maven Immutable POM (Project Object Model) classes, generated from <code>maven.mdo</code> model.
+ * The root class is {@link org.apache.maven.api.model.Model}.
+ */
+package org.apache.maven.api.model;
diff --git a/api/maven-api-model/src/main/mdo/maven.mdo b/api/maven-api-model/src/main/mdo/maven.mdo
new file mode 100644
index 0000000..3940c0b
--- /dev/null
+++ b/api/maven-api-model/src/main/mdo/maven.mdo
@@ -0,0 +1,3431 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<!--
+  | Improvements:
+  |
+  | o add specification element to a field, this would be more a technical description of
+  |   what is allowed in the field.
+  |
+  | o validators: there could be several levels of validation. Simple type validation could
+  |   be done with a regex, but we need inter-field validation and rules which could be
+  |   dealt with by something like drools.
+  |
+  | o i18n: would be good to be able to have names/descriptions/specifications
+  |   in as many languages as possible. (see MNG-3626)
+  |
+  | o annotation mechanism so that changes to the model can be accurately tracked.
+  |
+  | o need to clean up all the descriptions, matching anything to the current project-descriptor.xml file and
+  |   improving on that
+  |
+  | o use enums where appropriate (eg dependency scope)
+  |
+  | o a number of elements have a groupId/artifactId and sometimes version. It would be good to have them all extend one
+  |   definition of these types
+  |
+-->
+<model xmlns="http://codehaus-plexus.github.io/MODELLO/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/2.0.0 https://codehaus-plexus.github.io/modello/xsd/modello-2.0.0.xsd"
+  xml.namespace="http://maven.apache.org/POM/${version}"
+  xml.schemaLocation="https://maven.apache.org/xsd/maven-${version}.xsd">
+  <id>maven</id>
+  <name>Maven</name>
+  <description>
+    <![CDATA[
+    <p>This is a reference for the Maven project descriptor used in Maven.</p>
+    <p>An XSD is available at:</p>
+    <ul>
+      <li><a href="https://maven.apache.org/xsd/maven-v3_0_0.xsd">https://maven.apache.org/xsd/maven-v3_0_0.xsd</a> for Maven 1.1.</li>
+      <li><a href="https://maven.apache.org/xsd/maven-4.0.0.xsd">https://maven.apache.org/xsd/maven-4.0.0.xsd</a> for Maven 2.0.</li>
+      <li><a href="https://maven.apache.org/xsd/maven-4.1.0.xsd">https://maven.apache.org/xsd/maven-4.1.0.xsd</a> for Maven 4.0.</li>
+    </ul>
+    ]]>
+  </description>
+  <defaults>
+    <default>
+      <key>package</key>
+      <value>org.apache.maven.model</value>
+    </default>
+  </defaults>
+  <classes>
+    <class rootElement="true" xml.tagName="project">
+      <name>Model</name>
+      <superClass>ModelBase</superClass>
+      <description>
+        <![CDATA[
+        The {@code <project>} element is the root of the descriptor.
+        The following table lists all of the possible child elements.
+        ]]>
+      </description>
+      <version>3.0.0+</version>
+      <fields>
+
+        <field xml.transient="true">
+          <name>pomFile</name>
+          <version>4.1.0+</version>
+          <required>false</required>
+          <description>Originating POM file</description>
+          <type>DOM</type> <!-- This is transformed to a File/Path in the template -->
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- Model Version                                                          -->
+        <!-- ====================================================================== -->
+
+        <field>
+          <name>modelVersion</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <description>Declares to which version of project descriptor this POM conforms.</description>
+          <type>String</type>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- Parent Model                                                           -->
+        <!-- ====================================================================== -->
+
+        <field xdoc.separator="blank">
+          <name>parent</name>
+          <version>4.0.0+</version>
+          <description>The location of the parent project, if one exists. Values from the parent
+            project will be the default for this project if they are left unspecified. The location
+            is given as a group ID, artifact ID and version.</description>
+          <association>
+            <type>Parent</type>
+          </association>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- groupId/artifactId/Version/Packaging                                   -->
+        <!-- ====================================================================== -->
+
+        <field xdoc.separator="blank">
+          <name>groupId</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description>
+            <![CDATA[
+            A universally unique identifier for a project. It is normal to
+            use a fully-qualified package name to distinguish it from other
+            projects with a similar name (eg. {@code org.apache.maven}).
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description>The identifier for this artifact that is unique within the group given by the
+            group ID. An artifact is something that is either produced or used by a project.
+            Examples of artifacts produced by Maven for a project include: JARs, source and binary
+            distributions, and WARs.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>version</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <description>The current version of the artifact produced by this project.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>packaging</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The type of artifact this project produces, for example {@code jar}
+              {@code war}
+              {@code ear}
+              {@code pom}.
+            Plugins can create their own packaging, and
+            therefore their own packaging types,
+            so this list does not contain all possible types.
+            ]]>
+          </description>
+          <type>String</type>
+          <defaultValue>jar</defaultValue>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- Elements which describe a project                                      -->
+        <!-- ====================================================================== -->
+
+        <field xdoc.separator="blank">
+          <name>name</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description>The full name of the project.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>description</name>
+          <version>3.0.0+</version>
+          <description>A detailed description of the project, used by Maven whenever it needs to
+            describe the project, such as on the web site. While this element can be specified as
+            CDATA to enable the use of HTML tags within the description, it is discouraged to allow
+            plain text representation. If you need to modify the index page of the generated web
+            site, you are able to specify your own instead of adjusting this text.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The URL to the project's homepage.
+            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
+            project's {@code child.project.url.inherit.append.path="false"}
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.attribute="true" xml.tagName="child.project.url.inherit.append.path">
+          <name>childProjectUrlInheritAppendPath</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            When children inherit from project's url, append path or not? Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}
+            <br><b>Default value is</b>: {@code true}
+            <br><b>Since</b>: Maven 3.6.1
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.attribute="true" xml.tagName="root">
+          <name>root</name>
+          <version>4.1.0+</version>
+          <description>
+            <![CDATA[
+            Indicates that this project is the root project, located in the upper directory of the source tree.
+            This is the directory which may contain the .mvn directory.
+            <br><b>Since</b>: Maven 4.0.0
+            ]]>
+          </description>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field xml.attribute="true" xml.tagName="preserve.model.version">
+          <name>preserveModelVersion</name>
+          <version>4.1.0+</version>
+          <description>
+            <![CDATA[
+            Indicates if the build POM for this project should be preserved or downgraded to the lowest
+            compatible version.
+            <br><b>Since</b>: Maven 4.0.0
+            ]]>
+          </description>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>inceptionYear</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description>The year of the project's inception, specified with 4 digits. This value is
+            used when generating copyright notices as well as being informational.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>organization</name>
+          <version>3.0.0+</version>
+          <description>This element describes various attributes of the organization to which the
+            project belongs. These attributes are utilized when documentation is created (for
+            copyright notices and links).</description>
+          <alias>organisation</alias>
+          <association>
+            <type>Organization</type>
+          </association>
+        </field>
+        <field>
+          <name>licenses</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            This element describes all of the licenses for this project.
+            Each license is described by a {@code license} element, which
+            is then described by additional elements.
+            Projects should only list the license(s) that applies to the project
+            and not the licenses that apply to dependencies.
+            If multiple licenses are listed, it is assumed that the user can select
+            any of them, not that they must accept all.
+            ]]>
+          </description>
+          <association>
+            <type>License</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>developers</name>
+          <version>3.0.0+</version>
+          <description>Describes the committers of a project.</description>
+          <association>
+            <type>Developer</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>contributors</name>
+          <version>3.0.0+</version>
+          <description>Describes the contributors to a project that are not yet committers.</description>
+          <association>
+            <type>Contributor</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>mailingLists</name>
+          <version>3.0.0+</version>
+          <description>Contains information about a project's mailing lists.</description>
+          <association>
+            <type>MailingList</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- Build prerequisites                                                    -->
+        <!-- ====================================================================== -->
+
+        <field xdoc.separator="blank">
+          <name>prerequisites</name>
+          <version>4.0.0+</version>
+          <description>Describes the prerequisites in the build environment for this project.</description>
+          <association>
+            <type>Prerequisites</type>
+          </association>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- SCM                                                                    -->
+        <!-- ====================================================================== -->
+
+        <field xdoc.separator="blank" xml.insertParentFieldsUpTo="modules">
+          <name>scm</name>
+          <version>4.0.0+</version>
+          <description>Specification for the SCM used by the project, such as CVS, Subversion, etc.</description>
+          <association>
+            <type>Scm</type>
+          </association>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- Issue Tracking                                                         -->
+        <!-- ====================================================================== -->
+
+        <field>
+          <name>issueManagement</name>
+          <version>4.0.0+</version>
+          <description>The project's issue management system information.</description>
+          <association>
+            <type>IssueManagement</type>
+          </association>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- CI Management                                                          -->
+        <!-- ====================================================================== -->
+
+        <field>
+          <name>ciManagement</name>
+          <version>4.0.0+</version>
+          <description>The project's continuous integration information.</description>
+          <association>
+            <type>CiManagement</type>
+          </association>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- Build                                                                  -->
+        <!-- ====================================================================== -->
+
+        <field xdoc.separator="blank" xml.insertParentFieldsUpTo="pluginRepositories">
+          <name>build</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description>Information required to build the project.</description>
+          <association>
+            <type>Build</type>
+          </association>
+        </field>
+
+        <!-- ====================================================================== -->
+        <!-- Profiles                                                               -->
+        <!-- ====================================================================== -->
+
+        <field xdoc.separator="blank" xml.insertParentFieldsUpTo="reporting">
+          <name>profiles</name>
+          <version>4.0.0+</version>
+          <description>A listing of project-local build profiles which will modify the build process
+            when activated.</description>
+          <association>
+            <type>Profile</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    /**
+     * Gets the POM file for the corresponding project (if any).
+     *
+     * @return The POM file from which this model originated or {@code null} if this model does not belong to a local
+     *         project (e.g. describes the metadata of some artifact from the repository).
+     */
+    public java.io.File getPomFile()
+    {
+        return ( getDelegate().getPomFile() != null ) ? getDelegate().getPomFile().toFile() : null;
+    }
+
+    public void setPomFile( java.io.File pomFile )
+    {
+        update( getDelegate().withPomFile( pomFile != null ? pomFile.toPath() : null ) );
+    }
+
+    public void setModelEncoding( String modelEncoding )
+    {
+        update( getDelegate().with().modelEncoding( modelEncoding ).build() );
+    }
+
+    /**
+     * Gets the base directory for the corresponding project (if any).
+     *
+     * @return The base directory for the corresponding project or {@code null} if this model does not belong to a local
+     *         project (e.g. describes the metadata of some artifact from the repository).
+     */
+    public java.io.File getProjectDirectory()
+    {
+        return ( getDelegate().getProjectDirectory() != null ) ? getDelegate().getProjectDirectory().toFile() : null;
+    }
+
+    /**
+     * @return the model id as {@code groupId:artifactId:packaging:version}
+     */
+    public String getId()
+    {
+        StringBuilder id = new StringBuilder( 64 );
+
+        id.append( ( getGroupId() == null ) ? "[inherited]" : getGroupId() );
+        id.append( ":" );
+        id.append( getArtifactId() );
+        id.append( ":" );
+        id.append( getPackaging() );
+        id.append( ":" );
+        id.append( ( getVersion() == null ) ? "[inherited]" : getVersion() );
+
+        return id.toString();
+    }
+
+    @Override
+    public String toString()
+    {
+        return getId();
+    }
+
+    public boolean isChildProjectUrlInheritAppendPath()
+    {
+        return getDelegate().isChildProjectUrlInheritAppendPath();
+    }
+
+    public void setChildProjectUrlInheritAppendPath( boolean childProjectUrlInheritAppendPath )
+    {
+        delegate = getDelegate().withChildProjectUrlInheritAppendPath( String.valueOf( childProjectUrlInheritAppendPath ) );
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.1.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * Gets the base directory for the corresponding project (if any).
+     *
+     * @return The base directory for the corresponding project or {@code null} if this model does not belong to a local
+     *         project (e.g. describes the metadata of some artifact from the repository).
+     */
+    public Path getProjectDirectory()
+    {
+        return ( pomFile != null ) ? pomFile.getParent() : null;
+    }
+
+    /**
+     * @return the model id as {@code groupId:artifactId:packaging:version}
+     */
+    public String getId()
+    {
+        StringBuilder id = new StringBuilder( 64 );
+
+        id.append( ( getGroupId() == null ) ? "[inherited]" : getGroupId() );
+        id.append( ":" );
+        id.append( getArtifactId() );
+        id.append( ":" );
+        id.append( getPackaging() );
+        id.append( ":" );
+        id.append( ( getVersion() == null ) ? "[inherited]" : getVersion() );
+
+        return id.toString();
+    }
+
+    @Override
+    public String toString()
+    {
+        return getId();
+    }
+
+    public boolean isChildProjectUrlInheritAppendPath()
+    {
+        return ( getChildProjectUrlInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildProjectUrlInheritAppendPath() ) : true;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>ModelBase</name>
+      <version>3.0.0+</version>
+      <description>
+        <![CDATA[
+        Base class for the {@code Model} and the {@code Profile} objects.
+        ]]>
+      </description>
+      <fields>
+        <field xdoc.separator="blank">
+          <name>modules</name>
+          <version>4.0.0+</version>
+          <description>The modules (sometimes called subprojects) to build as a part of this
+            project. Each module listed is a relative path to the directory containing the module.
+            To be consistent with the way default urls are calculated from parent, it is recommended
+            to have module names match artifact ids.</description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>distributionManagement</name>
+          <version>4.0.0+</version>
+          <description>Distribution information for a project that enables deployment of the site
+            and artifacts to remote web servers and repositories respectively.</description>
+          <association>
+            <type>DistributionManagement</type>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>properties</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Properties that can be used throughout the POM as a substitution, and
+            are used as filters in resources if enabled.
+            The format is {@code <name>value</name>}.
+            ]]>
+          </description>
+          <type>Properties</type>
+          <association xml.mapStyle="inline">
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>dependencyManagement</name>
+          <version>4.0.0+</version>
+          <required>false</required>
+          <description>Default dependency information for projects that inherit from this one. The
+            dependencies in this section are not immediately resolved. Instead, when a POM derived
+            from this one declares a dependency described by a matching groupId and artifactId, the
+            version and other values from this section are used for that dependency if they were not
+            already specified.</description>
+          <association>
+            <type>DependencyManagement</type>
+          </association>
+        </field>
+        <field>
+          <name>dependencies</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            This element describes all of the dependencies associated with a
+            project.
+            These dependencies are used to construct a classpath for your
+            project during the build process. They are automatically downloaded from the
+            repositories defined in this project.
+            See <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">the
+            dependency mechanism</a> for more information.
+            ]]>
+          </description>
+          <association>
+            <type>Dependency</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>repositories</name>
+          <version>4.0.0+</version>
+          <description>The lists of the remote repositories for discovering dependencies and
+            extensions.</description>
+          <association>
+            <type>Repository</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>pluginRepositories</name>
+          <version>4.0.0+</version>
+          <description>The lists of the remote repositories for discovering plugins for builds and
+            reports.</description>
+          <association>
+            <type>Repository</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>reports</name>
+          <version>4.0.0</version>
+          <description>
+            <![CDATA[
+             <b>Deprecated</b>. Now ignored by Maven.
+             ]]>
+          </description>
+          <type>DOM</type>
+        </field>
+        <field>
+          <name>reporting</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            This element includes the specification of report plugins to use
+            to generate the reports on the Maven-generated site.
+            These reports will be run when a user executes {@code mvn site}.
+            All of the reports will be included in the navigation bar for browsing.
+            ]]>
+          </description>
+          <association>
+            <type>Reporting</type>
+          </association>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>PluginContainer</name>
+      <version>3.0.0+</version>
+      <description>Contains the plugins informations for the project.</description>
+      <fields>
+        <field>
+          <name>plugins</name>
+          <version>4.0.0+</version>
+          <description>The list of plugins to use.</description>
+          <association>
+            <type>Plugin</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    Map<String, Plugin> pluginMap;
+
+    /**
+     * Reset the {@code pluginsMap} field to {@code null}
+     */
+    public synchronized void flushPluginMap()
+    {
+        this.pluginMap = null;
+    }
+
+    /**
+     * @return a Map of plugins field with {@code Plugins#getKey()} as key
+     * @see Plugin#getKey()
+     */
+    public synchronized Map<String, Plugin> getPluginsAsMap()
+    {
+        if ( pluginMap == null )
+        {
+            pluginMap = new java.util.LinkedHashMap<String, Plugin>();
+            if ( getPlugins() != null )
+            {
+                for ( java.util.Iterator<Plugin> it = getPlugins().iterator(); it.hasNext(); )
+                {
+                    Plugin plugin = (Plugin) it.next();
+                    pluginMap.put( plugin.getKey(), plugin );
+                }
+            }
+        }
+
+        return pluginMap;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.1.0+</version>
+          <code>
+            <![CDATA[
+    volatile Map<String, Plugin> pluginMap;
+
+    /**
+     * @return a Map of plugins field with {@code Plugins#getKey()} as key
+     * @see Plugin#getKey()
+     */
+    public Map<String, Plugin> getPluginsAsMap() {
+        if (pluginMap == null) {
+            synchronized (this) {
+                if (pluginMap == null) {
+                    pluginMap = ImmutableCollections.copy(plugins.stream().collect(
+                            java.util.stream.Collectors.toMap(
+                                Plugin::getKey, java.util.function.Function.identity())));
+                }
+            }
+        }
+        return pluginMap;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+     @Override
+     public String toString()
+     {
+         return "PluginContainer {}";
+     }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>PluginConfiguration</name>
+      <version>3.0.0+</version>
+      <superClass>PluginContainer</superClass>
+      <description>Contains the plugins management informations for the project.</description>
+      <fields>
+        <!-- [ jdcasey:06-Mar-2005 ] Added to handle version management, etc. for
+          | plugins to be used in sub-projects. -->
+        <field>
+          <name>pluginManagement</name>
+          <version>4.0.0+</version>
+          <required>false</required>
+          <description>Default plugin information to be made available for reference by projects
+            derived from this one. This plugin configuration will not be resolved or bound to the
+            lifecycle unless referenced. Any local configuration for a given plugin will override
+            the plugin's entire definition here.</description>
+          <association>
+            <type>PluginManagement</type>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "PluginConfiguration {" + super.toString() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class xdoc.anchorName="profile_build">
+      <name>BuildBase</name>
+      <version>3.0.0+</version>
+      <superClass>PluginConfiguration</superClass>
+      <description>Build configuration in a profile.</description>
+      <fields>
+        <field>
+          <name>defaultGoal</name>
+          <version>3.0.0+</version>
+          <description>The default goal (or phase in Maven 2) to execute when none is specified for
+            the project. Note that in case of a multi-module build, only the default goal of the top-level
+            project is relevant, i.e. the default goals of child modules are ignored. Since Maven 3,
+            multiple goals/phases can be separated by whitespace.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>resources</name>
+          <version>3.0.0+</version>
+          <description><![CDATA[
+            This element describes all of the classpath resources such as properties
+            files associated with a project. These resources are often included in the final
+            package.
+            The default value is {@code src/main/resources}.]]>
+          </description>
+          <association>
+            <type>Resource</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>testResources</name>
+          <version>4.0.0+</version>
+          <description><![CDATA[
+            This element describes all of the classpath resources such as properties
+            files associated with a project's unit tests.
+            The default value is {@code src/test/resources}.]]>
+          </description>
+          <association>
+            <type>Resource</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>directory</name>
+          <version>4.0.0+</version>
+          <description><![CDATA[
+            The directory where all files generated by the build are placed.
+            The default value is {@code target}.]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>finalName</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The filename (excluding the extension, and with no path information) that
+            the produced artifact will be called.
+            The default value is {@code ${artifactId}-${version}}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>filters</name>
+          <version>4.0.0+</version>
+          <description>The list of filter properties files that are used when filtering is enabled.</description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "BuildBase {" + super.toString() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Build</name>
+      <version>3.0.0+</version>
+      <superClass>BuildBase</superClass>
+      <description>
+        <![CDATA[
+        The {@code <build>} element contains informations required to build the project.
+        Default values are defined in Super POM.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>sourceDirectory</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description><![CDATA[
+            This element specifies a directory containing the source of the project. The
+            generated build system will compile the sources from this directory when the project is
+            built. The path given is relative to the project descriptor.
+            The default value is {@code src/main/java}.]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>scriptSourceDirectory</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <description><![CDATA[
+            This element specifies a directory containing the script sources of the
+            project. This directory is meant to be different from the sourceDirectory, in that its
+            contents will be copied to the output directory in most cases (since scripts are
+            interpreted rather than compiled).
+            The default value is {@code src/main/scripts}.]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>testSourceDirectory</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <description><![CDATA[
+            This element specifies a directory containing the unit test source of the
+            project. The generated build system will compile these directories when the project is
+            being tested. The path given is relative to the project descriptor.
+            The default value is {@code src/test/java}.]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>outputDirectory</name>
+          <version>4.0.0+</version>
+          <description><![CDATA[
+            The directory where compiled application classes are placed.
+            The default value is {@code target/classes}.]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>testOutputDirectory</name>
+          <version>4.0.0+</version>
+          <description><![CDATA[
+            The directory where compiled test classes are placed.
+            The default value is {@code target/test-classes}.]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>extensions</name>
+          <version>4.0.0+</version>
+          <description>A set of build extensions to use from this project.</description>
+          <association>
+            <type>Extension</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Build {" + super.toString() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>CiManagement</name>
+      <version>4.0.0+</version>
+      <description>
+        <![CDATA[
+        The {@code <ciManagement>} element contains informations required to the
+        continuous integration system of the project.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>system</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The name of the continuous integration system, e.g. {@code continuum}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>4.0.0+</version>
+          <description>URL for the continuous integration system used by the project if it has a web
+            interface.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>notifiers</name>
+          <version>4.0.0+</version>
+          <description>Configuration for notifying developers/users when a build is unsuccessful,
+            including user information and notification mode.</description>
+          <association>
+            <multiplicity>*</multiplicity>
+            <type>Notifier</type>
+          </association>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Notifier</name>
+      <description>Configures one method for notifying users/developers when a build breaks.</description>
+      <version>4.0.0+</version>
+      <fields>
+        <field>
+          <name>type</name>
+          <version>4.0.0+</version>
+          <defaultValue>mail</defaultValue>
+          <type>String</type>
+          <description>The mechanism used to deliver notifications.</description>
+        </field>
+        <field>
+          <name>sendOnError</name>
+          <version>4.0.0+</version>
+          <defaultValue>true</defaultValue>
+          <type>boolean</type>
+          <description>Whether to send notifications on error.</description>
+        </field>
+        <field>
+          <name>sendOnFailure</name>
+          <version>4.0.0+</version>
+          <defaultValue>true</defaultValue>
+          <type>boolean</type>
+          <description>Whether to send notifications on failure.</description>
+        </field>
+        <field>
+          <name>sendOnSuccess</name>
+          <version>4.0.0+</version>
+          <defaultValue>true</defaultValue>
+          <type>boolean</type>
+          <description>Whether to send notifications on success.</description>
+        </field>
+        <field>
+          <name>sendOnWarning</name>
+          <version>4.0.0+</version>
+          <defaultValue>true</defaultValue>
+          <type>boolean</type>
+          <description>Whether to send notifications on warning.</description>
+        </field>
+        <!-- TODO: Remove it after continuum alpha-3 release -->
+        <field>
+          <name>address</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            <b>Deprecated</b>. Where to send the notification to - eg email address.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>configuration</name>
+          <description>Extended configuration specific to this notifier goes here.</description>
+          <type>Properties</type>
+          <association xml.mapStyle="inline">
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Contributor</name>
+      <description>Description of a person who has contributed to the project, but who does not have
+        commit privileges. Usually, these contributions come in the form of patches submitted.</description>
+      <version>3.0.0+</version>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>3.0.0+</version>
+          <description>The full name of the contributor.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>email</name>
+          <version>3.0.0+</version>
+          <description>The email address of the contributor.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>3.0.0+</version>
+          <description>The URL for the homepage of the contributor.</description>
+          <type>String</type>
+        </field>
+        <!-- TODO: should this just be a single Organization element -->
+        <field>
+          <name>organization</name>
+          <alias>organisation</alias>
+          <version>3.0.0+</version>
+          <description>The organization to which the contributor belongs.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>organizationUrl</name>
+          <alias>organisationUrl</alias>
+          <version>3.0.0+</version>
+          <description>The URL of the organization.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>roles</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The roles the contributor plays in the project. Each role is described by a
+            {@code role} element, the body of which is a role name. This can also be used to
+            describe the contribution.
+            ]]>
+          </description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>timezone</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+              The timezone the contributor is in. Typically, this is a number in the range
+              <a href="http://en.wikipedia.org/wiki/UTC%E2%88%9212:00">-12</a> to <a href="http://en.wikipedia.org/wiki/UTC%2B14:00">+14</a>
+              or a valid time zone id like "America/Montreal" (UTC-05:00) or "Europe/Paris" (UTC+01:00).
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>properties</name>
+          <version>3.0.0+</version>
+          <description>Properties about the contributor, such as an instant messenger handle.</description>
+          <type>Properties</type>
+          <association xml.mapStyle="inline">
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Contributor {name=" + getName() + ", email=" + getEmail() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Dependency</name>
+      <version>3.0.0+</version>
+      <description>
+        <![CDATA[
+        The {@code <dependency>} element contains information about a dependency
+        of the project.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description>
+            <![CDATA[
+            The project group that produced the dependency, e.g.
+            {@code org.apache.maven}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>3.0.0+</version>
+          <required>true</required>
+          <description>
+            <![CDATA[
+            The unique id for an artifact produced by the project group, e.g.
+            {@code maven-artifact}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>version</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The version of the dependency, e.g. {@code 3.2.1}. In Maven 2, this can also be
+            specified as a range of versions.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>type</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The type of dependency, that will be mapped to a file extension, an optional classifier, and a few other attributes.
+            Some examples are {@code jar}, {@code war}, {@code ejb-client}
+            and {@code test-jar}: see <a href="../maven-core/artifact-handlers.html">default
+            artifact handlers</a> for a list. New types can be defined by extensions, so this is not a complete list.
+            ]]>
+          </description>
+          <type>String</type>
+          <defaultValue>jar</defaultValue>
+        </field>
+        <field>
+          <name>classifier</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The classifier of the dependency. It is appended to
+            the filename after the version. This allows:
+            <ul>
+            <li>referring to attached artifact, for example {@code sources} and {@code javadoc}:
+            see <a href="../maven-core/artifact-handlers.html">default artifact handlers</a> for a list,</li>
+            <li>distinguishing two artifacts
+            that belong to the same POM but were built differently.
+            For example, {@code jdk14} and {@code jdk15}.</li>
+            </ul>
+            ]]>
+          </description>
+          <type>String</type>
+          <required>false</required>
+        </field>
+        <field>
+          <name>scope</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The scope of the dependency - {@code compile}, {@code runtime},
+            {@code test}, {@code system}, and {@code provided}. Used to
+            calculate the various classpaths used for compilation, testing, and so on.
+            It also assists in determining which artifacts to include in a distribution of
+            this project. For more information, see
+            <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">the
+            dependency mechanism</a>. The default scope is {@code compile}.
+            ]]>
+          </description>
+          <type>String</type>
+          <!-- This default has to be enforced at the maven-artifact layer, to allow
+            | injection of defaults from <dependencyManagement/>.
+            | TODO: how can we document it?
+            |-->
+          <!-- defaultValue>compile</defaultValue -->
+        </field>
+        <field>
+          <name>systemPath</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            FOR SYSTEM SCOPE ONLY. Note that use of this property is <b>discouraged</b>
+            and may be replaced in later versions. This specifies the path on the filesystem
+            for this dependency.
+            Requires an absolute path for the value, not relative.
+            Use a property that gives the machine specific absolute path,
+            e.g. {@code ${java.home}}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>exclusions</name>
+          <version>4.0.0+</version>
+          <description>Lists a set of artifacts that should be excluded from this dependency's
+            artifact list when it comes to calculating transitive dependencies.</description>
+          <association>
+            <type>Exclusion</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>optional</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Indicates the dependency is optional for use of this library. While the
+            version of the dependency will be taken into account for dependency calculation if the
+            library is used elsewhere, it will not be passed on transitively. Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}. Default value is {@code false}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    public boolean isOptional()
+    {
+        return ( getOptional() != null ) ? Boolean.parseBoolean( getOptional() ) : false;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    public void setOptional( boolean optional )
+    {
+        setOptional( String.valueOf( optional ) );
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Dependency {groupId=" + getGroupId() + ", artifactId=" + getArtifactId() + ", version=" + getVersion() + ", type=" + getType() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    private volatile String managementKey;
+
+    /**
+     * @return the management key as {@code groupId:artifactId:type}
+     */
+    public String getManagementKey()
+    {
+        if ( managementKey == null )
+        {
+            managementKey = getGroupId() + ":" + getArtifactId() + ":" + getType() + ( getClassifier() != null ? ":" + getClassifier() : "" );
+        }
+        return managementKey;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <superClass>Contributor</superClass>
+      <name>Developer</name>
+      <description>Information about one of the committers on this project.</description>
+      <version>3.0.0+</version>
+      <fields>
+        <field>
+          <name>id</name>
+          <version>3.0.0+</version>
+          <description>The unique ID of the developer in the SCM.</description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Developer {id=" + getId() + ", " + super.toString() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Exclusion</name>
+      <version>4.0.0+</version>
+      <description>
+        <![CDATA[
+        The {@code <exclusion>} element contains informations required to exclude
+        an artifact to the project.
+        <p>
+        The {@code groupId} and {@code artifactId} fields are interpreted as glob patterns,
+        see {@link java.nio.file.FileSystem#getPathMatcher}.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <version>4.0.0+</version>
+          <description>The group ID of the project to exclude.</description>
+          <type>String</type>
+          <required>true</required>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>4.0.0+</version>
+          <description>The artifact ID of the project to exclude.</description>
+          <type>String</type>
+          <required>true</required>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>IssueManagement</name>
+      <description>Information about the issue tracking (or bug tracking) system used to manage this
+        project.</description>
+      <version>4.0.0+</version>
+      <fields>
+        <field>
+          <name>system</name>
+          <version>4.0.0+</version>
+          <description>The name of the issue management system, e.g. Bugzilla</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>4.0.0+</version>
+          <description>URL for the issue management system used by the project.</description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "IssueManagement {system=" + getSystem() + ", url=" + getUrl() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>DistributionManagement</name>
+      <version>4.0.0+</version>
+      <description>This elements describes all that pertains to distribution for a project. It is
+        primarily used for deployment of artifacts and the site produced by the build.</description>
+      <fields>
+        <field>
+          <name>repository</name>
+          <version>4.0.0+</version>
+          <description>Information needed to deploy the artifacts generated by the project to a
+            remote repository.</description>
+          <association>
+            <type>DeploymentRepository</type>
+          </association>
+        </field>
+        <field>
+          <name>snapshotRepository</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Where to deploy snapshots of artifacts to. If not given, it defaults to the
+            {@code repository} element.
+            ]]>
+          </description>
+          <association>
+            <type>DeploymentRepository</type>
+          </association>
+        </field>
+        <field>
+          <name>site</name>
+          <description>Information needed for deploying the web site of the project.</description>
+          <version>4.0.0+</version>
+          <association>
+            <type>Site</type>
+          </association>
+        </field>
+        <field>
+          <name>downloadUrl</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The URL of the project's download page. If not given users will be
+            referred to the homepage given by {@code url}.
+            This is given to assist in locating artifacts that are not in the repository due to
+            licensing restrictions.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>relocation</name>
+          <version>4.0.0+</version>
+          <description>Relocation information of the artifact if it has been moved to a new group ID
+            and/or artifact ID.</description>
+          <association>
+            <type>Relocation</type>
+          </association>
+        </field>
+        <field>
+          <name>status</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Gives the status of this artifact in the remote repository.
+            This must not be set in your local project, as it is updated by
+            tools placing it in the reposiory. Valid values are: {@code none} (default),
+            {@code converted} (repository manager converted this from an Maven 1 POM),
+            {@code partner}
+            (directly synced from a partner Maven 2 repository), {@code deployed} (was deployed from a Maven 2
+            instance), {@code verified} (has been hand verified as correct and final).
+            ]]>
+          </description>
+          <required>false</required>
+          <type>String</type>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>License</name>
+      <description>Describes the licenses for this project. This is used to generate the license
+        page of the project's web site, as well as being taken into consideration in other reporting
+        and validation. The licenses listed for the project are that of the project itself, and not
+        of dependencies.</description>
+      <version>3.0.0+</version>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>3.0.0+</version>
+          <description>The full legal name of the license.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>3.0.0+</version>
+          <description>The official url for the license text.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>distribution</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The primary method by which this project may be distributed.
+            <dl>
+              <dt>repo</dt>
+              <dd>may be downloaded from the Maven repository</dd>
+              <dt>manual</dt>
+              <dd>user must manually download and install the dependency.</dd>
+            </dl>
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>comments</name>
+          <description>Addendum information pertaining to this license.</description>
+          <version>3.0.0+</version>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "License {name=" + getName() + ", url=" + getUrl() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>MailingList</name>
+      <version>3.0.0+</version>
+      <description>This element describes all of the mailing lists associated with a project. The
+        auto-generated site references this information.</description>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The name of the mailing list.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>subscribe</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The email address or link that can be used to subscribe to
+            the mailing list.  If this is an email address, a
+            {@code mailto:} link will automatically be created
+            when the documentation is created.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>unsubscribe</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The email address or link that can be used to unsubscribe to
+            the mailing list.  If this is an email address, a
+            {@code mailto:} link will automatically be created
+            when the documentation is created.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>post</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            The email address or link that can be used to post to
+            the mailing list.  If this is an email address, a
+            {@code mailto:} link will automatically be created
+            when the documentation is created.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>archive</name>
+          <version>3.0.0+</version>
+          <description>The link to a URL where you can browse the mailing list archive.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>otherArchives</name>
+          <version>3.0.0+</version>
+          <description>The link to alternate URLs where you can browse the list archive.</description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <comment>We could probably have a specific element for a dev mailing list for things like CI,
+        and maybe even a specific element for the user and scm mailing lists. Then leave the more
+        lose structure for any other type of mailing list.</comment>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "MailingList {name=" + getName() + ", archive=" + getArchive() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Organization</name>
+      <description>Specifies the organization that produces this project.</description>
+      <version>3.0.0+</version>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>3.0.0+</version>
+          <description>The full name of the organization.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>3.0.0+</version>
+          <description>The URL to the organization's home page.</description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Organization {name=" + getName() + ", url=" + getUrl() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>PatternSet</name>
+      <version>3.0.0+</version>
+      <description>Definition of include or exclude patterns.</description>
+      <fields>
+        <field>
+          <name>includes</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            A list of patterns to include, e.g. {@code **&#47;*.xml}.
+            ]]>
+          </description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>excludes</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            A list of patterns to exclude, e.g. {@code **&#47;*.xml}
+            ]]>
+          </description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder( 128 );
+
+        sb.append("PatternSet [includes: {");
+        for (java.util.Iterator i = getIncludes().iterator(); i.hasNext(); )
+        {
+            String str = (String) i.next();
+            sb.append(str).append(", ");
+        }
+        if (sb.substring(sb.length() - 2).equals(", ")) sb.delete(sb.length() - 2, sb.length());
+
+        sb.append("}, excludes: {");
+        for (java.util.Iterator i = getExcludes().iterator(); i.hasNext(); )
+        {
+            String str = (String) i.next();
+            sb.append(str).append(", ");
+        }
+        if (sb.substring(sb.length() - 2).equals(", ")) sb.delete(sb.length() - 2, sb.length());
+
+        sb.append("}]");
+        return sb.toString();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Parent</name>
+      <version>4.0.0+</version>
+      <description>
+        <![CDATA[
+        The {@code <parent>} element contains information required to locate the parent project from which
+        this project will inherit from.
+        <strong>Note:</strong> The children of this element are not interpolated and must be given as literal values.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <version>4.0.0+</version>
+          <description>The group id of the parent project to inherit from.</description>
+          <required>true</required>
+          <type>String</type>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>4.0.0+</version>
+          <description>The artifact id of the parent project to inherit from.</description>
+          <required>true</required>
+          <type>String</type>
+        </field>
+        <field>
+          <name>version</name>
+          <version>4.0.0+</version>
+          <description>The version of the parent project to inherit.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>relativePath</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The relative path of the parent {@code pom.xml} file within the check out.
+            If not specified, it defaults to {@code ../pom.xml}.
+            Maven looks for the parent POM first in this location on
+            the filesystem, then the local repository, and lastly in the remote repo.
+            {@code relativePath} allows you to select a different location,
+            for example when your structure is flat, or deeper without an intermediate parent POM.
+            However, the group ID, artifact ID and version are still required,
+            and must match the file in the location given or it will revert to the repository for the POM.
+            This feature is only for enhancing the development in a local checkout of that project.
+            Set the value to an empty string in case you want to disable the feature and always resolve
+            the parent POM from the repositories.
+            ]]>
+          </description>
+          <type>String</type>
+          <defaultValue>..</defaultValue>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @return the id as {@code groupId:artifactId:version}
+     */
+    public String getId()
+    {
+        StringBuilder id = new StringBuilder( 64 );
+
+        id.append( getGroupId() );
+        id.append( ":" );
+        id.append( getArtifactId() );
+        id.append( ":" );
+        id.append( "pom" );
+        id.append( ":" );
+        id.append( getVersion() );
+
+        return id.toString();
+    }
+
+    @Override
+    public String toString()
+    {
+        return getId();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+
+    </class>
+    <class>
+      <name>Scm</name>
+      <version>4.0.0+</version>
+      <description>
+        <![CDATA[
+        The {@code <scm>} element contains informations required to the SCM
+        (Source Control Management) of the project.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>connection</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The source control management system URL
+            that describes the repository and how to connect to the
+            repository. For more information, see the
+            <a href="https://maven.apache.org/scm/scm-url-format.html">URL format</a>
+            and <a href="https://maven.apache.org/scm/scms-overview.html">list of supported SCMs</a>.
+            This connection is read-only.
+            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
+            scm's {@code child.scm.connection.inherit.append.path="false"}
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>developerConnection</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Just like {@code connection}, but for developers, i.e. this scm connection
+            will not be read only.
+            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
+            scm's {@code child.scm.developerConnection.inherit.append.path="false"}
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>tag</name>
+          <version>4.0.0+</version>
+          <description>The tag of current code. By default, it's set to HEAD during development.</description>
+          <type>String</type>
+          <defaultValue>HEAD</defaultValue>
+        </field>
+        <field>
+          <name>url</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The URL to the project's browsable SCM repository, such as ViewVC or Fisheye.
+            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
+            scm's {@code child.scm.url.inherit.append.path="false"}
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.attribute="true" xml.tagName="child.scm.connection.inherit.append.path">
+          <name>childScmConnectionInheritAppendPath</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            When children inherit from scm connection, append path or not? Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}
+            <br><b>Default value is</b>: {@code true}
+            <br><b>Since</b>: Maven 3.6.1
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.attribute="true" xml.tagName="child.scm.developerConnection.inherit.append.path">
+          <name>childScmDeveloperConnectionInheritAppendPath</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            When children inherit from scm developer connection, append path or not? Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}
+            <br><b>Default value is</b>: {@code true}
+            <br><b>Since</b>: Maven 3.6.1
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.attribute="true" xml.tagName="child.scm.url.inherit.append.path">
+          <name>childScmUrlInheritAppendPath</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            When children inherit from scm url, append path or not? Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}
+            <br><b>Default value is</b>: {@code true}
+            <br><b>Since</b>: Maven 3.6.1
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+
+    public boolean isChildScmConnectionInheritAppendPath()
+    {
+        return ( getChildScmConnectionInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildScmConnectionInheritAppendPath() ) : true;
+    }
+
+    public boolean isChildScmDeveloperConnectionInheritAppendPath()
+    {
+        return ( getChildScmDeveloperConnectionInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildScmDeveloperConnectionInheritAppendPath() ) : true;
+    }
+
+    public boolean isChildScmUrlInheritAppendPath()
+    {
+        return ( getChildScmUrlInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildScmUrlInheritAppendPath() ) : true;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Scm {connection=" + getConnection() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>FileSet</name>
+      <version>3.0.0+</version>
+      <superClass>PatternSet</superClass>
+      <description>A PatternSet for files.</description>
+      <fields>
+        <field>
+          <name>directory</name>
+          <version>3.0.0+</version>
+          <description>Describe the directory where the resources are stored. The path is relative
+            to the POM.</description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "FileSet {directory: " + getDirectory() + ", " + super.toString() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Resource</name>
+      <description>This element describes all of the classpath resources associated with a project
+        or unit tests.</description>
+      <version>3.0.0+</version>
+      <superClass>FileSet</superClass>
+      <fields>
+        <field>
+          <name>targetPath</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            Describe the resource target path. The path is relative to the target/classes
+            directory (i.e. {@code ${project.build.outputDirectory}}).
+            For example, if you want that resource to appear in a specific package
+            ({@code org.apache.maven.messages}), you must specify this
+            element with this value: {@code org/apache/maven/messages}.
+            This is not required if you simply put the resources in that directory
+            structure at the source, however.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>filtering</name>
+          <version>3.0.0+</version>
+          <description>
+            <![CDATA[
+            Whether resources are filtered to replace tokens with parameterised values or not.
+            The values are taken from the {@code properties} element and from the
+            properties in the files listed in the {@code filters} element. Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}. Default value is {@code false}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.transient="true">
+          <name>mergeId</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            FOR INTERNAL USE ONLY. This is a unique identifier assigned to each
+            resource to allow Maven to merge changes to this resource that take
+            place during the execution of a plugin. This field must be managed
+            by the generated parser and formatter classes in order to allow it
+            to survive model interpolation.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    public boolean isFiltering()
+    {
+        return ( getFiltering() != null ) ? Boolean.parseBoolean( getFiltering() ) : false;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    public void setFiltering( boolean filtering )
+    {
+        setFiltering( String.valueOf( filtering ) );
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Resource {targetPath: " + getTargetPath() + ", filtering: " + isFiltering() + ", " + super.toString() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>RepositoryBase</name>
+      <version>4.0.0+</version>
+      <description>A repository contains the information needed for establishing connections with
+        remote repository.</description>
+      <fields>
+        <field>
+          <name>id</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <identifier>true</identifier>
+          <description>
+            <![CDATA[
+            A unique identifier for a repository. This is used to match the repository
+            to configuration in the {@code settings.xml} file, for example. Furthermore, the identifier is
+            used during POM inheritance and profile injection to detect repositories that should be merged.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>name</name>
+          <version>4.0.0+</version>
+          <description>Human readable name of the repository.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <description>
+            <![CDATA[
+            The url of the repository, in the form {@code protocol://hostname/path}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>layout</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The type of layout this repository uses for locating and storing artifacts -
+            can be {@code legacy} or {@code default}.
+            ]]>
+          </description>
+          <type>String</type>
+          <defaultValue>default</defaultValue>
+        </field>
+      </fields>
+    </class>
+
+    <class>
+      <name>Repository</name>
+      <superClass>RepositoryBase</superClass>
+      <version>4.0.0+</version>
+      <description>A repository contains the information needed for establishing connections with
+        remote repository.</description>
+      <fields>
+        <field>
+          <name>releases</name>
+          <version>4.0.0+</version>
+          <description>How to handle downloading of releases from this repository.</description>
+          <association>
+            <type>RepositoryPolicy</type>
+          </association>
+        </field>
+        <field>
+          <name>snapshots</name>
+          <version>4.0.0+</version>
+          <description>How to handle downloading of snapshots from this repository.</description>
+          <association>
+            <type>RepositoryPolicy</type>
+          </association>
+        </field>
+      </fields>
+    </class>
+
+    <class xdoc.anchorName="deployment_repository">
+      <name>DeploymentRepository</name>
+      <superClass>Repository</superClass>
+      <version>4.0.0+</version>
+      <description>Deployment repository contains the information needed for deploying to the remote
+        repository, which adds uniqueVersion property to usual repositories for download.</description>
+      <fields>
+        <field>
+          <name>uniqueVersion</name>
+          <description>Whether to assign snapshots a unique version comprised of the timestamp and
+            build number, or to use the same version each time</description>
+          <type>boolean</type>
+          <defaultValue>true</defaultValue>
+          <version>4.0.0+</version>
+        </field>
+      </fields>
+    </class>
+
+    <class>
+      <name>RepositoryPolicy</name>
+      <version>4.0.0+</version>
+      <description>Download policy.</description>
+      <fields>
+        <field>
+          <name>enabled</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Whether to use this repository for downloading this type of artifact. Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}. Default value is {@code true}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>updatePolicy</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The frequency for downloading updates - can be
+            {@code always,}
+            {@code daily}
+            (default),
+            {@code interval:XXX}
+            (in minutes) or
+            {@code never}
+            (only if it doesn't exist locally).
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>checksumPolicy</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            What to do when verification of an artifact checksum fails. Valid values are
+            {@code ignore},
+            {@code fail}
+            (default for Maven 4 and above) or
+            {@code warn}
+            (default for Maven 2 and 3)
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    public boolean isEnabled()
+    {
+        return ( getEnabled() != null ) ? Boolean.parseBoolean( getEnabled() ) : true;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    public void setEnabled( boolean enabled )
+    {
+        setEnabled( String.valueOf( enabled ) );
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+
+    <!--@todo find better solution for management of site deployments -->
+    <class>
+      <name>Site</name>
+      <version>4.0.0+</version>
+      <description>Contains the information needed for deploying websites.</description>
+      <fields>
+        <field>
+          <name>id</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            A unique identifier for a deployment location. This is used to match the
+            site to configuration in the {@code settings.xml} file, for example.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>name</name>
+          <version>4.0.0+</version>
+          <description>Human readable name of the deployment location.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The url of the location where website is deployed, in the form {@code protocol://hostname/path}.
+            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
+            site's {@code child.site.url.inherit.append.path="false"}
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.attribute="true" xml.tagName="child.site.url.inherit.append.path">
+          <name>childSiteUrlInheritAppendPath</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            When children inherit from distribution management site url, append path or not? Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}
+            <br><b>Default value is</b>: {@code true}
+            <br><b>Since</b>: Maven 3.6.1
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+
+    public boolean isChildSiteUrlInheritAppendPath()
+    {
+        return ( getChildSiteUrlInheritAppendPath() != null ) ? Boolean.parseBoolean( getChildSiteUrlInheritAppendPath() ) : true;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+
+    <class>
+      <name>ConfigurationContainer</name>
+      <version>4.0.0+</version>
+      <description>Contains the configuration information of the container like Plugin.</description>
+      <fields>
+        <field>
+          <name>inherited</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Whether any configuration should be propagated to child POMs. Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}. Default value is {@code true}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <description>
+            <![CDATA[
+            <p>The configuration as DOM object.</p>
+            <p>By default, every element content is trimmed, but starting with Maven 3.1.0, you can add
+            {@code xml:space="preserve"} to elements you want to preserve whitespace.</p>
+            <p>You can control how child POMs inherit configuration from parent POMs by adding {@code combine.children}
+            or {@code combine.self} attributes to the children of the configuration element:</p>
+            <ul>
+            <li>{@code combine.children}: available values are {@code merge} (default) and {@code append},</li>
+            <li>{@code combine.self}: available values are {@code merge} (default) and {@code override}.</li>
+            </ul>
+            <p>See <a href="https://maven.apache.org/pom.html#Plugins">POM Reference documentation</a> and
+            <a href="https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/xml/Xpp3DomUtils.html">Xpp3DomUtils</a>
+            for more information.</p>
+            ]]>
+          </description>
+          <name>configuration</name>
+          <type>DOM</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    public boolean isInherited()
+    {
+        return ( getInherited() != null ) ? Boolean.parseBoolean( getInherited() ) : true;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Plugin</name>
+      <version>4.0.0+</version>
+      <superClass>ConfigurationContainer</superClass>
+      <description>
+        <![CDATA[
+        The {@code <plugin>} element contains informations required for a plugin.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <description>The group ID of the plugin in the repository.</description>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <defaultValue>org.apache.maven.plugins</defaultValue>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <description>The artifact ID of the plugin in the repository.</description>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <required>true</required>
+        </field>
+        <field>
+          <name>version</name>
+          <version>4.0.0+</version>
+          <description>The version (or valid range of versions) of the plugin to be used.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>extensions</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            Whether to load Maven extensions (such as packaging and type handlers) from
+            this plugin. For performance reasons, this should only be enabled when necessary. Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}. Default value is {@code false}.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>executions</name>
+          <version>4.0.0+</version>
+          <description>Multiple specifications of a set of goals to execute during the build
+            lifecycle, each having (possibly) a different configuration.</description>
+          <association>
+            <type>PluginExecution</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>goals</name>
+          <version>4.0.0</version>
+          <description>
+            <![CDATA[
+             <b>Deprecated</b>. Unused by Maven.
+             ]]>
+          </description>
+          <type>DOM</type>
+        </field>
+        <field>
+          <name>dependencies</name>
+          <description>Additional dependencies that this project needs to introduce to the plugin's
+            classloader.</description>
+          <version>4.0.0+</version>
+          <association>
+            <type>Dependency</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    public boolean isExtensions() {
+        return (getExtensions() != null) ? Boolean.parseBoolean(getExtensions()) : false;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    public void setExtensions(boolean extensions) {
+        setExtensions(String.valueOf(extensions));
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    private Map<String, PluginExecution> executionMap = null;
+
+    /**
+     * Reset the {@code executionMap} field to {@code null}
+     */
+    public void flushExecutionMap() {
+        this.executionMap = null;
+    }
+
+    /**
+     * @return a Map of executions field with {@code PluginExecution#getId()} as key
+     * @see PluginExecution#getId()
+     */
+    public Map<String, PluginExecution> getExecutionsAsMap() {
+        if (executionMap == null) {
+            executionMap = new java.util.LinkedHashMap<String, PluginExecution>();
+            for (java.util.Iterator<PluginExecution> i = getExecutions().iterator(); i.hasNext();) {
+                PluginExecution exec = (PluginExecution) i.next();
+                if (executionMap.containsKey(exec.getId())) {
+                    throw new IllegalStateException("You cannot have two plugin executions with the same (or missing) <id/> elements.\nOffending execution\n\nId: \'" + exec.getId() + "\'\nPlugin:\'" + getKey() + "\'\n\n");
+                }
+                executionMap.put(exec.getId(), exec);
+            }
+        }
+        return executionMap;
+    }
+
+    /**
+     * Gets the identifier of the plugin.
+     *
+     * @return the plugin id in the form {@code <groupId>:<artifactId>:<version>}, never {@code null}
+     */
+    public String getId() {
+        return new StringBuilder(128)
+            .append((getGroupId() == null) ? "[unknown-group-id]" : getGroupId())
+            .append(":")
+            .append((getArtifactId() == null) ? "[unknown-artifact-id]" : getArtifactId())
+            .append(":")
+            .append((getVersion() == null) ? "[unknown-version]" : getVersion())
+            .toString();
+    }
+
+    /**
+     * @return the key of the plugin, ie {@code groupId:artifactId}
+     */
+    public String getKey() {
+        return constructKey(getGroupId(), getArtifactId());
+    }
+
+    /**
+     * @param groupId the group ID of the plugin in the repository
+     * @param artifactId the artifact ID of the reporting plugin in the repository
+     * @return the key of the plugin, ie {@code groupId:artifactId}
+     */
+    public static String constructKey(String groupId, String artifactId) {
+        return groupId + ":" + artifactId;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.1.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals(Object other) {
+        if (other instanceof Plugin) {
+            Plugin otherPlugin = (Plugin) other;
+            return getKey().equals(otherPlugin.getKey());
+        }
+        return false;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode() {
+        return getKey().hashCode();
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString() {
+        return "Plugin [" + getKey() + "]";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>PluginExecution</name>
+      <version>4.0.0+</version>
+      <superClass>ConfigurationContainer</superClass>
+      <description>
+        <![CDATA[
+        The {@code <execution>} element contains informations required for the
+        execution of a plugin.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>id</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <defaultValue>default</defaultValue>
+          <description>The identifier of this execution for labelling the goals during the build,
+            and for matching executions to merge during inheritance and profile injection.</description>
+        </field>
+        <field>
+          <name>phase</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>The build lifecycle phase to bind the goals in this execution to. If omitted,
+            the goals will be bound to the default phase specified by the plugin. </description>
+        </field>
+        <field xml.transient="true">
+          <name>priority</name>
+          <version>4.0.0/4.0.99</version>
+          <type>int</type>
+          <description>
+            <![CDATA[
+            The priority of this execution compared to other executions which are bound to the same phase.
+            <strong>Warning:</strong> This is an internal utility property that is only public for technical reasons,
+            it is not part of the public API. In particular, this property can be changed or deleted without prior
+            notice.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>priority</name>
+          <version>4.1.0+</version>
+          <type>int</type>
+          <description>
+            <![CDATA[
+            The priority of this execution compared to other executions which are bound to the same phase.
+            Executions derived from the default lifecycle have a negative priority by default so that they are executed
+            before any custom plugin executions.
+            <br><b>Since</b>: Maven 4.0.0
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>goals</name>
+          <version>4.0.0+</version>
+          <description>The goals to execute with the given configuration.</description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    public static final String DEFAULT_EXECUTION_ID = "default";
+
+    @Override
+    public String toString()
+    {
+        return getId();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>DependencyManagement</name>
+      <version>4.0.0+</version>
+      <description>Section for management of default dependency information for use in a group of
+        POMs.</description>
+      <fields>
+        <field>
+          <name>dependencies</name>
+          <version>4.0.0+</version>
+          <description>The dependencies specified here are not used until they are referenced in a
+            POM within the group. This allows the specification of a "standard" version for a
+            particular dependency.</description>
+          <association>
+            <type>Dependency</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>PluginManagement</name>
+      <version>4.0.0+</version>
+      <superClass>PluginContainer</superClass>
+      <description>Section for management of default plugin information for use in a group of POMs.
+      </description>
+    </class>
+    <class>
+      <name>Reporting</name>
+      <version>4.0.0+</version>
+      <description>Section for management of reports and their configuration.</description>
+      <fields>
+        <field>
+          <name>excludeDefaults</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            If true, then the default reports are not included in the site generation.
+            This includes the reports in the "Project Info" menu. Note: While the type
+            of this field is {@code String} for technical reasons, the semantic type is actually
+            {@code Boolean}. Default value is {@code false}.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>outputDirectory</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            Where to store all of the generated reports. The default is
+            {@code ${project.build.directory}/site}.
+            ]]>
+          </description>
+          <!-- TODO: why isn't default set here? -->
+        </field>
+        <field>
+          <name>plugins</name>
+          <version>4.0.0+</version>
+          <description>The reporting plugins to use and their configuration.</description>
+          <association>
+            <type>ReportPlugin</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    public boolean isExcludeDefaults()
+    {
+        return ( getExcludeDefaults() != null ) ? Boolean.parseBoolean( getExcludeDefaults() ) : false;
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    public void setExcludeDefaults( boolean excludeDefaults )
+    {
+        setExcludeDefaults( String.valueOf( excludeDefaults ) );
+    }
+
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <!-- Profile support -->
+    <class>
+      <name>Profile</name>
+      <superClass>ModelBase</superClass>
+      <version>4.0.0+</version>
+      <description>Modifications to the build process which is activated based on environmental
+        parameters or command line arguments.</description>
+      <fields>
+        <field>
+          <name>id</name>
+          <required>true</required>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <defaultValue>default</defaultValue>
+          <description>The identifier of this build profile. This is used for command line
+            activation, and identifies profiles to be merged.
+          </description>
+        </field>
+        <field>
+          <name>activation</name>
+          <version>4.0.0+</version>
+          <description>The conditional logic which will automatically trigger the inclusion of this
+            profile.</description>
+          <association>
+            <type>Activation</type>
+          </association>
+        </field>
+        <field xml.tagName="build">
+          <name>build</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <description>Information required to build the project.</description>
+          <association>
+            <type>BuildBase</type>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0/4.0.99</version>
+          <code>
+            <![CDATA[
+    public static final String SOURCE_POM = "pom";
+
+    public static final String SOURCE_SETTINGS = "settings.xml";
+
+    public void setSource( String source )
+    {
+        getDelegate().setSource( source );
+    }
+
+    public String getSource()
+    {
+        return getDelegate().getSource();
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Profile {id: " + getId() + ", source: " + getSource() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>4.1.0+</version>
+          <code>
+            <![CDATA[
+    public static final String SOURCE_POM = "pom";
+
+    public static final String SOURCE_SETTINGS = "settings.xml";
+
+    // We don't want this to be parseable...it's sort of 'hidden'
+    // default source for this profile is in the pom itself.
+    private String source = SOURCE_POM;
+
+    public void setSource( String source )
+    {
+        this.source = source;
+    }
+
+    public String getSource()
+    {
+        return source;
+    }
+
+    /**
+     * @see java.lang.Object#toString()
+     */
+    public String toString()
+    {
+        return "Profile {id: " + getId() + ", source: " + getSource() + "}";
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Activation</name>
+      <version>4.0.0+</version>
+      <description>The conditions within the build runtime environment which will trigger the
+        automatic inclusion of the build profile. Multiple conditions can be defined, which must
+        be all satisfied to activate the profile.
+      </description>
+      <fields>
+        <field>
+          <name>activeByDefault</name>
+          <version>4.0.0+</version>
+          <type>boolean</type>
+          <description>If set to true, this profile will be active unless another profile in this
+            pom is activated using the command line -P option or by one of that profile's
+            activators.</description>
+        </field>
+        <field>
+          <name>jdk</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            Specifies that this profile will be activated when a matching JDK is detected.
+            For example, {@code 1.4} only activates on JDKs versioned 1.4,
+            while {@code !1.4} matches any JDK that is not version 1.4. Ranges are supported too:
+            {@code [1.5,)} activates when the JDK is 1.5 minimum.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>os</name>
+          <version>4.0.0+</version>
+          <description>Specifies that this profile will be activated when matching operating system
+            attributes are detected.</description>
+          <association>
+            <type>ActivationOS</type>
+          </association>
+        </field>
+        <field>
+          <name>property</name>
+          <version>4.0.0+</version>
+          <description>Specifies that this profile will be activated when this property is
+            specified.</description>
+          <association>
+            <type>ActivationProperty</type>
+          </association>
+        </field>
+        <field>
+          <name>file</name>
+          <version>4.0.0+</version>
+          <description>Specifies that this profile will be activated based on existence of a file.</description>
+          <association>
+            <type>ActivationFile</type>
+          </association>
+        </field>
+        <!--
+        This could be included once we teach Maven to deal with multiple versions of the model
+        <field>
+          <name>custom</name>
+          <version>4.0.0+</version>
+          <description>Describes a custom profile activation trigger, brought in via build
+            extension.</description>
+          <association>
+            <type>ActivationCustom</type>
+          </association>
+        </field>
+        -->
+      </fields>
+    </class>
+    <class>
+      <name>ActivationProperty</name>
+      <version>4.0.0+</version>
+      <description>This is the property specification used to activate a profile. If the value field
+        is empty, then the existence of the named property will activate the profile, otherwise it
+        does a case-sensitive match against the property value as well.</description>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <required>true</required>
+          <description>The name of the property to be used to activate a profile.</description>
+        </field>
+        <field>
+          <name>value</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>The value of the property required to activate a profile.</description>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>ActivationOS</name>
+      <version>4.0.0+</version>
+      <description>This is an activator which will detect an operating system's attributes in order
+        to activate its profile.</description>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            The name of the operating system to be used to activate the profile. This must be an exact match
+            of the {@code ${os.name}} Java property, such as {@code Windows XP}.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>family</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            The general family of the OS to be used to activate the profile, such as
+            {@code windows} or {@code unix}.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>arch</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>The architecture of the operating system to be used to activate the
+          profile.</description>
+        </field>
+        <field>
+          <name>version</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>The version of the operating system to be used to activate the
+          profile.</description>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>ActivationFile</name>
+      <version>4.0.0+</version>
+      <description><![CDATA[This is the file specification used to activate the profile. The {@code missing} value
+        is the location of a file that needs to exist, and if it doesn't, the profile will be
+        activated. On the other hand, {@code exists} will test for the existence of the file and if it is
+        there, the profile will be activated.<br>
+        Variable interpolation for these file specifications is limited to {@code ${project.basedir}},
+        system properties and user properties.]]></description>
+      <fields>
+        <field>
+          <name>missing</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>The name of the file that must be missing to activate the
+          profile.</description>
+        </field>
+        <field>
+          <name>exists</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>The name of the file that must exist to activate the profile.</description>
+        </field>
+      </fields>
+    </class>
+    <!--
+    This can be put back in when we figure out how to have multiple model versions
+    <class>
+      <name>ActivationCustom</name>
+      <version>4.0.0+</version>
+      <description>This activation allows users to specify their own custom trigger for a profile.</description>
+      <fields>
+        <field>
+          <name>configuration</name>
+          <version>4.0.0+</version>
+          <type>DOM</type>
+          <description>The specification for triggering the profile according to the rules of the
+            custom activation type.</description>
+        </field>
+        <field>
+          <name>type</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>The type (role-hint) of activation which is to be used to activate the
+            profile.</description>
+        </field>
+      </fields>
+    </class>
+    -->
+    <!-- /BuildProfile support -->
+    <class xml.tagName="plugin" xdoc.anchorName="report_plugin" java.clone="deep">
+      <name>ReportPlugin</name>
+      <version>4.0.0+</version>
+      <superClass>ConfigurationContainer</superClass>
+      <description>
+        <![CDATA[
+        The {@code <plugin>} element in {@code <reporting><plugins>} contains informations required for a report plugin.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <required>true</required>
+          <defaultValue>org.apache.maven.plugins</defaultValue>
+          <description>The group ID of the reporting plugin in the repository.</description>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <required>true</required>
+          <description>The artifact ID of the reporting plugin in the repository.</description>
+        </field>
+        <field>
+          <name>version</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            The version of the reporting plugin to be used. Starting with Maven 3, if no version is defined explicitly,
+            version is searched in {@code build/plugins} then in {@code build/pluginManagement}.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>reportSets</name>
+          <version>4.0.0+</version>
+          <description>
+            <![CDATA[
+            Multiple specifications of a set of reports, each having (possibly) different
+            configuration. This is the reporting parallel to an {@code execution} in the build.
+            ]]>
+          </description>
+          <association>
+            <type>ReportSet</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    private java.util.Map<String, ReportSet> reportSetMap = null;
+
+    /**
+     * Reset the {@code reportSetMap} field to {@code null}
+     */
+    public void flushReportSetMap()
+    {
+        this.reportSetMap = null;
+    }
+
+    /**
+     * @return a Map of reportSets field with {@code ReportSet#getId()} as key
+     * @see ReportSet#getId()
+     */
+    public java.util.Map<String, ReportSet> getReportSetsAsMap()
+    {
+        if ( reportSetMap == null )
+        {
+            reportSetMap = new java.util.LinkedHashMap<String, ReportSet>();
+            if ( getReportSets() != null )
+            {
+                for ( java.util.Iterator<ReportSet> i = getReportSets().iterator(); i.hasNext(); )
+                {
+                    ReportSet reportSet = (ReportSet) i.next();
+                    reportSetMap.put( reportSet.getId(), reportSet );
+                }
+            }
+        }
+
+        return reportSetMap;
+    }
+
+    /**
+     * @return the key of the report plugin, ie {@code groupId:artifactId}
+     */
+    public String getKey()
+    {
+        return constructKey( getGroupId(), getArtifactId() );
+    }
+
+    /**
+     * @param groupId The group ID of the plugin in the repository
+     * @param artifactId The artifact ID of the reporting plugin in the repository
+     * @return the key of the report plugin, ie {@code groupId:artifactId}
+     */
+    public static String constructKey( String groupId, String artifactId )
+    {
+        return groupId + ":" + artifactId;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>ReportSet</name>
+      <version>4.0.0+</version>
+      <superClass>ConfigurationContainer</superClass>
+      <description>Represents a set of reports and configuration to be used to generate them.</description>
+      <fields>
+        <field>
+          <name>id</name>
+          <type>String</type>
+          <required>true</required>
+          <description>The unique id for this report set, to be used during POM inheritance and profile injection
+            for merging of report sets.
+          </description>
+          <defaultValue>default</defaultValue>
+        </field>
+        <field>
+          <name>reports</name>
+          <version>4.0.0+</version>
+          <required>true</required>
+          <description>The list of reports from this plugin which should be generated from this set.</description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    @Override
+    public String toString()
+    {
+        return getId();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Prerequisites</name>
+      <version>4.0.0+</version>
+      <description>Describes the prerequisites a project can have.</description>
+      <fields>
+        <field>
+          <name>maven</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <defaultValue>2.0</defaultValue>
+          <description><![CDATA[
+            For a plugin project (packaging is {@code maven-plugin}), the minimum version of
+            Maven required to use the resulting plugin.<br>
+            In Maven 2, this was also specifying the minimum version of Maven required to build a
+            project, but this usage is <b>deprecated</b> in Maven 3 and not checked any more: use
+            the <a href="https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html">Maven Enforcer Plugin's
+            {@code requireMavenVersion} rule</a> instead.
+            ]]>
+          </description>
+          <required>false</required>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Relocation</name>
+      <version>4.0.0+</version>
+      <description>Describes where an artifact has moved to. If any of the values are omitted, it is
+        assumed to be the same as it was before.</description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <version>4.0.0+</version>
+          <description>The group ID the artifact has moved to.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>4.0.0+</version>
+          <description>The new artifact ID of the artifact.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>version</name>
+          <version>4.0.0+</version>
+          <description>The new version of the artifact.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>message</name>
+          <version>4.0.0+</version>
+          <description>An additional message to show the user about the move, such as the reason.</description>
+          <type>String</type>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Extension</name>
+      <version>4.0.0+</version>
+      <description>Describes a build extension to utilise.</description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <version>4.0.0+</version>
+          <description>The group ID of the extension's artifact.</description>
+          <required>true</required>
+          <type>String</type>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>4.0.0+</version>
+          <description>The artifact ID of the extension.</description>
+          <required>true</required>
+          <type>String</type>
+        </field>
+        <field>
+          <name>version</name>
+          <version>4.0.0+</version>
+          <description>The version of the extension.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>configuration</name>
+          <version>4.1.0+</version>
+          <description>
+            <![CDATA[
+            The configuration of the extension.
+            <br><b>Since</b>: Maven 4.0.0
+            ]]>
+          </description>
+          <type>DOM</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.1.0+</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object o )
+    {
+        if ( this == o )
+        {
+            return true;
+        }
+
+        if ( !( o instanceof Extension ) )
+        {
+            return false;
+        }
+
+        Extension e = (Extension) o;
+
+        if ( !equal( e.getArtifactId(), getArtifactId() ) )
+        {
+            return false;
+        }
+        else if ( !equal( e.getGroupId(), getGroupId() ) )
+        {
+            return false;
+        }
+        else if ( !equal( e.getVersion(), getVersion() ) )
+        {
+            return false;
+        }
+        return true;
+    }
+
+    private static <T> boolean equal( T obj1, T obj2 )
+    {
+        return ( obj1 != null ) ? obj1.equals( obj2 ) : obj2 == null;
+    }
+
+    /**
+     * @see java.lang.Object#hashCode()
+     */
+    public int hashCode()
+    {
+        int result = 17;
+        result = 37 * result + ( getArtifactId() != null ? getArtifactId().hashCode() : 0 );
+        result = 37 * result + ( getGroupId() != null ? getGroupId().hashCode() : 0 );
+        result = 37 * result + ( getVersion() != null ? getVersion().hashCode() : 0 );
+        return result;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class locationTracker="locations">
+      <name>InputLocation</name>
+      <version>4.0.0+</version>
+      <fields>
+        <!-- line, column and source fields are auto-generated by Modello -->
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+
+    @Override
+    public String toString()
+    {
+        return getLineNumber() + " : " + getColumnNumber() + ", " + getSource();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class sourceTracker="source">
+      <name>InputSource</name>
+      <version>4.0.0+</version>
+      <fields>
+        <field>
+          <name>modelId</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            The identifier of the POM in the format {@code <groupId>:<artifactId>:<version>}.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>location</name>
+          <version>4.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            The path/URL of the POM or {@code null} if unknown.
+            ]]>
+          </description>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>4.0.0+</version>
+          <code>
+            <![CDATA[
+    @Override
+    public String toString()
+    {
+        return getModelId() + " " + getLocation();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+  </classes>
+</model>
diff --git a/api/maven-api-model/src/site/apt/index.apt b/api/maven-api-model/src/site/apt/index.apt
new file mode 100644
index 0000000..e64b4fb
--- /dev/null
+++ b/api/maven-api-model/src/site/apt/index.apt
@@ -0,0 +1,36 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ -----
+ Introduction
+ -----
+ Jason van Zyl
+ Vincent Siveton
+ Hervé Boutemy
+ -----
+ 2011-06-12
+ -----
+
+Maven 4 API - Immutable Maven Model
+
+ This is strictly the immutable model for Maven POM (Project Object Model), so really just plain objects in <<<org.apache.maven.api.model>>> package.
+
+ The following are generated from this model:
+
+   * {{{./apidocs/index.html}Java sources}} with <<<Builder>>> inner classes for immutable instances creation.
+
+ See also corresponding {{{../../maven-model/index.html}Maven classical POM model documentation}}.
diff --git a/api/maven-api-model/src/site/site.xml b/api/maven-api-model/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/maven-api-model/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/api/maven-api-plugin/pom.xml b/api/maven-api-plugin/pom.xml
new file mode 100644
index 0000000..b5b4713
--- /dev/null
+++ b/api/maven-api-plugin/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-plugin</artifactId>
+
+  <name>Maven 4 API :: Plugin</name>
+  <description>Maven 4 API - Immutable Plugin model.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-xml</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.modello</groupId>
+        <artifactId>modello-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>plugin</id>
+            <goals>
+              <goal>velocity</goal>
+              <goal>xdoc</goal>
+              <goal>xsd</goal>
+            </goals>
+            <phase>generate-resources</phase>
+            <configuration>
+              <velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
+              <version>2.0.0</version>
+              <models>
+                <model>src/main/mdo/plugin.mdo</model>
+              </models>
+              <templates>
+                <template>model.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV4=org.apache.maven.api.plugin.descriptor</param>
+              </params>
+            </configuration>
+          </execution>
+          <execution>
+            <id>lifecycle</id>
+            <goals>
+              <goal>velocity</goal>
+              <goal>xdoc</goal>
+              <goal>xsd</goal>
+            </goals>
+            <phase>generate-resources</phase>
+            <configuration>
+              <velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
+              <version>1.0.0</version>
+              <models>
+                <model>src/main/mdo/lifecycle.mdo</model>
+              </models>
+              <templates>
+                <template>model.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV4=org.apache.maven.api.plugin.descriptor.lifecycle</param>
+              </params>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/package-info.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/api/maven-api-plugin/src/main/java/org/apache/maven/api/plugin/descriptor/lifecycle/package-info.java b/api/maven-api-plugin/src/main/java/org/apache/maven/api/plugin/descriptor/lifecycle/package-info.java
new file mode 100644
index 0000000..eec9c50
--- /dev/null
+++ b/api/maven-api-plugin/src/main/java/org/apache/maven/api/plugin/descriptor/lifecycle/package-info.java
@@ -0,0 +1,5 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/**
+ * Maven Plugin forked lifecycle model.
+ */
+package org.apache.maven.api.plugin.descriptor.lifecycle;
diff --git a/api/maven-api-plugin/src/main/java/org/apache/maven/api/plugin/descriptor/package-info.java b/api/maven-api-plugin/src/main/java/org/apache/maven/api/plugin/descriptor/package-info.java
new file mode 100644
index 0000000..0435496
--- /dev/null
+++ b/api/maven-api-plugin/src/main/java/org/apache/maven/api/plugin/descriptor/package-info.java
@@ -0,0 +1,5 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/**
+ * Maven Plugin descriptor model.
+ */
+package org.apache.maven.api.plugin.descriptor;
diff --git a/api/maven-api-plugin/src/main/mdo/lifecycle.mdo b/api/maven-api-plugin/src/main/mdo/lifecycle.mdo
new file mode 100644
index 0000000..db51be6
--- /dev/null
+++ b/api/maven-api-plugin/src/main/mdo/lifecycle.mdo
@@ -0,0 +1,123 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<model xmlns="http://codehaus-plexus.github.io/MODELLO/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/2.0.0 http://codehaus-plexus.github.io/modello/xsd/modello-2.0.0.xsd"
+  xml.namespace="http://maven.apache.org/LIFECYCLE/${version}"
+  xml.schemaLocation="http://maven.apache.org/xsd/lifecycle-${version}.xsd">
+  <id>lifecycle</id>
+  <name>Lifecycle</name>
+  <description><![CDATA[
+    Configuration of custom lifecycle mappings for the plugin, as generally stored in
+    <code>META-INF/maven/lifecycle.xml</code> in a plugin's jar artifact.
+  ]]></description>
+  <classes>
+    <class rootElement="true" xml.tagName="lifecycles" xsd.compositor="sequence">
+      <name>LifecycleConfiguration</name>
+      <version>1.0.0</version>
+      <description><![CDATA[Root element of the <code>lifecycle.xml</code> file.]]></description>
+      <fields>
+        <field>
+          <name>lifecycles</name>
+          <version>1.0.0</version>
+          <association xml.itemsStyle="flat">
+            <type>Lifecycle</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Lifecycle</name>
+      <version>1.0.0</version>
+      <description><![CDATA[
+        A custom lifecycle mapping definition.
+      ]]></description>
+      <fields>
+        <field>
+          <name>id</name>
+          <required>true</required>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>The ID of this lifecycle, for identification in the mojo descriptor.</description>
+        </field>
+        <field>
+          <name>phases</name>
+          <version>1.0.0</version>
+          <description>The phase mappings for this lifecycle.</description>
+          <association>
+            <type>Phase</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Phase</name>
+      <version>1.0.0</version>
+      <description>A phase mapping definition.</description>
+      <fields>
+        <field>
+          <name>id</name>
+          <required>true</required>
+          <version>1.0.0</version>
+          <type>String</type>
+          <description>The ID of this phase, e.g., &lt;code&gt;generate-sources&lt;/code&gt;.</description>
+        </field>
+        <field>
+          <name>executions</name>
+          <version>1.0.0</version>
+          <description>The goals to execute within the phase.</description>
+          <association>
+            <type>Execution</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>configuration</name>
+          <version>1.0.0</version>
+          <type>DOM</type>
+          <description>Configuration to pass to all goals run in this phase.</description>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Execution</name>
+      <version>1.0.0</version>
+      <description>A set of goals to execute.</description>
+      <fields>
+        <field>
+          <name>configuration</name>
+          <version>1.0.0</version>
+          <type>DOM</type>
+          <description>Configuration to pass to the goals.</description>
+        </field>
+        <field>
+          <name>goals</name>
+          <version>1.0.0</version>
+          <description>The goals to execute.</description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+    </class>
+  </classes>
+</model>
diff --git a/api/maven-api-plugin/src/main/mdo/plugin.mdo b/api/maven-api-plugin/src/main/mdo/plugin.mdo
new file mode 100644
index 0000000..019236d
--- /dev/null
+++ b/api/maven-api-plugin/src/main/mdo/plugin.mdo
@@ -0,0 +1,579 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<model xmlns="http://codehaus-plexus.github.io/MODELLO/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/2.0.0 https://codehaus-plexus.github.io/modello/xsd/modello-2.0.0.xsd"
+  xml.namespace="http://maven.apache.org/PLUGIN/${version}"
+  xml.schemaLocation="https://maven.apache.org/xsd/plugin-${version}.xsd">
+  <id>plugin</id>
+  <name>PluginDescriptor</name>
+  <description><![CDATA[
+    Maven 4 Plugin descriptor, stored in <code>META-INF/maven/plugin.xml</code> in a plugin's jar artifact.
+    This descriptor is generally using the information contained in the annotations of the plugin api.
+    <p>An XSD is available at <a href="https://maven.apache.org/xsd/plugin-2.0.0.xsd">https://maven.apache.org/xsd/plugin-2.0.0.xsd</a></p>
+  ]]></description>
+  <classes>
+    <class rootElement="true" xml.tagName="plugin" xdoc.anchorName="plugin">
+      <name>PluginDescriptor</name>
+      <version>1.0.0+</version>
+      <description><![CDATA[Root element of the <code>plugin.xml</code> file.]]></description>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>1.0.0+</version>
+          <description>Name of the plugin.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>description</name>
+          <version>1.0.0+</version>
+          <description>Description of the plugin.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>groupId</name>
+          <version>1.0.0+</version>
+          <description>The group id of the plugin.</description>
+          <type>String</type>
+          <required>true</required>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <version>1.0.0+</version>
+          <description>The artifact id of the plugin.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>version</name>
+          <version>1.0.0+</version>
+          <description>The version of the plugin.</description>
+          <type>String</type>
+          <required>true</required>
+        </field>
+        <field>
+          <name>goalPrefix</name>
+          <version>1.0.0+</version>
+          <description></description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>isolatedRealm</name>
+          <version>1.0.0+</version>
+          <description></description>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>inheritedByDefault</name>
+          <version>1.0.0+</version>
+          <description></description>
+          <type>boolean</type>
+          <defaultValue>true</defaultValue>
+        </field>
+        <field>
+          <name>requiredJavaVersion</name>
+          <version>1.1.0+</version>
+          <description>A version range which specifies the supported Java versions. A version range can either use the usual mathematical syntax "[2.0.10,2.1.0),[3.0,)" or use a single version "2.2.1". The latter is a short form for "[2.2.1,)", i.e. denotes the minimum version required.</description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>requiredMavenVersion</name>
+          <version>1.1.0+</version>
+          <description>A version range which specifies the supported Maven versions. A version range can either use the usual mathematical syntax "[2.0.10,2.1.0),[3.0,)" or use a single version "2.2.1". The latter is a short form for "[2.2.1,)", i.e. denotes the minimum version required. This value takes precedence over the POMs Maven prerequisite.</description>
+          <type>String</type>
+        </field>
+        <field xdoc.separator="blank">
+          <name>mojos</name>
+          <version>1.0.0+</version>
+          <association>
+            <type>MojoDescriptor</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <description>Description of each Mojo provided by the plugin.</description>
+        </field>
+        <field xdoc.separator="blank">
+          <name>dependencies</name>
+          <version>1.0.0/1.1.0</version>
+          <association>
+            <type>Dependency</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <description>
+            A set of dependencies which the plugin requires in order to function. This enables the plugin to function
+            independently of its POM (or at least to declare the libraries it needs to run).
+          </description>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>2.0.0+</version>
+          <code><![CDATA[
+    public String getPluginLookupKey() {
+        return groupId + ":" + artifactId;
+    }
+
+    public String getId() {
+        return groupId + ":" + artifactId + ":" + version;
+    }
+
+          ]]></code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+
+    <class xdoc.anchorName="mojo">
+      <name>MojoDescriptor</name>
+      <version>1.0.0+</version>
+      <description><![CDATA[
+        A Mojo description.
+      ]]></description>
+      <fields>
+        <field>
+          <name>goal</name>
+          <required>true</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The goal name for the Mojo, that users will reference from the command line to execute the Mojo directly,
+            or inside a POM in order to provide Mojo-specific configuration.
+          </description>
+        </field>
+        <field>
+          <name>description</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>The description of this Mojo's functionality.</description>
+        </field>
+        <field>
+          <name>implementation</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The Mojo's fully-qualified class name (or script path in the case of non-Java Mojos).
+          </description>
+        </field>
+        <field>
+          <name>language</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <defaultValue>java</defaultValue>
+          <description>The implementation language for this Mojo (java, beanshell, etc.).</description>
+        </field>
+        <field>
+          <name>phase</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description><![CDATA[
+            Defines a default phase to bind a Mojo execution to if the user does not explicitly set a phase in the POM.
+            <i>Note:</i> This will not automagically make a Mojo run when the plugin declaration is added
+            to the POM. It merely enables the user to omit the <code>&lt;phase&gt;</code> element from the
+            surrounding <code>&lt;execution&gt;</code> element.
+          ]]></description>
+        </field>
+        <field>
+          <name>executePhase</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>Reference the invocation phase of the Mojo.</description>
+        </field>
+        <field>
+          <name>executeGoal</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>Reference the invocation goal of the Mojo.</description>
+        </field>
+        <field>
+          <name>executeLifecycle</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description></description>
+        </field>
+        <field>
+          <name>requiresDependencyResolution</name>
+          <version>1.0.0/1.1.0</version>
+          <type>String</type>
+          <defaultValue>runtime</defaultValue>
+          <description><![CDATA[
+            Flags this Mojo as requiring the dependencies in the specified class path to be resolved before it can
+            execute: <code>compile</code>, <code>runtime</code>, <code>test</code>,
+            <code>compile+runtime</code> (since Maven 3.0) or <code>runtime+system</code> (since Maven 3.0)
+          ]]></description>
+        </field>
+        <field>
+          <name>dependencyResolution</name>
+          <version>2.0.0+</version>
+          <type>String</type>
+          <defaultValue>runtime</defaultValue>
+          <description><![CDATA[
+            Flags this Mojo as requiring the dependencies in the specified class path to be resolved before it can
+            execute: <code>compile</code>, <code>runtime</code>, <code>test</code>,
+            <code>compile+runtime</code> (since Maven 3.0) or <code>runtime+system</code> (since Maven 3.0)
+          ]]></description>
+        </field>
+        <field>
+          <name>requiresDependencyCollection</name>
+          <version>1.0.0/1.1.0</version>
+          <type>String</type>
+          <description><![CDATA[
+            Flags this Mojo as requiring information about the dependencies that would make up the specified class
+            path. As the name suggests, this is similar to requiresDependencyResolution and supports the same values.
+            The important difference is this will not resolve the files for the dependencies, i.e. the artifacts
+            associated with a Maven project can lack a file. As such, this annotation is meant for Mojos that only
+            want to analyze the set of transitive dependencies, in particular during early lifecycle phases where
+            full dependency resolution might fail due to projects which haven't been built yet.
+          ]]></description>
+        </field>
+        <field>
+          <name>dependencyCollection</name>
+          <version>2.0.0+</version>
+          <type>String</type>
+          <description><![CDATA[
+            Flags this Mojo as requiring information about the dependencies that would make up the specified class
+            path. As the name suggests, this is similar to requiresDependencyResolution and supports the same values.
+            The important difference is this will not resolve the files for the dependencies, i.e. the artifacts
+            associated with a Maven project can lack a file. As such, this annotation is meant for Mojos that only
+            want to analyze the set of transitive dependencies, in particular during early lifecycle phases where
+            full dependency resolution might fail due to projects which haven't been built yet.
+          ]]></description>
+        </field>
+        <field>
+          <name>requiresDirectInvocation</name>
+          <version>1.0.0/1.1.0</version>
+          <type>boolean</type>
+          <description>Flags this Mojo to be invoked directly only.</description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>directInvocationOnly</name>
+          <version>2.0.0+</version>
+          <type>boolean</type>
+          <description>Flags this Mojo to be invoked directly only.</description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>requiresProject</name>
+          <version>1.0.0/1.1.0</version>
+          <type>boolean</type>
+          <description>Flags this Mojo to require running inside of a project.</description>
+          <defaultValue>true</defaultValue>
+        </field>
+        <field>
+          <name>projectRequired</name>
+          <version>2.0.0+</version>
+          <type>boolean</type>
+          <description>Flags this Mojo to require running inside of a project.</description>
+          <defaultValue>true</defaultValue>
+        </field>
+        <field>
+          <name>requiresReports</name>
+          <version>1.0.0</version><!-- no longer part of 1.1.0 -->
+          <type>boolean</type>
+          <description>Flags this Mojo to require running inside of a reports context. Unsupported since Maven 3.0.</description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>requiresOnline</name>
+          <version>1.0.0/1.1.0</version>
+          <type>boolean</type>
+          <description>Flags this Mojo to require online mode for its operation.</description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>onlineRequired</name>
+          <version>2.0.0+</version>
+          <type>boolean</type>
+          <description>Flags this Mojo to require online mode for its operation.</description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>aggregator</name>
+          <version>1.0.0+</version>
+          <type>boolean</type>
+          <description>
+            Flags this Mojo to run it in a multi-module way, i.e. aggregate the build with the set of projects
+            listed as modules.
+          </description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>inheritedByDefault</name>
+          <version>1.0.0+</version>
+          <type>boolean</type>
+          <description>Specify that the Mojo is inherited.</description>
+          <defaultValue>true</defaultValue>
+        </field>
+        <field>
+          <name>threadSafe</name>
+          <version>1.0.0/1.1.0</version>
+          <type>boolean</type>
+          <description>
+            Marks this Mojo as being thread-safe, i.e. the Mojo safely supports concurrent execution during parallel
+            builds. Mojos without this annotation will make Maven output a warning when used during a parallel build
+            session. Since Maven 3.0.
+          </description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>v4Api</name>
+          <version>1.1.0</version>
+          <type>boolean</type>
+          <description>Marks this Mojo as using Maven 4 API. This makes the plugin implicitly incompatible with earlier Maven versions. Only evaluated since Maven 4.</description>
+          <defaultValue>false</defaultValue>
+        </field>
+        <field>
+          <name>instantiationStrategy</name>
+          <version>1.0.0/1.1.0</version>
+          <type>String</type>
+          <defaultValue>per-lookup</defaultValue>
+          <description>Specify the instantiation strategy.</description>
+        </field>
+        <field>
+          <name>executionStrategy</name>
+          <version>1.0.0/1.1.0</version>
+          <type>String</type>
+          <description><![CDATA[
+            Specify the execution strategy: <code>once-per-session</code>, <code>always</code>.
+          ]]></description>
+          <defaultValue>once-per-session</defaultValue>
+        </field>
+        <field>
+          <name>since</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>Specify the version when the Mojo was added to the API. Similar to Javadoc since.</description>
+        </field>
+        <field>
+          <name>deprecated</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description><![CDATA[
+            Description with the reason of Mojo deprecation. Similar to Javadoc <code>@deprecated</code>
+            This will trigger a warning when a user tries to use a Mojo marked as deprecated.
+          ]]></description>
+        </field>
+        <field>
+          <name>configurator</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The configurator type to use when injecting parameter values into this Mojo. The value is normally deduced
+            from the Mojo's implementation language, but can be specified to allow a custom ComponentConfigurator
+            implementation to be used.
+          </description>
+        </field>
+        <field>
+          <name>composer</name>
+          <version>1.0.0/1.1.0</version>
+          <type>String</type>
+          <description></description>
+        </field>
+        <field xdoc.separator="blank">
+          <name>parameters</name>
+          <version>1.0.0+</version>
+          <description></description>
+          <association>
+            <type>Parameter</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>requirements</name>
+          <version>1.0.0/1.1.0</version>
+          <description></description>
+          <association>
+            <type>Requirement</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xml.format="((PluginDescriptor.Builder) context.peekLast()).build().getId() + &quot;:&quot; + mojoDescriptor.build().getGoal()">
+          <name>id</name>
+          <version>2.0.0+</version>
+          <type>String</type>
+          <description>the id of the mojo, based on the goal name</description>
+        </field>
+        <field xml.format="((PluginDescriptor.Builder) context.peekLast()).build().getGoalPrefix() + &quot;:&quot; + mojoDescriptor.build().getGoal()">
+          <name>fullGoalName</name>
+          <version>2.0.0+</version>
+          <type>String</type>
+          <description>the full goal name</description>
+        </field>
+      </fields>
+    </class>
+
+    <class xdoc.anchorName="parameter">
+      <name>Parameter</name>
+      <version>1.0.0+</version>
+      <description>A phase mapping definition.</description>
+      <!-- see o.a.m.plugin.descriptor.Parameter -->
+      <fields>
+        <field>
+          <name>name</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <required>true</required>
+          <description>
+            The name of the parameter, to be used while configuring this parameter from the Mojo's declared defaults
+            or from the POM.
+          </description>
+        </field>
+        <field>
+          <name>alias</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            Specifies an alias which can be used to configure this parameter from the POM.
+            This is primarily useful to improve user-friendliness, where Mojo field names are not intuitive to the
+            user or are otherwise not conducive to configuration via the POM.
+          </description>
+        </field>
+        <field>
+          <name>type</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <required>true</required>
+          <description>
+            The Java type for this parameter. This is used to validate the result of any expressions used to calculate
+            the value which should be injected into the Mojo for this parameter.
+          </description>
+        </field>
+        <field>
+          <name>required</name>
+          <version>1.0.0+</version>
+          <type>boolean</type>
+          <description>
+            Whether this parameter is required for the Mojo to function. This is used to validate the configuration
+            for a Mojo before it is injected, and before the Mojo is executed from some half-state.
+          </description>
+        </field>
+        <field>
+          <name>editable</name>
+          <version>1.0.0+</version>
+          <type>boolean</type>
+          <defaultValue>true</defaultValue>
+          <description><![CDATA[
+            Specifies that this parameter can be configured directly by the user (as in the case of POM-specified
+            configuration). This is useful when you want to force the user to use common POM elements rather than
+            plugin configurations, as in the case where you want to use the artifact's final name as a parameter. In
+            this case, you want the user to modify <code>&lt;build&gt;&lt;finalName/&gt;&lt;/build&gt;</code> rather
+            than specifying a value for finalName directly in the plugin configuration section. It is also useful to
+            ensure that - for example - a List-typed parameter which expects items of type Artifact doesn't get a List
+            full of Strings.
+          ]]></description>
+        </field>
+        <field>
+          <name>description</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>The description of this parameter's use inside the Mojo.</description>
+        </field>
+        <field>
+          <name>since</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>Specify the version when the parameter was added to the API. Similar to Javadoc since.</description>
+        </field>
+        <field>
+          <name>deprecated</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description><![CDATA[
+            Description with the reason of parameter deprecation. Similar to Javadoc <code>@deprecated</code>
+            This will trigger a warning when a user tries to configure a parameter marked as deprecated.
+          ]]></description>
+        </field>
+        <field>
+          <name>expression</name>
+          <version>2.0.0+</version>
+          <type>String</type>
+          <description>Parameter expression, to let user override default value with a user property, system property or project property.</description>
+        </field>
+        <field>
+          <name>defaultValue</name>
+          <version>2.0.0+</version>
+          <type>String</type>
+          <description>The default value, as an expression that will be evaluated at injection or run-time.</description>
+        </field>
+      </fields>
+    </class>
+
+    <class xdoc.anchorName="requirement">
+      <name>Requirement</name>
+      <version>1.0.0/1.1.0</version>
+      <description>Describes a component requirement.</description>
+      <!-- see o.a.m.plugin.descriptor.Requirement -->
+      <fields>
+        <field>
+          <name>role</name>
+          <required>true</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description></description>
+        </field>
+        <field xml.tagName="role-hint">
+          <name>roleHint</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description></description>
+        </field>
+        <field xml.tagName="field-name">
+          <name>fieldName</name>
+          <required>true</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>The field name which has this requirement.</description>
+        </field>
+      </fields>
+    </class>
+
+    <class xdoc.anchorName="dependency">
+      <name>Dependency</name>
+      <version>1.0.0/1.1.0</version>
+      <description>Definition of a dependency, needed by the plugin at runtime.</description>
+      <fields>
+        <field>
+          <name>groupId</name>
+          <required>true</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>The group id of the dependency.</description>
+        </field>
+        <field>
+          <name>artifactId</name>
+          <required>true</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>The artifact id of the dependency.</description>
+        </field>
+        <field>
+          <name>version</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>The version of the dependency.</description>
+        </field>
+        <field>
+          <name>type</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <defaultValue>jar</defaultValue>
+          <description>The type of dependency.</description>
+        </field>
+      </fields>
+    </class>
+  </classes>
+</model>
diff --git a/api/maven-api-plugin/src/site/apt/index.apt b/api/maven-api-plugin/src/site/apt/index.apt
new file mode 100644
index 0000000..f229c29
--- /dev/null
+++ b/api/maven-api-plugin/src/site/apt/index.apt
@@ -0,0 +1,33 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ -----
+ Introduction
+ -----
+ Guillaume Nodet
+ -----
+ 2023-11-15
+ -----
+
+Maven 4 API - Plugin Descriptor Model
+
+ This is the immutable model for Maven Plugin Descriptor in <<<org.apache.maven.api.plugin.descriptor>>> package.
+
+ The following are generated from this model:
+
+   * {{{./apidocs/index.html}Java sources}} with <<<Builder>>> inner classes for immutable instances creation.
+
diff --git a/api/maven-api-plugin/src/site/site.xml b/api/maven-api-plugin/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/maven-api-plugin/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/api/maven-api-settings/pom.xml b/api/maven-api-settings/pom.xml
new file mode 100644
index 0000000..145724a
--- /dev/null
+++ b/api/maven-api-settings/pom.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-settings</artifactId>
+
+  <name>Maven 4 API :: Settings</name>
+  <description>Maven 4 API - Immutable Settings model.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-xml</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.modello</groupId>
+        <artifactId>modello-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>velocity</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <configuration>
+              <version>2.0.0</version>
+              <velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
+              <models>
+                <model>src/main/mdo/settings.mdo</model>
+              </models>
+              <templates>
+                <template>model.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV4=org.apache.maven.api.settings</param>
+                <param>locationTracking=true</param>
+              </params>
+            </configuration>
+          </execution>
+          <execution>
+            <id>modello-site-docs</id>
+            <goals>
+              <goal>xdoc</goal>
+              <goal>xsd</goal>
+            </goals>
+            <phase>generate-resources</phase>
+            <configuration>
+              <version>1.3.0</version>
+              <models>
+                <model>src/main/mdo/settings.mdo</model>
+              </models>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/package-info.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocation.java b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocation.java
new file mode 100644
index 0000000..b3ea387
--- /dev/null
+++ b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocation.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.settings;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Class InputLocation.
+ */
+public class InputLocation implements Serializable, InputLocationTracker {
+    private final int lineNumber;
+    private final int columnNumber;
+    private final InputSource source;
+    private final Map<Object, InputLocation> locations;
+
+    public InputLocation(InputSource source) {
+        this.lineNumber = -1;
+        this.columnNumber = -1;
+        this.source = source;
+        this.locations = Collections.singletonMap(0, this);
+    }
+
+    public InputLocation(int lineNumber, int columnNumber) {
+        this(lineNumber, columnNumber, null, null);
+    }
+
+    public InputLocation(int lineNumber, int columnNumber, InputSource source) {
+        this(lineNumber, columnNumber, source, null);
+    }
+
+    public InputLocation(int lineNumber, int columnNumber, InputSource source, Object selfLocationKey) {
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+        this.source = source;
+        this.locations =
+                selfLocationKey != null ? Collections.singletonMap(selfLocationKey, this) : Collections.emptyMap();
+    }
+
+    public InputLocation(int lineNumber, int columnNumber, InputSource source, Map<Object, InputLocation> locations) {
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+        this.source = source;
+        this.locations = ImmutableCollections.copy(locations);
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+
+    public InputSource getSource() {
+        return source;
+    }
+
+    public InputLocation getLocation(Object key) {
+        return locations != null ? locations.get(key) : null;
+    }
+
+    public Map<Object, InputLocation> getLocations() {
+        return locations;
+    }
+
+    /**
+     * Merges the {@code source} location into the {@code target} location.
+     *
+     * @param target the target location
+     * @param source the source location
+     * @param sourceDominant the boolean indicating of {@code source} is dominant compared to {@code target}
+     * @return the merged location
+     */
+    public static InputLocation merge(InputLocation target, InputLocation source, boolean sourceDominant) {
+        if (source == null) {
+            return target;
+        } else if (target == null) {
+            return source;
+        }
+
+        Map<Object, InputLocation> locations;
+        Map<Object, InputLocation> sourceLocations = source.locations;
+        Map<Object, InputLocation> targetLocations = target.locations;
+        if (sourceLocations == null) {
+            locations = targetLocations;
+        } else if (targetLocations == null) {
+            locations = sourceLocations;
+        } else {
+            locations = new LinkedHashMap<>();
+            locations.putAll(sourceDominant ? targetLocations : sourceLocations);
+            locations.putAll(sourceDominant ? sourceLocations : targetLocations);
+        }
+
+        return new InputLocation(target.getLineNumber(), target.getColumnNumber(), target.getSource(), locations);
+    } // -- InputLocation merge( InputLocation, InputLocation, boolean )
+
+    /**
+     * Merges the {@code source} location into the {@code target} location.
+     * This method is used when the locations refer to lists and also merges the indices.
+     *
+     * @param target the target location
+     * @param source the source location
+     * @param indices the list of integers for the indices
+     * @return the merged location
+     */
+    public static InputLocation merge(InputLocation target, InputLocation source, Collection<Integer> indices) {
+        if (source == null) {
+            return target;
+        } else if (target == null) {
+            return source;
+        }
+
+        Map<Object, InputLocation> locations;
+        Map<Object, InputLocation> sourceLocations = source.locations;
+        Map<Object, InputLocation> targetLocations = target.locations;
+        if (sourceLocations == null) {
+            locations = targetLocations;
+        } else if (targetLocations == null) {
+            locations = sourceLocations;
+        } else {
+            locations = new LinkedHashMap<>();
+            for (int index : indices) {
+                InputLocation location;
+                if (index < 0) {
+                    location = sourceLocations.get(~index);
+                } else {
+                    location = targetLocations.get(index);
+                }
+                locations.put(locations.size(), location);
+            }
+        }
+
+        return new InputLocation(target.getLineNumber(), target.getColumnNumber(), target.getSource(), locations);
+    } // -- InputLocation merge( InputLocation, InputLocation, java.util.Collection )
+
+    /**
+     * Class StringFormatter.
+     *
+     * @version $Revision$ $Date$
+     */
+    public interface StringFormatter {
+
+        // -----------/
+        // - Methods -/
+        // -----------/
+
+        /**
+         * Method toString.
+         */
+        String toString(InputLocation location);
+    }
+}
diff --git a/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocationTracker.java b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocationTracker.java
new file mode 100644
index 0000000..d49d723
--- /dev/null
+++ b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputLocationTracker.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.settings;
+
+public interface InputLocationTracker {
+    InputLocation getLocation(Object field);
+}
diff --git a/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputSource.java b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputSource.java
new file mode 100644
index 0000000..2450c1d
--- /dev/null
+++ b/api/maven-api-settings/src/main/java/org/apache/maven/api/settings/InputSource.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.settings;
+
+import java.io.Serializable;
+
+/**
+ * Class InputSource.
+ */
+public class InputSource implements Serializable {
+
+    private final String location;
+
+    public InputSource(String location) {
+        this.location = location;
+    }
+
+    /**
+     * Get the path/URL of the settings definition or {@code null} if unknown.
+     *
+     * @return the location
+     */
+    public String getLocation() {
+        return this.location;
+    }
+
+    @Override
+    public String toString() {
+        return getLocation();
+    }
+}
diff --git a/api/maven-api-settings/src/main/mdo/settings.mdo b/api/maven-api-settings/src/main/mdo/settings.mdo
new file mode 100644
index 0000000..d3ad60e
--- /dev/null
+++ b/api/maven-api-settings/src/main/mdo/settings.mdo
@@ -0,0 +1,1209 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+
+<model xmlns="http://codehaus-plexus.github.io/MODELLO/1.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/1.4.0 http://codehaus-plexus.github.io/modello/xsd/modello-1.4.0.xsd"
+  xml.namespace="http://maven.apache.org/SETTINGS/${version}"
+  xml.schemaLocation="http://maven.apache.org/xsd/settings-${version}.xsd">
+  <id>settings</id>
+  <name>Settings</name>
+  <description>
+    <![CDATA[
+    <p>This is a reference for the user-specific configuration for Maven.</p>
+    <p>Includes things that should not be distributed with the pom.xml file, such as developer identity, along with
+    local settings, like proxy information.</p>
+    <p>The default location for the settings file is <i>~/.m2/settings.xml</i></p>
+    ]]>
+  </description>
+  <defaults>
+    <default>
+      <key>package</key>
+      <value>org.apache.maven.settings</value>
+    </default>
+  </defaults>
+  <classes>
+    <class java.clone="deep">
+      <name>TrackableBase</name>
+      <version>1.0.0+</version>
+      <description>
+        common base class that contains code to track the source for
+        this instance (USER|GLOBAL)
+      </description>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0+</version>
+          <code>
+            <![CDATA[
+    public static final String USER_LEVEL = "user-level";
+    public static final String PROJECT_LEVEL = "project-level";
+    public static final String GLOBAL_LEVEL = "global-level";
+
+    private String sourceLevel = USER_LEVEL;
+    private boolean sourceLevelSet = false;
+
+    public void setSourceLevel( String sourceLevel )
+    {
+        if ( sourceLevelSet )
+        {
+            throw new IllegalStateException( "Cannot reset sourceLevel attribute; it is already set to: " + sourceLevel );
+        }
+        else if ( !( USER_LEVEL.equals( sourceLevel ) || PROJECT_LEVEL.equals( sourceLevel )  || GLOBAL_LEVEL.equals( sourceLevel ) ) )
+        {
+            throw new IllegalArgumentException( "sourceLevel must be one of: {" + USER_LEVEL + "," + PROJECT_LEVEL + "," + GLOBAL_LEVEL + "}" );
+        }
+        else
+        {
+            this.sourceLevel = sourceLevel;
+            this.sourceLevelSet = true;
+        }
+    }
+
+    public String getSourceLevel()
+    {
+        return sourceLevel;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>IdentifiableBase</name>
+      <superClass>TrackableBase</superClass>
+      <version>1.0.0+</version>
+      <description>
+        <![CDATA[
+        Base class for <code>Mirror</code>, <code>Profile</code>, <code>Proxy</code> and <code>Server</code>.
+        ]]></description>
+      <fields>
+        <field>
+          <name>id</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <defaultValue>default</defaultValue>
+          <required>true</required>
+        </field>
+      </fields>
+    </class>
+    <class rootElement="true" xml.tagName="settings">
+      <name>Settings</name>
+      <version>1.0.0+</version>
+      <superClass>TrackableBase</superClass>
+      <description>
+        Root element of the user configuration file.
+      </description>
+      <fields>
+        <field>
+          <name>localRepository</name>
+          <version>1.0.0+</version>
+          <required>true</required>
+          <description>
+            <![CDATA[
+            The local repository.<br><b>Default value is:</b> <code>${user.home}/.m2/repository</code>
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>interactiveMode</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Whether Maven should attempt to interact with the user for input.
+            ]]>
+          </description>
+          <type>boolean</type>
+          <defaultValue>true</defaultValue>
+        </field>
+        <field>
+          <name>usePluginRegistry</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Whether Maven should use the plugin-registry.xml file to manage plugin versions.
+            ]]>
+          </description>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>
+        <!-- [JC] Not ready to use yet, so I'm making if unavailable for now. -->
+        <!-- field>
+          <name>passwordStore</name>
+          <version>1.0.0+</version>
+          <required>false</required>
+          <description><![CDATA[The keystore used to store passwords.]]></description>
+          <type>String</type>
+          </field -->
+        <field>
+          <name>offline</name>
+          <version>1.0.0+</version>
+          <required>false</required>
+          <description>
+            <![CDATA[
+            Indicate whether maven should operate in offline mode full-time.
+            ]]>
+          </description>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+        </field>
+        <!-- [JC] Not ready to use yet, so I'm making if unavailable for now. -->
+        <!-- field>
+          <name>jdks</name>
+          <version>1.0.0+</version>
+          <description><![CDATA[
+          Configuration for different java environment profiles. One good use
+          for this might be to configure both JDK 1.4 and JDK 1.5 to work with
+          maven. Profiles will allow switching of entire java environments
+          based on the profile id, either in the defaults section below, or on
+          the command line.
+          ]]></description>
+          <association>
+          <type>Jdk</type>
+          <multiplicity>*</multiplicity>
+          </association>
+          </field -->
+        <field xdoc.separator="blank">
+          <name>proxies</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Configuration for different proxy profiles. Multiple proxy profiles
+            might come in handy for anyone working from a notebook or other
+            mobile platform, to enable easy switching of entire proxy
+            configurations by simply specifying the profile id, again either from
+            the command line or from the defaults section below.
+            ]]>
+          </description>
+          <association>
+            <type>Proxy</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>servers</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Configuration of server-specific settings, mainly authentication
+            method. This allows configuration of authentication on a per-server
+            basis.
+            ]]>
+          </description>
+          <association>
+            <type>Server</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>mirrors</name>
+          <version>1.0.0+</version>
+          <description>
+            Configuration of download mirrors for repositories.
+          </description>
+          <association>
+            <type>Mirror</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>repositories</name>
+          <version>1.3.0+</version>
+          <description>
+            <![CDATA[
+            The lists of the remote repositories.
+            ]]>
+          </description>
+          <association>
+            <type>Repository</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>pluginRepositories</name>
+          <version>1.3.0+</version>
+          <description>
+            <![CDATA[
+            The lists of the remote repositories for discovering plugins.
+            ]]>
+          </description>
+          <association>
+            <type>Repository</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <comment>
+            <![CDATA[
+            This may be removed or relocated in the near
+            future. It is undecided whether plugins really need a remote
+            repository set of their own.
+            ]]>
+          </comment>
+        </field>
+        <field xdoc.separator="blank">
+          <name>profiles</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Configuration of build profiles for adjusting the build
+            according to environmental parameters.
+            ]]>
+          </description>
+          <association>
+            <type>Profile</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>activeProfiles</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            List of manually-activated build profiles, specified in the order in which
+            they should be applied.
+            ]]>
+          </description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>pluginGroups</name>
+          <version>1.0.0+</version>
+          <description>
+            List of groupIds to search for a plugin when that plugin
+            groupId is not explicitly provided.
+          </description>
+          <association>
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0/1.3.0</version>
+          <code>
+            <![CDATA[
+    public Boolean getInteractiveMode()
+    {
+        return Boolean.valueOf( isInteractiveMode() );
+    }
+
+    private Proxy activeProxy;
+
+    /**
+     * Reset the <code>activeProxy</code> field to <code>null</code>
+     */
+    public void flushActiveProxy()
+    {
+        this.activeProxy = null;
+    }
+
+    /**
+     * @return the first active proxy
+     */
+    public synchronized Proxy getActiveProxy()
+    {
+        if ( activeProxy == null )
+        {
+            java.util.List<Proxy> proxies = getProxies();
+            if ( proxies != null && !proxies.isEmpty() )
+            {
+                for ( Proxy proxy : proxies )
+                {
+                    if ( proxy.isActive() )
+                    {
+                        activeProxy = proxy;
+                        break;
+                    }
+                }
+            }
+        }
+
+        return activeProxy;
+    }
+
+    public Server getServer( String serverId )
+    {
+        Server match = null;
+
+        java.util.List<Server> servers = getServers();
+        if ( servers != null && serverId != null )
+        {
+            for ( Server server : servers )
+            {
+                if ( serverId.equals( server.getId() ) )
+                {
+                    match = server;
+                    break;
+                }
+            }
+        }
+
+        return match;
+    }
+
+    @Deprecated
+    public Mirror getMirrorOf( String repositoryId )
+    {
+        Mirror match = null;
+
+        java.util.List<Mirror> mirrors = getMirrors();
+        if ( mirrors != null && repositoryId != null )
+        {
+            for ( Mirror mirror : mirrors )
+            {
+                if ( repositoryId.equals( mirror.getMirrorOf() ) )
+                {
+                    match = mirror;
+                    break;
+                }
+            }
+        }
+
+        return match;
+    }
+
+    private java.util.Map<String, Profile> profileMap;
+
+    /**
+     * Reset the <code>profileMap</code> field to <code>null</code>
+     */
+    public void flushProfileMap()
+    {
+        this.profileMap = null;
+    }
+
+    /**
+     * @return a Map of profiles field with <code>Profile#getId()</code> as key
+     * @see Profile#getId()
+     */
+    public java.util.Map<String, Profile> getProfilesAsMap()
+    {
+        if ( profileMap == null )
+        {
+            profileMap = new java.util.LinkedHashMap<String, Profile>();
+
+            if ( getProfiles() != null )
+            {
+                for ( Profile profile : getProfiles() )
+                {
+                    profileMap.put( profile.getId(), profile );
+                }
+            }
+        }
+
+        return profileMap;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <!-- @todo: is any of this too CVS specific? Investigate other SCMs -->
+    <!-- [JC] Commenting out until we're ready to use it... -->
+    <!-- class>
+      <name>Jdk</name>
+      <version>1.0.0+</version>
+      <superClass>TrackableBase</superClass>
+      <description><![CDATA[Describes one Java environment]]></description>
+      <fields>
+      <field>
+      <name>active</name>
+      <version>1.0.0+</version>
+      <required>false</required>
+      <defaultValue>false</defaultValue>
+      <description><![CDATA[Whether this JDK is the active one.]]></description>
+      <type>boolean</type>
+      </field>
+      <field>
+      <name>version</name>
+      <version>1.0.0+</version>
+      <required>true</required>
+      <description><![CDATA[The JDK major version (eg. '1.4').]]></description>
+      <type>String</type>
+      </field>
+      <field>
+      <name>javaHome</name>
+      <version>1.0.0+</version>
+      <required>true</required>
+      <description><![CDATA[The JDK home.]]></description>
+      <type>String</type>
+      </field>
+      </fields>
+      </class -->
+    <class>
+      <name>Proxy</name>
+      <version>1.0.0+</version>
+      <superClass>IdentifiableBase</superClass>
+      <description>
+        <![CDATA[
+        The <code>&lt;proxy&gt;</code> element contains informations required to a proxy settings.
+        ]]></description>
+      <fields>
+        <field xml.tagName="active">
+          <name>activeString</name>
+          <version>1.0.0+</version>
+          <required>false</required>
+          <defaultValue>true</defaultValue>
+          <description>
+            Whether this proxy configuration is the active one. Note: While the type of this field
+            is {@code String} for technical reasons, the semantic type is actually {@code boolean}.
+            @see #isActive()
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>protocol</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The proxy protocol.
+            ]]>
+          </description>
+          <type>String</type>
+          <defaultValue>http</defaultValue>
+        </field>
+        <field>
+          <name>username</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The proxy user.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>password</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The proxy password.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field xml.tagName="port">
+          <name>portString</name>
+          <version>1.0.0+</version>
+          <description>
+            The proxy port. Note: While the type of this field is {@code String} for technical
+            reasons, the semantic type is actually {@code int}.
+            @see #getPort()
+          </description>
+          <type>String</type>
+          <defaultValue>8080</defaultValue>
+        </field>
+        <field>
+          <name>host</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The proxy host.
+            ]]>
+          </description>
+          <type>String</type>
+          <required>true</required>
+        </field>
+        <field>
+          <name>nonProxyHosts</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The list of non-proxied hosts (delimited by |).
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0/1.3.0</version>
+          <code>
+    public boolean isActive() {
+        return (getActiveString() != null) ? Boolean.parseBoolean(getActiveString()) : true;
+    }
+
+    public void setActive(boolean active) {
+        setActiveString(String.valueOf(active));
+    }
+
+    public int getPort() {
+        return (getPortString() != null) ? Integer.parseInt(getPortString()) : 8080;
+    }
+
+    public void setPort(int port) {
+        setPortString(String.valueOf(port));
+    }
+          </code>
+        </codeSegment>
+        <codeSegment>
+          <version>2.0.0+</version>
+          <code>
+    /**
+     * Indicates if this proxy is active.
+     * To allow interpolation of this field, this method lazily parses
+     * the {@link #getActiveString()} value as a boolean and defaults to {@code true}
+     * if not set.
+     *
+     * @return a boolean indicating if this proxy is active
+     */
+    public boolean isActive() {
+        return (getActiveString() != null) ? Boolean.parseBoolean(getActiveString()) : true;
+    }
+
+    /**
+     * Returns the port to use for this proxy.
+     * To allow interpolation of this field, this method lazily parses
+     * the {@link #getPortString()} value as an integer and defaults to {@code 8080}
+     * if not set.
+     *
+     * @return an integer indicating the port to use for this proxy
+     */
+    public int getPort() {
+        return (getPortString() != null) ? Integer.parseInt(getPortString()) : 8080;
+    }
+
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class>
+      <name>Server</name>
+      <version>1.0.0+</version>
+      <superClass>IdentifiableBase</superClass>
+      <description>
+        <![CDATA[
+        The <code>&lt;server&gt;</code> element contains informations required to a server settings.
+        ]]></description>
+      <fields>
+        <field>
+          <name>username</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The username used to authenticate.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>password</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The password used in conjunction with the username to authenticate.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>privateKey</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The private key location used to authenticate.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>passphrase</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The passphrase used in conjunction with the privateKey to authenticate.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>filePermissions</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The permissions for files when they are created.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>directoryPermissions</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The permissions for directories when they are created.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>configuration</name>
+          <type>DOM</type>
+          <description>
+            <![CDATA[
+            Extra configuration for the transport layer.
+            ]]>
+          </description>
+        </field>
+      </fields>
+    </class>
+    <class>
+      <name>Mirror</name>
+      <version>1.0.0+</version>
+      <superClass>IdentifiableBase</superClass>
+      <description>
+        A download mirror for a given repository.
+      </description>
+      <fields>
+        <field>
+          <name>mirrorOf</name>
+          <required>true</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The server ID of the repository being mirrored, e.g.,
+            "central". This MUST NOT match the mirror id.
+          </description>
+        </field>
+        <field>
+          <name>name</name>
+          <required>false</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The optional name that describes the mirror.
+          </description>
+        </field>
+        <field>
+          <name>url</name>
+          <required>true</required>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>The URL of the mirror repository.</description>
+        </field>
+        <field>
+          <name>layout</name>
+          <version>1.1.0+</version>
+          <type>String</type>
+          <defaultValue>default</defaultValue>
+          <description>The layout of the mirror repository. Since Maven 3.</description>
+        </field>
+        <field>
+          <name>mirrorOfLayouts</name>
+          <version>1.1.0+</version>
+          <type>String</type>
+          <defaultValue>default,legacy</defaultValue>
+          <description>
+            The layouts of repositories being mirrored. This value can be used to restrict the usage
+            of the mirror to repositories with a matching layout (apart from a matching id). Since Maven 3.
+          </description>
+        </field>
+        <field>
+          <name>blocked</name>
+          <version>1.2.0+</version>
+          <type>boolean</type>
+          <defaultValue>false</defaultValue>
+          <description>
+            Whether this mirror should be blocked from any download request but fail the download process, explaining why.
+          </description>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0+</version>
+          <code>
+            <![CDATA[
+
+    public String toString()
+    {
+        StringBuilder sb = new StringBuilder( 128 );
+        sb.append( "Mirror[" );
+        sb.append( "id=" ).append( this.getId() );
+        sb.append( ",mirrorOf=" ).append( this.getMirrorOf() );
+        sb.append( ",url=" ).append( this.getUrl() );
+        sb.append( ",name=" ).append( this.getName() );
+        if ( isBlocked() )
+        {
+            sb.append( ",blocked" );
+        }
+        sb.append( "]" );
+        return sb.toString();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <!-- Profile support -->
+    <class>
+      <name>Profile</name>
+      <version>1.0.0+</version>
+      <superClass>IdentifiableBase</superClass>
+      <description>
+        <![CDATA[
+        Modifications to the build process which is keyed on some
+        sort of environmental parameter.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>activation</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The conditional logic which will automatically
+            trigger the inclusion of this profile.
+            ]]>
+          </description>
+          <association>
+            <type>Activation</type>
+          </association>
+        </field>
+        <field>
+          <name>properties</name>
+          <description>
+            <![CDATA[
+            Extended configuration specific to this profile goes here.
+            Contents take the form of
+            <code>&lt;property.name&gt;property.value&lt;/property.name&gt;</code>
+            ]]>
+          </description>
+          <type>Properties</type>
+          <association xml.mapStyle="inline">
+            <type>String</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field xdoc.separator="blank">
+          <name>repositories</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The lists of the remote repositories.
+            ]]>
+          </description>
+          <association>
+            <type>Repository</type>
+            <multiplicity>*</multiplicity>
+          </association>
+        </field>
+        <field>
+          <name>pluginRepositories</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The lists of the remote repositories for discovering plugins.
+            ]]>
+          </description>
+          <association>
+            <type>Repository</type>
+            <multiplicity>*</multiplicity>
+          </association>
+          <comment>
+            <![CDATA[
+            This may be removed or relocated in the near
+            future. It is undecided whether plugins really need a remote
+            repository set of their own.
+            ]]>
+          </comment>
+        </field>
+      </fields>
+    </class>
+    <class java.clone="deep">
+      <name>Activation</name>
+      <version>1.0.0+</version>
+      <description>
+        <![CDATA[
+        The conditions within the build runtime environment which will trigger
+        the automatic inclusion of the parent build profile.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>activeByDefault</name>
+          <version>1.0.0+</version>
+          <type>boolean</type>
+          <description>
+            Flag specifying whether this profile is active as a default.
+          </description>
+        </field>
+        <field>
+          <name>jdk</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            Specifies that this profile will be activated when a matching JDK is detected.
+            ]]>
+          </description>
+        </field>
+        <field>
+          <name>os</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Specifies that this profile will be activated when matching OS attributes are detected.
+            ]]>
+          </description>
+          <association>
+            <type>ActivationOS</type>
+          </association>
+        </field>
+        <field>
+          <name>property</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Specifies that this profile will be activated when this property is specified.
+            ]]>
+          </description>
+          <association>
+            <type>ActivationProperty</type>
+          </association>
+        </field>
+        <field>
+          <name>file</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Specifies that this profile will be activated based on existence of a file.
+            ]]>
+          </description>
+          <association>
+            <type>ActivationFile</type>
+          </association>
+        </field>
+      </fields>
+    </class>
+
+    <!-- TODO: reproduced from maven-model/maven.mdo, instead should inherit code and link to external docs -->
+    <class java.clone="deep">
+      <name>RepositoryBase</name>
+      <version>1.0.0+</version>
+      <superClass>IdentifiableBase</superClass>
+      <description>
+        <![CDATA[
+        Repository contains the information needed
+        for establishing connections with remote repository
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            Human readable name of the repository.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>url</name>
+          <version>1.0.0+</version>
+          <description>
+            <![CDATA[
+            The url of the repository.
+            ]]>
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>layout</name>
+          <version>1.0.0+</version>
+          <description>
+            The type of layout this repository uses for locating and
+            storing artifacts - can be "legacy" or "default".
+          </description>
+          <type>String</type>
+          <defaultValue>default</defaultValue>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0/1.1.0</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    public boolean equals( Object obj )
+    {
+        RepositoryBase other =  (RepositoryBase) obj;
+        boolean retValue = false;
+        if ( this.getId() != null )
+        {
+            retValue = this.getId().equals( other.getId() );
+        }
+        return retValue;
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+
+    <class>
+      <name>Repository</name>
+      <superClass>RepositoryBase</superClass>
+      <version>1.0.0+</version>
+      <description>
+        Repository contains the information needed for establishing
+        connections with remote repository
+      </description>
+      <fields>
+        <field>
+          <name>releases</name>
+          <version>1.0.0+</version>
+          <description>
+            How to handle downloading of releases from this repository
+          </description>
+          <association>
+            <type>RepositoryPolicy</type>
+          </association>
+        </field>
+        <field>
+          <name>snapshots</name>
+          <version>1.0.0+</version>
+          <description>
+            How to handle downloading of snapshots from this repository
+          </description>
+          <association>
+            <type>RepositoryPolicy</type>
+          </association>
+        </field>
+      </fields>
+      <!-- prevent Modello generation of an incorrect equals method. Could be avoided by using <identity/> tags to mark ID as the only identity field -->
+      <codeSegments>
+        <codeSegment>
+          <version>1.0.0/1.1.0</version>
+          <code>
+            <![CDATA[
+    /**
+     * @see RepositoryBase#equals(java.lang.Object)
+     */
+    public boolean equals( Object obj )
+    {
+        return super.equals( obj );
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+
+    <class java.clone="deep">
+      <name>RepositoryPolicy</name>
+      <version>1.0.0+</version>
+      <description>Download policy</description>
+      <fields>
+        <field>
+          <name>enabled</name>
+          <version>1.0.0+</version>
+          <description>
+            Whether to use this repository for downloading this type of
+            artifact.
+          </description>
+          <type>boolean</type>
+          <defaultValue>true</defaultValue>
+        </field>
+        <field>
+          <name>updatePolicy</name>
+          <version>1.0.0+</version>
+          <description>
+            The frequency for downloading updates - can be "always",
+            "daily" (default), "interval:XXX" (in minutes) or "never"
+            (only if it doesn't exist locally).
+          </description>
+          <type>String</type>
+        </field>
+        <field>
+          <name>checksumPolicy</name>
+          <version>1.0.0+</version>
+          <description>
+            What to do when verification of an artifact checksum fails. Valid values are "fail" (default for Maven 4 and
+            above), "warn" (default for Maven 2 and 3) or "ignore".
+          </description>
+          <type>String</type>
+        </field>
+      </fields>
+    </class>
+
+    <class java.clone="deep">
+      <name>ActivationProperty</name>
+      <version>1.0.0+</version>
+      <description>
+        <![CDATA[
+        This is the property specification used to activate a profile. If the value field is empty,
+        then the existence of the named property will activate the profile, otherwise it does a case-sensitive
+        match against the property value as well.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <required>true</required>
+          <description>
+            The name of the property to be used to activate a profile.
+          </description>
+        </field>
+        <field>
+          <name>value</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The value of the property to be used to activate a profile.
+          </description>
+        </field>
+      </fields>
+    </class>
+    <class java.clone="deep">
+      <name>ActivationOS</name>
+      <version>1.0.0+</version>
+      <description>
+        <![CDATA[
+        This is an activator which will detect an operating system's attributes in order to activate
+        its profile.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>name</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The name of the OS to be used to activate a profile.
+          </description>
+        </field>
+        <field>
+          <name>family</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The general family of the OS to be used to activate a
+            profile (e.g. 'windows')
+          </description>
+        </field>
+        <field>
+          <name>arch</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The architecture of the OS to be used to activate a profile.
+          </description>
+        </field>
+        <field>
+          <name>version</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The version of the OS to be used to activate a profile.
+          </description>
+        </field>
+      </fields>
+    </class>
+    <class java.clone="deep">
+      <name>ActivationFile</name>
+      <version>1.0.0+</version>
+      <description>
+        <![CDATA[
+        This is the file specification used to activate a profile. The missing value will be a the location
+        of a file that needs to exist, and if it doesn't the profile must run.  On the other hand exists will test
+        for the existence of the file and if it is there will run the profile.
+        ]]>
+      </description>
+      <fields>
+        <field>
+          <name>missing</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The name of the file that should be missing to activate a
+            profile.
+          </description>
+        </field>
+        <field>
+          <name>exists</name>
+          <version>1.0.0+</version>
+          <type>String</type>
+          <description>
+            The name of the file that should exist to activate a profile.
+          </description>
+        </field>
+      </fields>
+    </class>
+    <!-- /BuildProfile support -->
+    <class locationTracker="locations">
+      <name>InputLocation</name>
+      <version>2.0.0+</version>
+      <fields>
+        <!-- line, column and source fields are auto-generated by Modello -->
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>2.0.0+</version>
+          <code>
+            <![CDATA[
+
+    @Override
+    public String toString() {
+        return getLineNumber() + " : " + getColumnNumber() + ", " + getSource();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+    <class sourceTracker="source">
+      <name>InputSource</name>
+      <version>2.0.0+</version>
+      <fields>
+        <field>
+          <name>location</name>
+          <version>2.0.0+</version>
+          <type>String</type>
+          <description>
+            <![CDATA[
+            The path/URL of the settings definition or {@code null} if unknown.
+            ]]>
+          </description>
+        </field>
+      </fields>
+      <codeSegments>
+        <codeSegment>
+          <version>2.0.0+</version>
+          <code>
+            <![CDATA[
+    @Override
+    public String toString() {
+        return getLocation();
+    }
+            ]]>
+          </code>
+        </codeSegment>
+      </codeSegments>
+    </class>
+  </classes>
+</model>
diff --git a/api/maven-api-settings/src/site/apt/index.apt b/api/maven-api-settings/src/site/apt/index.apt
new file mode 100644
index 0000000..ca71c0d
--- /dev/null
+++ b/api/maven-api-settings/src/site/apt/index.apt
@@ -0,0 +1,35 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ -----
+ Introduction
+ -----
+ Vincent Siveton
+ -----
+ 2006-11-04
+ -----
+
+Maven 4 API - Immutable Settings Model
+
+ This is strictly the immutable model for Maven settings in <<<org.apache.maven.api.settings>>> package.
+
+ The following are generated from this model:
+
+   * {{{./apidocs/index.html}Java sources}} with <<<Builder>>> inner classes for immutable instances creation.
+
+ See also corresponding {{{../../maven-settings/index.html}Maven classical settings model documentation}}.
+ 
\ No newline at end of file
diff --git a/api/maven-api-settings/src/site/site.xml b/api/maven-api-settings/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/maven-api-settings/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/api/maven-api-settings/src/test/java/org/apache/maven/api/settings/SettingsTest.java b/api/maven-api-settings/src/test/java/org/apache/maven/api/settings/SettingsTest.java
new file mode 100644
index 0000000..b786307
--- /dev/null
+++ b/api/maven-api-settings/src/test/java/org/apache/maven/api/settings/SettingsTest.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.settings;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class SettingsTest {
+
+    @Test
+    void testSetLocalRepository() {
+        Settings s = Settings.newInstance();
+
+        s = s.withLocalRepository("xxx");
+        assertEquals("xxx", s.getLocalRepository());
+
+        s = s.withLocalRepository("yyy");
+        assertEquals("yyy", s.getLocalRepository());
+
+        s = s.withLocalRepository(null);
+        assertNull(s.getLocalRepository());
+    }
+}
diff --git a/api/maven-api-spi/pom.xml b/api/maven-api-spi/pom.xml
new file mode 100644
index 0000000..01ba557
--- /dev/null
+++ b/api/maven-api-spi/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-spi</artifactId>
+  <name>Maven 4 API :: SPI</name>
+  <description>Maven 4 API - Maven SPI.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-meta</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-model</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-core</artifactId>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParser.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParser.java
new file mode 100644
index 0000000..68d8097
--- /dev/null
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParser.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.spi;
+
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.services.Source;
+
+/**
+ * The {@code ModelParser} interface is used to locate and read {@link Model}s from the file system.
+ * This allows plugging in additional syntaxes for the main model read by Maven when building a project.
+ */
+@Experimental
+public interface ModelParser {
+
+    /**
+     * Locates the pom in the given directory.
+     *
+     * @param dir the directory to locate the pom for, never {@code null}
+     * @return a {@code Source} pointing to the located pom or an empty {@code Optional} if none was found by this parser
+     */
+    @Nonnull
+    Optional<Source> locate(@Nonnull Path dir);
+
+    /**
+     * Parse the model obtained previously by a previous call to {@link #locate(Path)}.
+     *
+     * @param source the source to parse, never {@code null}
+     * @param options possible parsing options, may be {@code null}
+     * @return the parsed {@link Model}, never {@code null}
+     * @throws ModelParserException if the model cannot be parsed
+     */
+    @Nonnull
+    Model parse(@Nonnull Source source, @Nullable Map<String, ?> options) throws ModelParserException;
+
+    /**
+     * Locate and parse the model in the specified directory.
+     * This is equivalent to {@code locate(dir).map(s -> parse(s, options))}.
+     *
+     * @param dir the directory to locate the pom for, never {@code null}
+     * @param options possible parsing options, may be {@code null}
+     * @return an optional parsed {@link Model} or {@code null} if none could be found
+     * @throws ModelParserException if the located model cannot be parsed
+     */
+    default Optional<Model> locateAndParse(@Nonnull Path dir, @Nullable Map<String, ?> options)
+            throws ModelParserException {
+        return locate(dir).map(s -> parse(s, options));
+    }
+}
diff --git a/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParserException.java b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParserException.java
new file mode 100644
index 0000000..4520f06
--- /dev/null
+++ b/api/maven-api-spi/src/main/java/org/apache/maven/api/spi/ModelParserException.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.spi;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.services.MavenException;
+
+@Experimental
+public class ModelParserException extends MavenException {
+
+    /**
+     * The one-based index of the line containing the error.
+     */
+    private final int lineNumber;
+
+    /**
+     * The one-based index of the column containing the error.
+     */
+    private final int columnNumber;
+
+    public ModelParserException() {
+        this(null, null);
+    }
+
+    public ModelParserException(String message) {
+        this(message, null);
+    }
+
+    public ModelParserException(String message, Throwable cause) {
+        this(message, -1, -1, cause);
+    }
+
+    public ModelParserException(String message, int lineNumber, int columnNumber, Throwable cause) {
+        super(message, cause);
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+    }
+
+    public ModelParserException(Throwable cause) {
+        this(null, cause);
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public int getColumnNumber() {
+        return columnNumber;
+    }
+}
diff --git a/api/maven-api-toolchain/pom.xml b/api/maven-api-toolchain/pom.xml
new file mode 100644
index 0000000..f7d288f
--- /dev/null
+++ b/api/maven-api-toolchain/pom.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-toolchain</artifactId>
+
+  <name>Maven 4 API :: Toolchain</name>
+  <description>Maven 4 API - Immutable Toolchain model.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-xml</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.modello</groupId>
+        <artifactId>modello-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>velocity</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <configuration>
+              <version>1.2.0</version>
+              <velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
+              <models>
+                <model>src/main/mdo/toolchains.mdo</model>
+              </models>
+              <templates>
+                <template>model.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV4=org.apache.maven.api.toolchain</param>
+              </params>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/package-info.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/api/maven-api-toolchain/src/main/mdo/toolchains.mdo b/api/maven-api-toolchain/src/main/mdo/toolchains.mdo
new file mode 100644
index 0000000..322d750
--- /dev/null
+++ b/api/maven-api-toolchain/src/main/mdo/toolchains.mdo
@@ -0,0 +1,231 @@
+<?xml version="1.0"?>
+
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+
+-->
+<model xmlns="http://codehaus-plexus.github.io/MODELLO/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/1.0.0 http://codehaus-plexus.github.io/modello/xsd/modello-1.0.0.xsd"
+  xml.namespace="http://maven.apache.org/TOOLCHAINS/${version}"
+  xml.schemaLocation="http://maven.apache.org/xsd/toolchains-${version}.xsd">
+    <id>toolchains</id>
+    <name>MavenToolchains</name>
+    <description><![CDATA[
+    <p>This is a reference for the Maven Toolchains descriptor.</p>
+    <p>The default location for the toolchains file is <code>~/.m2/toolchains.xml</code></p>
+    <p>A Toolchain is a preconfigured object that Maven plugins can use for tool configuration retrieval (location and other information).</p>
+    <p>The <a href="/plugins/maven-toolchains-plugin/">toolchains-plugin</a> can read available toolchains on the user's computer
+    and match them against the toolchain requirements of the project (as configured in <code>pom.xml</code>):
+    if match is found, the toolchain instance is made available to other Maven plugins.</p>
+    <p>With <code>jdk</code> toolchain, for example, instead of being stuck with the JDK used to run Maven, all plugins can use
+    the same other JDK instance without hardcoding absolute paths into the <code>pom.xml</code>
+    and without configuring every plugin that require path to JDK tools.</p>
+    <p>See the <a href="/guides/mini/guide-using-toolchains.html">Guide to Using Toolchains</a> for
+    more information.</p>
+    ]]></description>
+
+    <defaults>
+        <default>
+            <key>package</key>
+            <value>org.apache.maven.toolchain.model</value>
+        </default>
+    </defaults>
+
+    <classes>
+    <class java.clone="deep">
+          <name>TrackableBase</name>
+          <version>1.1.0+</version>
+          <description>
+            common base class that contains code to track the source for
+            this instance (USER|GLOBAL)
+          </description>
+          <codeSegments>
+            <codeSegment>
+              <version>1.1.0+</version>
+              <code>
+                <![CDATA[
+        public static final String USER_LEVEL = "user-level";
+        public static final String GLOBAL_LEVEL = "global-level";
+
+        private String sourceLevel = USER_LEVEL;
+        private boolean sourceLevelSet = false;
+
+        public void setSourceLevel( String sourceLevel )
+        {
+            if ( sourceLevelSet )
+            {
+                throw new IllegalStateException( "Cannot reset sourceLevel attribute; it is already set to: " + sourceLevel );
+            }
+            else if ( !( USER_LEVEL.equals( sourceLevel ) || GLOBAL_LEVEL.equals( sourceLevel ) ) )
+            {
+                throw new IllegalArgumentException( "sourceLevel must be one of: {" + USER_LEVEL + "," + GLOBAL_LEVEL + "}" );
+            }
+            else
+            {
+                this.sourceLevel = sourceLevel;
+                this.sourceLevelSet = true;
+            }
+        }
+
+        public String getSourceLevel()
+        {
+            return sourceLevel;
+        }
+                ]]>
+              </code>
+            </codeSegment>
+          </codeSegments>
+        </class>
+        <class rootElement="true" xml.tagName="toolchains" xsd.compositor="sequence">
+            <name>PersistedToolchains</name>
+            <superClass>TrackableBase</superClass>
+            <description><![CDATA[
+         The <code>&lt;toolchains&gt;</code> element is the root of the descriptor.
+         The following table lists all of the possible child elements.
+            ]]></description>
+            <version>1.0.0+</version>
+            <fields>
+                <field>
+                    <name>toolchains</name>
+                    <version>1.0.0+</version>
+                    <description><![CDATA[The toolchain instance definition.]]></description>
+                    <association xml.itemsStyle="flat">
+                        <type>ToolchainModel</type>
+                        <multiplicity>*</multiplicity>
+                    </association>
+                </field>
+            </fields>
+        </class>
+        <class>
+            <name>ToolchainModel</name>
+            <superClass>TrackableBase</superClass>
+            <version>1.0.0+</version>
+            <description>Definition of a toolchain instance.</description>
+            <fields>
+                <field>
+                    <name>type</name>
+                    <version>1.0.0+</version>
+                    <!-- <identifier>true</identifier> -->
+                    <description>
+                    <![CDATA[Type of toolchain:<ul>
+                    <li><code>jdk</code> for
+                    <a href="https://maven.apache.org/plugins/maven-toolchains-plugin/toolchains/jdk.html">JDK Standard Toolchain</a>,</li>
+                    <li>other value for
+                    <a href="https://maven.apache.org/plugins/maven-toolchains-plugin/toolchains/custom.html">Custom Toolchain</a></li>
+                    </ul>
+                    ]]></description>
+                    <type>String</type>
+                </field>
+                <field>
+                    <name>provides</name>
+                    <version>1.0.0/1.0.99</version> <!-- fake upperbound, it's inclusive -->
+                    <type>DOM</type> <!-- DOM for Maven 2.0.9/2.3.3 -->
+                    <description>
+                    <![CDATA[
+                    <p>Toolchain identification information, which will be matched against project requirements.</p>
+                    <p>Actual content structure is completely open: each toolchain type will define its own format and semantics.</p>
+                    <p>In general, this is a properties format: <code>&lt;name&gt;value&lt;/name&gt;</code> with
+                    predefined properties names.</p>
+                    ]]></description>
+                </field>
+                <field>
+                    <name>provides</name>
+                    <version>1.1.0+</version>
+                    <type>Properties</type> <!-- Properties for Maven 2.3.4+ -->
+                    <association xml.mapStyle="inline">
+                      <type>String</type>
+                      <multiplicity>*</multiplicity>
+                    </association>
+                    <!-- <identifier>true</identifier> -->
+                    <description>
+                    <![CDATA[
+                    <p>Toolchain identification information, which will be matched against project requirements.</p>
+                    <p>For Maven 2.0.9 to 3.2.3, the actual content structure was completely open: each toolchain type would define its own format and semantics.
+                    In general, this was a properties format.</p>
+                    <p>Since Maven 3.2.4, the type for this field has been changed to Properties to match the de-facto format.</p>
+                    <p>Each toolchain defines its own properties names and semantics.</p>
+                    ]]></description>
+                </field>
+                <field>
+                    <name>configuration</name>
+                    <version>1.0.0+</version>
+                    <type>DOM</type>
+                    <description>
+                    <![CDATA[
+                    <p>Toolchain configuration information, like location or any information that is to be retrieved.</p>
+                    <p>Actual content structure is completely open: each toolchain type will define its own format and semantics.</p>
+                    <p>In general, this is a properties format: <code>&lt;name&gt;value&lt;/name&gt;</code> with
+                    per-toolchain defined properties names.</p>
+                    ]]></description>
+                </field>
+            </fields>
+            <codeSegments>
+            <codeSegment>
+              <version>1.2.0+</version>
+              <comment>Generated hashCode() and equals() based on identifier also calls its super, which breaks comparison</comment>
+              <code>
+                <![CDATA[
+    /**
+     * Method hashCode.
+     *
+     * @return int
+     */
+    public int hashCode()
+    {
+        int result = 17;
+
+        result = 37 * result + ( getType() != null ? getType().hashCode() : 0 );
+        result = 37 * result + ( getProvides() != null ? getProvides().hashCode() : 0 );
+
+        return result;
+    } //-- int hashCode()
+
+    /**
+     * Method equals.
+     *
+     * @param other
+     * @return boolean
+     */
+    public boolean equals( Object other )
+    {
+        if ( this == other )
+        {
+            return true;
+        }
+
+        if ( !( other instanceof ToolchainModel ) )
+        {
+            return false;
+        }
+
+        ToolchainModel that = (ToolchainModel) other;
+        boolean result = true;
+
+        result = result && ( getType() == null ? that.getType() == null : getType().equals( that.getType() ) );
+        result = result && ( getProvides() == null ? that.getProvides() == null : getProvides().equals( that.getProvides() ) );
+
+        return result;
+    } //-- boolean equals( Object )
+                ]]>
+              </code>
+            </codeSegment>
+          </codeSegments>
+        </class>
+    </classes>
+</model>
+
diff --git a/api/maven-api-toolchain/src/site/apt/index.apt b/api/maven-api-toolchain/src/site/apt/index.apt
new file mode 100644
index 0000000..689b044
--- /dev/null
+++ b/api/maven-api-toolchain/src/site/apt/index.apt
@@ -0,0 +1,35 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ -----
+ Introduction
+ -----
+ Vincent Siveton
+ -----
+ 2006-11-04
+ -----
+
+Maven 4 API - Immutable Toolchains Model
+
+ This is strictly the immutable model for Maven toolchains in <<<org.apache.maven.api.toolchain>>> package.
+
+ The following are generated from this model:
+
+   * {{{./apidocs/index.html}Java sources}} with <<<Builder>>> inner classes for immutable instances creation.
+
+ See also corresponding {{{../../maven-toolchain-model/index.html}Maven classical toolchains model documentation}}.
+ 
\ No newline at end of file
diff --git a/api/maven-api-toolchain/src/site/site.xml b/api/maven-api-toolchain/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/maven-api-toolchain/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/api/maven-api-xml/pom.xml b/api/maven-api-xml/pom.xml
new file mode 100644
index 0000000..f950d49
--- /dev/null
+++ b/api/maven-api-xml/pom.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven-api</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api-xml</artifactId>
+  <name>Maven 4 API :: XML</name>
+  <description>Maven 4 API - Immutable XML.</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-meta</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java
new file mode 100644
index 0000000..87ad7ae
--- /dev/null
+++ b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.api.xml;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Immutable;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.annotations.ThreadSafe;
+
+/**
+ * An immutable xml node.
+ *
+ * @since 4.0.0
+ */
+@Experimental
+@ThreadSafe
+@Immutable
+public interface XmlNode {
+
+    String CHILDREN_COMBINATION_MODE_ATTRIBUTE = "combine.children";
+
+    String CHILDREN_COMBINATION_MERGE = "merge";
+
+    String CHILDREN_COMBINATION_APPEND = "append";
+
+    /**
+     * This default mode for combining children DOMs during merge means that where element names match, the process will
+     * try to merge the element data, rather than putting the dominant and recessive elements (which share the same
+     * element name) as siblings in the resulting DOM.
+     */
+    String DEFAULT_CHILDREN_COMBINATION_MODE = CHILDREN_COMBINATION_MERGE;
+
+    String SELF_COMBINATION_MODE_ATTRIBUTE = "combine.self";
+
+    String SELF_COMBINATION_OVERRIDE = "override";
+
+    String SELF_COMBINATION_MERGE = "merge";
+
+    String SELF_COMBINATION_REMOVE = "remove";
+
+    /**
+     * In case of complex XML structures, combining can be done based on id.
+     */
+    String ID_COMBINATION_MODE_ATTRIBUTE = "combine.id";
+
+    /**
+     * In case of complex XML structures, combining can be done based on keys.
+     * This is a comma separated list of attribute names.
+     */
+    String KEYS_COMBINATION_MODE_ATTRIBUTE = "combine.keys";
+
+    /**
+     * This default mode for combining a DOM node during merge means that where element names match, the process will
+     * try to merge the element attributes and values, rather than overriding the recessive element completely with the
+     * dominant one. This means that wherever the dominant element doesn't provide the value or a particular attribute,
+     * that value or attribute will be set from the recessive DOM node.
+     */
+    String DEFAULT_SELF_COMBINATION_MODE = SELF_COMBINATION_MERGE;
+
+    @Nonnull
+    String getName();
+
+    @Nonnull
+    String getNamespaceUri();
+
+    @Nonnull
+    String getPrefix();
+
+    @Nullable
+    String getValue();
+
+    @Nonnull
+    Map<String, String> getAttributes();
+
+    @Nullable
+    String getAttribute(@Nonnull String name);
+
+    @Nonnull
+    List<XmlNode> getChildren();
+
+    @Nullable
+    XmlNode getChild(String name);
+
+    @Nullable
+    Object getInputLocation();
+
+    default XmlNode merge(@Nullable XmlNode source) {
+        return merge(source, (Boolean) null);
+    }
+
+    XmlNode merge(@Nullable XmlNode source, @Nullable Boolean childMergeOverride);
+
+    /**
+     * Merge recessive into dominant and return either {@code dominant}
+     * with merged information or a clone of {@code recessive} if
+     * {@code dominant} is {@code null}.
+     *
+     * @param dominant the node
+     * @param recessive if {@code null}, nothing will happen
+     * @return the merged node
+     */
+    @Nullable
+    static XmlNode merge(@Nullable XmlNode dominant, @Nullable XmlNode recessive) {
+        return merge(dominant, recessive, null);
+    }
+
+    @Nullable
+    static XmlNode merge(
+            @Nullable XmlNode dominant, @Nullable XmlNode recessive, @Nullable Boolean childMergeOverride) {
+        if (recessive == null) {
+            return dominant;
+        }
+        if (dominant == null) {
+            return recessive;
+        }
+        return dominant.merge(recessive, childMergeOverride);
+    }
+}
diff --git a/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/package-info.java b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/package-info.java
new file mode 100644
index 0000000..db25d3a
--- /dev/null
+++ b/api/maven-api-xml/src/main/java/org/apache/maven/api/xml/package-info.java
@@ -0,0 +1,5 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/**
+ * Maven immutable XML api.
+ */
+package org.apache.maven.api.xml;
diff --git a/api/maven-api-xml/src/site/site.xml b/api/maven-api-xml/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/maven-api-xml/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/api/pom.xml b/api/pom.xml
new file mode 100644
index 0000000..16116d4
--- /dev/null
+++ b/api/pom.xml
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-api</artifactId>
+  <packaging>pom</packaging>
+  <name>Maven 4 API</name>
+  <description>A new immutable API for Maven 4 to better manage what plugins and extensions can influence.</description>
+
+  <modules>
+    <module>maven-api-meta</module>
+    <module>maven-api-xml</module>
+    <module>maven-api-model</module>
+    <module>maven-api-plugin</module>
+    <module>maven-api-settings</module>
+    <module>maven-api-toolchain</module>
+    <module>maven-api-core</module>
+    <module>maven-api-spi</module>
+  </modules>
+
+  <properties>
+    <project.directory>api</project.directory>
+  </properties>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.codehaus.modello</groupId>
+          <artifactId>modello-maven-plugin</artifactId>
+          <executions>
+            <execution>
+              <id>modello-site-docs</id>
+              <goals>
+                <goal>xdoc</goal>
+                <goal>xsd</goal>
+              </goals>
+              <phase>none</phase>
+            </execution>
+          </executions>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>reporting</id>
+      <reporting>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <configuration>
+              <tags>
+                <tag>
+                  <name>provisional</name>
+                  <placement>tf</placement>
+                  <head>Provisional:</head>
+                </tag>
+              </tags>
+            </configuration>
+            <reportSets>
+              <reportSet>
+                <id>aggregate</id>
+                <reports>
+                  <report>aggregate</report>
+                </reports>
+                <inherited>false</inherited>
+              </reportSet>
+            </reportSets>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-jxr-plugin</artifactId>
+            <reportSets>
+              <reportSet>
+                <id>aggregate</id>
+                <reports>
+                  <report>aggregate</report>
+                </reports>
+                <inherited>false</inherited>
+              </reportSet>
+            </reportSets>
+          </plugin>
+        </plugins>
+      </reporting>
+    </profile>
+  </profiles>
+
+</project>
diff --git a/api/src/site/site.xml b/api/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/api/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/build/checkstyle-suppressions.xml b/build/checkstyle-suppressions.xml
index 78e9e3c..4570299 100644
--- a/build/checkstyle-suppressions.xml
+++ b/build/checkstyle-suppressions.xml
@@ -26,5 +26,4 @@
 <suppressions>
     <suppress checks="JavadocVariable|JavadocMethod" files=".*" />
     <suppress checks="HiddenField" files=".*" />
-    <suppress checks="FileLength" files="ModelMerger\.java" />
 </suppressions>
diff --git a/doap_Maven.rdf b/doap_Maven.rdf
index f157b2f..5eb94be 100644
--- a/doap_Maven.rdf
+++ b/doap_Maven.rdf
@@ -32,7 +32,161 @@
     <category rdf:resource="http://projects.apache.org/category/build-management"/>
     <release>
       <Version>
+        <name>Apache Maven 4.0.0-alpha-7</name>
+        <created>2023-06-28</created>
+        <revision>4.0.0-alpha-7</revision>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-7/binaries/apache-maven-4.0.0-alpha-7-bin.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-7/binaries/apache-maven-4.0.0-alpha-7-bin.tar.gz</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-7/source/apache-maven-4.0.0-alpha-7-src.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-7/source/apache-maven-4.0.0-alpha-7-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 4.0.0-alpha-5</name>
+        <created>2023-03-20</created>
+        <revision>4.0.0-alpha-5</revision>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-5/binaries/apache-maven-4.0.0-alpha-5-bin.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-5/binaries/apache-maven-4.0.0-alpha-5-bin.tar.gz</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-5/source/apache-maven-4.0.0-alpha-5-src.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-5/source/apache-maven-4.0.0-alpha-5-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 4.0.0-alpha-4</name>
+        <created>2023-01-31</created>
+        <revision>4.0.0-alpha-4</revision>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-4/binaries/apache-maven-4.0.0-alpha-4-bin.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-4/binaries/apache-maven-4.0.0-alpha-4-bin.tar.gz</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-4/source/apache-maven-4.0.0-alpha-4-src.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-4/source/apache-maven-4.0.0-alpha-4-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 4.0.0-alpha-3</name>
+        <created>2022-12-15</created>
+        <revision>4.0.0-alpha-3</revision>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-3/binaries/apache-maven-4.0.0-alpha-3-bin.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-3/binaries/apache-maven-4.0.0-alpha-3-bin.tar.gz</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-3/source/apache-maven-4.0.0-alpha-3-src.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-3/source/apache-maven-4.0.0-alpha-3-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 4.0.0-alpha-2</name>
+        <created>2022-10-15</created>
+        <revision>4.0.0-alpha-2</revision>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-2/binaries/apache-maven-4.0.0-alpha-2-bin.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-2/binaries/apache-maven-4.0.0-alpha-2-bin.tar.gz</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-2/source/apache-maven-4.0.0-alpha-2-src.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-4/4.0.0-alpha-2/source/apache-maven-4.0.0-alpha-2-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
         <name>Latest stable release</name>
+        <created>2023-12-01</created>
+        <revision>3.9.6</revision>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.6/source/apache-maven-3.9.6-src.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.6/source/apache-maven-3.9.6-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.9.5</name>
+        <created>2023-10-04</created>
+        <revision>3.9.5</revision>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.5/binaries/apache-maven-3.9.5-bin.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.5/binaries/apache-maven-3.9.5-bin.tar.gz</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.5/source/apache-maven-3.9.5-src.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.5/source/apache-maven-3.9.5-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.9.4</name>
+        <created>2023-08-03</created>
+        <revision>3.9.4</revision>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.4/binaries/apache-maven-3.9.4-bin.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.4/binaries/apache-maven-3.9.4-bin.tar.gz</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.4/source/apache-maven-3.9.4-src.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.4/source/apache-maven-3.9.4-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.9.3</name>
+        <created>2023-06-26</created>
+        <revision>3.9.3</revision>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.3/binaries/apache-maven-3.9.3-bin.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.3/binaries/apache-maven-3.9.3-bin.tar.gz</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.3/source/apache-maven-3.9.3-src.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.3/source/apache-maven-3.9.3-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.9.2</name>
+        <created>2023-05-11</created>
+        <revision>3.9.2</revision>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.2/binaries/apache-maven-3.9.2-bin.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.2/binaries/apache-maven-3.9.2-bin.tar.gz</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.2/source/apache-maven-3.9.2-src.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.2/source/apache-maven-3.9.2-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.9.1</name>
+        <created>2023-03-15</created>
+        <revision>3.9.1</revision>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.1/binaries/apache-maven-3.9.1-bin.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.1/binaries/apache-maven-3.9.1-bin.tar.gz</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.1/source/apache-maven-3.9.1-src.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.1/source/apache-maven-3.9.1-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.9.0</name>
+        <created>2023-01-31</created>
+        <revision>3.9.0</revision>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.0/binaries/apache-maven-3.9.0-bin.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.0/binaries/apache-maven-3.9.0-bin.tar.gz</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.0/source/apache-maven-3.9.0-src.zip</file-release>
+        <file-release>https://archive.apache.org/dist/maven/maven-3/3.9.0/source/apache-maven-3.9.0-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.8.8</name>
+        <created>2023-03-08</created>
+        <revision>3.8.8</revision>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.8/binaries/apache-maven-3.8.8-bin.tar.gz</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.8/source/apache-maven-3.8.8-src.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.8/source/apache-maven-3.8.8-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.8.7</name>
+        <created>2022-12-24</created>
+        <revision>3.8.7</revision>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.7/binaries/apache-maven-3.8.7-bin.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.7/binaries/apache-maven-3.8.7-bin.tar.gz</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.7/source/apache-maven-3.8.7-src.zip</file-release>
+        <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.7/source/apache-maven-3.8.7-src.tar.gz</file-release>
+      </Version>
+    </release>
+    <release>
+      <Version>
+        <name>Apache Maven 3.8.6</name>
         <created>2022-06-06</created>
         <revision>3.8.6</revision>
         <file-release>http://archive.apache.org/dist/maven/maven-3/3.8.6/binaries/apache-maven-3.8.6-bin.zip</file-release>
diff --git a/maven-artifact/pom.xml b/maven-artifact/pom.xml
index f47867b..e5af4d5 100644
--- a/maven-artifact/pom.xml
+++ b/maven-artifact/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,31 +17,19 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-artifact</artifactId>
 
   <name>Maven Artifact</name>
 
-  <dependencies>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-lang3</artifactId>
-    </dependency>
-  </dependencies>
-
   <build>
     <plugins>
       <plugin>
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java
index 377935d..df98a1a 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/Artifact.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import java.io.File;
 import java.util.Collection;
@@ -36,9 +35,7 @@
  * Maven Artifact interface. Notice that it mixes artifact definition concepts (groupId, artifactId, version)
  * with dependency information (version range, scope).
  */
-public interface Artifact
-    extends Comparable<Artifact>
-{
+public interface Artifact extends Comparable<Artifact> {
 
     String RELEASE_VERSION = "RELEASE";
 
@@ -46,7 +43,7 @@
 
     String SNAPSHOT_VERSION = "SNAPSHOT";
 
-    Pattern VERSION_FILE_PATTERN = Pattern.compile( "^(.*)-([0-9]{8}\\.[0-9]{6})-([0-9]+)$" );
+    Pattern VERSION_FILE_PATTERN = Pattern.compile("^(.*)-(\\d{8}\\.\\d{6})-(\\d+)$");
 
     // TODO into artifactScope handler
 
@@ -64,7 +61,7 @@
 
     String SCOPE_SYSTEM = "system";
 
-    String SCOPE_IMPORT = "import";   // Used to import dependencyManagement dependencies
+    String SCOPE_IMPORT = "import"; // Used to import dependencyManagement dependencies
 
     String getGroupId();
 
@@ -72,7 +69,7 @@
 
     String getVersion();
 
-    void setVersion( String version );
+    void setVersion(String version);
 
     String getScope();
 
@@ -84,78 +81,75 @@
 
     File getFile();
 
-    void setFile( File destination );
+    void setFile(File destination);
 
     String getBaseVersion();
 
-    void setBaseVersion( String baseVersion );
+    void setBaseVersion(String baseVersion);
 
     String getId();
 
     String getDependencyConflictId();
 
-    void addMetadata( ArtifactMetadata metadata );
+    void addMetadata(ArtifactMetadata metadata);
 
     Collection<ArtifactMetadata> getMetadataList();
 
-    void setRepository( ArtifactRepository remoteRepository );
+    void setRepository(ArtifactRepository remoteRepository);
 
     ArtifactRepository getRepository();
 
-    void updateVersion( String version, ArtifactRepository localRepository );
+    void updateVersion(String version, ArtifactRepository localRepository);
 
     String getDownloadUrl();
 
-    void setDownloadUrl( String downloadUrl );
+    void setDownloadUrl(String downloadUrl);
 
     ArtifactFilter getDependencyFilter();
 
-    void setDependencyFilter( ArtifactFilter artifactFilter );
+    void setDependencyFilter(ArtifactFilter artifactFilter);
 
     ArtifactHandler getArtifactHandler();
 
     List<String> getDependencyTrail();
 
-    void setDependencyTrail( List<String> dependencyTrail );
+    void setDependencyTrail(List<String> dependencyTrail);
 
-    void setScope( String scope );
+    void setScope(String scope);
 
     VersionRange getVersionRange();
 
-    void setVersionRange( VersionRange newRange );
+    void setVersionRange(VersionRange newRange);
 
-    void selectVersion( String version );
+    void selectVersion(String version);
 
-    void setGroupId( String groupId );
+    void setGroupId(String groupId);
 
-    void setArtifactId( String artifactId );
+    void setArtifactId(String artifactId);
 
     boolean isSnapshot();
 
-    void setResolved( boolean resolved );
+    void setResolved(boolean resolved);
 
     boolean isResolved();
 
-    void setResolvedVersion( String version );
+    void setResolvedVersion(String version);
 
-    void setArtifactHandler( ArtifactHandler handler );
+    void setArtifactHandler(ArtifactHandler handler);
 
     boolean isRelease();
 
-    void setRelease( boolean release );
+    void setRelease(boolean release);
 
     List<ArtifactVersion> getAvailableVersions();
 
-    void setAvailableVersions( List<ArtifactVersion> versions );
+    void setAvailableVersions(List<ArtifactVersion> versions);
 
     boolean isOptional();
 
-    void setOptional( boolean optional );
+    void setOptional(boolean optional);
 
-    ArtifactVersion getSelectedVersion()
-        throws OverConstrainedVersionException;
+    ArtifactVersion getSelectedVersion() throws OverConstrainedVersionException;
 
-    boolean isSelectedVersionKnown()
-        throws OverConstrainedVersionException;
-
+    boolean isSelectedVersionKnown() throws OverConstrainedVersionException;
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/ArtifactUtils.java b/maven-artifact/src/main/java/org/apache/maven/artifact/ArtifactUtils.java
index 8007321..8ea6710 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/ArtifactUtils.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/ArtifactUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -26,110 +25,97 @@
 import java.util.Map;
 import java.util.regex.Matcher;
 
-import org.apache.commons.lang3.Validate;
 import org.apache.maven.artifact.versioning.VersionRange;
 
 /**
  * ArtifactUtils
  */
-public final class ArtifactUtils
-{
+public final class ArtifactUtils {
 
-    public static boolean isSnapshot( String version )
-    {
-        if ( version != null )
-        {
-            if ( version.regionMatches( true, version.length() - Artifact.SNAPSHOT_VERSION.length(),
-                                        Artifact.SNAPSHOT_VERSION, 0, Artifact.SNAPSHOT_VERSION.length() ) )
-            {
+    public static boolean isSnapshot(String version) {
+        if (version != null) {
+            if (version.regionMatches(
+                    true,
+                    version.length() - Artifact.SNAPSHOT_VERSION.length(),
+                    Artifact.SNAPSHOT_VERSION,
+                    0,
+                    Artifact.SNAPSHOT_VERSION.length())) {
                 return true;
-            }
-            else
-            {
-                return Artifact.VERSION_FILE_PATTERN.matcher( version ).matches();
+            } else {
+                return Artifact.VERSION_FILE_PATTERN.matcher(version).matches();
             }
         }
         return false;
     }
 
-    public static String toSnapshotVersion( String version )
-    {
-        notBlank( version, "version can neither be null, empty nor blank" );
+    public static String toSnapshotVersion(String version) {
+        notBlank(version, "version can neither be null, empty nor blank");
 
-        int lastHyphen = version.lastIndexOf( '-' );
-        if ( lastHyphen > 0 )
-        {
-            int prevHyphen = version.lastIndexOf( '-', lastHyphen - 1 );
-            if ( prevHyphen > 0 )
-            {
-                Matcher m = Artifact.VERSION_FILE_PATTERN.matcher( version );
-                if ( m.matches() )
-                {
-                    return m.group( 1 ) + "-" + Artifact.SNAPSHOT_VERSION;
+        int lastHyphen = version.lastIndexOf('-');
+        if (lastHyphen > 0) {
+            int prevHyphen = version.lastIndexOf('-', lastHyphen - 1);
+            if (prevHyphen > 0) {
+                Matcher m = Artifact.VERSION_FILE_PATTERN.matcher(version);
+                if (m.matches()) {
+                    return m.group(1) + "-" + Artifact.SNAPSHOT_VERSION;
                 }
             }
         }
         return version;
     }
 
-    public static String versionlessKey( Artifact artifact )
-    {
-        return versionlessKey( artifact.getGroupId(), artifact.getArtifactId() );
+    public static String versionlessKey(Artifact artifact) {
+        return versionlessKey(artifact.getGroupId(), artifact.getArtifactId());
     }
 
-    public static String versionlessKey( String groupId, String artifactId )
-    {
-        notBlank( groupId, "groupId can neither be null, empty nor blank" );
-        notBlank( artifactId, "artifactId can neither be null, empty nor blank" );
+    public static String versionlessKey(String groupId, String artifactId) {
+        notBlank(groupId, "groupId can neither be null, empty nor blank");
+        notBlank(artifactId, "artifactId can neither be null, empty nor blank");
 
         return groupId + ":" + artifactId;
     }
 
-    public static String key( Artifact artifact )
-    {
-        return key( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
+    public static String key(Artifact artifact) {
+        return key(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion());
     }
 
-    public static String key( String groupId, String artifactId, String version )
-    {
-        notBlank( groupId, "groupId can neither be null, empty nor blank" );
-        notBlank( artifactId, "artifactId can neither be null, empty nor blank" );
-        notBlank( version, "version can neither be null, empty nor blank" );
+    public static String key(String groupId, String artifactId, String version) {
+        notBlank(groupId, "groupId can neither be null, empty nor blank");
+        notBlank(artifactId, "artifactId can neither be null, empty nor blank");
+        notBlank(version, "version can neither be null, empty nor blank");
 
         return groupId + ":" + artifactId + ":" + version;
     }
 
-    private static void notBlank( String str, String message )
-    {
-        int c = str != null && str.length() > 0 ? str.charAt( 0 ) : 0;
-        if ( ( c < '0' || c > '9' ) && ( c < 'a' || c > 'z' ) )
-        {
-            Validate.notBlank( str, message );
+    private static void notBlank(String str, String message) {
+        final int strLen = str != null ? str.length() : 0;
+        if (strLen > 0) {
+            for (int i = 0; i < strLen; i++) {
+                if (!Character.isWhitespace(str.charAt(i))) {
+                    return;
+                }
+            }
         }
+        throw new IllegalArgumentException(message);
     }
 
-    public static Map<String, Artifact> artifactMapByVersionlessId( Collection<Artifact> artifacts )
-    {
+    public static Map<String, Artifact> artifactMapByVersionlessId(Collection<Artifact> artifacts) {
         Map<String, Artifact> artifactMap = new LinkedHashMap<>();
 
-        if ( artifacts != null )
-        {
-            for ( Artifact artifact : artifacts )
-            {
-                artifactMap.put( versionlessKey( artifact ), artifact );
+        if (artifacts != null) {
+            for (Artifact artifact : artifacts) {
+                artifactMap.put(versionlessKey(artifact), artifact);
             }
         }
 
         return artifactMap;
     }
 
-    public static Artifact copyArtifactSafe( Artifact artifact )
-    {
-        return ( artifact != null ) ? copyArtifact( artifact ) : null;
+    public static Artifact copyArtifactSafe(Artifact artifact) {
+        return (artifact != null) ? copyArtifact(artifact) : null;
     }
 
-    public static Artifact copyArtifact( Artifact artifact )
-    {
+    public static Artifact copyArtifact(Artifact artifact) {
         VersionRange range = artifact.getVersionRange();
 
         // For some reason with the introduction of MNG-1577 we have the case in Yoko where a depMan section has
@@ -147,28 +133,32 @@
         //
         // And the range is not set so we'll check here and set it. jvz.
 
-        if ( range == null )
-        {
-            range = VersionRange.createFromVersion( artifact.getVersion() );
+        if (range == null) {
+            range = VersionRange.createFromVersion(artifact.getVersion());
         }
 
-        DefaultArtifact clone = new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(), range,
-            artifact.getScope(), artifact.getType(), artifact.getClassifier(),
-            artifact.getArtifactHandler(), artifact.isOptional() );
-        clone.setRelease( artifact.isRelease() );
-        clone.setResolvedVersion( artifact.getVersion() );
-        clone.setResolved( artifact.isResolved() );
-        clone.setFile( artifact.getFile() );
+        DefaultArtifact clone = new DefaultArtifact(
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                range,
+                artifact.getScope(),
+                artifact.getType(),
+                artifact.getClassifier(),
+                artifact.getArtifactHandler(),
+                artifact.isOptional());
+        clone.setRelease(artifact.isRelease());
+        clone.setResolvedVersion(artifact.getVersion());
+        clone.setResolved(artifact.isResolved());
+        clone.setFile(artifact.getFile());
 
-        clone.setAvailableVersions( copyList( artifact.getAvailableVersions() ) );
-        if ( artifact.getVersion() != null )
-        {
-            clone.setBaseVersion( artifact.getBaseVersion() );
+        clone.setAvailableVersions(copyList(artifact.getAvailableVersions()));
+        if (artifact.getVersion() != null) {
+            clone.setBaseVersion(artifact.getBaseVersion());
         }
-        clone.setDependencyFilter( artifact.getDependencyFilter() );
-        clone.setDependencyTrail( copyList( artifact.getDependencyTrail() ) );
-        clone.setDownloadUrl( artifact.getDownloadUrl() );
-        clone.setRepository( artifact.getRepository() );
+        clone.setDependencyFilter(artifact.getDependencyFilter());
+        clone.setDependencyTrail(copyList(artifact.getDependencyTrail()));
+        clone.setDownloadUrl(artifact.getDownloadUrl());
+        clone.setRepository(artifact.getRepository());
 
         return clone;
     }
@@ -181,43 +171,34 @@
      * @param to the target artifact collection
      * @return <code>to</code> collection
      */
-    public static <T extends Collection<Artifact>> T copyArtifacts( Collection<Artifact> from, T to )
-    {
-        for ( Artifact artifact : from )
-        {
-            to.add( ArtifactUtils.copyArtifact( artifact ) );
+    public static <T extends Collection<Artifact>> T copyArtifacts(Collection<Artifact> from, T to) {
+        for (Artifact artifact : from) {
+            to.add(ArtifactUtils.copyArtifact(artifact));
         }
         return to;
     }
 
-    public static <K, T extends Map<K, Artifact>> T copyArtifacts( Map<K, ? extends Artifact> from, T to )
-    {
-        if ( from != null )
-        {
-            for ( Map.Entry<K, ? extends Artifact> entry : from.entrySet() )
-            {
-                to.put( entry.getKey(), ArtifactUtils.copyArtifact( entry.getValue() ) );
+    public static <K, T extends Map<K, Artifact>> T copyArtifacts(Map<K, ? extends Artifact> from, T to) {
+        if (from != null) {
+            for (Map.Entry<K, ? extends Artifact> entry : from.entrySet()) {
+                to.put(entry.getKey(), ArtifactUtils.copyArtifact(entry.getValue()));
             }
         }
 
         return to;
     }
 
-    private static <T> List<T> copyList( List<T> original )
-    {
+    private static <T> List<T> copyList(List<T> original) {
         List<T> copy = null;
 
-        if ( original != null )
-        {
+        if (original != null) {
             copy = new ArrayList<>();
 
-            if ( !original.isEmpty() )
-            {
-                copy.addAll( original );
+            if (!original.isEmpty()) {
+                copy.addAll(original);
             }
         }
 
         return copy;
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java
index 4aafcff..3293bd5 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import java.io.File;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import org.apache.maven.artifact.handler.ArtifactHandler;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
@@ -34,14 +29,10 @@
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
 import org.apache.maven.artifact.versioning.VersionRange;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
- * @author Jason van Zyl
  */
-public class DefaultArtifact
-    implements Artifact
-{
+public class DefaultArtifact implements Artifact {
     private String groupId;
 
     private String artifactId;
@@ -80,23 +71,46 @@
 
     private boolean optional;
 
-    public DefaultArtifact( String groupId, String artifactId, String version, String scope, String type,
-                            String classifier, ArtifactHandler artifactHandler )
-    {
-        this( groupId, artifactId, VersionRange.createFromVersion( version ), scope, type, classifier, artifactHandler,
-              false );
+    public DefaultArtifact(
+            String groupId,
+            String artifactId,
+            String version,
+            String scope,
+            String type,
+            String classifier,
+            ArtifactHandler artifactHandler) {
+        this(
+                groupId,
+                artifactId,
+                VersionRange.createFromVersion(version),
+                scope,
+                type,
+                classifier,
+                artifactHandler,
+                false);
     }
 
-    public DefaultArtifact( String groupId, String artifactId, VersionRange versionRange, String scope, String type,
-                            String classifier, ArtifactHandler artifactHandler )
-    {
-        this( groupId, artifactId, versionRange, scope, type, classifier, artifactHandler, false );
+    public DefaultArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String scope,
+            String type,
+            String classifier,
+            ArtifactHandler artifactHandler) {
+        this(groupId, artifactId, versionRange, scope, type, classifier, artifactHandler, false);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public DefaultArtifact( String groupId, String artifactId, VersionRange versionRange, String scope, String type,
-                            String classifier, ArtifactHandler artifactHandler, boolean optional )
-    {
+    @SuppressWarnings("checkstyle:parameternumber")
+    public DefaultArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String scope,
+            String type,
+            String classifier,
+            ArtifactHandler artifactHandler,
+            boolean optional) {
         this.groupId = groupId;
 
         this.artifactId = artifactId;
@@ -111,8 +125,7 @@
 
         this.type = type;
 
-        if ( classifier == null )
-        {
+        if (classifier == null) {
             classifier = artifactHandler.getClassifier();
         }
 
@@ -123,97 +136,78 @@
         validateIdentity();
     }
 
-    private void validateIdentity()
-    {
-        if ( empty( groupId ) )
-        {
-            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
-                "The groupId cannot be empty." );
+    private void validateIdentity() {
+        if (empty(groupId)) {
+            throw new InvalidArtifactRTException(
+                    groupId, artifactId, getVersion(), type, "The groupId cannot be empty.");
         }
 
-        if ( artifactId == null )
-        {
-            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
-                "The artifactId cannot be empty." );
+        if (artifactId == null) {
+            throw new InvalidArtifactRTException(
+                    groupId, artifactId, getVersion(), type, "The artifactId cannot be empty.");
         }
 
-        if ( type == null )
-        {
-            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
-                "The type cannot be empty." );
+        if (type == null) {
+            throw new InvalidArtifactRTException(groupId, artifactId, getVersion(), type, "The type cannot be empty.");
         }
 
-        if ( ( version == null ) && ( versionRange == null ) )
-        {
-            throw new InvalidArtifactRTException( groupId, artifactId, getVersion(), type,
-                "The version cannot be empty." );
+        if ((version == null) && (versionRange == null)) {
+            throw new InvalidArtifactRTException(
+                    groupId, artifactId, getVersion(), type, "The version cannot be empty.");
         }
     }
 
-    private boolean empty( String value )
-    {
-        return ( value == null ) || ( value.trim().length() < 1 );
+    private boolean empty(String value) {
+        return (value == null) || (value.trim().length() < 1);
     }
 
-    public String getClassifier()
-    {
+    public String getClassifier() {
         return classifier;
     }
 
-    public boolean hasClassifier()
-    {
-        return StringUtils.isNotEmpty( classifier );
+    public boolean hasClassifier() {
+        return classifier != null && !classifier.isEmpty();
     }
 
-    public String getScope()
-    {
+    public String getScope() {
         return scope;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
-    public void setVersion( String version )
-    {
+    public void setVersion(String version) {
         this.version = version;
-        setBaseVersionInternal( version );
+        setBaseVersionInternal(version);
         versionRange = null;
     }
 
-    public String getType()
-    {
+    public String getType() {
         return type;
     }
 
-    public void setFile( File file )
-    {
+    public void setFile(File file) {
         this.file = file;
     }
 
-    public File getFile()
-    {
+    public File getFile() {
         return file;
     }
 
-    public ArtifactRepository getRepository()
-    {
+    public ArtifactRepository getRepository() {
         return repository;
     }
 
-    public void setRepository( ArtifactRepository repository )
-    {
+    public void setRepository(ArtifactRepository repository) {
         this.repository = repository;
     }
 
@@ -221,206 +215,140 @@
     //
     // ----------------------------------------------------------------------
 
-    public String getId()
-    {
+    public String getId() {
         return getDependencyConflictId() + ":" + getBaseVersion();
     }
 
-    public String getDependencyConflictId()
-    {
-        StringBuilder sb = new StringBuilder( 128 );
-        sb.append( getGroupId() );
-        sb.append( ':' );
-        appendArtifactTypeClassifierString( sb );
+    public String getDependencyConflictId() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append(getGroupId());
+        sb.append(':');
+        appendArtifactTypeClassifierString(sb);
         return sb.toString();
     }
 
-    private void appendArtifactTypeClassifierString( StringBuilder sb )
-    {
-        sb.append( getArtifactId() );
-        sb.append( ':' );
-        sb.append( getType() );
-        if ( hasClassifier() )
-        {
-            sb.append( ':' );
-            sb.append( getClassifier() );
+    private void appendArtifactTypeClassifierString(StringBuilder sb) {
+        sb.append(getArtifactId());
+        sb.append(':');
+        sb.append(getType());
+        if (hasClassifier()) {
+            sb.append(':');
+            sb.append(getClassifier());
         }
     }
 
-    public void addMetadata( ArtifactMetadata metadata )
-    {
-        if ( metadataMap == null )
-        {
+    public void addMetadata(ArtifactMetadata metadata) {
+        if (metadataMap == null) {
             metadataMap = new HashMap<>();
         }
 
-        ArtifactMetadata m = metadataMap.get( metadata.getKey() );
-        if ( m != null )
-        {
-            m.merge( metadata );
-        }
-        else
-        {
-            metadataMap.put( metadata.getKey(), metadata );
+        ArtifactMetadata m = metadataMap.get(metadata.getKey());
+        if (m != null) {
+            m.merge(metadata);
+        } else {
+            metadataMap.put(metadata.getKey(), metadata);
         }
     }
 
-    public Collection<ArtifactMetadata> getMetadataList()
-    {
-        if ( metadataMap == null )
-        {
+    public Collection<ArtifactMetadata> getMetadataList() {
+        if (metadataMap == null) {
             return Collections.emptyList();
         }
 
-        return Collections.unmodifiableCollection( metadataMap.values() );
+        return Collections.unmodifiableCollection(metadataMap.values());
     }
 
     // ----------------------------------------------------------------------
     // Object overrides
     // ----------------------------------------------------------------------
 
-    public String toString()
-    {
+    public String toString() {
         StringBuilder sb = new StringBuilder();
-        if ( getGroupId() != null )
-        {
-            sb.append( getGroupId() );
-            sb.append( ':' );
+        if (getGroupId() != null) {
+            sb.append(getGroupId());
+            sb.append(':');
         }
-        appendArtifactTypeClassifierString( sb );
-        sb.append( ':' );
-        if ( getBaseVersionInternal() != null )
-        {
-            sb.append( getBaseVersionInternal() );
+        appendArtifactTypeClassifierString(sb);
+        sb.append(':');
+        if (getBaseVersionInternal() != null) {
+            sb.append(getBaseVersionInternal());
+        } else {
+            sb.append(versionRange.toString());
         }
-        else
-        {
-            sb.append( versionRange.toString() );
-        }
-        if ( scope != null )
-        {
-            sb.append( ':' );
-            sb.append( scope );
+        if (scope != null) {
+            sb.append(':');
+            sb.append(scope);
         }
         return sb.toString();
     }
 
-    public int hashCode()
-    {
-        int result = 17;
-        result = 37 * result + groupId.hashCode();
-        result = 37 * result + artifactId.hashCode();
-        result = 37 * result + type.hashCode();
-        if ( version != null )
-        {
-            result = 37 * result + version.hashCode();
-        }
-        result = 37 * result + ( classifier != null ? classifier.hashCode() : 0 );
-        return result;
-    }
-
-    public boolean equals( Object o )
-    {
-        if ( o == this )
-        {
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
             return true;
         }
-
-        if ( !( o instanceof Artifact ) )
-        {
+        if (o == null || getClass() != o.getClass()) {
             return false;
         }
-
-        Artifact a = (Artifact) o;
-
-        if ( !a.getGroupId().equals( groupId ) )
-        {
-            return false;
-        }
-        else if ( !a.getArtifactId().equals( artifactId ) )
-        {
-            return false;
-        }
-        else if ( !a.getVersion().equals( version ) )
-        {
-            return false;
-        }
-        else if ( !a.getType().equals( type ) )
-        {
-            return false;
-        }
-        else
-        {
-            return a.getClassifier() == null ? classifier == null : a.getClassifier().equals( classifier );
-        }
-
-        // We don't consider the version range in the comparison, just the resolved version
+        DefaultArtifact that = (DefaultArtifact) o;
+        return Objects.equals(groupId, that.groupId)
+                && Objects.equals(artifactId, that.artifactId)
+                && Objects.equals(type, that.type)
+                && Objects.equals(classifier, that.classifier)
+                && Objects.equals(version, that.version);
     }
 
-    public String getBaseVersion()
-    {
-        if ( baseVersion == null && version != null )
-        {
-            setBaseVersionInternal( version );
+    @Override
+    public int hashCode() {
+        return Objects.hash(groupId, artifactId, type, classifier, version);
+    }
+
+    public String getBaseVersion() {
+        if (baseVersion == null && version != null) {
+            setBaseVersionInternal(version);
         }
 
         return baseVersion;
     }
 
-    protected String getBaseVersionInternal()
-    {
-        if ( ( baseVersion == null ) && ( version != null ) )
-        {
-            setBaseVersionInternal( version );
+    protected String getBaseVersionInternal() {
+        if ((baseVersion == null) && (version != null)) {
+            setBaseVersionInternal(version);
         }
 
         return baseVersion;
     }
 
-    public void setBaseVersion( String baseVersion )
-    {
-        setBaseVersionInternal( baseVersion );
+    public void setBaseVersion(String baseVersion) {
+        setBaseVersionInternal(baseVersion);
     }
 
-    protected void setBaseVersionInternal( String baseVersion )
-    {
-        this.baseVersion = ArtifactUtils.toSnapshotVersion( baseVersion );
+    protected void setBaseVersionInternal(String baseVersion) {
+        this.baseVersion = ArtifactUtils.toSnapshotVersion(baseVersion);
     }
 
-    public int compareTo( Artifact a )
-    {
-        int result = groupId.compareTo( a.getGroupId() );
-        if ( result == 0 )
-        {
-            result = artifactId.compareTo( a.getArtifactId() );
-            if ( result == 0 )
-            {
-                result = type.compareTo( a.getType() );
-                if ( result == 0 )
-                {
-                    if ( classifier == null )
-                    {
-                        if ( a.getClassifier() != null )
-                        {
+    public int compareTo(Artifact a) {
+        int result = groupId.compareTo(a.getGroupId());
+        if (result == 0) {
+            result = artifactId.compareTo(a.getArtifactId());
+            if (result == 0) {
+                result = type.compareTo(a.getType());
+                if (result == 0) {
+                    if (classifier == null) {
+                        if (a.getClassifier() != null) {
                             result = 1;
                         }
-                    }
-                    else
-                    {
-                        if ( a.getClassifier() != null )
-                        {
-                            result = classifier.compareTo( a.getClassifier() );
-                        }
-                        else
-                        {
+                    } else {
+                        if (a.getClassifier() != null) {
+                            result = classifier.compareTo(a.getClassifier());
+                        } else {
                             result = -1;
                         }
                     }
-                    if ( result == 0 )
-                    {
+                    if (result == 0) {
                         // We don't consider the version range in the comparison, just the resolved version
-                        result = new DefaultArtifactVersion( version ).compareTo(
-                            new DefaultArtifactVersion( a.getVersion() ) );
+                        result = new DefaultArtifactVersion(version)
+                                .compareTo(new DefaultArtifactVersion(a.getVersion()));
                     }
                 }
             }
@@ -428,159 +356,126 @@
         return result;
     }
 
-    public void updateVersion( String version, ArtifactRepository localRepository )
-    {
-        setResolvedVersion( version );
-        setFile( new File( localRepository.getBasedir(), localRepository.pathOf( this ) ) );
+    public void updateVersion(String version, ArtifactRepository localRepository) {
+        setResolvedVersion(version);
+        setFile(new File(localRepository.getBasedir(), localRepository.pathOf(this)));
     }
 
-    public String getDownloadUrl()
-    {
+    public String getDownloadUrl() {
         return downloadUrl;
     }
 
-    public void setDownloadUrl( String downloadUrl )
-    {
+    public void setDownloadUrl(String downloadUrl) {
         this.downloadUrl = downloadUrl;
     }
 
-    public ArtifactFilter getDependencyFilter()
-    {
+    public ArtifactFilter getDependencyFilter() {
         return dependencyFilter;
     }
 
-    public void setDependencyFilter( ArtifactFilter artifactFilter )
-    {
+    public void setDependencyFilter(ArtifactFilter artifactFilter) {
         dependencyFilter = artifactFilter;
     }
 
-    public ArtifactHandler getArtifactHandler()
-    {
+    public ArtifactHandler getArtifactHandler() {
         return artifactHandler;
     }
 
-    public List<String> getDependencyTrail()
-    {
+    public List<String> getDependencyTrail() {
         return dependencyTrail;
     }
 
-    public void setDependencyTrail( List<String> dependencyTrail )
-    {
+    public void setDependencyTrail(List<String> dependencyTrail) {
         this.dependencyTrail = dependencyTrail;
     }
 
-    public void setScope( String scope )
-    {
+    public void setScope(String scope) {
         this.scope = scope;
     }
 
-    public VersionRange getVersionRange()
-    {
+    public VersionRange getVersionRange() {
         return versionRange;
     }
 
-    public void setVersionRange( VersionRange versionRange )
-    {
+    public void setVersionRange(VersionRange versionRange) {
         this.versionRange = versionRange;
         selectVersionFromNewRangeIfAvailable();
     }
 
-    private void selectVersionFromNewRangeIfAvailable()
-    {
-        if ( ( versionRange != null ) && ( versionRange.getRecommendedVersion() != null ) )
-        {
-            selectVersion( versionRange.getRecommendedVersion().toString() );
-        }
-        else
-        {
+    private void selectVersionFromNewRangeIfAvailable() {
+        if ((versionRange != null) && (versionRange.getRecommendedVersion() != null)) {
+            selectVersion(versionRange.getRecommendedVersion().toString());
+        } else {
             version = null;
             baseVersion = null;
         }
     }
 
-    public void selectVersion( String version )
-    {
+    public void selectVersion(String version) {
         this.version = version;
-        setBaseVersionInternal( version );
+        setBaseVersionInternal(version);
     }
 
-    public void setGroupId( String groupId )
-    {
+    public void setGroupId(String groupId) {
         this.groupId = groupId;
     }
 
-    public void setArtifactId( String artifactId )
-    {
+    public void setArtifactId(String artifactId) {
         this.artifactId = artifactId;
     }
 
-    public boolean isSnapshot()
-    {
+    public boolean isSnapshot() {
         return getBaseVersion() != null
-            && ( getBaseVersion().endsWith( SNAPSHOT_VERSION ) || getBaseVersion().equals( LATEST_VERSION ) );
+                && (getBaseVersion().endsWith(SNAPSHOT_VERSION)
+                        || getBaseVersion().equals(LATEST_VERSION));
     }
 
-    public void setResolved( boolean resolved )
-    {
+    public void setResolved(boolean resolved) {
         this.resolved = resolved;
     }
 
-    public boolean isResolved()
-    {
+    public boolean isResolved() {
         return resolved;
     }
 
-    public void setResolvedVersion( String version )
-    {
+    public void setResolvedVersion(String version) {
         this.version = version;
         // retain baseVersion
     }
 
-    public void setArtifactHandler( ArtifactHandler artifactHandler )
-    {
+    public void setArtifactHandler(ArtifactHandler artifactHandler) {
         this.artifactHandler = artifactHandler;
     }
 
-    public void setRelease( boolean release )
-    {
+    public void setRelease(boolean release) {
         this.release = release;
     }
 
-    public boolean isRelease()
-    {
+    public boolean isRelease() {
         return release;
     }
 
-    public List<ArtifactVersion> getAvailableVersions()
-    {
+    public List<ArtifactVersion> getAvailableVersions() {
         return availableVersions;
     }
 
-    public void setAvailableVersions( List<ArtifactVersion> availableVersions )
-    {
+    public void setAvailableVersions(List<ArtifactVersion> availableVersions) {
         this.availableVersions = availableVersions;
     }
 
-    public boolean isOptional()
-    {
+    public boolean isOptional() {
         return optional;
     }
 
-    public ArtifactVersion getSelectedVersion()
-        throws OverConstrainedVersionException
-    {
-        return versionRange.getSelectedVersion( this );
+    public ArtifactVersion getSelectedVersion() throws OverConstrainedVersionException {
+        return versionRange.getSelectedVersion(this);
     }
 
-    public boolean isSelectedVersionKnown()
-        throws OverConstrainedVersionException
-    {
-        return versionRange.isSelectedVersionKnown( this );
+    public boolean isSelectedVersionKnown() throws OverConstrainedVersionException {
+        return versionRange.isSelectedVersionKnown(this);
     }
 
-    public void setOptional( boolean optional )
-    {
+    public void setOptional(boolean optional) {
         this.optional = optional;
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/InvalidArtifactRTException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/InvalidArtifactRTException.java
index 357ec71..5582e98 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/InvalidArtifactRTException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/InvalidArtifactRTException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 /**
  * Exception thrown when the identity of an artifact can not be established,
  * e.g. one of groupId, artifactId, version or type is null.
  */
-public class InvalidArtifactRTException
-    extends RuntimeException
-{
+public class InvalidArtifactRTException extends RuntimeException {
 
     private final String groupId;
     private final String artifactId;
@@ -33,12 +30,7 @@
     private final String type;
     private final String baseMessage;
 
-    public InvalidArtifactRTException( String groupId,
-                                       String artifactId,
-                                       String version,
-                                       String type,
-                                       String message )
-    {
+    public InvalidArtifactRTException(String groupId, String artifactId, String version, String type, String message) {
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.version = version;
@@ -46,14 +38,9 @@
         this.baseMessage = message;
     }
 
-    public InvalidArtifactRTException( String groupId,
-                                       String artifactId,
-                                       String version,
-                                       String type,
-                                       String message,
-                                       Throwable cause )
-    {
-        super( cause );
+    public InvalidArtifactRTException(
+            String groupId, String artifactId, String version, String type, String message, Throwable cause) {
+        super(cause);
 
         this.groupId = groupId;
         this.artifactId = artifactId;
@@ -62,39 +49,31 @@
         this.baseMessage = message;
     }
 
-    public String getMessage()
-    {
+    public String getMessage() {
         return "For artifact {" + getArtifactKey() + "}: " + getBaseMessage();
     }
 
-    public String getBaseMessage()
-    {
+    public String getBaseMessage() {
         return baseMessage;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public String getType()
-    {
+    public String getType() {
         return type;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
-    public String getArtifactKey()
-    {
+    public String getArtifactKey() {
         return groupId + ":" + artifactId + ":" + version + ":" + type;
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java
index db101bf..92cca2a 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/handler/ArtifactHandler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.handler;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.handler;
 
 /**
- * An artifact handler defines for a dependency type, defined as Plexus role:<ul>
- * <li>extension and classifier, to be able to download the file,</li>
- * <li>information on how to use the artifact: whether to add it to the classpath, or to take into account its
- * dependencies.</li>
+ * An artifact handler contains information explaining how an artifact plugs into the Maven build:<ul>
+ * <li>Information needed to find the artifact file in a repository including extension and classifier</li>
+ * <li>Information on how to use the artifact as a dependency: whether to add it to the classpath, whether to load its
+ * dependencies transitively</li>
  * </ul>
  *
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-public interface ArtifactHandler
-{
+public interface ArtifactHandler {
     @Deprecated
     String ROLE = ArtifactHandler.class.getName();
 
     /**
-     * Get the file extension associated to the file represented by the dependency type.
+     * Returns the file name extension of the artifact;
+     * e.g. "jar", "pom", "xml", etc.
      *
      * @return the file extension
      */
@@ -43,7 +41,7 @@
     String getDirectory();
 
     /**
-     * Get the classifier associated to the dependency type.
+     * Returns the default classifier used if a different one is not set in pom.xml.
      *
      * @return the classifier
      */
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadata.java b/maven-artifact/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadata.java
index 7bf8c61..fd07999 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadata.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.metadata;
 
 /**
  * Contains metadata about an artifact, and methods to retrieve/store it from an artifact repository.
  */
 @Deprecated
-public interface ArtifactMetadata
-    extends org.apache.maven.repository.legacy.metadata.ArtifactMetadata
-{
-    void merge( ArtifactMetadata metadata );
+public interface ArtifactMetadata extends org.apache.maven.repository.legacy.metadata.ArtifactMetadata {
+    void merge(ArtifactMetadata metadata);
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java
index aecffb9..e80ff31 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepository.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 import java.util.List;
 
@@ -29,18 +28,20 @@
 /**
  * Abstraction of an artifact repository. Artifact repositories can be remote, local, or even build reactor or
  * IDE workspace.
+ *
+ * @deprecated Avoid use of this type, if you need access to local repository use repository system classes instead.
  */
-public interface ArtifactRepository
-{
-    String pathOf( Artifact artifact );
+@Deprecated
+public interface ArtifactRepository {
+    String pathOf(Artifact artifact);
 
-    String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata );
+    String pathOfRemoteRepositoryMetadata(ArtifactMetadata artifactMetadata);
 
-    String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository );
+    String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository);
 
     String getUrl();
 
-    void setUrl( String url );
+    void setUrl(String url);
 
     String getBasedir();
 
@@ -48,19 +49,19 @@
 
     String getId();
 
-    void setId( String id );
+    void setId(String id);
 
     ArtifactRepositoryPolicy getSnapshots();
 
-    void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy policy );
+    void setSnapshotUpdatePolicy(ArtifactRepositoryPolicy policy);
 
     ArtifactRepositoryPolicy getReleases();
 
-    void setReleaseUpdatePolicy( ArtifactRepositoryPolicy policy );
+    void setReleaseUpdatePolicy(ArtifactRepositoryPolicy policy);
 
     ArtifactRepositoryLayout getLayout();
 
-    void setLayout( ArtifactRepositoryLayout layout );
+    void setLayout(ArtifactRepositoryLayout layout);
 
     String getKey();
 
@@ -71,7 +72,7 @@
     boolean isBlacklisted();
 
     @Deprecated
-    void setBlacklisted( boolean blackListed );
+    void setBlacklisted(boolean blackListed);
 
     /**
      * @return whether the repository is blocked
@@ -83,7 +84,7 @@
      * @param blocked block the repository?
      * @since 3.8.1
      **/
-    void setBlocked( boolean blocked );
+    void setBlocked(boolean blocked);
 
     //
     // New interface methods for the repository system.
@@ -94,7 +95,7 @@
      * @return found artifact
      * @since 3.0-alpha-3
      */
-    Artifact find( Artifact artifact );
+    Artifact find(Artifact artifact);
 
     /**
      * Finds the versions of the specified artifact that are available in this repository.
@@ -103,7 +104,7 @@
      * @return The available versions of the artifact or an empty list if none, never {@code null}.
      * @since 3.0-alpha-3
      */
-    List<String> findVersions( Artifact artifact );
+    List<String> findVersions(Artifact artifact);
 
     /**
      * Indicates whether this repository is backed by actual projects. For instance, the build reactor or IDE workspace
@@ -118,7 +119,7 @@
      * @param authentication authentication
      * @since 3.0-alpha-3
      */
-    void setAuthentication( Authentication authentication );
+    void setAuthentication(Authentication authentication);
 
     /**
      * @return repository authentication
@@ -130,7 +131,7 @@
      * @param proxy proxy
      * @since 3.0-alpha-3
      */
-    void setProxy( Proxy proxy );
+    void setProxy(Proxy proxy);
 
     /**
      * @since 3.0-alpha-3
@@ -148,6 +149,5 @@
      * @since 3.0.3
      * @param mirroredRepositories the repositories that the actual one mirrors
      */
-    void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories );
-
+    void setMirroredRepositories(List<ArtifactRepository> mirroredRepositories);
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java
index 6ad2a26..75d9b8a 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryPolicy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 import java.util.Calendar;
 import java.util.Date;
@@ -25,10 +24,10 @@
 /**
  * Describes a set of policies for a repository to use under certain conditions.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
+ * @deprecated Avoid use of this type, if you need access to local repository use repository system session instead.
  */
-public class ArtifactRepositoryPolicy
-{
+@Deprecated
+public class ArtifactRepositoryPolicy {
     public static final String UPDATE_POLICY_NEVER = "never";
 
     public static final String UPDATE_POLICY_ALWAYS = "always";
@@ -51,100 +50,79 @@
 
     private String checksumPolicy;
 
-    public ArtifactRepositoryPolicy()
-    {
-        this( true, null, null );
+    public ArtifactRepositoryPolicy() {
+        this(true, null, null);
     }
 
-    public ArtifactRepositoryPolicy( ArtifactRepositoryPolicy policy )
-    {
-        this( policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy() );
+    public ArtifactRepositoryPolicy(ArtifactRepositoryPolicy policy) {
+        this(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy());
     }
 
-    public ArtifactRepositoryPolicy( boolean enabled, String updatePolicy, String checksumPolicy )
-    {
+    public ArtifactRepositoryPolicy(boolean enabled, String updatePolicy, String checksumPolicy) {
         this.enabled = enabled;
 
-        if ( updatePolicy == null )
-        {
+        if (updatePolicy == null) {
             updatePolicy = UPDATE_POLICY_DAILY;
         }
         this.updatePolicy = updatePolicy;
 
-        if ( checksumPolicy == null )
-        {
+        if (checksumPolicy == null) {
             checksumPolicy = DEFAULT_CHECKSUM_POLICY;
         }
         this.checksumPolicy = checksumPolicy;
     }
 
-    public void setEnabled( boolean enabled )
-    {
+    public void setEnabled(boolean enabled) {
         this.enabled = enabled;
     }
 
-    public void setUpdatePolicy( String updatePolicy )
-    {
-        if ( updatePolicy != null )
-        {
+    public void setUpdatePolicy(String updatePolicy) {
+        if (updatePolicy != null) {
             this.updatePolicy = updatePolicy;
         }
     }
 
-    public void setChecksumPolicy( String checksumPolicy )
-    {
-        if ( checksumPolicy != null )
-        {
+    public void setChecksumPolicy(String checksumPolicy) {
+        if (checksumPolicy != null) {
             this.checksumPolicy = checksumPolicy;
         }
     }
 
-    public boolean isEnabled()
-    {
+    public boolean isEnabled() {
         return enabled;
     }
 
-    public String getUpdatePolicy()
-    {
+    public String getUpdatePolicy() {
         return updatePolicy;
     }
 
-    public String getChecksumPolicy()
-    {
+    public String getChecksumPolicy() {
         return checksumPolicy;
     }
 
-    public boolean checkOutOfDate( Date lastModified )
-    {
+    public boolean checkOutOfDate(Date lastModified) {
         boolean checkForUpdates = false;
 
-        if ( UPDATE_POLICY_ALWAYS.equals( updatePolicy ) )
-        {
+        if (UPDATE_POLICY_ALWAYS.equals(updatePolicy)) {
             checkForUpdates = true;
-        }
-        else if ( UPDATE_POLICY_DAILY.equals( updatePolicy ) )
-        {
+        } else if (UPDATE_POLICY_DAILY.equals(updatePolicy)) {
             // Get local midnight boundary
             Calendar cal = Calendar.getInstance();
 
-            cal.set( Calendar.HOUR_OF_DAY, 0 );
-            cal.set( Calendar.MINUTE, 0 );
-            cal.set( Calendar.SECOND, 0 );
-            cal.set( Calendar.MILLISECOND, 0 );
+            cal.set(Calendar.HOUR_OF_DAY, 0);
+            cal.set(Calendar.MINUTE, 0);
+            cal.set(Calendar.SECOND, 0);
+            cal.set(Calendar.MILLISECOND, 0);
 
-            if ( cal.getTime().after( lastModified ) )
-            {
+            if (cal.getTime().after(lastModified)) {
                 checkForUpdates = true;
             }
-        }
-        else if ( updatePolicy.startsWith( UPDATE_POLICY_INTERVAL ) )
-        {
-            String s = updatePolicy.substring( UPDATE_POLICY_INTERVAL.length() + 1 );
-            int minutes = Integer.parseInt( s );
+        } else if (updatePolicy.startsWith(UPDATE_POLICY_INTERVAL)) {
+            String s = updatePolicy.substring(UPDATE_POLICY_INTERVAL.length() + 1);
+            int minutes = Integer.parseInt(s);
             Calendar cal = Calendar.getInstance();
-            cal.add( Calendar.MINUTE, -minutes );
-            if ( cal.getTime().after( lastModified ) )
-            {
+            cal.add(Calendar.MINUTE, -minutes);
+            if (cal.getTime().after(lastModified)) {
                 checkForUpdates = true;
             }
         }
@@ -153,73 +131,53 @@
     }
 
     @Override
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder( 64 );
-        buffer.append( "{enabled=" );
-        buffer.append( enabled );
-        buffer.append( ", checksums=" );
-        buffer.append( checksumPolicy );
-        buffer.append( ", updates=" );
-        buffer.append( updatePolicy );
-        buffer.append( '}' );
+    public String toString() {
+        StringBuilder buffer = new StringBuilder(64);
+        buffer.append("{enabled=");
+        buffer.append(enabled);
+        buffer.append(", checksums=");
+        buffer.append(checksumPolicy);
+        buffer.append(", updates=");
+        buffer.append(updatePolicy);
+        buffer.append('}');
         return buffer.toString();
     }
 
-    public void merge( ArtifactRepositoryPolicy policy )
-    {
-        if ( policy != null && policy.isEnabled() )
-        {
-            setEnabled( true );
+    public void merge(ArtifactRepositoryPolicy policy) {
+        if (policy != null && policy.isEnabled()) {
+            setEnabled(true);
 
-            if ( ordinalOfCksumPolicy( policy.getChecksumPolicy() ) < ordinalOfCksumPolicy( getChecksumPolicy() ) )
-            {
-                setChecksumPolicy( policy.getChecksumPolicy() );
+            if (ordinalOfCksumPolicy(policy.getChecksumPolicy()) < ordinalOfCksumPolicy(getChecksumPolicy())) {
+                setChecksumPolicy(policy.getChecksumPolicy());
             }
 
-            if ( ordinalOfUpdatePolicy( policy.getUpdatePolicy() ) < ordinalOfUpdatePolicy( getUpdatePolicy() ) )
-            {
-                setUpdatePolicy( policy.getUpdatePolicy() );
+            if (ordinalOfUpdatePolicy(policy.getUpdatePolicy()) < ordinalOfUpdatePolicy(getUpdatePolicy())) {
+                setUpdatePolicy(policy.getUpdatePolicy());
             }
         }
     }
 
-    private int ordinalOfCksumPolicy( String policy )
-    {
-        if ( ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( policy ) )
-        {
+    private int ordinalOfCksumPolicy(String policy) {
+        if (ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL.equals(policy)) {
             return 2;
-        }
-        else if ( ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( policy ) )
-        {
+        } else if (ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals(policy)) {
             return 0;
-        }
-        else
-        {
+        } else {
             return 1;
         }
     }
 
-    @SuppressWarnings( "checkstyle:magicnumber" )
-    private int ordinalOfUpdatePolicy( String policy )
-    {
-        if ( ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY.equals( policy ) )
-        {
+    @SuppressWarnings("checkstyle:magicnumber")
+    private int ordinalOfUpdatePolicy(String policy) {
+        if (ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY.equals(policy)) {
             return 1440;
-        }
-        else if ( ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS.equals( policy ) )
-        {
+        } else if (ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS.equals(policy)) {
             return 0;
-        }
-        else if ( policy != null && policy.startsWith( ArtifactRepositoryPolicy.UPDATE_POLICY_INTERVAL ) )
-        {
-            String s = policy.substring( UPDATE_POLICY_INTERVAL.length() + 1 );
-            return Integer.parseInt( s );
-        }
-        else
-        {
+        } else if (policy != null && policy.startsWith(ArtifactRepositoryPolicy.UPDATE_POLICY_INTERVAL)) {
+            String s = policy.substring(UPDATE_POLICY_INTERVAL.length() + 1);
+            return Integer.parseInt(s);
+        } else {
             return Integer.MAX_VALUE;
         }
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/Authentication.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/Authentication.java
index b6f1d93..62d0165 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/Authentication.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/Authentication.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,19 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 /**
  * Authentication
  */
-public class Authentication
-{
+public class Authentication {
 
     private String privateKey;
 
     private String passphrase;
 
-    public Authentication( String userName, String password )
-    {
+    public Authentication(String userName, String password) {
         this.username = userName;
         this.password = password;
     }
@@ -50,8 +47,7 @@
      *
      * @return password of user
      */
-    public String getPassword()
-    {
+    public String getPassword() {
         return password;
     }
 
@@ -60,8 +56,7 @@
      *
      * @param password password of the user
      */
-    public void setPassword( String password )
-    {
+    public void setPassword(String password) {
         this.password = password;
     }
 
@@ -70,8 +65,7 @@
      *
      * @return username at repository
      */
-    public String getUsername()
-    {
+    public String getUsername() {
         return username;
     }
 
@@ -80,8 +74,7 @@
      *
      * @param userName the username used to access repository
      */
-    public void setUsername( final String userName )
-    {
+    public void setUsername(final String userName) {
         this.username = userName;
     }
 
@@ -91,8 +84,7 @@
      *
      * @return passphrase of the private key file
      */
-    public String getPassphrase()
-    {
+    public String getPassphrase() {
         return passphrase;
     }
 
@@ -101,8 +93,7 @@
      *
      * @param passphrase passphrase of the private key file
      */
-    public void setPassphrase( final String passphrase )
-    {
+    public void setPassphrase(final String passphrase) {
         this.passphrase = passphrase;
     }
 
@@ -111,8 +102,7 @@
      *
      * @return absolute path to private key
      */
-    public String getPrivateKey()
-    {
+    public String getPrivateKey() {
         return privateKey;
     }
 
@@ -121,9 +111,7 @@
      *
      * @param privateKey path to private key in local file system
      */
-    public void setPrivateKey( final String privateKey )
-    {
+    public void setPrivateKey(final String privateKey) {
         this.privateKey = privateKey;
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout.java
index 2a18c86..ec00976 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.layout;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,21 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.layout;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 
-/** @author jdcasey */
-public interface ArtifactRepositoryLayout
-{
+/**
+ * Repository layout.
+ *
+ * @deprecated Avoid use of this type, if you need access to local repository use repository system session instead.
+ */
+@Deprecated
+public interface ArtifactRepositoryLayout {
     String ROLE = ArtifactRepositoryLayout.class.getName();
 
     String getId();
 
-    String pathOf( Artifact artifact );
+    String pathOf(Artifact artifact);
 
-    String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository );
+    String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository);
 
-    String pathOfRemoteRepositoryMetadata( ArtifactMetadata metadata );
+    String pathOfRemoteRepositoryMetadata(ArtifactMetadata metadata);
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout2.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout2.java
index f6bc573..8cdc09d 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout2.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/layout/ArtifactRepositoryLayout2.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.layout;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.layout;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
@@ -25,10 +24,8 @@
 /**
  * ArtifactRepositoryLayout2
  */
-public interface ArtifactRepositoryLayout2
-    extends ArtifactRepositoryLayout
-{
+public interface ArtifactRepositoryLayout2 extends ArtifactRepositoryLayout {
 
-    ArtifactRepository newMavenArtifactRepository( String id, String url, ArtifactRepositoryPolicy snapshots,
-                                                   ArtifactRepositoryPolicy releases );
+    ArtifactRepository newMavenArtifactRepository(
+            String id, String url, ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases);
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataStoreException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataStoreException.java
index 3848852..0db5434 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataStoreException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataStoreException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata;
 
 /**
  * Problem storing the repository metadata in the local repository.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class RepositoryMetadataStoreException
-    extends Exception
-{
-    public RepositoryMetadataStoreException( String message )
-    {
-        super( message );
+public class RepositoryMetadataStoreException extends Exception {
+    public RepositoryMetadataStoreException(String message) {
+        super(message);
     }
 
-    public RepositoryMetadataStoreException( String message,
-                                             Exception e )
-    {
-        super( message, e );
+    public RepositoryMetadataStoreException(String message, Exception e) {
+        super(message, e);
     }
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java
index a2917b5..d7bc153 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/AbstractArtifactResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.Iterator;
 import java.util.List;
@@ -29,11 +28,8 @@
 /**
  * Base class for artifact resolution exceptions.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class AbstractArtifactResolutionException
-    extends Exception
-{
+public class AbstractArtifactResolutionException extends Exception {
     private String groupId;
 
     private String artifactId;
@@ -54,31 +50,31 @@
 
     static final String LS = System.lineSeparator();
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    protected AbstractArtifactResolutionException( String message,
-                                                   String groupId,
-                                                   String artifactId,
-                                                   String version,
-                                                   String type,
-                                                   String classifier,
-                                                   List<ArtifactRepository> remoteRepositories,
-                                                   List<String> path )
-    {
-        this( message, groupId, artifactId, version, type, classifier, remoteRepositories, path, null );
+    @SuppressWarnings("checkstyle:parameternumber")
+    protected AbstractArtifactResolutionException(
+            String message,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            String classifier,
+            List<ArtifactRepository> remoteRepositories,
+            List<String> path) {
+        this(message, groupId, artifactId, version, type, classifier, remoteRepositories, path, null);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    protected AbstractArtifactResolutionException( String message,
-                                                   String groupId,
-                                                   String artifactId,
-                                                   String version,
-                                                   String type,
-                                                   String classifier,
-                                                   List<ArtifactRepository> remoteRepositories,
-                                                   List<String> path,
-                                                   Throwable t )
-    {
-        super( constructMessageBase( message, groupId, artifactId, version, type, remoteRepositories, path ), t );
+    @SuppressWarnings("checkstyle:parameternumber")
+    protected AbstractArtifactResolutionException(
+            String message,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            String classifier,
+            List<ArtifactRepository> remoteRepositories,
+            List<String> path,
+            Throwable t) {
+        super(constructMessageBase(message, groupId, artifactId, version, type, remoteRepositories, path), t);
 
         this.originalMessage = message;
         this.groupId = groupId;
@@ -87,261 +83,241 @@
         this.classifier = classifier;
         this.version = version;
         this.remoteRepositories = remoteRepositories;
-        this.path = constructArtifactPath( path, "" );
+        this.path = constructArtifactPath(path, "");
     }
 
-    protected AbstractArtifactResolutionException( String message,
-                                                   Artifact artifact )
-    {
-        this( message, artifact, null );
+    protected AbstractArtifactResolutionException(String message, Artifact artifact) {
+        this(message, artifact, null);
     }
 
-    protected AbstractArtifactResolutionException( String message,
-                                                   Artifact artifact,
-                                                   List<ArtifactRepository> remoteRepositories )
-    {
-        this( message, artifact, remoteRepositories, null );
+    protected AbstractArtifactResolutionException(
+            String message, Artifact artifact, List<ArtifactRepository> remoteRepositories) {
+        this(message, artifact, remoteRepositories, null);
     }
 
-    protected AbstractArtifactResolutionException( String message,
-                                                   Artifact artifact,
-                                                   List<ArtifactRepository> remoteRepositories,
-                                                   Throwable t )
-    {
-        this( message, artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getType(),
-            artifact.getClassifier(), remoteRepositories, artifact.getDependencyTrail(), t );
+    protected AbstractArtifactResolutionException(
+            String message, Artifact artifact, List<ArtifactRepository> remoteRepositories, Throwable t) {
+        this(
+                message,
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getVersion(),
+                artifact.getType(),
+                artifact.getClassifier(),
+                remoteRepositories,
+                artifact.getDependencyTrail(),
+                t);
         this.artifact = artifact;
     }
 
-    public Artifact getArtifact()
-    {
+    public Artifact getArtifact() {
         return artifact;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
-    public String getType()
-    {
+    public String getType() {
         return type;
     }
 
     /** @return the classifier */
-    public String getClassifier()
-    {
+    public String getClassifier() {
         return this.classifier;
     }
 
     /** @return the path */
-    public String getPath()
-    {
+    public String getPath() {
         return this.path;
     }
 
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
+    public List<ArtifactRepository> getRemoteRepositories() {
         return remoteRepositories;
     }
 
-    public String getOriginalMessage()
-    {
+    public String getOriginalMessage() {
         return originalMessage;
     }
 
-    protected static String constructArtifactPath( List<String> path,
-                                                   String indentation )
-    {
+    protected static String constructArtifactPath(List<String> path, String indentation) {
         StringBuilder sb = new StringBuilder();
 
-        if ( path != null )
-        {
-            sb.append( LS );
-            sb.append( indentation );
-            sb.append( "Path to dependency: " );
-            sb.append( LS );
+        if (path != null) {
+            sb.append(LS);
+            sb.append(indentation);
+            sb.append("Path to dependency: ");
+            sb.append(LS);
             int num = 1;
-            for ( Iterator<String> i = path.iterator(); i.hasNext(); num++ )
-            {
-                sb.append( indentation );
-                sb.append( '\t' );
-                sb.append( num );
-                sb.append( ") " );
-                sb.append( i.next() );
-                sb.append( LS );
+            for (Iterator<String> i = path.iterator(); i.hasNext(); num++) {
+                sb.append(indentation);
+                sb.append('\t');
+                sb.append(num);
+                sb.append(") ");
+                sb.append(i.next());
+                sb.append(LS);
             }
         }
 
         return sb.toString();
     }
 
-    private static String constructMessageBase( String message,
-                                                String groupId,
-                                                String artifactId,
-                                                String version,
-                                                String type,
-                                                List<ArtifactRepository> remoteRepositories,
-                                                List<String> path )
-    {
+    private static String constructMessageBase(
+            String message,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            List<ArtifactRepository> remoteRepositories,
+            List<String> path) {
         StringBuilder sb = new StringBuilder();
 
-        sb.append( message );
+        sb.append(message);
 
-        if ( message == null || !message.contains( "from the specified remote repositories:" ) )
-        {
-            sb.append( LS );
-            sb.append( "  " ).append( groupId ).append( ':' ).append( artifactId ).append( ':' ).append( type ).append(
-                ':' ).append( version );
-            sb.append( LS );
-            if ( remoteRepositories != null )
-            {
-                sb.append( LS );
-                sb.append( "from the specified remote repositories:" );
-                sb.append( LS ).append( "  " );
+        if (message == null || !message.contains("from the specified remote repositories:")) {
+            sb.append(LS);
+            sb.append("  ")
+                    .append(groupId)
+                    .append(':')
+                    .append(artifactId)
+                    .append(':')
+                    .append(type)
+                    .append(':')
+                    .append(version);
+            sb.append(LS);
+            if (remoteRepositories != null) {
+                sb.append(LS);
+                sb.append("from the specified remote repositories:");
+                sb.append(LS).append("  ");
 
-                if ( remoteRepositories.isEmpty() )
-                {
-                    sb.append( "(none)" );
+                if (remoteRepositories.isEmpty()) {
+                    sb.append("(none)");
                 }
 
-                for ( Iterator<ArtifactRepository> i = remoteRepositories.iterator(); i.hasNext(); )
-                {
+                for (Iterator<ArtifactRepository> i = remoteRepositories.iterator(); i.hasNext(); ) {
                     ArtifactRepository remoteRepository = i.next();
 
-                    sb.append( remoteRepository.getId() );
-                    sb.append( " (" );
-                    sb.append( remoteRepository.getUrl() );
+                    sb.append(remoteRepository.getId());
+                    sb.append(" (");
+                    sb.append(remoteRepository.getUrl());
 
                     ArtifactRepositoryPolicy releases = remoteRepository.getReleases();
-                    if ( releases != null )
-                    {
-                        sb.append( ", releases=" ).append( releases.isEnabled() );
+                    if (releases != null) {
+                        sb.append(", releases=").append(releases.isEnabled());
                     }
 
                     ArtifactRepositoryPolicy snapshots = remoteRepository.getSnapshots();
-                    if ( snapshots != null )
-                    {
-                        sb.append( ", snapshots=" ).append( snapshots.isEnabled() );
+                    if (snapshots != null) {
+                        sb.append(", snapshots=").append(snapshots.isEnabled());
                     }
 
-                    sb.append( ')' );
-                    if ( i.hasNext() )
-                    {
-                        sb.append( ',' ).append( LS ).append( "  " );
+                    sb.append(')');
+                    if (i.hasNext()) {
+                        sb.append(',').append(LS).append("  ");
                     }
                 }
             }
 
-            sb.append( constructArtifactPath( path, "" ) );
-            sb.append( LS );
+            sb.append(constructArtifactPath(path, ""));
+            sb.append(LS);
         }
 
         return sb.toString();
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    protected static String constructMissingArtifactMessage( String message,
-                                                             String indentation,
-                                                             String groupId,
-                                                             String artifactId,
-                                                             String version,
-                                                             String type,
-                                                             String classifier,
-                                                             String downloadUrl,
-                                                             List<String> path )
-    {
-        StringBuilder sb = new StringBuilder( message );
+    @SuppressWarnings("checkstyle:parameternumber")
+    protected static String constructMissingArtifactMessage(
+            String message,
+            String indentation,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            String classifier,
+            String downloadUrl,
+            List<String> path) {
+        StringBuilder sb = new StringBuilder(message);
 
-        if ( !"pom".equals( type ) )
-        {
-            if ( downloadUrl != null )
-            {
-                sb.append( LS );
-                sb.append( LS );
-                sb.append( indentation );
-                sb.append( "Try downloading the file manually from: " );
-                sb.append( LS );
-                sb.append( indentation );
-                sb.append( "    " );
-                sb.append( downloadUrl );
-            }
-            else
-            {
-                sb.append( LS );
-                sb.append( LS );
-                sb.append( indentation );
-                sb.append( "Try downloading the file manually from the project website." );
+        if (!"pom".equals(type)) {
+            if (downloadUrl != null) {
+                sb.append(LS);
+                sb.append(LS);
+                sb.append(indentation);
+                sb.append("Try downloading the file manually from: ");
+                sb.append(LS);
+                sb.append(indentation);
+                sb.append("    ");
+                sb.append(downloadUrl);
+            } else {
+                sb.append(LS);
+                sb.append(LS);
+                sb.append(indentation);
+                sb.append("Try downloading the file manually from the project website.");
             }
 
-            sb.append( LS );
-            sb.append( LS );
-            sb.append( indentation );
-            sb.append( "Then, install it using the command: " );
-            sb.append( LS );
-            sb.append( indentation );
-            sb.append( "    mvn install:install-file -DgroupId=" );
-            sb.append( groupId );
-            sb.append( " -DartifactId=" );
-            sb.append( artifactId );
-            sb.append( " -Dversion=" );
-            sb.append( version );
+            sb.append(LS);
+            sb.append(LS);
+            sb.append(indentation);
+            sb.append("Then, install it using the command: ");
+            sb.append(LS);
+            sb.append(indentation);
+            sb.append("    mvn install:install-file -DgroupId=");
+            sb.append(groupId);
+            sb.append(" -DartifactId=");
+            sb.append(artifactId);
+            sb.append(" -Dversion=");
+            sb.append(version);
 
-            //insert classifier only if it was used in the artifact
-            if ( classifier != null && !classifier.equals( "" ) )
-            {
-                sb.append( " -Dclassifier=" );
-                sb.append( classifier );
+            // insert classifier only if it was used in the artifact
+            if (classifier != null && !classifier.equals("")) {
+                sb.append(" -Dclassifier=");
+                sb.append(classifier);
             }
-            sb.append( " -Dpackaging=" );
-            sb.append( type );
-            sb.append( " -Dfile=/path/to/file" );
-            sb.append( LS );
+            sb.append(" -Dpackaging=");
+            sb.append(type);
+            sb.append(" -Dfile=/path/to/file");
+            sb.append(LS);
 
             // If people want to deploy it
-            sb.append( LS );
-            sb.append( indentation );
-            sb.append( "Alternatively, if you host your own repository you can deploy the file there: " );
-            sb.append( LS );
-            sb.append( indentation );
-            sb.append( "    mvn deploy:deploy-file -DgroupId=" );
-            sb.append( groupId );
-            sb.append( " -DartifactId=" );
-            sb.append( artifactId );
-            sb.append( " -Dversion=" );
-            sb.append( version );
+            sb.append(LS);
+            sb.append(indentation);
+            sb.append("Alternatively, if you host your own repository you can deploy the file there: ");
+            sb.append(LS);
+            sb.append(indentation);
+            sb.append("    mvn deploy:deploy-file -DgroupId=");
+            sb.append(groupId);
+            sb.append(" -DartifactId=");
+            sb.append(artifactId);
+            sb.append(" -Dversion=");
+            sb.append(version);
 
-            //insert classifier only if it was used in the artifact
-            if ( classifier != null && !classifier.equals( "" ) )
-            {
-                sb.append( " -Dclassifier=" );
-                sb.append( classifier );
+            // insert classifier only if it was used in the artifact
+            if (classifier != null && !classifier.equals("")) {
+                sb.append(" -Dclassifier=");
+                sb.append(classifier);
             }
-            sb.append( " -Dpackaging=" );
-            sb.append( type );
-            sb.append( " -Dfile=/path/to/file" );
-            sb.append( " -Durl=[url] -DrepositoryId=[id]" );
-            sb.append( LS );
+            sb.append(" -Dpackaging=");
+            sb.append(type);
+            sb.append(" -Dfile=/path/to/file");
+            sb.append(" -Durl=[url] -DrepositoryId=[id]");
+            sb.append(LS);
         }
 
-        sb.append( constructArtifactPath( path, indentation ) );
-        sb.append( LS );
+        sb.append(constructArtifactPath(path, indentation));
+        sb.append(LS);
 
         return sb.toString();
     }
 
-    public String getArtifactPath()
-    {
+    public String getArtifactPath() {
         return path;
     }
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactNotFoundException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactNotFoundException.java
index 76f7b58..f9f706b 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactNotFoundException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
+package org.apache.maven.artifact.resolver;
 
 import java.util.List;
 
@@ -26,60 +24,96 @@
 import org.apache.maven.artifact.repository.ArtifactRepository;
 
 /**
- * @author Jason van Zyl
  */
-public class ArtifactNotFoundException
-    extends AbstractArtifactResolutionException
-{
+public class ArtifactNotFoundException extends AbstractArtifactResolutionException {
     private String downloadUrl;
 
-    protected ArtifactNotFoundException( String message, Artifact artifact,
-                                         List<ArtifactRepository> remoteRepositories )
-    {
-        super( message, artifact, remoteRepositories );
+    protected ArtifactNotFoundException(
+            String message, Artifact artifact, List<ArtifactRepository> remoteRepositories) {
+        super(message, artifact, remoteRepositories);
     }
 
-    public ArtifactNotFoundException( String message, Artifact artifact )
-    {
-        this( message, artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getType(),
-              artifact.getClassifier(), null, artifact.getDownloadUrl(), artifact.getDependencyTrail() );
+    public ArtifactNotFoundException(String message, Artifact artifact) {
+        this(
+                message,
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getVersion(),
+                artifact.getType(),
+                artifact.getClassifier(),
+                null,
+                artifact.getDownloadUrl(),
+                artifact.getDependencyTrail());
     }
 
-    protected ArtifactNotFoundException( String message, Artifact artifact,
-                                         List<ArtifactRepository> remoteRepositories, Throwable cause )
-    {
-        this( message, artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getType(),
-              artifact.getClassifier(), remoteRepositories, artifact.getDownloadUrl(), artifact.getDependencyTrail(),
-              cause );
+    protected ArtifactNotFoundException(
+            String message, Artifact artifact, List<ArtifactRepository> remoteRepositories, Throwable cause) {
+        this(
+                message,
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getVersion(),
+                artifact.getType(),
+                artifact.getClassifier(),
+                remoteRepositories,
+                artifact.getDownloadUrl(),
+                artifact.getDependencyTrail(),
+                cause);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactNotFoundException( String message, String groupId, String artifactId, String version, String type,
-                                      String classifier, List<ArtifactRepository> remoteRepositories,
-                                      String downloadUrl, List<String> path, Throwable cause )
-    {
-        super( constructMissingArtifactMessage( message, "", groupId, artifactId, version, type, classifier,
-                                                downloadUrl, path ), groupId, artifactId, version, type, classifier,
-               remoteRepositories, null, cause );
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactNotFoundException(
+            String message,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            String classifier,
+            List<ArtifactRepository> remoteRepositories,
+            String downloadUrl,
+            List<String> path,
+            Throwable cause) {
+        super(
+                constructMissingArtifactMessage(
+                        message, "", groupId, artifactId, version, type, classifier, downloadUrl, path),
+                groupId,
+                artifactId,
+                version,
+                type,
+                classifier,
+                remoteRepositories,
+                null,
+                cause);
 
         this.downloadUrl = downloadUrl;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private ArtifactNotFoundException( String message, String groupId, String artifactId, String version, String type,
-                                       String classifier, List<ArtifactRepository> remoteRepositories,
-                                       String downloadUrl, List<String> path )
-    {
-        super( constructMissingArtifactMessage( message, "", groupId, artifactId, version, type, classifier,
-                                                downloadUrl, path ), groupId, artifactId, version, type, classifier,
-               remoteRepositories, null );
+    @SuppressWarnings("checkstyle:parameternumber")
+    private ArtifactNotFoundException(
+            String message,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            String classifier,
+            List<ArtifactRepository> remoteRepositories,
+            String downloadUrl,
+            List<String> path) {
+        super(
+                constructMissingArtifactMessage(
+                        message, "", groupId, artifactId, version, type, classifier, downloadUrl, path),
+                groupId,
+                artifactId,
+                version,
+                type,
+                classifier,
+                remoteRepositories,
+                null);
 
         this.downloadUrl = downloadUrl;
     }
 
-    public String getDownloadUrl()
-    {
+    public String getDownloadUrl() {
         return downloadUrl;
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionException.java
index 074d812..2326d2f 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.List;
 
@@ -25,44 +24,47 @@
 import org.apache.maven.artifact.repository.ArtifactRepository;
 
 /**
- * @author Jason van Zyl
  */
-public class ArtifactResolutionException
-    extends AbstractArtifactResolutionException
-{
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactResolutionException( String message, String groupId, String artifactId, String version, String type,
-                                        String classifier, List<ArtifactRepository> remoteRepositories,
-                                        List<String> path, Throwable t )
-    {
-        super( message, groupId, artifactId, version, type, classifier, remoteRepositories, path, t );
+public class ArtifactResolutionException extends AbstractArtifactResolutionException {
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactResolutionException(
+            String message,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            String classifier,
+            List<ArtifactRepository> remoteRepositories,
+            List<String> path,
+            Throwable t) {
+        super(message, groupId, artifactId, version, type, classifier, remoteRepositories, path, t);
     }
 
-    public ArtifactResolutionException( String message, String groupId, String artifactId, String version, String type,
-                                        String classifier, Throwable t )
-    {
-        super( message, groupId, artifactId, version, type, classifier, null, null, t );
+    public ArtifactResolutionException(
+            String message,
+            String groupId,
+            String artifactId,
+            String version,
+            String type,
+            String classifier,
+            Throwable t) {
+        super(message, groupId, artifactId, version, type, classifier, null, null, t);
     }
 
-    public ArtifactResolutionException( String message, Artifact artifact )
-    {
-        super( message, artifact );
+    public ArtifactResolutionException(String message, Artifact artifact) {
+        super(message, artifact);
     }
 
-    public ArtifactResolutionException( String message, Artifact artifact, List<ArtifactRepository> remoteRepositories )
-    {
-        super( message, artifact, remoteRepositories );
+    public ArtifactResolutionException(String message, Artifact artifact, List<ArtifactRepository> remoteRepositories) {
+        super(message, artifact, remoteRepositories);
     }
 
-    public ArtifactResolutionException( String message, Artifact artifact, Throwable cause )
-    {
-        super( message, artifact, null, cause );
+    public ArtifactResolutionException(String message, Artifact artifact, Throwable cause) {
+        super(message, artifact, null, cause);
     }
 
-    public ArtifactResolutionException( String message, Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                        Throwable cause )
-    {
-        super( message, artifact, remoteRepositories, cause );
+    public ArtifactResolutionException(
+            String message, Artifact artifact, List<ArtifactRepository> remoteRepositories, Throwable cause) {
+        super(message, artifact, remoteRepositories, cause);
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/CyclicDependencyException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/CyclicDependencyException.java
index bbc6733..a47d6a6 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/CyclicDependencyException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/CyclicDependencyException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,28 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import org.apache.maven.artifact.Artifact;
 
 /**
  * Indicates a cycle in the dependency graph.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class CyclicDependencyException
-    extends ArtifactResolutionException
-{
+public class CyclicDependencyException extends ArtifactResolutionException {
     private Artifact artifact;
 
-    public CyclicDependencyException( String message,
-                                      Artifact artifact )
-    {
-        super( message, artifact );
+    public CyclicDependencyException(String message, Artifact artifact) {
+        super(message, artifact);
         this.artifact = artifact;
     }
 
-    public Artifact getArtifact()
-    {
+    public Artifact getArtifact() {
         return artifact;
     }
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/MultipleArtifactsNotFoundException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/MultipleArtifactsNotFoundException.java
index 24dcdb4..96d8c50 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/MultipleArtifactsNotFoundException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/MultipleArtifactsNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -29,9 +28,7 @@
  * Exception caused when one or more artifacts can not be resolved because they are not found in the
  * local or remote repositories.
  */
-public class MultipleArtifactsNotFoundException
-    extends ArtifactResolutionException
-{
+public class MultipleArtifactsNotFoundException extends ArtifactResolutionException {
     private static final String LS = System.lineSeparator();
 
     private final List<Artifact> resolvedArtifacts;
@@ -44,11 +41,11 @@
      * @deprecated use {@link #MultipleArtifactsNotFoundException(Artifact, List, List, List)}
      */
     @Deprecated
-    public MultipleArtifactsNotFoundException( Artifact originatingArtifact,
-                                               List<Artifact> missingArtifacts,
-                                               List<ArtifactRepository> remoteRepositories )
-    {
-        this( originatingArtifact, new ArrayList<>(), missingArtifacts, remoteRepositories );
+    public MultipleArtifactsNotFoundException(
+            Artifact originatingArtifact,
+            List<Artifact> missingArtifacts,
+            List<ArtifactRepository> remoteRepositories) {
+        this(originatingArtifact, new ArrayList<>(), missingArtifacts, remoteRepositories);
     }
 
     /**
@@ -59,12 +56,12 @@
      * @param missingArtifacts    artifacts that could not be resolved
      * @param remoteRepositories  remote repositories where the missing artifacts were not found
      */
-    public MultipleArtifactsNotFoundException( Artifact originatingArtifact,
-                                               List<Artifact> resolvedArtifacts,
-                                               List<Artifact> missingArtifacts,
-                                               List<ArtifactRepository> remoteRepositories )
-    {
-        super( constructMessage( missingArtifacts ), originatingArtifact, remoteRepositories );
+    public MultipleArtifactsNotFoundException(
+            Artifact originatingArtifact,
+            List<Artifact> resolvedArtifacts,
+            List<Artifact> missingArtifacts,
+            List<ArtifactRepository> remoteRepositories) {
+        super(constructMessage(missingArtifacts), originatingArtifact, remoteRepositories);
         this.resolvedArtifacts = resolvedArtifacts;
         this.missingArtifacts = missingArtifacts;
     }
@@ -74,8 +71,7 @@
      *
      * @return {@link List} of {@link Artifact}
      */
-    public List<Artifact> getResolvedArtifacts()
-    {
+    public List<Artifact> getResolvedArtifacts() {
         return resolvedArtifacts;
     }
 
@@ -84,47 +80,47 @@
      *
      * @return {@link List} of {@link Artifact}
      */
-    public List<Artifact> getMissingArtifacts()
-    {
+    public List<Artifact> getMissingArtifacts() {
         return missingArtifacts;
     }
 
-    private static String constructMessage( List<Artifact> artifacts )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
+    private static String constructMessage(List<Artifact> artifacts) {
+        StringBuilder buffer = new StringBuilder(256);
 
-        buffer.append( "Missing:" ).append( LS );
-        buffer.append( "----------" ).append( LS );
+        buffer.append("Missing:").append(LS);
+        buffer.append("----------").append(LS);
 
         int counter = 0;
 
-        for ( Artifact artifact : artifacts )
-        {
-            String message = ( ++counter ) + ") " + artifact.getId();
+        for (Artifact artifact : artifacts) {
+            String message = (++counter) + ") " + artifact.getId();
 
-            buffer.append( constructMissingArtifactMessage( message, "  ", artifact.getGroupId(),
-                    artifact.getArtifactId(), artifact.getVersion(), artifact.getType(), artifact.getClassifier(),
-                    artifact.getDownloadUrl(), artifact.getDependencyTrail() ) );
+            buffer.append(constructMissingArtifactMessage(
+                    message,
+                    "  ",
+                    artifact.getGroupId(),
+                    artifact.getArtifactId(),
+                    artifact.getVersion(),
+                    artifact.getType(),
+                    artifact.getClassifier(),
+                    artifact.getDownloadUrl(),
+                    artifact.getDependencyTrail()));
         }
 
-        buffer.append( "----------" ).append( LS );
+        buffer.append("----------").append(LS);
 
         int size = artifacts.size();
 
-        buffer.append( size ).append( " required artifact" );
+        buffer.append(size).append(" required artifact");
 
-        if ( size > 1 )
-        {
-            buffer.append( "s are" );
-        }
-        else
-        {
-            buffer.append( " is" );
+        if (size > 1) {
+            buffer.append("s are");
+        } else {
+            buffer.append(" is");
         }
 
-        buffer.append( " missing." ).append( LS ).append( LS ).append( "for artifact: " );
+        buffer.append(" missing.").append(LS).append(LS).append("for artifact: ");
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/filter/ArtifactFilter.java b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/filter/ArtifactFilter.java
index 27b08a8..c28331b 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/filter/ArtifactFilter.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/resolver/filter/ArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import org.apache.maven.artifact.Artifact;
 
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-public interface ArtifactFilter
-{
-    boolean include( Artifact artifact );
+public interface ArtifactFilter {
+    boolean include(Artifact artifact);
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ArtifactVersion.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ArtifactVersion.java
index 5b516a9..176af91 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ArtifactVersion.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ArtifactVersion.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 /**
  * Describes an artifact version in terms of its components, converts it to/from a string and
  * compares two versions.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public interface ArtifactVersion
-    extends Comparable<ArtifactVersion>
-{
+public interface ArtifactVersion extends Comparable<ArtifactVersion> {
     int getMajorVersion();
 
     int getMinorVersion();
@@ -38,5 +34,5 @@
 
     String getQualifier();
 
-    void parseVersion( String version );
+    void parseVersion(String version);
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java
index 24c7886..e806eab 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/ComparableVersion.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import java.math.BigInteger;
 import java.util.ArrayDeque;
@@ -27,18 +26,19 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 import java.util.Properties;
 
 /**
  * <p>
  * Generic implementation of version comparison.
  * </p>
- *
+ * <p>
  * Features:
  * <ul>
  * <li>mixing of '<code>-</code>' (hyphen) and '<code>.</code>' (dot) separators,</li>
  * <li>transition between characters and digits also constitutes a separator:
- *     <code>1.0alpha1 =&gt; [1, 0, alpha, 1]</code></li>
+ *     <code>1.0alpha1 =&gt; [1, [alpha, 1]]</code></li>
  * <li>unlimited number of version components,</li>
  * <li>version components in the text can be digits or strings,</li>
  * <li>strings are checked for well-known qualifiers and the qualifier ordering is used for version ordering.
@@ -53,16 +53,15 @@
  *     </ul>
  *     Unknown qualifiers are considered after known qualifiers, with lexical order (always case insensitive),
  *   </li>
- * <li>a hyphen usually precedes a qualifier, and is always less important than something preceded with a dot.</li>
+ * <li>a hyphen usually precedes a qualifier, and is always less important than digits/number, for example
+ *   {@code 1.0.RC2 < 1.0-RC3 < 1.0.1}; but prefer {@code 1.0.0-RC1} over {@code 1.0.0.RC1}, and more
+ *   generally: {@code 1.0.X2 < 1.0-X3 < 1.0.1} for any string {@code X}; but prefer {@code 1.0.0-X1}
+ *   over {@code 1.0.0.X1}.</li>
  * </ul>
  *
- * @see <a href="https://cwiki.apache.org/confluence/display/MAVENOLD/Versioning">"Versioning" on Maven Wiki</a>
- * @author <a href="mailto:kenney@apache.org">Kenney Westerhof</a>
- * @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
+ * @see <a href="https://maven.apache.org/pom.html#version-order-specification">"Versioning" in the POM reference</a>
  */
-public class ComparableVersion
-    implements Comparable<ComparableVersion>
-{
+public class ComparableVersion implements Comparable<ComparableVersion> {
     private static final int MAX_INTITEM_LENGTH = 9;
 
     private static final int MAX_LONGITEM_LENGTH = 18;
@@ -73,15 +72,15 @@
 
     private ListItem items;
 
-    private interface Item
-    {
+    private interface Item {
         int INT_ITEM = 3;
         int LONG_ITEM = 4;
         int BIGINTEGER_ITEM = 0;
         int STRING_ITEM = 1;
         int LIST_ITEM = 2;
+        int COMBINATION_ITEM = 5;
 
-        int compareTo( Item item );
+        int compareTo(Item item);
 
         int getType();
 
@@ -91,258 +90,221 @@
     /**
      * Represents a numeric item in the version item list that can be represented with an int.
      */
-    private static class IntItem
-        implements Item
-    {
+    private static class IntItem implements Item {
         private final int value;
 
         public static final IntItem ZERO = new IntItem();
 
-        private IntItem()
-        {
+        private IntItem() {
             this.value = 0;
         }
 
-        IntItem( String str )
-        {
-            this.value = Integer.parseInt( str );
+        IntItem(String str) {
+            this.value = Integer.parseInt(str);
         }
 
         @Override
-        public int getType()
-        {
+        public int getType() {
             return INT_ITEM;
         }
 
         @Override
-        public boolean isNull()
-        {
+        public boolean isNull() {
             return value == 0;
         }
 
         @Override
-        public int compareTo( Item item )
-        {
-            if ( item == null )
-            {
-                return ( value == 0 ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
+        public int compareTo(Item item) {
+            if (item == null) {
+                return (value == 0) ? 0 : 1; // 1.0 == 1, 1.1 > 1
             }
 
-            switch ( item.getType() )
-            {
+            switch (item.getType()) {
                 case INT_ITEM:
-                    int itemValue = ( (IntItem) item ).value;
-                    return Integer.compare( value, itemValue );
+                    int itemValue = ((IntItem) item).value;
+                    return Integer.compare(value, itemValue);
                 case LONG_ITEM:
                 case BIGINTEGER_ITEM:
                     return -1;
 
                 case STRING_ITEM:
+                    return 1;
+                case COMBINATION_ITEM:
                     return 1; // 1.1 > 1-sp
 
                 case LIST_ITEM:
                     return 1; // 1.1 > 1-1
 
                 default:
-                    throw new IllegalStateException( "invalid item: " + item.getClass() );
+                    throw new IllegalStateException("invalid item: " + item.getClass());
             }
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
+        public boolean equals(Object o) {
+            if (this == o) {
                 return true;
             }
-            if ( o == null || getClass() != o.getClass() )
-            {
+            if (o == null || getClass() != o.getClass()) {
                 return false;
             }
 
             IntItem intItem = (IntItem) o;
 
             return value == intItem.value;
-
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return value;
         }
 
         @Override
-        public String toString()
-        {
-            return Integer.toString( value );
+        public String toString() {
+            return Integer.toString(value);
         }
     }
 
     /**
      * Represents a numeric item in the version item list that can be represented with a long.
      */
-    private static class LongItem
-        implements Item
-    {
+    private static class LongItem implements Item {
         private final long value;
 
-        LongItem( String str )
-        {
-            this.value = Long.parseLong( str );
+        LongItem(String str) {
+            this.value = Long.parseLong(str);
         }
 
         @Override
-        public int getType()
-        {
+        public int getType() {
             return LONG_ITEM;
         }
 
         @Override
-        public boolean isNull()
-        {
+        public boolean isNull() {
             return value == 0;
         }
 
         @Override
-        public int compareTo( Item item )
-        {
-            if ( item == null )
-            {
-                return ( value == 0 ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
+        public int compareTo(Item item) {
+            if (item == null) {
+                return (value == 0) ? 0 : 1; // 1.0 == 1, 1.1 > 1
             }
 
-            switch ( item.getType() )
-            {
+            switch (item.getType()) {
                 case INT_ITEM:
                     return 1;
                 case LONG_ITEM:
-                    long itemValue = ( (LongItem) item ).value;
-                    return Long.compare( value, itemValue );
+                    long itemValue = ((LongItem) item).value;
+                    return Long.compare(value, itemValue);
                 case BIGINTEGER_ITEM:
                     return -1;
 
                 case STRING_ITEM:
+                    return 1;
+                case COMBINATION_ITEM:
                     return 1; // 1.1 > 1-sp
 
                 case LIST_ITEM:
                     return 1; // 1.1 > 1-1
 
                 default:
-                    throw new IllegalStateException( "invalid item: " + item.getClass() );
+                    throw new IllegalStateException("invalid item: " + item.getClass());
             }
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
+        public boolean equals(Object o) {
+            if (this == o) {
                 return true;
             }
-            if ( o == null || getClass() != o.getClass() )
-            {
+            if (o == null || getClass() != o.getClass()) {
                 return false;
             }
 
             LongItem longItem = (LongItem) o;
 
             return value == longItem.value;
-
         }
 
         @Override
-        public int hashCode()
-        {
-            return (int) ( value ^ ( value >>> 32 ) );
+        public int hashCode() {
+            return (int) (value ^ (value >>> 32));
         }
 
         @Override
-        public String toString()
-        {
-            return Long.toString( value );
+        public String toString() {
+            return Long.toString(value);
         }
     }
 
     /**
      * Represents a numeric item in the version item list.
      */
-    private static class BigIntegerItem
-        implements Item
-    {
+    private static class BigIntegerItem implements Item {
         private final BigInteger value;
 
-        BigIntegerItem( String str )
-        {
-            this.value = new BigInteger( str );
+        BigIntegerItem(String str) {
+            this.value = new BigInteger(str);
         }
 
         @Override
-        public int getType()
-        {
+        public int getType() {
             return BIGINTEGER_ITEM;
         }
 
         @Override
-        public boolean isNull()
-        {
-            return BigInteger.ZERO.equals( value );
+        public boolean isNull() {
+            return BigInteger.ZERO.equals(value);
         }
 
         @Override
-        public int compareTo( Item item )
-        {
-            if ( item == null )
-            {
-                return BigInteger.ZERO.equals( value ) ? 0 : 1; // 1.0 == 1, 1.1 > 1
+        public int compareTo(Item item) {
+            if (item == null) {
+                return BigInteger.ZERO.equals(value) ? 0 : 1; // 1.0 == 1, 1.1 > 1
             }
 
-            switch ( item.getType() )
-            {
+            switch (item.getType()) {
                 case INT_ITEM:
                 case LONG_ITEM:
                     return 1;
 
                 case BIGINTEGER_ITEM:
-                    return value.compareTo( ( (BigIntegerItem) item ).value );
+                    return value.compareTo(((BigIntegerItem) item).value);
 
                 case STRING_ITEM:
+                    return 1;
+                case COMBINATION_ITEM:
                     return 1; // 1.1 > 1-sp
 
                 case LIST_ITEM:
                     return 1; // 1.1 > 1-1
 
                 default:
-                    throw new IllegalStateException( "invalid item: " + item.getClass() );
+                    throw new IllegalStateException("invalid item: " + item.getClass());
             }
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
+        public boolean equals(Object o) {
+            if (this == o) {
                 return true;
             }
-            if ( o == null || getClass() != o.getClass() )
-            {
+            if (o == null || getClass() != o.getClass()) {
                 return false;
             }
 
             BigIntegerItem that = (BigIntegerItem) o;
 
-            return value.equals( that.value );
-
+            return value.equals(that.value);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return value.hashCode();
         }
 
-        public String toString()
-        {
+        public String toString() {
             return value.toString();
         }
     }
@@ -350,36 +312,29 @@
     /**
      * Represents a string in the version item list, usually a qualifier.
      */
-    private static class StringItem
-        implements Item
-    {
+    private static class StringItem implements Item {
         private static final List<String> QUALIFIERS =
-                Arrays.asList( "alpha", "beta", "milestone", "rc", "snapshot", "", "sp"  );
+                Arrays.asList("alpha", "beta", "milestone", "rc", "snapshot", "", "sp");
+        private static final List<String> RELEASE_QUALIFIERS = Arrays.asList("ga", "final", "release");
 
         private static final Properties ALIASES = new Properties();
-        static
-        {
-            ALIASES.put( "ga", "" );
-            ALIASES.put( "final", "" );
-            ALIASES.put( "release", "" );
-            ALIASES.put( "cr", "rc" );
+
+        static {
+            ALIASES.put("cr", "rc");
         }
 
         /**
          * A comparable value for the empty-string qualifier. This one is used to determine if a given qualifier makes
          * the version older than one without a qualifier, or more recent.
          */
-        private static final String RELEASE_VERSION_INDEX = String.valueOf( QUALIFIERS.indexOf( "" ) );
+        private static final String RELEASE_VERSION_INDEX = String.valueOf(QUALIFIERS.indexOf(""));
 
         private final String value;
 
-        StringItem( String value, boolean followedByDigit )
-        {
-            if ( followedByDigit && value.length() == 1 )
-            {
+        StringItem(String value, boolean followedByDigit) {
+            if (followedByDigit && value.length() == 1) {
                 // a1 = alpha-1, b1 = beta-1, m1 = milestone-1
-                switch ( value.charAt( 0 ) )
-                {
+                switch (value.charAt(0)) {
                     case 'a':
                         value = "alpha";
                         break;
@@ -392,179 +347,268 @@
                     default:
                 }
             }
-            this.value = ALIASES.getProperty( value , value );
+            this.value = ALIASES.getProperty(value, value);
         }
 
         @Override
-        public int getType()
-        {
+        public int getType() {
             return STRING_ITEM;
         }
 
         @Override
-        public boolean isNull()
-        {
-            return ( comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX ) == 0 );
+        public boolean isNull() {
+            return value == null || value.isEmpty();
         }
 
         /**
          * Returns a comparable value for a qualifier.
-         *
+         * <p>
          * This method takes into account the ordering of known qualifiers then unknown qualifiers with lexical
          * ordering.
-         *
-         * just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for -1
-         * or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first character,
-         * so this is still fast. If more characters are needed then it requires a lexical sort anyway.
+         * <p>
          *
          * @param qualifier
          * @return an equivalent value that can be used with lexical comparison
          */
-        public static String comparableQualifier( String qualifier )
-        {
-            int i = QUALIFIERS.indexOf( qualifier );
+        public static String comparableQualifier(String qualifier) {
+            if (RELEASE_QUALIFIERS.contains(qualifier)) {
+                return String.valueOf(QUALIFIERS.indexOf(""));
+            }
 
-            return i == -1 ? ( QUALIFIERS.size() + "-" + qualifier ) : String.valueOf( i );
+            int i = QUALIFIERS.indexOf(qualifier);
+
+            // Just returning an Integer with the index here is faster, but requires a lot of if/then/else to check for
+            // -1
+            //  or QUALIFIERS.size and then resort to lexical ordering. Most comparisons are decided by the first
+            // character,
+            // so this is still fast. If more characters are needed then it requires a lexical sort anyway.
+            return i == -1 ? (QUALIFIERS.size() + "-" + qualifier) : String.valueOf(i);
         }
 
         @Override
-        public int compareTo( Item item )
-        {
-            if ( item == null )
-            {
+        public int compareTo(Item item) {
+            if (item == null) {
                 // 1-rc < 1, 1-ga > 1
-                return comparableQualifier( value ).compareTo( RELEASE_VERSION_INDEX );
+                return comparableQualifier(value).compareTo(RELEASE_VERSION_INDEX);
             }
-            switch ( item.getType() )
-            {
+            switch (item.getType()) {
                 case INT_ITEM:
                 case LONG_ITEM:
                 case BIGINTEGER_ITEM:
                     return -1; // 1.any < 1.1 ?
 
                 case STRING_ITEM:
-                    return comparableQualifier( value ).compareTo( comparableQualifier( ( (StringItem) item ).value ) );
+                    return comparableQualifier(value).compareTo(comparableQualifier(((StringItem) item).value));
+
+                case COMBINATION_ITEM:
+                    int result = this.compareTo(((CombinationItem) item).getStringPart());
+                    if (result == 0) {
+                        return -1;
+                    }
+                    return result;
 
                 case LIST_ITEM:
                     return -1; // 1.any < 1-1
 
                 default:
-                    throw new IllegalStateException( "invalid item: " + item.getClass() );
+                    throw new IllegalStateException("invalid item: " + item.getClass());
             }
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
+        public boolean equals(Object o) {
+            if (this == o) {
                 return true;
             }
-            if ( o == null || getClass() != o.getClass() )
-            {
+            if (o == null || getClass() != o.getClass()) {
                 return false;
             }
 
             StringItem that = (StringItem) o;
 
-            return value.equals( that.value );
-
+            return value.equals(that.value);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return value.hashCode();
         }
 
-        public String toString()
-        {
+        public String toString() {
             return value;
         }
     }
 
     /**
+     * Represents a combination in the version item list.
+     * It is usually a combination of a string and a number, with the string first and the number second.
+     */
+    private static class CombinationItem implements Item {
+
+        StringItem stringPart;
+
+        Item digitPart;
+
+        CombinationItem(String value) {
+            int index = 0;
+            for (int i = 0; i < value.length(); i++) {
+                char c = value.charAt(i);
+                if (Character.isDigit(c)) {
+                    index = i;
+                    break;
+                }
+            }
+
+            stringPart = new StringItem(value.substring(0, index), true);
+            digitPart = parseItem(true, value.substring(index));
+        }
+
+        @Override
+        public int compareTo(Item item) {
+            if (item == null) {
+                // 1-rc1 < 1, 1-ga1 > 1
+                return stringPart.compareTo(item);
+            }
+            int result = 0;
+            switch (item.getType()) {
+                case INT_ITEM:
+                case LONG_ITEM:
+                case BIGINTEGER_ITEM:
+                    return -1;
+
+                case STRING_ITEM:
+                    result = stringPart.compareTo(item);
+                    if (result == 0) {
+                        // X1 > X
+                        return 1;
+                    }
+                    return result;
+
+                case LIST_ITEM:
+                    return -1;
+
+                case COMBINATION_ITEM:
+                    result = stringPart.compareTo(((CombinationItem) item).getStringPart());
+                    if (result == 0) {
+                        return digitPart.compareTo(((CombinationItem) item).getDigitPart());
+                    }
+                    return result;
+                default:
+                    return 0;
+            }
+        }
+
+        public StringItem getStringPart() {
+            return stringPart;
+        }
+
+        public Item getDigitPart() {
+            return digitPart;
+        }
+
+        @Override
+        public int getType() {
+            return COMBINATION_ITEM;
+        }
+
+        @Override
+        public boolean isNull() {
+            return false;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            CombinationItem that = (CombinationItem) o;
+            return Objects.equals(stringPart, that.stringPart) && Objects.equals(digitPart, that.digitPart);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(stringPart, digitPart);
+        }
+
+        @Override
+        public String toString() {
+            return stringPart.toString() + digitPart.toString();
+        }
+    }
+
+    /**
      * Represents a version list item. This class is used both for the global item list and for sub-lists (which start
      * with '-(number)' in the version specification).
      */
-    private static class ListItem
-        extends ArrayList<Item>
-        implements Item
-    {
+    private static class ListItem extends ArrayList<Item> implements Item {
         @Override
-        public int getType()
-        {
+        public int getType() {
             return LIST_ITEM;
         }
 
         @Override
-        public boolean isNull()
-        {
-            return ( size() == 0 );
+        public boolean isNull() {
+            return (size() == 0);
         }
 
-        void normalize()
-        {
-            for ( int i = size() - 1; i >= 0; i-- )
-            {
-                Item lastItem = get( i );
+        void normalize() {
+            for (int i = size() - 1; i >= 0; i--) {
+                Item lastItem = get(i);
 
-                if ( lastItem.isNull() )
-                {
-                    // remove null trailing items: 0, "", empty list
-                    remove( i );
-                }
-                else if ( !( lastItem instanceof ListItem ) )
-                {
-                    break;
+                if (lastItem.isNull()) {
+                    if (i == size() - 1 || get(i + 1).getType() == STRING_ITEM) {
+                        remove(i);
+                    } else if (get(i + 1).getType() == LIST_ITEM) {
+                        Item item = ((ListItem) get(i + 1)).get(0);
+                        if (item.getType() == COMBINATION_ITEM || item.getType() == STRING_ITEM) {
+                            remove(i);
+                        }
+                    }
                 }
             }
         }
 
         @Override
-        public int compareTo( Item item )
-        {
-            if ( item == null )
-            {
-                if ( size() == 0 )
-                {
+        public int compareTo(Item item) {
+            if (item == null) {
+                if (size() == 0) {
                     return 0; // 1-0 = 1- (normalize) = 1
                 }
                 // Compare the entire list of items with null - not just the first one, MNG-6964
-                for ( Item i : this )
-                {
-                    int result = i.compareTo( null );
-                    if ( result != 0 )
-                    {
+                for (Item i : this) {
+                    int result = i.compareTo(null);
+                    if (result != 0) {
                         return result;
                     }
                 }
                 return 0;
             }
-            switch ( item.getType() )
-            {
+            switch (item.getType()) {
                 case INT_ITEM:
                 case LONG_ITEM:
                 case BIGINTEGER_ITEM:
                     return -1; // 1-1 < 1.0.x
 
                 case STRING_ITEM:
+                    return 1;
+                case COMBINATION_ITEM:
                     return 1; // 1-1 > 1-sp
 
                 case LIST_ITEM:
                     Iterator<Item> left = iterator();
-                    Iterator<Item> right = ( (ListItem) item ).iterator();
+                    Iterator<Item> right = ((ListItem) item).iterator();
 
-                    while ( left.hasNext() || right.hasNext() )
-                    {
+                    while (left.hasNext() || right.hasNext()) {
                         Item l = left.hasNext() ? left.next() : null;
                         Item r = right.hasNext() ? right.next() : null;
 
                         // if this is shorter, then invert the compare and mul with -1
-                        int result = l == null ? ( r == null ? 0 : -1 * r.compareTo( l ) ) : l.compareTo( r );
+                        int result = l == null ? (r == null ? 0 : -1 * r.compareTo(l)) : l.compareTo(r);
 
-                        if ( result != 0 )
-                        {
+                        if (result != 0) {
                             return result;
                         }
                     }
@@ -572,21 +616,18 @@
                     return 0;
 
                 default:
-                    throw new IllegalStateException( "invalid item: " + item.getClass() );
+                    throw new IllegalStateException("invalid item: " + item.getClass());
             }
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             StringBuilder buffer = new StringBuilder();
-            for ( Item item : this )
-            {
-                if ( buffer.length() > 0 )
-                {
-                    buffer.append( ( item instanceof ListItem ) ? '-' : '.' );
+            for (Item item : this) {
+                if (buffer.length() > 0) {
+                    buffer.append((item instanceof ListItem) ? '-' : '.');
                 }
-                buffer.append( item );
+                buffer.append(item);
             }
             return buffer.toString();
         }
@@ -594,195 +635,185 @@
         /**
          * Return the contents in the same format that is used when you call toString() on a List.
          */
-        private String toListString()
-        {
+        private String toListString() {
             StringBuilder buffer = new StringBuilder();
-            buffer.append( "[" );
-            for ( Item item : this )
-            {
-                if ( buffer.length() > 1 )
-                {
-                    buffer.append( ", " );
+            buffer.append("[");
+            for (Item item : this) {
+                if (buffer.length() > 1) {
+                    buffer.append(", ");
                 }
-                if ( item instanceof ListItem )
-                {
-                    buffer.append( ( (ListItem ) item ).toListString() );
-                }
-                else
-                {
-                    buffer.append( item );
+                if (item instanceof ListItem) {
+                    buffer.append(((ListItem) item).toListString());
+                } else {
+                    buffer.append(item);
                 }
             }
-            buffer.append( "]" );
+            buffer.append("]");
             return buffer.toString();
         }
     }
 
-    public ComparableVersion( String version )
-    {
-        parseVersion( version );
+    public ComparableVersion(String version) {
+        parseVersion(version);
     }
 
-    @SuppressWarnings( "checkstyle:innerassignment" )
-    public final void parseVersion( String version )
-    {
+    @SuppressWarnings("checkstyle:innerassignment")
+    public final void parseVersion(String version) {
         this.value = version;
 
         items = new ListItem();
 
-        version = version.toLowerCase( Locale.ENGLISH );
+        version = version.toLowerCase(Locale.ENGLISH);
 
         ListItem list = items;
 
         Deque<Item> stack = new ArrayDeque<>();
-        stack.push( list );
+        stack.push(list);
 
         boolean isDigit = false;
 
+        boolean isCombination = false;
+
         int startIndex = 0;
 
-        for ( int i = 0; i < version.length(); i++ )
-        {
-            char c = version.charAt( i );
+        for (int i = 0; i < version.length(); i++) {
+            char c = version.charAt(i);
 
-            if ( c == '.' )
-            {
-                if ( i == startIndex )
-                {
-                    list.add( IntItem.ZERO );
+            if (c == '.') {
+                if (i == startIndex) {
+                    list.add(IntItem.ZERO);
+                } else {
+                    list.add(parseItem(isCombination, isDigit, version.substring(startIndex, i)));
                 }
-                else
-                {
-                    list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
-                }
+                isCombination = false;
                 startIndex = i + 1;
-            }
-            else if ( c == '-' )
-            {
-                if ( i == startIndex )
-                {
-                    list.add( IntItem.ZERO );
-                }
-                else
-                {
-                    list.add( parseItem( isDigit, version.substring( startIndex, i ) ) );
+            } else if (c == '-') {
+                if (i == startIndex) {
+                    list.add(IntItem.ZERO);
+                } else {
+                    // X-1 is going to be treated as X1
+                    if (!isDigit && i != version.length() - 1) {
+                        char c1 = version.charAt(i + 1);
+                        if (Character.isDigit(c1)) {
+                            isCombination = true;
+                            continue;
+                        }
+                    }
+                    list.add(parseItem(isCombination, isDigit, version.substring(startIndex, i)));
                 }
                 startIndex = i + 1;
 
-                list.add( list = new ListItem() );
-                stack.push( list );
-            }
-            else if ( Character.isDigit( c ) )
-            {
-                if ( !isDigit && i > startIndex )
-                {
-                    list.add( new StringItem( version.substring( startIndex, i ), true ) );
-                    startIndex = i;
+                if (!list.isEmpty()) {
+                    list.add(list = new ListItem());
+                    stack.push(list);
+                }
+                isCombination = false;
+            } else if (Character.isDigit(c)) {
+                if (!isDigit && i > startIndex) {
+                    // X1
+                    isCombination = true;
 
-                    list.add( list = new ListItem() );
-                    stack.push( list );
+                    if (!list.isEmpty()) {
+                        list.add(list = new ListItem());
+                        stack.push(list);
+                    }
                 }
 
                 isDigit = true;
-            }
-            else
-            {
-                if ( isDigit && i > startIndex )
-                {
-                    list.add( parseItem( true, version.substring( startIndex, i ) ) );
+            } else {
+                if (isDigit && i > startIndex) {
+                    list.add(parseItem(isCombination, true, version.substring(startIndex, i)));
                     startIndex = i;
 
-                    list.add( list = new ListItem() );
-                    stack.push( list );
+                    list.add(list = new ListItem());
+                    stack.push(list);
+                    isCombination = false;
                 }
 
                 isDigit = false;
             }
         }
 
-        if ( version.length() > startIndex )
-        {
-            list.add( parseItem( isDigit, version.substring( startIndex ) ) );
+        if (version.length() > startIndex) {
+            // 1.0.0.X1 < 1.0.0-X2
+            // treat .X as -X for any string qualifier X
+            if (!isDigit && !list.isEmpty()) {
+                list.add(list = new ListItem());
+                stack.push(list);
+            }
+
+            list.add(parseItem(isCombination, isDigit, version.substring(startIndex)));
         }
 
-        while ( !stack.isEmpty() )
-        {
+        while (!stack.isEmpty()) {
             list = (ListItem) stack.pop();
             list.normalize();
         }
     }
 
-    private static Item parseItem( boolean isDigit, String buf )
-    {
-        if ( isDigit )
-        {
-            buf = stripLeadingZeroes( buf );
-            if ( buf.length() <= MAX_INTITEM_LENGTH )
-            {
-                // lower than 2^31
-                return new IntItem( buf );
-            }
-            else if ( buf.length() <= MAX_LONGITEM_LENGTH )
-            {
-                // lower than 2^63
-                return new LongItem( buf );
-            }
-            return new BigIntegerItem( buf );
-        }
-        return new StringItem( buf, false );
+    private static Item parseItem(boolean isDigit, String buf) {
+        return parseItem(false, isDigit, buf);
     }
 
-    private static String stripLeadingZeroes( String buf )
-    {
-        if ( buf == null || buf.isEmpty() )
-        {
+    private static Item parseItem(boolean isCombination, boolean isDigit, String buf) {
+        if (isCombination) {
+            return new CombinationItem(buf.replace("-", ""));
+        } else if (isDigit) {
+            buf = stripLeadingZeroes(buf);
+            if (buf.length() <= MAX_INTITEM_LENGTH) {
+                // lower than 2^31
+                return new IntItem(buf);
+            } else if (buf.length() <= MAX_LONGITEM_LENGTH) {
+                // lower than 2^63
+                return new LongItem(buf);
+            }
+            return new BigIntegerItem(buf);
+        }
+        return new StringItem(buf, false);
+    }
+
+    private static String stripLeadingZeroes(String buf) {
+        if (buf == null || buf.isEmpty()) {
             return "0";
         }
-        for ( int i = 0; i < buf.length(); ++i )
-        {
-            char c = buf.charAt( i );
-            if ( c != '0' )
-            {
-                return buf.substring( i );
+        for (int i = 0; i < buf.length(); ++i) {
+            char c = buf.charAt(i);
+            if (c != '0') {
+                return buf.substring(i);
             }
         }
         return buf;
     }
 
     @Override
-    public int compareTo( ComparableVersion o )
-    {
-        return items.compareTo( o.items );
+    public int compareTo(ComparableVersion o) {
+        return items.compareTo(o.items);
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return value;
     }
 
-    public String getCanonical()
-    {
-        if ( canonical == null )
-        {
+    public String getCanonical() {
+        if (canonical == null) {
             canonical = items.toString();
         }
         return canonical;
     }
 
     @Override
-    public boolean equals( Object o )
-    {
-        return ( o instanceof ComparableVersion ) && items.equals( ( (ComparableVersion) o ).items );
+    public boolean equals(Object o) {
+        return (o instanceof ComparableVersion) && items.equals(((ComparableVersion) o).items);
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         return items.hashCode();
     }
 
     // CHECKSTYLE_OFF: LineLength
+
     /**
      * Main to test version parsing and comparison.
      * <p>
@@ -797,33 +828,29 @@
      * </pre>
      *
      * @param args the version strings to parse and compare. You can pass arbitrary number of version strings and always
-     * two adjacent will be compared
+     *             two adjacent will be compared.
      */
     // CHECKSTYLE_ON: LineLength
-    public static void main( String... args )
-    {
-        System.out.println( "Display parameters as parsed by Maven (in canonical form and as a list of tokens) and"
-                                + " comparison result:" );
-        if ( args.length == 0 )
-        {
+    public static void main(String... args) {
+        System.out.println("Display parameters as parsed by Maven (in canonical form and as a list of tokens) and"
+                + " comparison result:");
+        if (args.length == 0) {
             return;
         }
 
         ComparableVersion prev = null;
         int i = 1;
-        for ( String version : args )
-        {
-            ComparableVersion c = new ComparableVersion( version );
+        for (String version : args) {
+            ComparableVersion c = new ComparableVersion(version);
 
-            if ( prev != null )
-            {
-                int compare = prev.compareTo( c );
-                System.out.println( "   " + prev.toString() + ' '
-                    + ( ( compare == 0 ) ? "==" : ( ( compare < 0 ) ? "<" : ">" ) ) + ' ' + version );
+            if (prev != null) {
+                int compare = prev.compareTo(c);
+                System.out.println("   " + prev.toString() + ' ' + ((compare == 0) ? "==" : ((compare < 0) ? "<" : ">"))
+                        + ' ' + version);
             }
 
-            System.out.println( ( i++ ) + ". " + version + " -> " + c.getCanonical()
-                                    + "; tokens: " + c.items.toListString() );
+            System.out.println(
+                    (i++) + ". " + version + " -> " + c.getCanonical() + "; tokens: " + c.items.toListString());
 
             prev = c;
         }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/DefaultArtifactVersion.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/DefaultArtifactVersion.java
index cf81eb3..039b383 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/DefaultArtifactVersion.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/DefaultArtifactVersion.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.StringTokenizer;
-
-import static org.apache.commons.lang3.math.NumberUtils.isDigits;
+package org.apache.maven.artifact.versioning;
 
 /**
  * Default implementation of artifact versioning.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class DefaultArtifactVersion
-    implements ArtifactVersion
-{
+public class DefaultArtifactVersion implements ArtifactVersion {
     private Integer majorVersion;
 
     private Integer minorVersion;
@@ -43,162 +35,125 @@
 
     private ComparableVersion comparable;
 
-    public DefaultArtifactVersion( String version )
-    {
-        parseVersion( version );
+    public DefaultArtifactVersion(String version) {
+        parseVersion(version);
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         return 11 + comparable.hashCode();
     }
 
     @Override
-    public boolean equals( Object other )
-    {
-        if ( this == other )
-        {
+    public boolean equals(Object other) {
+        if (this == other) {
             return true;
         }
 
-        if ( !( other instanceof ArtifactVersion ) )
-        {
+        if (!(other instanceof ArtifactVersion)) {
             return false;
         }
 
-        return compareTo( (ArtifactVersion) other ) == 0;
+        return compareTo((ArtifactVersion) other) == 0;
     }
 
-    public int compareTo( ArtifactVersion otherVersion )
-    {
-        if ( otherVersion instanceof DefaultArtifactVersion )
-        {
-            return this.comparable.compareTo( ( (DefaultArtifactVersion) otherVersion ).comparable );
-        }
-        else
-        {
-            return compareTo( new DefaultArtifactVersion( otherVersion.toString() ) );
+    public int compareTo(ArtifactVersion otherVersion) {
+        if (otherVersion instanceof DefaultArtifactVersion) {
+            return this.comparable.compareTo(((DefaultArtifactVersion) otherVersion).comparable);
+        } else {
+            return compareTo(new DefaultArtifactVersion(otherVersion.toString()));
         }
     }
 
-    public int getMajorVersion()
-    {
+    public int getMajorVersion() {
         return majorVersion != null ? majorVersion : 0;
     }
 
-    public int getMinorVersion()
-    {
+    public int getMinorVersion() {
         return minorVersion != null ? minorVersion : 0;
     }
 
-    public int getIncrementalVersion()
-    {
+    public int getIncrementalVersion() {
         return incrementalVersion != null ? incrementalVersion : 0;
     }
 
-    public int getBuildNumber()
-    {
+    public int getBuildNumber() {
         return buildNumber != null ? buildNumber : 0;
     }
 
-    public String getQualifier()
-    {
+    public String getQualifier() {
         return qualifier;
     }
 
-    public final void parseVersion( String version )
-    {
-        comparable = new ComparableVersion( version );
+    public final void parseVersion(String version) {
+        comparable = new ComparableVersion(version);
 
-        int index = version.indexOf( '-' );
+        int index = version.indexOf('-');
 
         String part1;
         String part2 = null;
 
-        if ( index < 0 )
-        {
+        if (index < 0) {
             part1 = version;
-        }
-        else
-        {
-            part1 = version.substring( 0, index );
-            part2 = version.substring( index + 1 );
+        } else {
+            part1 = version.substring(0, index);
+            part2 = version.substring(index + 1);
         }
 
-        if ( part2 != null )
-        {
-            if ( part2.length() == 1  || !part2.startsWith( "0" ) )
-            {
-                buildNumber = tryParseInt( part2 );
-                if ( buildNumber == null )
-                {
+        if (part2 != null) {
+            if (part2.length() == 1 || !part2.startsWith("0")) {
+                buildNumber = tryParseInt(part2);
+                if (buildNumber == null) {
                     qualifier = part2;
                 }
-            }
-            else
-            {
+            } else {
                 qualifier = part2;
             }
         }
 
-        if ( ( !part1.contains( "." ) ) && !part1.startsWith( "0" ) )
-        {
-            majorVersion = tryParseInt( part1 );
-            if ( majorVersion == null )
-            {
+        if ((!part1.contains(".")) && !part1.startsWith("0")) {
+            majorVersion = tryParseInt(part1);
+            if (majorVersion == null) {
                 // qualifier is the whole version, including "-"
                 qualifier = version;
                 buildNumber = null;
             }
-        }
-        else
-        {
+        } else {
             boolean fallback = false;
 
-            StringTokenizer tok = new StringTokenizer( part1, "." );
-            if ( tok.hasMoreTokens() )
-            {
-                majorVersion = getNextIntegerToken( tok );
-                if ( majorVersion == null )
-                {
+            String[] tok = part1.split("\\.");
+            int idx = 0;
+            if (idx < tok.length) {
+                majorVersion = getNextIntegerToken(tok[idx++]);
+                if (majorVersion == null) {
                     fallback = true;
                 }
-            }
-            else
-            {
+            } else {
                 fallback = true;
             }
-            if ( tok.hasMoreTokens() )
-            {
-                minorVersion = getNextIntegerToken( tok );
-                if ( minorVersion == null )
-                {
+            if (idx < tok.length) {
+                minorVersion = getNextIntegerToken(tok[idx++]);
+                if (minorVersion == null) {
                     fallback = true;
                 }
             }
-            if ( tok.hasMoreTokens() )
-            {
-                incrementalVersion = getNextIntegerToken( tok );
-                if ( incrementalVersion == null )
-                {
+            if (idx < tok.length) {
+                incrementalVersion = getNextIntegerToken(tok[idx++]);
+                if (incrementalVersion == null) {
                     fallback = true;
                 }
             }
-            if ( tok.hasMoreTokens() )
-            {
-                qualifier = tok.nextToken();
-                fallback = isDigits( qualifier );
+            if (idx < tok.length) {
+                qualifier = tok[idx++];
+                fallback = isDigits(qualifier);
             }
 
             // string tokenizer won't detect these and ignores them
-            if ( part1.contains( ".." ) || part1.startsWith( "." ) || part1.endsWith( "." ) )
-            {
+            if (part1.contains("..") || part1.startsWith(".") || part1.endsWith(".")) {
                 fallback = true;
             }
 
-            if ( fallback )
-            {
+            if (fallback) {
                 // qualifier is the whole version, including "-"
                 qualifier = version;
                 majorVersion = null;
@@ -209,43 +164,46 @@
         }
     }
 
-    private static Integer getNextIntegerToken( StringTokenizer tok )
-    {
-        String s = tok.nextToken();
-        if ( ( s.length() > 1 ) && s.startsWith( "0" ) )
-        {
-            return null;
+    private static boolean isDigits(String cs) {
+        if (cs == null || cs.isEmpty()) {
+            return false;
         }
-        return tryParseInt( s );
+        final int sz = cs.length();
+        for (int i = 0; i < sz; i++) {
+            if (!Character.isDigit(cs.charAt(i))) {
+                return false;
+            }
+        }
+        return true;
     }
 
-    private static Integer tryParseInt( String s )
-    {
+    private static Integer getNextIntegerToken(String s) {
+        if ((s.length() > 1) && s.startsWith("0")) {
+            return null;
+        }
+        return tryParseInt(s);
+    }
+
+    private static Integer tryParseInt(String s) {
         // for performance, check digits instead of relying later on catching NumberFormatException
-        if ( !isDigits( s ) )
-        {
+        if (!isDigits(s)) {
             return null;
         }
 
-        try
-        {
-            long longValue = Long.parseLong( s );
-            if ( longValue > Integer.MAX_VALUE )
-            {
+        try {
+            long longValue = Long.parseLong(s);
+            if (longValue > Integer.MAX_VALUE) {
                 return null;
             }
             return (int) longValue;
-        }
-        catch ( NumberFormatException e )
-        {
+        } catch (NumberFormatException e) {
             // should never happen since checked isDigits(s) before
             return null;
         }
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return comparable.toString();
     }
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/InvalidVersionSpecificationException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/InvalidVersionSpecificationException.java
index adc48b9..abc4038 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/InvalidVersionSpecificationException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/InvalidVersionSpecificationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 /**
  * Occurs when a version is invalid.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class InvalidVersionSpecificationException
-    extends Exception
-{
-    public InvalidVersionSpecificationException( String message )
-    {
-        super( message );
+public class InvalidVersionSpecificationException extends Exception {
+    public InvalidVersionSpecificationException(String message) {
+        super(message);
     }
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/OverConstrainedVersionException.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/OverConstrainedVersionException.java
index bd8f383..9a07592 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/OverConstrainedVersionException.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/OverConstrainedVersionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import java.util.List;
 
@@ -28,22 +27,13 @@
 /**
  * Occurs when ranges exclude each other and no valid value remains.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class OverConstrainedVersionException
-    extends ArtifactResolutionException
-{
-    public OverConstrainedVersionException( String msg,
-                                            Artifact artifact )
-    {
-        super( msg, artifact );
+public class OverConstrainedVersionException extends ArtifactResolutionException {
+    public OverConstrainedVersionException(String msg, Artifact artifact) {
+        super(msg, artifact);
     }
 
-    public OverConstrainedVersionException( String msg,
-                                            Artifact artifact,
-                                            List<ArtifactRepository> remoteRepositories )
-    {
-        super( msg, artifact, remoteRepositories );
+    public OverConstrainedVersionException(String msg, Artifact artifact, List<ArtifactRepository> remoteRepositories) {
+        super(msg, artifact, remoteRepositories);
     }
-
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/Restriction.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/Restriction.java
index 2b37793..89c06e7 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/Restriction.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/Restriction.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 /**
  * Describes a restriction in versioning.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class Restriction
-{
+public class Restriction {
     private final ArtifactVersion lowerBound;
 
     private final boolean lowerBoundInclusive;
@@ -34,58 +31,50 @@
 
     private final boolean upperBoundInclusive;
 
-    public static final Restriction EVERYTHING = new Restriction( null, false, null, false );
+    public static final Restriction EVERYTHING = new Restriction(null, false, null, false);
 
-    public Restriction( ArtifactVersion lowerBound, boolean lowerBoundInclusive, ArtifactVersion upperBound,
-                        boolean upperBoundInclusive )
-    {
+    public Restriction(
+            ArtifactVersion lowerBound,
+            boolean lowerBoundInclusive,
+            ArtifactVersion upperBound,
+            boolean upperBoundInclusive) {
         this.lowerBound = lowerBound;
         this.lowerBoundInclusive = lowerBoundInclusive;
         this.upperBound = upperBound;
         this.upperBoundInclusive = upperBoundInclusive;
     }
 
-    public ArtifactVersion getLowerBound()
-    {
+    public ArtifactVersion getLowerBound() {
         return lowerBound;
     }
 
-    public boolean isLowerBoundInclusive()
-    {
+    public boolean isLowerBoundInclusive() {
         return lowerBoundInclusive;
     }
 
-    public ArtifactVersion getUpperBound()
-    {
+    public ArtifactVersion getUpperBound() {
         return upperBound;
     }
 
-    public boolean isUpperBoundInclusive()
-    {
+    public boolean isUpperBoundInclusive() {
         return upperBoundInclusive;
     }
 
-    public boolean containsVersion( ArtifactVersion version )
-    {
-        if ( lowerBound != null )
-        {
-            int comparison = lowerBound.compareTo( version );
+    public boolean containsVersion(ArtifactVersion version) {
+        if (lowerBound != null) {
+            int comparison = lowerBound.compareTo(version);
 
-            if ( ( comparison == 0 ) && !lowerBoundInclusive )
-            {
+            if ((comparison == 0) && !lowerBoundInclusive) {
                 return false;
             }
-            if ( comparison > 0 )
-            {
+            if (comparison > 0) {
                 return false;
             }
         }
-        if ( upperBound != null )
-        {
-            int comparison = upperBound.compareTo( version );
+        if (upperBound != null) {
+            int comparison = upperBound.compareTo(version);
 
-            if ( ( comparison == 0 ) && !upperBoundInclusive )
-            {
+            if ((comparison == 0) && !upperBoundInclusive) {
                 return false;
             }
             return comparison >= 0;
@@ -95,27 +84,20 @@
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int result = 13;
 
-        if ( lowerBound == null )
-        {
+        if (lowerBound == null) {
             result += 1;
-        }
-        else
-        {
+        } else {
             result += lowerBound.hashCode();
         }
 
         result *= lowerBoundInclusive ? 1 : 2;
 
-        if ( upperBound == null )
-        {
+        if (upperBound == null) {
             result -= 3;
-        }
-        else
-        {
+        } else {
             result -= upperBound.hashCode();
         }
 
@@ -125,67 +107,51 @@
     }
 
     @Override
-    public boolean equals( Object other )
-    {
-        if ( this == other )
-        {
+    public boolean equals(Object other) {
+        if (this == other) {
             return true;
         }
 
-        if ( !( other instanceof Restriction ) )
-        {
+        if (!(other instanceof Restriction)) {
             return false;
         }
 
         Restriction restriction = (Restriction) other;
-        if ( lowerBound != null )
-        {
-            if ( !lowerBound.equals( restriction.lowerBound ) )
-            {
+        if (lowerBound != null) {
+            if (!lowerBound.equals(restriction.lowerBound)) {
                 return false;
             }
-        }
-        else if ( restriction.lowerBound != null )
-        {
+        } else if (restriction.lowerBound != null) {
             return false;
         }
 
-        if ( lowerBoundInclusive != restriction.lowerBoundInclusive )
-        {
+        if (lowerBoundInclusive != restriction.lowerBoundInclusive) {
             return false;
         }
 
-        if ( upperBound != null )
-        {
-            if ( !upperBound.equals( restriction.upperBound ) )
-            {
+        if (upperBound != null) {
+            if (!upperBound.equals(restriction.upperBound)) {
                 return false;
             }
-        }
-        else if ( restriction.upperBound != null )
-        {
+        } else if (restriction.upperBound != null) {
             return false;
         }
 
         return upperBoundInclusive == restriction.upperBoundInclusive;
-
     }
 
-    public String toString()
-    {
+    public String toString() {
         StringBuilder buf = new StringBuilder();
 
-        buf.append( isLowerBoundInclusive() ? '[' : '(' );
-        if ( getLowerBound() != null )
-        {
-            buf.append( getLowerBound().toString() );
+        buf.append(isLowerBoundInclusive() ? '[' : '(');
+        if (getLowerBound() != null) {
+            buf.append(getLowerBound().toString());
         }
-        buf.append( ',' );
-        if ( getUpperBound() != null )
-        {
-            buf.append( getUpperBound().toString() );
+        buf.append(',');
+        if (getUpperBound() != null) {
+            buf.append(getUpperBound().toString());
         }
-        buf.append( isUpperBoundInclusive() ? ']' : ')' );
+        buf.append(isUpperBoundInclusive() ? ']' : ')');
 
         return buf.toString();
     }
diff --git a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java
index 8267a45..9650034 100644
--- a/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java
+++ b/maven-artifact/src/main/java/org/apache/maven/artifact/versioning/VersionRange.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,48 +16,41 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.WeakHashMap;
 import java.util.Objects;
+import java.util.WeakHashMap;
 
 import org.apache.maven.artifact.Artifact;
 
 /**
  * Construct a version range from a specification.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class VersionRange
-{
-    private static final Map<String, VersionRange> CACHE_SPEC =
-        Collections.synchronizedMap( new WeakHashMap<>() );
+public class VersionRange {
+    private static final Map<String, VersionRange> CACHE_SPEC = Collections.synchronizedMap(new WeakHashMap<>());
 
-    private static final Map<String, VersionRange> CACHE_VERSION =
-                    Collections.synchronizedMap( new WeakHashMap<>() );
+    private static final Map<String, VersionRange> CACHE_VERSION = Collections.synchronizedMap(new WeakHashMap<>());
 
     private final ArtifactVersion recommendedVersion;
 
     private final List<Restriction> restrictions;
 
-    private VersionRange( ArtifactVersion recommendedVersion,
-                          List<Restriction> restrictions )
-    {
+    private VersionRange(ArtifactVersion recommendedVersion, List<Restriction> restrictions) {
         this.recommendedVersion = recommendedVersion;
         this.restrictions = restrictions;
     }
 
-    public ArtifactVersion getRecommendedVersion()
-    {
+    public ArtifactVersion getRecommendedVersion() {
         return recommendedVersion;
     }
 
-    public List<Restriction> getRestrictions()
-    {
+    public List<Restriction> getRestrictions() {
         return restrictions;
     }
 
@@ -68,21 +59,18 @@
      * @return a clone
      */
     @Deprecated
-    public VersionRange cloneOf()
-    {
+    public VersionRange cloneOf() {
         List<Restriction> copiedRestrictions = null;
 
-        if ( restrictions != null )
-        {
+        if (restrictions != null) {
             copiedRestrictions = new ArrayList<>();
 
-            if ( !restrictions.isEmpty() )
-            {
-                copiedRestrictions.addAll( restrictions );
+            if (!restrictions.isEmpty()) {
+                copiedRestrictions.addAll(restrictions);
             }
         }
 
-        return new VersionRange( recommendedVersion, copiedRestrictions );
+        return new VersionRange(recommendedVersion, copiedRestrictions);
     }
 
     /**
@@ -103,17 +91,13 @@
      * @return a new {@link VersionRange} object that represents the spec
      * @throws InvalidVersionSpecificationException if invalid version specification
      */
-    public static VersionRange createFromVersionSpec( String spec )
-        throws InvalidVersionSpecificationException
-    {
-        if ( spec == null )
-        {
+    public static VersionRange createFromVersionSpec(String spec) throws InvalidVersionSpecificationException {
+        if (spec == null) {
             return null;
         }
 
-        VersionRange cached = CACHE_SPEC.get( spec );
-        if ( cached != null )
-        {
+        VersionRange cached = CACHE_SPEC.get(spec);
+        if (cached != null) {
             return cached;
         }
 
@@ -123,129 +107,106 @@
         ArtifactVersion upperBound = null;
         ArtifactVersion lowerBound = null;
 
-        while ( process.startsWith( "[" ) || process.startsWith( "(" ) )
-        {
-            int index1 = process.indexOf( ')' );
-            int index2 = process.indexOf( ']' );
+        while (process.startsWith("[") || process.startsWith("(")) {
+            int index1 = process.indexOf(')');
+            int index2 = process.indexOf(']');
 
             int index = index2;
-            if ( index2 < 0 || index1 < index2 )
-            {
-                if ( index1 >= 0 )
-                {
+            if (index2 < 0 || index1 < index2) {
+                if (index1 >= 0) {
                     index = index1;
                 }
             }
 
-            if ( index < 0 )
-            {
-                throw new InvalidVersionSpecificationException( "Unbounded range: " + spec );
+            if (index < 0) {
+                throw new InvalidVersionSpecificationException("Unbounded range: " + spec);
             }
 
-            Restriction restriction = parseRestriction( process.substring( 0, index + 1 ) );
-            if ( lowerBound == null )
-            {
+            Restriction restriction = parseRestriction(process.substring(0, index + 1));
+            if (lowerBound == null) {
                 lowerBound = restriction.getLowerBound();
             }
-            if ( upperBound != null )
-            {
-                if ( restriction.getLowerBound() == null || restriction.getLowerBound().compareTo( upperBound ) < 0 )
-                {
-                    throw new InvalidVersionSpecificationException( "Ranges overlap: " + spec );
+            if (upperBound != null) {
+                if (restriction.getLowerBound() == null
+                        || restriction.getLowerBound().compareTo(upperBound) < 0) {
+                    throw new InvalidVersionSpecificationException("Ranges overlap: " + spec);
                 }
             }
-            restrictions.add( restriction );
+            restrictions.add(restriction);
             upperBound = restriction.getUpperBound();
 
-            process = process.substring( index + 1 ).trim();
+            process = process.substring(index + 1).trim();
 
-            if ( process.startsWith( "," ) )
-            {
-                process = process.substring( 1 ).trim();
+            if (process.startsWith(",")) {
+                process = process.substring(1).trim();
             }
         }
 
-        if ( process.length() > 0 )
-        {
-            if ( restrictions.size() > 0 )
-            {
+        if (process.length() > 0) {
+            if (restrictions.size() > 0) {
                 throw new InvalidVersionSpecificationException(
-                    "Only fully-qualified sets allowed in multiple set scenario: " + spec );
-            }
-            else
-            {
-                version = new DefaultArtifactVersion( process );
-                restrictions.add( Restriction.EVERYTHING );
+                        "Only fully-qualified sets allowed in multiple set scenario: " + spec);
+            } else {
+                version = new DefaultArtifactVersion(process);
+                restrictions.add(Restriction.EVERYTHING);
             }
         }
 
-        cached = new VersionRange( version, restrictions );
-        CACHE_SPEC.put( spec, cached );
+        cached = new VersionRange(version, restrictions);
+        CACHE_SPEC.put(spec, cached);
         return cached;
     }
 
-    private static Restriction parseRestriction( String spec )
-        throws InvalidVersionSpecificationException
-    {
-        boolean lowerBoundInclusive = spec.startsWith( "[" );
-        boolean upperBoundInclusive = spec.endsWith( "]" );
+    private static Restriction parseRestriction(String spec) throws InvalidVersionSpecificationException {
+        boolean lowerBoundInclusive = spec.startsWith("[");
+        boolean upperBoundInclusive = spec.endsWith("]");
 
-        String process = spec.substring( 1, spec.length() - 1 ).trim();
+        String process = spec.substring(1, spec.length() - 1).trim();
 
         Restriction restriction;
 
-        int index = process.indexOf( ',' );
+        int index = process.indexOf(',');
 
-        if ( index < 0 )
-        {
-            if ( !lowerBoundInclusive || !upperBoundInclusive )
-            {
-                throw new InvalidVersionSpecificationException( "Single version must be surrounded by []: " + spec );
+        if (index < 0) {
+            if (!lowerBoundInclusive || !upperBoundInclusive) {
+                throw new InvalidVersionSpecificationException("Single version must be surrounded by []: " + spec);
             }
 
-            ArtifactVersion version = new DefaultArtifactVersion( process );
+            ArtifactVersion version = new DefaultArtifactVersion(process);
 
-            restriction = new Restriction( version, lowerBoundInclusive, version, upperBoundInclusive );
-        }
-        else
-        {
-            String lowerBound = process.substring( 0, index ).trim();
-            String upperBound = process.substring( index + 1 ).trim();
-            if ( lowerBound.equals( upperBound ) )
-            {
-                throw new InvalidVersionSpecificationException( "Range cannot have identical boundaries: " + spec );
-            }
+            restriction = new Restriction(version, lowerBoundInclusive, version, upperBoundInclusive);
+        } else {
+            String lowerBound = process.substring(0, index).trim();
+            String upperBound = process.substring(index + 1).trim();
 
             ArtifactVersion lowerVersion = null;
-            if ( lowerBound.length() > 0 )
-            {
-                lowerVersion = new DefaultArtifactVersion( lowerBound );
+            if (lowerBound.length() > 0) {
+                lowerVersion = new DefaultArtifactVersion(lowerBound);
             }
             ArtifactVersion upperVersion = null;
-            if ( upperBound.length() > 0 )
-            {
-                upperVersion = new DefaultArtifactVersion( upperBound );
+            if (upperBound.length() > 0) {
+                upperVersion = new DefaultArtifactVersion(upperBound);
             }
 
-            if ( upperVersion != null && lowerVersion != null && upperVersion.compareTo( lowerVersion ) < 0 )
-            {
-                throw new InvalidVersionSpecificationException( "Range defies version ordering: " + spec );
+            if (upperVersion != null && lowerVersion != null) {
+                int result = upperVersion.compareTo(lowerVersion);
+                if (result < 0 || (result == 0 && (!lowerBoundInclusive || !upperBoundInclusive))) {
+                    throw new InvalidVersionSpecificationException("Range defies version ordering: " + spec);
+                }
             }
 
-            restriction = new Restriction( lowerVersion, lowerBoundInclusive, upperVersion, upperBoundInclusive );
+            restriction = new Restriction(lowerVersion, lowerBoundInclusive, upperVersion, upperBoundInclusive);
         }
 
         return restriction;
     }
 
-    public static VersionRange createFromVersion( String version )
-    {
-        VersionRange cached = CACHE_VERSION.get( version );
-        if ( cached == null )
-        {
+    public static VersionRange createFromVersion(String version) {
+        VersionRange cached = CACHE_VERSION.get(version);
+        if (cached == null) {
             List<Restriction> restrictions = Collections.emptyList();
-            cached = new VersionRange( new DefaultArtifactVersion( version ), restrictions );
-            CACHE_VERSION.put( version, cached );
+            cached = new VersionRange(new DefaultArtifactVersion(version), restrictions);
+            CACHE_VERSION.put(version, cached);
         }
         return cached;
     }
@@ -278,203 +239,148 @@
      * @throws NullPointerException if the specified <code>VersionRange</code> is
      *                              <code>null</code>.
      */
-    public VersionRange restrict( VersionRange restriction )
-    {
+    public VersionRange restrict(VersionRange restriction) {
         List<Restriction> r1 = this.restrictions;
         List<Restriction> r2 = restriction.restrictions;
         List<Restriction> restrictions;
 
-        if ( r1.isEmpty() || r2.isEmpty() )
-        {
+        if (r1.isEmpty() || r2.isEmpty()) {
             restrictions = Collections.emptyList();
-        }
-        else
-        {
-            restrictions = Collections.unmodifiableList( intersection( r1, r2 ) );
+        } else {
+            restrictions = Collections.unmodifiableList(intersection(r1, r2));
         }
 
         ArtifactVersion version = null;
-        if ( restrictions.size() > 0 )
-        {
-            for ( Restriction r : restrictions )
-            {
-                if ( recommendedVersion != null && r.containsVersion( recommendedVersion ) )
-                {
+        if (restrictions.size() > 0) {
+            for (Restriction r : restrictions) {
+                if (recommendedVersion != null && r.containsVersion(recommendedVersion)) {
                     // if we find the original, use that
                     version = recommendedVersion;
                     break;
-                }
-                else if ( version == null && restriction.getRecommendedVersion() != null
-                    && r.containsVersion( restriction.getRecommendedVersion() ) )
-                {
+                } else if (version == null
+                        && restriction.getRecommendedVersion() != null
+                        && r.containsVersion(restriction.getRecommendedVersion())) {
                     // use this if we can, but prefer the original if possible
                     version = restriction.getRecommendedVersion();
                 }
             }
         }
         // Either the original or the specified version ranges have no restrictions
-        else if ( recommendedVersion != null )
-        {
+        else if (recommendedVersion != null) {
             // Use the original recommended version since it exists
             version = recommendedVersion;
-        }
-        else if ( restriction.recommendedVersion != null )
-        {
+        } else if (restriction.recommendedVersion != null) {
             // Use the recommended version from the specified VersionRange since there is no
             // original recommended version
             version = restriction.recommendedVersion;
         }
-/* TODO should throw this immediately, but need artifact
-        else
-        {
-            throw new OverConstrainedVersionException( "Restricting incompatible version ranges" );
-        }
-*/
+        /* TODO should throw this immediately, but need artifact
+                else
+                {
+                    throw new OverConstrainedVersionException( "Restricting incompatible version ranges" );
+                }
+        */
 
-        return new VersionRange( version, restrictions );
+        return new VersionRange(version, restrictions);
     }
 
-    private List<Restriction> intersection( List<Restriction> r1, List<Restriction> r2 )
-    {
-        List<Restriction> restrictions = new ArrayList<>( r1.size() + r2.size() );
+    private List<Restriction> intersection(List<Restriction> r1, List<Restriction> r2) {
+        List<Restriction> restrictions = new ArrayList<>(r1.size() + r2.size());
         Iterator<Restriction> i1 = r1.iterator();
         Iterator<Restriction> i2 = r2.iterator();
         Restriction res1 = i1.next();
         Restriction res2 = i2.next();
 
         boolean done = false;
-        while ( !done )
-        {
-            if ( res1.getLowerBound() == null || res2.getUpperBound() == null
-                || res1.getLowerBound().compareTo( res2.getUpperBound() ) <= 0 )
-            {
-                if ( res1.getUpperBound() == null || res2.getLowerBound() == null
-                    || res1.getUpperBound().compareTo( res2.getLowerBound() ) >= 0 )
-                {
+        while (!done) {
+            if (res1.getLowerBound() == null
+                    || res2.getUpperBound() == null
+                    || res1.getLowerBound().compareTo(res2.getUpperBound()) <= 0) {
+                if (res1.getUpperBound() == null
+                        || res2.getLowerBound() == null
+                        || res1.getUpperBound().compareTo(res2.getLowerBound()) >= 0) {
                     ArtifactVersion lower;
                     ArtifactVersion upper;
                     boolean lowerInclusive;
                     boolean upperInclusive;
 
                     // overlaps
-                    if ( res1.getLowerBound() == null )
-                    {
+                    if (res1.getLowerBound() == null) {
                         lower = res2.getLowerBound();
                         lowerInclusive = res2.isLowerBoundInclusive();
-                    }
-                    else if ( res2.getLowerBound() == null )
-                    {
+                    } else if (res2.getLowerBound() == null) {
                         lower = res1.getLowerBound();
                         lowerInclusive = res1.isLowerBoundInclusive();
-                    }
-                    else
-                    {
-                        int comparison = res1.getLowerBound().compareTo( res2.getLowerBound() );
-                        if ( comparison < 0 )
-                        {
+                    } else {
+                        int comparison = res1.getLowerBound().compareTo(res2.getLowerBound());
+                        if (comparison < 0) {
                             lower = res2.getLowerBound();
                             lowerInclusive = res2.isLowerBoundInclusive();
-                        }
-                        else if ( comparison == 0 )
-                        {
+                        } else if (comparison == 0) {
                             lower = res1.getLowerBound();
                             lowerInclusive = res1.isLowerBoundInclusive() && res2.isLowerBoundInclusive();
-                        }
-                        else
-                        {
+                        } else {
                             lower = res1.getLowerBound();
                             lowerInclusive = res1.isLowerBoundInclusive();
                         }
                     }
 
-                    if ( res1.getUpperBound() == null )
-                    {
+                    if (res1.getUpperBound() == null) {
                         upper = res2.getUpperBound();
                         upperInclusive = res2.isUpperBoundInclusive();
-                    }
-                    else if ( res2.getUpperBound() == null )
-                    {
+                    } else if (res2.getUpperBound() == null) {
                         upper = res1.getUpperBound();
                         upperInclusive = res1.isUpperBoundInclusive();
-                    }
-                    else
-                    {
-                        int comparison = res1.getUpperBound().compareTo( res2.getUpperBound() );
-                        if ( comparison < 0 )
-                        {
+                    } else {
+                        int comparison = res1.getUpperBound().compareTo(res2.getUpperBound());
+                        if (comparison < 0) {
                             upper = res1.getUpperBound();
                             upperInclusive = res1.isUpperBoundInclusive();
-                        }
-                        else if ( comparison == 0 )
-                        {
+                        } else if (comparison == 0) {
                             upper = res1.getUpperBound();
                             upperInclusive = res1.isUpperBoundInclusive() && res2.isUpperBoundInclusive();
-                        }
-                        else
-                        {
+                        } else {
                             upper = res2.getUpperBound();
                             upperInclusive = res2.isUpperBoundInclusive();
                         }
                     }
 
                     // don't add if they are equal and one is not inclusive
-                    if ( lower == null || upper == null || lower.compareTo( upper ) != 0 )
-                    {
-                        restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
-                    }
-                    else if ( lowerInclusive && upperInclusive )
-                    {
-                        restrictions.add( new Restriction( lower, lowerInclusive, upper, upperInclusive ) );
+                    if (lower == null || upper == null || lower.compareTo(upper) != 0) {
+                        restrictions.add(new Restriction(lower, lowerInclusive, upper, upperInclusive));
+                    } else if (lowerInclusive && upperInclusive) {
+                        restrictions.add(new Restriction(lower, lowerInclusive, upper, upperInclusive));
                     }
 
                     //noinspection ObjectEquality
-                    if ( upper == res2.getUpperBound() )
-                    {
+                    if (upper == res2.getUpperBound()) {
                         // advance res2
-                        if ( i2.hasNext() )
-                        {
+                        if (i2.hasNext()) {
                             res2 = i2.next();
-                        }
-                        else
-                        {
+                        } else {
                             done = true;
                         }
-                    }
-                    else
-                    {
+                    } else {
                         // advance res1
-                        if ( i1.hasNext() )
-                        {
+                        if (i1.hasNext()) {
                             res1 = i1.next();
-                        }
-                        else
-                        {
+                        } else {
                             done = true;
                         }
                     }
-                }
-                else
-                {
+                } else {
                     // move on to next in r1
-                    if ( i1.hasNext() )
-                    {
+                    if (i1.hasNext()) {
                         res1 = i1.next();
-                    }
-                    else
-                    {
+                    } else {
                         done = true;
                     }
                 }
-            }
-            else
-            {
+            } else {
                 // move on to next in r2
-                if ( i2.hasNext() )
-                {
+                if (i2.hasNext()) {
                     res2 = i2.next();
-                }
-                else
-                {
+                } else {
                     done = true;
                 }
             }
@@ -483,19 +389,13 @@
         return restrictions;
     }
 
-    public ArtifactVersion getSelectedVersion( Artifact artifact )
-        throws OverConstrainedVersionException
-    {
+    public ArtifactVersion getSelectedVersion(Artifact artifact) throws OverConstrainedVersionException {
         ArtifactVersion version;
-        if ( recommendedVersion != null )
-        {
+        if (recommendedVersion != null) {
             version = recommendedVersion;
-        }
-        else
-        {
-            if ( restrictions.size() == 0 )
-            {
-                throw new OverConstrainedVersionException( "The artifact has no valid ranges", artifact );
+        } else {
+            if (restrictions.size() == 0) {
+                throw new OverConstrainedVersionException("The artifact has no valid ranges", artifact);
             }
 
             version = null;
@@ -503,60 +403,44 @@
         return version;
     }
 
-    public boolean isSelectedVersionKnown( Artifact artifact )
-        throws OverConstrainedVersionException
-    {
+    public boolean isSelectedVersionKnown(Artifact artifact) throws OverConstrainedVersionException {
         boolean value = false;
-        if ( recommendedVersion != null )
-        {
+        if (recommendedVersion != null) {
             value = true;
-        }
-        else
-        {
-            if ( restrictions.size() == 0 )
-            {
-                throw new OverConstrainedVersionException( "The artifact has no valid ranges", artifact );
+        } else {
+            if (restrictions.size() == 0) {
+                throw new OverConstrainedVersionException("The artifact has no valid ranges", artifact);
             }
         }
         return value;
     }
 
-    public String toString()
-    {
-        if ( recommendedVersion != null )
-        {
+    public String toString() {
+        if (recommendedVersion != null) {
             return recommendedVersion.toString();
-        }
-        else
-        {
+        } else {
             StringBuilder buf = new StringBuilder();
-            for ( Iterator<Restriction> i = restrictions.iterator(); i.hasNext(); )
-            {
+            for (Iterator<Restriction> i = restrictions.iterator(); i.hasNext(); ) {
                 Restriction r = i.next();
 
-                buf.append( r.toString() );
+                buf.append(r.toString());
 
-                if ( i.hasNext() )
-                {
-                    buf.append( ',' );
+                if (i.hasNext()) {
+                    buf.append(',');
                 }
             }
             return buf.toString();
         }
     }
 
-    public ArtifactVersion matchVersion( List<ArtifactVersion> versions )
-    {
+    public ArtifactVersion matchVersion(List<ArtifactVersion> versions) {
         // TODO could be more efficient by sorting the list and then moving along the restrictions in order?
 
         ArtifactVersion matched = null;
-        for ( ArtifactVersion version : versions )
-        {
-            if ( containsVersion( version ) )
-            {
+        for (ArtifactVersion version : versions) {
+            if (containsVersion(version)) {
                 // valid - check if it is greater than the currently matched version
-                if ( matched == null || version.compareTo( matched ) > 0 )
-                {
+                if (matched == null || version.compareTo(matched) > 0) {
                     matched = version;
                 }
             }
@@ -564,44 +448,36 @@
         return matched;
     }
 
-    public boolean containsVersion( ArtifactVersion version )
-    {
-        for ( Restriction restriction : restrictions )
-        {
-            if ( restriction.containsVersion( version ) )
-            {
+    public boolean containsVersion(ArtifactVersion version) {
+        for (Restriction restriction : restrictions) {
+            if (restriction.containsVersion(version)) {
                 return true;
             }
         }
         return false;
     }
 
-    public boolean hasRestrictions()
-    {
+    public boolean hasRestrictions() {
         return !restrictions.isEmpty() && recommendedVersion == null;
     }
 
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
-        if ( !( obj instanceof VersionRange ) )
-        {
+        if (!(obj instanceof VersionRange)) {
             return false;
         }
         VersionRange other = (VersionRange) obj;
 
-        return Objects.equals( recommendedVersion, other.recommendedVersion )
-            && Objects.equals( restrictions, other.restrictions );
+        return Objects.equals(recommendedVersion, other.recommendedVersion)
+                && Objects.equals(restrictions, other.restrictions);
     }
 
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 7;
-        hash = 31 * hash + ( recommendedVersion == null ? 0 : recommendedVersion.hashCode() );
-        hash = 31 * hash + ( restrictions == null ? 0 : restrictions.hashCode() );
+        hash = 31 * hash + (recommendedVersion == null ? 0 : recommendedVersion.hashCode());
+        hash = 31 * hash + (restrictions == null ? 0 : restrictions.hashCode());
         return hash;
     }
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/repository/Proxy.java b/maven-artifact/src/main/java/org/apache/maven/repository/Proxy.java
index 4669276..aa27e62 100644
--- a/maven-artifact/src/main/java/org/apache/maven/repository/Proxy.java
+++ b/maven-artifact/src/main/java/org/apache/maven/repository/Proxy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 /**
  * Proxy
  */
-public class Proxy
-{
+public class Proxy {
     public static final String PROXY_SOCKS5 = "SOCKS_5";
 
     public static final String PROXY_SOCKS4 = "SOCKS4";
@@ -75,8 +73,7 @@
      *
      * @return proxy server host name
      */
-    public String getHost()
-    {
+    public String getHost() {
         return host;
     }
 
@@ -85,8 +82,7 @@
      *
      * @param host proxy server host name
      */
-    public void setHost( String host )
-    {
+    public void setHost(String host) {
         this.host = host;
     }
 
@@ -95,8 +91,7 @@
      *
      * @return user's password at proxy host
      */
-    public String getPassword()
-    {
+    public String getPassword() {
         return password;
     }
 
@@ -105,8 +100,7 @@
      *
      * @param password password to use to log in to a proxy server
      */
-    public void setPassword( String password )
-    {
+    public void setPassword(String password) {
         this.password = password;
     }
 
@@ -115,8 +109,7 @@
      *
      * @return proxy server port
      */
-    public int getPort()
-    {
+    public int getPort() {
         return port;
     }
 
@@ -125,8 +118,7 @@
      *
      * @param port proxy server port
      */
-    public void setPort( int port )
-    {
+    public void setPort(int port) {
         this.port = port;
     }
 
@@ -135,8 +127,7 @@
      *
      * @return username for the proxy server
      */
-    public String getUserName()
-    {
+    public String getUserName() {
         return userName;
     }
 
@@ -145,8 +136,7 @@
      *
      * @param userName username for the proxy server
      */
-    public void setUserName( String userName )
-    {
+    public void setUserName(String userName) {
         this.userName = userName;
     }
 
@@ -155,46 +145,38 @@
      *
      * @return the protocol of the proxy server
      */
-    public String getProtocol()
-    {
+    public String getProtocol() {
         return protocol;
     }
 
     /**
      * @param protocol the protocol of the proxy server like <i>SOCKSv4</i>
      */
-    public void setProtocol( String protocol )
-    {
+    public void setProtocol(String protocol) {
         this.protocol = protocol;
     }
 
-    public String getNonProxyHosts()
-    {
+    public String getNonProxyHosts() {
         return nonProxyHosts;
     }
 
-    public void setNonProxyHosts( String nonProxyHosts )
-    {
+    public void setNonProxyHosts(String nonProxyHosts) {
         this.nonProxyHosts = nonProxyHosts;
     }
 
-    public String getNtlmHost()
-    {
+    public String getNtlmHost() {
         return ntlmHost;
     }
 
-    public void setNtlmHost( String ntlmHost )
-    {
+    public void setNtlmHost(String ntlmHost) {
         this.ntlmHost = ntlmHost;
     }
 
-    public void setNtlmDomain( String ntlmDomain )
-    {
+    public void setNtlmDomain(String ntlmDomain) {
         this.ntlmDomain = ntlmDomain;
     }
 
-    public String getNtlmDomain()
-    {
+    public String getNtlmDomain() {
         return ntlmDomain;
     }
 }
diff --git a/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java b/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java
index 136ab44..5a9ec7e 100644
--- a/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java
+++ b/maven-artifact/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.metadata;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.metadata.RepositoryMetadataStoreException;
@@ -27,10 +26,8 @@
  * TODO merge with artifactmetadatasource
  * TODO retrieval exception not appropriate for store
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public interface ArtifactMetadata
-{
+public interface ArtifactMetadata {
     /**
      * Whether this metadata should be stored alongside the artifact.
      *
@@ -59,7 +56,7 @@
      * @param repository the remote repository it came from
      * @return the filename
      */
-    String getLocalFilename( ArtifactRepository repository );
+    String getLocalFilename(ArtifactRepository repository);
 
     /**
      * Get the filename of this metadata on the remote repository.
@@ -74,7 +71,7 @@
      *
      * @param metadata the new metadata
      */
-    void merge( ArtifactMetadata metadata );
+    void merge(ArtifactMetadata metadata);
 
     /**
      * Store the metadata in the local repository.
@@ -84,9 +81,8 @@
      * @param remoteRepository the remote repository it came from
      * @throws RepositoryMetadataStoreException in case of issue
      */
-    void storeInLocalRepository( ArtifactRepository localRepository,
-                                 ArtifactRepository remoteRepository )
-        throws RepositoryMetadataStoreException;
+    void storeInLocalRepository(ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws RepositoryMetadataStoreException;
 
     String extendedToString();
 }
diff --git a/maven-artifact/src/site/site.xml b/maven-artifact/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-artifact/src/site/site.xml
+++ b/maven-artifact/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/ArtifactUtilsTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/ArtifactUtilsTest.java
index 485b3f6..740bdee 100644
--- a/maven-artifact/src/test/java/org/apache/maven/artifact/ArtifactUtilsTest.java
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/ArtifactUtilsTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -34,54 +33,46 @@
 /**
  * Tests {@link ArtifactUtils}.
  *
- * @author Benjamin Bentmann
  */
-public class ArtifactUtilsTest
-{
+class ArtifactUtilsTest {
 
-    private Artifact newArtifact( String aid )
-    {
-        return new DefaultArtifact( "group", aid, VersionRange.createFromVersion( "1.0" ), "test", "jar", "tests", null );
+    private Artifact newArtifact(String aid) {
+        return new DefaultArtifact("group", aid, VersionRange.createFromVersion("1.0"), "test", "jar", "tests", null);
     }
 
     @Test
-    public void testIsSnapshot()
-    {
-        assertFalse( ArtifactUtils.isSnapshot( null ) );
-        assertFalse( ArtifactUtils.isSnapshot( "" ) );
-        assertFalse( ArtifactUtils.isSnapshot( "1.2.3" ) );
-        assertTrue( ArtifactUtils.isSnapshot( "1.2.3-SNAPSHOT" ) );
-        assertTrue( ArtifactUtils.isSnapshot( "1.2.3-snapshot" ) );
-        assertTrue( ArtifactUtils.isSnapshot( "1.2.3-20090413.094722-2" ) );
-        assertFalse( ArtifactUtils.isSnapshot( "1.2.3-20090413X094722-2" ) );
+    void testIsSnapshot() {
+        assertFalse(ArtifactUtils.isSnapshot(null));
+        assertFalse(ArtifactUtils.isSnapshot(""));
+        assertFalse(ArtifactUtils.isSnapshot("1.2.3"));
+        assertTrue(ArtifactUtils.isSnapshot("1.2.3-SNAPSHOT"));
+        assertTrue(ArtifactUtils.isSnapshot("1.2.3-snapshot"));
+        assertTrue(ArtifactUtils.isSnapshot("1.2.3-20090413.094722-2"));
+        assertFalse(ArtifactUtils.isSnapshot("1.2.3-20090413X094722-2"));
     }
 
     @Test
-    public void testToSnapshotVersion()
-    {
-        assertEquals( "1.2.3", ArtifactUtils.toSnapshotVersion( "1.2.3" ) );
-        assertEquals( "1.2.3-SNAPSHOT", ArtifactUtils.toSnapshotVersion( "1.2.3-SNAPSHOT" ) );
-        assertEquals( "1.2.3-SNAPSHOT", ArtifactUtils.toSnapshotVersion( "1.2.3-20090413.094722-2" ) );
-        assertEquals( "1.2.3-20090413X094722-2", ArtifactUtils.toSnapshotVersion( "1.2.3-20090413X094722-2" ) );
+    void testToSnapshotVersion() {
+        assertEquals("1.2.3", ArtifactUtils.toSnapshotVersion("1.2.3"));
+        assertEquals("1.2.3-SNAPSHOT", ArtifactUtils.toSnapshotVersion("1.2.3-SNAPSHOT"));
+        assertEquals("1.2.3-SNAPSHOT", ArtifactUtils.toSnapshotVersion("1.2.3-20090413.094722-2"));
+        assertEquals("1.2.3-20090413X094722-2", ArtifactUtils.toSnapshotVersion("1.2.3-20090413X094722-2"));
     }
 
     /**
      * Tests that the ordering of the map resembles the ordering of the input collection of artifacts.
      */
     @Test
-    public void testArtifactMapByVersionlessIdOrdering()
-        throws Exception
-    {
+    void testArtifactMapByVersionlessIdOrdering() throws Exception {
         List<Artifact> list = new ArrayList<>();
-        list.add( newArtifact( "b" ) );
-        list.add( newArtifact( "a" ) );
-        list.add( newArtifact( "c" ) );
-        list.add( newArtifact( "e" ) );
-        list.add( newArtifact( "d" ) );
+        list.add(newArtifact("b"));
+        list.add(newArtifact("a"));
+        list.add(newArtifact("c"));
+        list.add(newArtifact("e"));
+        list.add(newArtifact("d"));
 
-        Map<String, Artifact> map = ArtifactUtils.artifactMapByVersionlessId( list );
-        assertNotNull( map );
-        assertEquals( list, new ArrayList<>( map.values() ) );
+        Map<String, Artifact> map = ArtifactUtils.artifactMapByVersionlessId(list);
+        assertNotNull(map);
+        assertEquals(list, new ArrayList<>(map.values()));
     }
-
 }
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/DefaultArtifactTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/DefaultArtifactTest.java
index 4f91962..21dd537 100644
--- a/maven-artifact/src/test/java/org/apache/maven/artifact/DefaultArtifactTest.java
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/DefaultArtifactTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import org.apache.maven.artifact.handler.ArtifactHandlerMock;
 import org.apache.maven.artifact.versioning.VersionRange;
@@ -28,15 +27,18 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class DefaultArtifactTest
-{
+class DefaultArtifactTest {
 
     private DefaultArtifact artifact;
 
     private DefaultArtifact snapshotArtifact;
 
-    private String groupId = "groupid", artifactId = "artifactId", version = "1.0", scope = "artifactScope", type = "type",
-        classifier = "classifier";
+    private String groupId = "groupid",
+            artifactId = "artifactId",
+            version = "1.0",
+            scope = "artifactScope",
+            type = "type",
+            classifier = "classifier";
 
     private String snapshotSpecVersion = "1.0-SNAPSHOT";
     private String snapshotResolvedVersion = "1.0-20070606.010101-1";
@@ -47,108 +49,107 @@
     private ArtifactHandlerMock artifactHandler;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
+    void setUp() throws Exception {
         artifactHandler = new ArtifactHandlerMock();
-        versionRange = VersionRange.createFromVersion( version );
-        artifact = new DefaultArtifact( groupId, artifactId, versionRange, scope, type, classifier, artifactHandler );
+        versionRange = VersionRange.createFromVersion(version);
+        artifact = new DefaultArtifact(groupId, artifactId, versionRange, scope, type, classifier, artifactHandler);
 
-        snapshotVersionRange = VersionRange.createFromVersion( snapshotResolvedVersion );
-        snapshotArtifact = new DefaultArtifact( groupId, artifactId, snapshotVersionRange, scope, type, classifier, artifactHandler );
+        snapshotVersionRange = VersionRange.createFromVersion(snapshotResolvedVersion);
+        snapshotArtifact = new DefaultArtifact(
+                groupId, artifactId, snapshotVersionRange, scope, type, classifier, artifactHandler);
     }
 
     @Test
-    public void testGetVersionReturnsResolvedVersionOnSnapshot()
-    {
-        assertEquals( snapshotResolvedVersion, snapshotArtifact.getVersion() );
+    void testGetVersionReturnsResolvedVersionOnSnapshot() {
+        assertEquals(snapshotResolvedVersion, snapshotArtifact.getVersion());
 
         // this is FOUL!
-//        snapshotArtifact.isSnapshot();
+        //        snapshotArtifact.isSnapshot();
 
-        assertEquals( snapshotSpecVersion, snapshotArtifact.getBaseVersion() );
+        assertEquals(snapshotSpecVersion, snapshotArtifact.getBaseVersion());
     }
 
     @Test
-    public void testGetDependencyConflictId()
-    {
-        assertEquals( groupId + ":" + artifactId + ":" + type + ":" + classifier, artifact.getDependencyConflictId() );
+    void testGetDependencyConflictId() {
+        assertEquals(groupId + ":" + artifactId + ":" + type + ":" + classifier, artifact.getDependencyConflictId());
     }
 
     @Test
-    public void testGetDependencyConflictIdNullGroupId()
-    {
-        artifact.setGroupId( null );
-        assertEquals( null + ":" + artifactId + ":" + type + ":" + classifier, artifact.getDependencyConflictId() );
+    void testGetDependencyConflictIdNullGroupId() {
+        artifact.setGroupId(null);
+        assertEquals(null + ":" + artifactId + ":" + type + ":" + classifier, artifact.getDependencyConflictId());
     }
 
     @Test
-    public void testGetDependencyConflictIdNullClassifier()
-    {
-        artifact = new DefaultArtifact( groupId, artifactId, versionRange, scope, type, null, artifactHandler );
-        assertEquals( groupId + ":" + artifactId + ":" + type, artifact.getDependencyConflictId() );
+    void testGetDependencyConflictIdNullClassifier() {
+        artifact = new DefaultArtifact(groupId, artifactId, versionRange, scope, type, null, artifactHandler);
+        assertEquals(groupId + ":" + artifactId + ":" + type, artifact.getDependencyConflictId());
     }
 
     @Test
-    public void testGetDependencyConflictIdNullScope()
-    {
-        artifact.setScope( null );
-        assertEquals( groupId + ":" + artifactId + ":" + type + ":" + classifier, artifact.getDependencyConflictId() );
+    void testGetDependencyConflictIdNullScope() {
+        artifact.setScope(null);
+        assertEquals(groupId + ":" + artifactId + ":" + type + ":" + classifier, artifact.getDependencyConflictId());
     }
 
     @Test
-    public void testToString()
-    {
-        assertEquals( groupId + ":" + artifactId + ":" + type + ":" + classifier + ":" + version + ":" + scope,
-                      artifact.toString() );
+    void testToString() {
+        assertEquals(
+                groupId + ":" + artifactId + ":" + type + ":" + classifier + ":" + version + ":" + scope,
+                artifact.toString());
     }
 
     @Test
-    public void testToStringNullGroupId()
-    {
-        artifact.setGroupId( null );
-        assertEquals( artifactId + ":" + type + ":" + classifier + ":" + version + ":" + scope, artifact.toString() );
+    void testToStringNullGroupId() {
+        artifact.setGroupId(null);
+        assertEquals(artifactId + ":" + type + ":" + classifier + ":" + version + ":" + scope, artifact.toString());
     }
 
     @Test
-    public void testToStringNullClassifier()
-    {
-        artifact = new DefaultArtifact( groupId, artifactId, versionRange, scope, type, null, artifactHandler );
-        assertEquals( groupId + ":" + artifactId + ":" + type + ":" + version + ":" + scope, artifact.toString() );
+    void testToStringNullClassifier() {
+        artifact = new DefaultArtifact(groupId, artifactId, versionRange, scope, type, null, artifactHandler);
+        assertEquals(groupId + ":" + artifactId + ":" + type + ":" + version + ":" + scope, artifact.toString());
     }
 
     @Test
-    public void testToStringNullScope()
-    {
-        artifact.setScope( null );
-        assertEquals( groupId + ":" + artifactId + ":" + type + ":" + classifier + ":" + version, artifact.toString() );
+    void testToStringNullScope() {
+        artifact.setScope(null);
+        assertEquals(groupId + ":" + artifactId + ":" + type + ":" + classifier + ":" + version, artifact.toString());
     }
 
     @Test
-    public void testComparisonByVersion()
-    {
-        Artifact artifact1 = new DefaultArtifact( groupId, artifactId, VersionRange.createFromVersion( "5.0" ), scope,
-                                                  type, classifier, artifactHandler );
-        Artifact artifact2 = new DefaultArtifact( groupId, artifactId, VersionRange.createFromVersion( "12.0" ), scope,
-                                                  type, classifier, artifactHandler );
+    void testComparisonByVersion() {
+        Artifact artifact1 = new DefaultArtifact(
+                groupId, artifactId, VersionRange.createFromVersion("5.0"), scope, type, classifier, artifactHandler);
+        Artifact artifact2 = new DefaultArtifact(
+                groupId, artifactId, VersionRange.createFromVersion("12.0"), scope, type, classifier, artifactHandler);
 
-        assertTrue( artifact1.compareTo( artifact2 ) < 0 );
-        assertTrue( artifact2.compareTo( artifact1 ) > 0 );
+        assertTrue(artifact1.compareTo(artifact2) < 0);
+        assertTrue(artifact2.compareTo(artifact1) > 0);
 
-        Artifact artifact = new DefaultArtifact( groupId, artifactId, VersionRange.createFromVersion( "5.0" ), scope,
-                                                  type, classifier, artifactHandler );
-        assertTrue( artifact.compareTo( artifact1 ) == 0 );
-        assertTrue( artifact1.compareTo( artifact ) == 0 );
+        Artifact artifact = new DefaultArtifact(
+                groupId, artifactId, VersionRange.createFromVersion("5.0"), scope, type, classifier, artifactHandler);
+        assertTrue(artifact.compareTo(artifact1) == 0);
+        assertTrue(artifact1.compareTo(artifact) == 0);
     }
 
     @Test
-    public void testNonResolvedVersionRangeConsistentlyYieldsNullVersions()
-        throws Exception
-    {
-        VersionRange vr = VersionRange.createFromVersionSpec( "[1.0,2.0)" );
-        artifact = new DefaultArtifact( groupId, artifactId, vr, scope, type, null, artifactHandler );
-        assertNull( artifact.getVersion() );
-        assertNull( artifact.getBaseVersion() );
+    void testNonResolvedVersionRangeConsistentlyYieldsNullVersions() throws Exception {
+        VersionRange vr = VersionRange.createFromVersionSpec("[1.0,2.0)");
+        artifact = new DefaultArtifact(groupId, artifactId, vr, scope, type, null, artifactHandler);
+        assertNull(artifact.getVersion());
+        assertNull(artifact.getBaseVersion());
     }
 
+    @Test
+    void testMNG7780() throws Exception {
+        VersionRange vr = VersionRange.createFromVersionSpec("[1.0,2.0)");
+        artifact = new DefaultArtifact(groupId, artifactId, vr, scope, type, null, artifactHandler);
+        assertNull(artifact.getVersion());
+        assertNull(artifact.getBaseVersion());
+
+        DefaultArtifact nullVersionArtifact =
+                new DefaultArtifact(groupId, artifactId, vr, scope, type, null, artifactHandler);
+        assertEquals(artifact, nullVersionArtifact);
+    }
 }
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java
index a9f335e..deb3e77 100644
--- a/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerMock.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.handler;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,83 +16,66 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.handler;
 
-public class ArtifactHandlerMock
-    implements ArtifactHandler
-{
+public class ArtifactHandlerMock implements ArtifactHandler {
 
     private String extension, directory, classifier, packaging, language;
-
     private boolean includesDependencies, addedToClasspath;
 
-    public void setExtension( String extension )
-    {
+    public void setExtension(String extension) {
         this.extension = extension;
     }
 
-    public String getExtension()
-    {
+    public String getExtension() {
         return extension;
     }
 
-    public void setDirectory( String directory )
-    {
+    public void setDirectory(String directory) {
         this.directory = directory;
     }
 
-    public String getDirectory()
-    {
+    public String getDirectory() {
         return directory;
     }
 
-    public void setClassifier( String classifier )
-    {
+    public void setClassifier(String classifier) {
         this.classifier = classifier;
     }
 
-    public String getClassifier()
-    {
+    public String getClassifier() {
         return classifier;
     }
 
-    public void setPackaging( String packaging )
-    {
+    public void setPackaging(String packaging) {
         this.packaging = packaging;
     }
 
-    public String getPackaging()
-    {
+    public String getPackaging() {
         return packaging;
     }
 
-    public void setIncludesDependencies( boolean includesDependencies )
-    {
+    public void setIncludesDependencies(boolean includesDependencies) {
         this.includesDependencies = includesDependencies;
     }
 
-    public boolean isIncludesDependencies()
-    {
+    public boolean isIncludesDependencies() {
         return includesDependencies;
     }
 
-    public void setLanguage( String language )
-    {
+    public void setLanguage(String language) {
         this.language = language;
     }
 
-    public String getLanguage()
-    {
+    public String getLanguage() {
         return language;
     }
 
-    public void setAddedToClasspath( boolean addedToClasspath )
-    {
+    public void setAddedToClasspath(boolean addedToClasspath) {
         this.addedToClasspath = addedToClasspath;
     }
 
-    public boolean isAddedToClasspath()
-    {
+    public boolean isAddedToClasspath() {
         return addedToClasspath;
     }
-
 }
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionIT.java b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionIT.java
index cd63b4d..a78591d 100644
--- a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionIT.java
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionIT.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import java.io.IOException;
 import java.io.InterruptedIOException;
@@ -33,61 +32,44 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class ComparableVersionIT
-{
+class ComparableVersionIT {
 
     @Test
-    public void test()
-        throws Exception
-    {
-        Files.walkFileTree( Paths.get( "target" ), new SimpleFileVisitor<Path>()
-        {
-            Pattern mavenArtifactJar = Pattern.compile( "maven-artifact-[\\d.]+(-SNAPSHOT)?\\.jar" );
+    void test() throws Exception {
+        Files.walkFileTree(Paths.get("target"), new SimpleFileVisitor<Path>() {
+            Pattern mavenArtifactJar = Pattern.compile("maven-artifact-[\\d.]+(-SNAPSHOT)?\\.jar");
 
             @Override
-            public FileVisitResult visitFile( Path file, BasicFileAttributes attrs )
-                throws IOException
-            {
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                 String filename = file.getFileName().toString();
-                if ( mavenArtifactJar.matcher( filename ).matches() )
-                {
-                    Process p = Runtime.getRuntime().exec( new String[] {
-                        Paths.get( System.getProperty( "java.home" ), "bin/java" ).toString(),
+                if (mavenArtifactJar.matcher(filename).matches()) {
+                    Process p = Runtime.getRuntime().exec(new String[] {
+                        Paths.get(System.getProperty("java.home"), "bin/java").toString(),
                         "-jar",
                         file.toAbsolutePath().toString(),
                         "5.32",
-                        "5.27" } );
+                        "5.27"
+                    });
 
-                    try
-                    {
-                        assertEquals( 0, p.waitFor(), "Unexpected exit code" );
-                    }
-                    catch ( InterruptedException e )
-                    {
-                        throw new InterruptedIOException( e.toString() );
+                    try {
+                        assertEquals(0, p.waitFor(), "Unexpected exit code");
+                    } catch (InterruptedException e) {
+                        throw new InterruptedIOException(e.toString());
                     }
                     return FileVisitResult.TERMINATE;
-                }
-                else
-                {
+                } else {
                     return FileVisitResult.CONTINUE;
                 }
             }
 
             @Override
-            public FileVisitResult preVisitDirectory( Path dir, BasicFileAttributes attrs )
-                throws IOException
-            {
-                if ( Paths.get( "target" ).equals( dir ) )
-                {
+            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+                if (Paths.get("target").equals(dir)) {
                     return FileVisitResult.CONTINUE;
-                }
-                else
-                {
+                } else {
                     return FileVisitResult.SKIP_SUBTREE;
                 }
             }
-        } );
+        });
     }
-
 }
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java
index a36f605..ebda3cb 100644
--- a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/ComparableVersionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import java.util.Locale;
 
@@ -29,176 +28,212 @@
 /**
  * Test ComparableVersion.
  *
- * @author <a href="mailto:hboutemy@apache.org">Hervé Boutemy</a>
  */
-@SuppressWarnings( "unchecked" )
-public class ComparableVersionTest
-{
-    private Comparable newComparable( String version )
-    {
-        ComparableVersion ret = new ComparableVersion( version );
+@SuppressWarnings("unchecked")
+class ComparableVersionTest {
+    private ComparableVersion newComparable(String version) {
+        ComparableVersion ret = new ComparableVersion(version);
         String canonical = ret.getCanonical();
-        String parsedCanonical = new ComparableVersion( canonical ).getCanonical();
+        String parsedCanonical = new ComparableVersion(canonical).getCanonical();
 
-        System.out.println( "canonical( " + version + " ) = " + canonical );
-        assertEquals( canonical, parsedCanonical,
-                "canonical( " + version + " ) = " + canonical + " -> canonical: " + parsedCanonical );
+        assertEquals(
+                canonical,
+                parsedCanonical,
+                "canonical( " + version + " ) = " + canonical + " -> canonical: " + parsedCanonical);
 
         return ret;
     }
 
-    private static final String[] VERSIONS_QUALIFIER =
-        { "1-alpha2snapshot", "1-alpha2", "1-alpha-123", "1-beta-2", "1-beta123", "1-m2", "1-m11", "1-rc", "1-cr2",
-            "1-rc123", "1-SNAPSHOT", "1", "1-sp", "1-sp2", "1-sp123", "1-abc", "1-def", "1-pom-1", "1-1-snapshot",
-            "1-1", "1-2", "1-123" };
+    private static final String[] VERSIONS_QUALIFIER = {
+        "1-alpha2snapshot",
+        "1-alpha2",
+        "1-alpha-123",
+        "1-beta-2",
+        "1-beta123",
+        "1-m2",
+        "1-m11",
+        "1-rc",
+        "1-cr2",
+        "1-rc123",
+        "1-SNAPSHOT",
+        "1",
+        "1-sp",
+        "1-sp2",
+        "1-sp123",
+        "1-abc",
+        "1-def",
+        "1-pom-1",
+        "1-1-snapshot",
+        "1-1",
+        "1-2",
+        "1-123"
+    };
 
-    private static final String[] VERSIONS_NUMBER =
-        { "2.0", "2-1", "2.0.a", "2.0.0.a", "2.0.2", "2.0.123", "2.1.0", "2.1-a", "2.1b", "2.1-c", "2.1-1", "2.1.0.1",
-            "2.2", "2.123", "11.a2", "11.a11", "11.b2", "11.b11", "11.m2", "11.m11", "11", "11.a", "11b", "11c", "11m" };
+    private static final String[] VERSIONS_NUMBER = {
+        "2.0", "2.0.a", "2-1", "2.0.2", "2.0.123", "2.1.0", "2.1-a", "2.1b", "2.1-c", "2.1-1", "2.1.0.1", "2.2",
+        "2.123", "11.a2", "11.a11", "11.b2", "11.b11", "11.m2", "11.m11", "11", "11.a", "11b", "11c", "11m"
+    };
 
-    private void checkVersionsOrder( String[] versions )
-    {
+    private void checkVersionsOrder(String[] versions) {
         Comparable[] c = new Comparable[versions.length];
-        for ( int i = 0; i < versions.length; i++ )
-        {
-            c[i] = newComparable( versions[i] );
+        for (int i = 0; i < versions.length; i++) {
+            c[i] = newComparable(versions[i]);
         }
 
-        for ( int i = 1; i < versions.length; i++ )
-        {
+        for (int i = 1; i < versions.length; i++) {
             Comparable low = c[i - 1];
-            for ( int j = i; j < versions.length; j++ )
-            {
+            for (int j = i; j < versions.length; j++) {
                 Comparable high = c[j];
-                assertTrue( low.compareTo( high ) < 0, "expected " + low + " < " + high );
-                assertTrue( high.compareTo( low ) > 0, "expected " + high + " > " + low );
+                assertTrue(low.compareTo(high) < 0, "expected " + low + " < " + high);
+                assertTrue(high.compareTo(low) > 0, "expected " + high + " > " + low);
             }
         }
     }
 
-    private void checkVersionsEqual( String v1, String v2 )
-    {
-        Comparable c1 = newComparable( v1 );
-        Comparable c2 = newComparable( v2 );
-        assertTrue( c1.compareTo( c2 ) == 0, "expected " + v1 + " == " + v2 );
-        assertTrue( c2.compareTo( c1 ) == 0, "expected " + v2 + " == " + v1 );
-        assertTrue( c1.hashCode() == c2.hashCode(), "expected same hashcode for " + v1 + " and " + v2 );
-        assertTrue( c1.equals( c2 ), "expected " + v1 + ".equals( " + v2 + " )" );
-        assertTrue( c2.equals( c1 ), "expected " + v2 + ".equals( " + v1 + " )" );
+    private void checkVersionsEqual(String v1, String v2) {
+        Comparable c1 = newComparable(v1);
+        Comparable c2 = newComparable(v2);
+        assertEquals(0, c1.compareTo(c2), "expected " + v1 + " == " + v2);
+        assertEquals(0, c2.compareTo(c1), "expected " + v2 + " == " + v1);
+        assertEquals(c1.hashCode(), c2.hashCode(), "expected same hashcode for " + v1 + " and " + v2);
+        assertEquals(c1, c2, "expected " + v1 + ".equals( " + v2 + " )");
+        assertEquals(c2, c1, "expected " + v2 + ".equals( " + v1 + " )");
     }
 
-    private void checkVersionsArrayEqual( String[] array )
-    {
+    private void checkVersionsHaveSameOrder(String v1, String v2) {
+        ComparableVersion c1 = new ComparableVersion(v1);
+        ComparableVersion c2 = new ComparableVersion(v2);
+        assertEquals(0, c1.compareTo(c2), "expected " + v1 + " == " + v2);
+        assertEquals(0, c2.compareTo(c1), "expected " + v2 + " == " + v1);
+    }
+
+    private void checkVersionsArrayEqual(String[] array) {
         // compare against each other (including itself)
-        for ( int i = 0; i < array.length; ++i )
-            for ( int j = i; j < array.length; ++j )
-                checkVersionsEqual( array[i], array[j] );
+        for (int i = 0; i < array.length; ++i)
+            for (int j = i; j < array.length; ++j) checkVersionsEqual(array[i], array[j]);
     }
 
-    private void checkVersionsOrder( String v1, String v2 )
-    {
-        Comparable c1 = newComparable( v1 );
-        Comparable c2 = newComparable( v2 );
-        assertTrue( c1.compareTo( c2 ) < 0, "expected " + v1 + " < " + v2 );
-        assertTrue( c2.compareTo( c1 ) > 0, "expected " + v2 + " > " + v1 );
+    private void checkVersionsOrder(String v1, String v2) {
+        Comparable c1 = newComparable(v1);
+        Comparable c2 = newComparable(v2);
+        assertTrue(c1.compareTo(c2) < 0, "expected " + v1 + " < " + v2);
+        assertTrue(c2.compareTo(c1) > 0, "expected " + v2 + " > " + v1);
     }
 
     @Test
-    public void testVersionsQualifier()
-    {
-        checkVersionsOrder( VERSIONS_QUALIFIER );
+    void testVersionsQualifier() {
+        checkVersionsOrder(VERSIONS_QUALIFIER);
     }
 
     @Test
-    public void testVersionsNumber()
-    {
-        checkVersionsOrder( VERSIONS_NUMBER );
+    void testVersionsNumber() {
+        checkVersionsOrder(VERSIONS_NUMBER);
     }
 
     @Test
-    public void testVersionsEqual()
-    {
-        newComparable( "1.0-alpha" );
-        checkVersionsEqual( "1", "1" );
-        checkVersionsEqual( "1", "1.0" );
-        checkVersionsEqual( "1", "1.0.0" );
-        checkVersionsEqual( "1.0", "1.0.0" );
-        checkVersionsEqual( "1", "1-0" );
-        checkVersionsEqual( "1", "1.0-0" );
-        checkVersionsEqual( "1.0", "1.0-0" );
+    void testVersionsEqual() {
+        newComparable("1.0-alpha");
+        checkVersionsEqual("1", "1");
+        checkVersionsEqual("1", "1.0");
+        checkVersionsEqual("1", "1.0.0");
+        checkVersionsEqual("1.0", "1.0.0");
+        checkVersionsEqual("1", "1-0");
+        checkVersionsEqual("1", "1.0-0");
+        checkVersionsEqual("1.0", "1.0-0");
         // no separator between number and character
-        checkVersionsEqual( "1a", "1-a" );
-        checkVersionsEqual( "1a", "1.0-a" );
-        checkVersionsEqual( "1a", "1.0.0-a" );
-        checkVersionsEqual( "1.0a", "1-a" );
-        checkVersionsEqual( "1.0.0a", "1-a" );
-        checkVersionsEqual( "1x", "1-x" );
-        checkVersionsEqual( "1x", "1.0-x" );
-        checkVersionsEqual( "1x", "1.0.0-x" );
-        checkVersionsEqual( "1.0x", "1-x" );
-        checkVersionsEqual( "1.0.0x", "1-x" );
-
-        // aliases
-        checkVersionsEqual( "1ga", "1" );
-        checkVersionsEqual( "1release", "1" );
-        checkVersionsEqual( "1final", "1" );
-        checkVersionsEqual( "1cr", "1rc" );
+        checkVersionsEqual("1a", "1-a");
+        checkVersionsEqual("1a", "1.0-a");
+        checkVersionsEqual("1a", "1.0.0-a");
+        checkVersionsEqual("1.0a", "1-a");
+        checkVersionsEqual("1.0.0a", "1-a");
+        checkVersionsEqual("1x", "1-x");
+        checkVersionsEqual("1x", "1.0-x");
+        checkVersionsEqual("1x", "1.0.0-x");
+        checkVersionsEqual("1.0x", "1-x");
+        checkVersionsEqual("1.0.0x", "1-x");
+        checkVersionsEqual("1cr", "1rc");
 
         // special "aliases" a, b and m for alpha, beta and milestone
-        checkVersionsEqual( "1a1", "1-alpha-1" );
-        checkVersionsEqual( "1b2", "1-beta-2" );
-        checkVersionsEqual( "1m3", "1-milestone-3" );
+        checkVersionsEqual("1a1", "1-alpha-1");
+        checkVersionsEqual("1b2", "1-beta-2");
+        checkVersionsEqual("1m3", "1-milestone-3");
 
         // case insensitive
-        checkVersionsEqual( "1X", "1x" );
-        checkVersionsEqual( "1A", "1a" );
-        checkVersionsEqual( "1B", "1b" );
-        checkVersionsEqual( "1M", "1m" );
-        checkVersionsEqual( "1Ga", "1" );
-        checkVersionsEqual( "1GA", "1" );
-        checkVersionsEqual( "1RELEASE", "1" );
-        checkVersionsEqual( "1release", "1" );
-        checkVersionsEqual( "1RELeaSE", "1" );
-        checkVersionsEqual( "1Final", "1" );
-        checkVersionsEqual( "1FinaL", "1" );
-        checkVersionsEqual( "1FINAL", "1" );
-        checkVersionsEqual( "1Cr", "1Rc" );
-        checkVersionsEqual( "1cR", "1rC" );
-        checkVersionsEqual( "1m3", "1Milestone3" );
-        checkVersionsEqual( "1m3", "1MileStone3" );
-        checkVersionsEqual( "1m3", "1MILESTONE3" );
+        checkVersionsEqual("1X", "1x");
+        checkVersionsEqual("1A", "1a");
+        checkVersionsEqual("1B", "1b");
+        checkVersionsEqual("1M", "1m");
+        checkVersionsEqual("1Cr", "1Rc");
+        checkVersionsEqual("1cR", "1rC");
+        checkVersionsEqual("1m3", "1Milestone3");
+        checkVersionsEqual("1m3", "1MileStone3");
+        checkVersionsEqual("1m3", "1MILESTONE3");
     }
 
     @Test
-    public void testVersionComparing()
-    {
-        checkVersionsOrder( "1", "2" );
-        checkVersionsOrder( "1.5", "2" );
-        checkVersionsOrder( "1", "2.5" );
-        checkVersionsOrder( "1.0", "1.1" );
-        checkVersionsOrder( "1.1", "1.2" );
-        checkVersionsOrder( "1.0.0", "1.1" );
-        checkVersionsOrder( "1.0.1", "1.1" );
-        checkVersionsOrder( "1.1", "1.2.0" );
+    void testVersionsHaveSameOrderButAreNotEqual() {
+        checkVersionsHaveSameOrder("1ga", "1");
+        checkVersionsHaveSameOrder("1release", "1");
+        checkVersionsHaveSameOrder("1final", "1");
+        checkVersionsHaveSameOrder("1Ga", "1");
+        checkVersionsHaveSameOrder("1GA", "1");
+        checkVersionsHaveSameOrder("1RELEASE", "1");
+        checkVersionsHaveSameOrder("1release", "1");
+        checkVersionsHaveSameOrder("1RELeaSE", "1");
+        checkVersionsHaveSameOrder("1Final", "1");
+        checkVersionsHaveSameOrder("1FinaL", "1");
+        checkVersionsHaveSameOrder("1FINAL", "1");
+    }
 
-        checkVersionsOrder( "1.0-alpha-1", "1.0" );
-        checkVersionsOrder( "1.0-alpha-1", "1.0-alpha-2" );
-        checkVersionsOrder( "1.0-alpha-1", "1.0-beta-1" );
+    @Test
+    void testVersionComparing() {
+        checkVersionsOrder("1", "2");
+        checkVersionsOrder("1.5", "2");
+        checkVersionsOrder("1", "2.5");
+        checkVersionsOrder("1.0", "1.1");
+        checkVersionsOrder("1.1", "1.2");
+        checkVersionsOrder("1.0.0", "1.1");
+        checkVersionsOrder("1.0.1", "1.1");
+        checkVersionsOrder("1.1", "1.2.0");
 
-        checkVersionsOrder( "1.0-beta-1", "1.0-SNAPSHOT" );
-        checkVersionsOrder( "1.0-SNAPSHOT", "1.0" );
-        checkVersionsOrder( "1.0-alpha-1-SNAPSHOT", "1.0-alpha-1" );
+        checkVersionsOrder("1.0-alpha-1", "1.0");
+        checkVersionsOrder("1.0-alpha-1", "1.0-alpha-2");
+        checkVersionsOrder("1.0-alpha-1", "1.0-beta-1");
 
-        checkVersionsOrder( "1.0", "1.0-1" );
-        checkVersionsOrder( "1.0-1", "1.0-2" );
-        checkVersionsOrder( "1.0.0", "1.0-1" );
+        checkVersionsOrder("1.0-beta-1", "1.0-SNAPSHOT");
+        checkVersionsOrder("1.0-SNAPSHOT", "1.0");
+        checkVersionsOrder("1.0-alpha-1-SNAPSHOT", "1.0-alpha-1");
 
-        checkVersionsOrder( "2.0-1", "2.0.1" );
-        checkVersionsOrder( "2.0.1-klm", "2.0.1-lmn" );
-        checkVersionsOrder( "2.0.1", "2.0.1-xyz" );
+        checkVersionsOrder("1.0", "1.0-1");
+        checkVersionsOrder("1.0-1", "1.0-2");
+        checkVersionsOrder("1.0.0", "1.0-1");
 
-        checkVersionsOrder( "2.0.1", "2.0.1-123" );
-        checkVersionsOrder( "2.0.1-xyz", "2.0.1-123" );
+        checkVersionsOrder("2.0-1", "2.0.1");
+        checkVersionsOrder("2.0.1-klm", "2.0.1-lmn");
+        checkVersionsOrder("2.0.1", "2.0.1-xyz");
+
+        checkVersionsOrder("2.0.1", "2.0.1-123");
+        checkVersionsOrder("2.0.1-xyz", "2.0.1-123");
+    }
+
+    @Test
+    void testLeadingZeroes() {
+        checkVersionsOrder("0.7", "2");
+        checkVersionsOrder("0.2", "1.0.7");
+    }
+
+    @Test
+    void testGetCanonical() {
+        // MNG-7700
+        newComparable("0.x");
+        newComparable("0-x");
+        newComparable("0.rc");
+        newComparable("0-1");
+
+        ComparableVersion version = new ComparableVersion("0.x");
+        assertEquals("x", version.getCanonical());
+        ComparableVersion version2 = new ComparableVersion("0.2");
+        assertEquals("0.2", version2.getCanonical());
     }
 
     /**
@@ -209,34 +244,32 @@
      * <a href="https://netbeans.org/bugzilla/show_bug.cgi?id=226100">226100</a>
      */
     @Test
-    public void testMng5568()
-    {
+    void testMng5568() {
         String a = "6.1.0";
         String b = "6.1.0rc3";
         String c = "6.1H.5-beta"; // this is the unusual version string, with 'H' in the middle
 
-        checkVersionsOrder( b, a ); // classical
-        checkVersionsOrder( b, c ); // now b < c, but before MNG-5568, we had b > c
-        checkVersionsOrder( a, c );
+        checkVersionsOrder(b, a); // classical
+        checkVersionsOrder(b, c); // now b < c, but before MNG-5568, we had b > c
+        checkVersionsOrder(a, c);
     }
 
     /**
      * Test <a href="https://jira.apache.org/jira/browse/MNG-6572">MNG-6572</a> optimization.
      */
     @Test
-    public void testMng6572()
-    {
+    void testMng6572() {
         String a = "20190126.230843"; // resembles a SNAPSHOT
         String b = "1234567890.12345"; // 10 digit number
         String c = "123456789012345.1H.5-beta"; // 15 digit number
         String d = "12345678901234567890.1H.5-beta"; // 20 digit number
 
-        checkVersionsOrder( a, b );
-        checkVersionsOrder( b, c );
-        checkVersionsOrder( a, c );
-        checkVersionsOrder( c, d );
-        checkVersionsOrder( b, d );
-        checkVersionsOrder( a, d );
+        checkVersionsOrder(a, b);
+        checkVersionsOrder(b, c);
+        checkVersionsOrder(a, c);
+        checkVersionsOrder(c, d);
+        checkVersionsOrder(b, d);
+        checkVersionsOrder(a, d);
     }
 
     /**
@@ -244,8 +277,7 @@
      * (related to MNG-6572 optimization)
      */
     @Test
-    public void testVersionEqualWithLeadingZeroes()
-    {
+    void testVersionEqualWithLeadingZeroes() {
         // versions with string lengths from 1 to 19
         String[] arr = new String[] {
             "0000000000000000001",
@@ -269,7 +301,7 @@
             "1"
         };
 
-        checkVersionsArrayEqual( arr );
+        checkVersionsArrayEqual(arr);
     }
 
     /**
@@ -277,8 +309,7 @@
      * (related to MNG-6572 optimization)
      */
     @Test
-    public void testVersionZeroEqualWithLeadingZeroes()
-    {
+    void testVersionZeroEqualWithLeadingZeroes() {
         // versions with string lengths from 1 to 19
         String[] arr = new String[] {
             "0000000000000000000",
@@ -302,7 +333,7 @@
             "0"
         };
 
-        checkVersionsArrayEqual( arr );
+        checkVersionsArrayEqual(arr);
     }
 
     /**
@@ -310,44 +341,65 @@
      * for qualifiers that start with "-0.", which was showing A == C and B == C but A &lt; B.
      */
     @Test
-    public void testMng6964()
-    {
+    void testMng6964() {
         String a = "1-0.alpha";
         String b = "1-0.beta";
         String c = "1";
 
-        checkVersionsOrder( a, c ); // Now a < c, but before MNG-6964 they were equal
-        checkVersionsOrder( b, c ); // Now b < c, but before MNG-6964 they were equal
-        checkVersionsOrder( a, b ); // Should still be true
+        checkVersionsOrder(a, c); // Now a < c, but before MNG-6964 they were equal
+        checkVersionsOrder(b, c); // Now b < c, but before MNG-6964 they were equal
+        checkVersionsOrder(a, b); // Should still be true
     }
 
     @Test
-    public void testLocaleIndependent()
-    {
+    void testLocaleIndependent() {
         Locale orig = Locale.getDefault();
-        Locale[] locales = { Locale.ENGLISH, new Locale( "tr" ), Locale.getDefault() };
-        try
-        {
-            for ( Locale locale : locales )
-            {
-                Locale.setDefault( locale );
-                checkVersionsEqual( "1-abcdefghijklmnopqrstuvwxyz", "1-ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
+        Locale[] locales = {Locale.ENGLISH, new Locale("tr"), Locale.getDefault()};
+        try {
+            for (Locale locale : locales) {
+                Locale.setDefault(locale);
+                checkVersionsEqual("1-abcdefghijklmnopqrstuvwxyz", "1-ABCDEFGHIJKLMNOPQRSTUVWXYZ");
             }
-        }
-        finally
-        {
-            Locale.setDefault( orig );
+        } finally {
+            Locale.setDefault(orig);
         }
     }
 
     @Test
-    public void testReuse()
-    {
-        ComparableVersion c1 = new ComparableVersion( "1" );
-        c1.parseVersion( "2" );
+    void testReuse() {
+        ComparableVersion c1 = new ComparableVersion("1");
+        c1.parseVersion("2");
 
-        Comparable c2 = newComparable( "2" );
+        Comparable<?> c2 = newComparable("2");
 
-        assertEquals( c1, c2, "reused instance should be equivalent to new instance" );
+        assertEquals(c1, c2, "reused instance should be equivalent to new instance");
+    }
+
+    /**
+     * Test <a href="https://issues.apache.org/jira/browse/MNG-7644">MNG-7644</a> edge cases
+     * 1.0.0.RC1 &lt; 1.0.0-RC2 and more generally:
+     * 1.0.0.X1 &lt; 1.0.0-X2 for any string X
+     */
+    @Test
+    void testMng7644() {
+        for (String x : new String[] {"abc", "alpha", "a", "beta", "b", "def", "milestone", "m", "RC"}) {
+            // 1.0.0.X1 < 1.0.0-X2 for any string x
+            checkVersionsOrder("1.0.0." + x + "1", "1.0.0-" + x + "2");
+            // 2.0.X == 2-X == 2.0.0.X for any string x
+            checkVersionsEqual("2-" + x, "2.0." + x); // previously ordered, now equals
+            checkVersionsEqual("2-" + x, "2.0.0." + x); // previously ordered, now equals
+            checkVersionsEqual("2.0." + x, "2.0.0." + x); // previously ordered, now equals
+        }
+    }
+
+    @Test
+    public void testMng7714() {
+        ComparableVersion f = new ComparableVersion("1.0.final-redhat");
+        ComparableVersion sp1 = new ComparableVersion("1.0-sp1-redhat");
+        ComparableVersion sp2 = new ComparableVersion("1.0-sp-1-redhat");
+        ComparableVersion sp3 = new ComparableVersion("1.0-sp.1-redhat");
+        assertTrue(f.compareTo(sp1) < 0, "expected " + f + " < " + sp1);
+        assertTrue(f.compareTo(sp1) < 0, "expected " + f + " < " + sp2);
+        assertTrue(f.compareTo(sp1) < 0, "expected " + f + " < " + sp3);
     }
 }
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/DefaultArtifactVersionTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/DefaultArtifactVersionTest.java
index 13f3ffa..370b0f0 100644
--- a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/DefaultArtifactVersionTest.java
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/DefaultArtifactVersionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,198 +27,184 @@
 /**
  * Test DefaultArtifactVersion.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class DefaultArtifactVersionTest
-{
-    private ArtifactVersion newArtifactVersion( String version )
-    {
-        return new DefaultArtifactVersion( version );
+class DefaultArtifactVersionTest {
+    private ArtifactVersion newArtifactVersion(String version) {
+        return new DefaultArtifactVersion(version);
     }
 
-    private void checkVersionParsing( String version, int major, int minor, int incremental, int buildnumber,
-                                      String qualifier )
-    {
-        ArtifactVersion artifactVersion = newArtifactVersion( version );
-        String parsed =
-            "'" + version + "' parsed as ('" + artifactVersion.getMajorVersion() + "', '"
+    private void checkVersionParsing(
+            String version, int major, int minor, int incremental, int buildnumber, String qualifier) {
+        ArtifactVersion artifactVersion = newArtifactVersion(version);
+        String parsed = "'" + version + "' parsed as ('" + artifactVersion.getMajorVersion() + "', '"
                 + artifactVersion.getMinorVersion() + "', '" + artifactVersion.getIncrementalVersion() + "', '"
                 + artifactVersion.getBuildNumber() + "', '" + artifactVersion.getQualifier() + "'), ";
-        assertEquals( major, artifactVersion.getMajorVersion(), parsed + "check major version" );
-        assertEquals( minor, artifactVersion.getMinorVersion(), parsed + "check minor version" );
-        assertEquals( incremental, artifactVersion.getIncrementalVersion(), parsed + "check incremental version" );
-        assertEquals( buildnumber, artifactVersion.getBuildNumber(), parsed + "check build number" );
-        assertEquals( qualifier, artifactVersion.getQualifier(), parsed + "check qualifier" );
-        assertEquals( version, artifactVersion.toString(), "check " + version + " string value" );
+        assertEquals(major, artifactVersion.getMajorVersion(), parsed + "check major version");
+        assertEquals(minor, artifactVersion.getMinorVersion(), parsed + "check minor version");
+        assertEquals(incremental, artifactVersion.getIncrementalVersion(), parsed + "check incremental version");
+        assertEquals(buildnumber, artifactVersion.getBuildNumber(), parsed + "check build number");
+        assertEquals(qualifier, artifactVersion.getQualifier(), parsed + "check qualifier");
+        assertEquals(version, artifactVersion.toString(), "check " + version + " string value");
     }
 
     @Test
-    public void testVersionParsing()
-    {
-        checkVersionParsing( "1", 1, 0, 0, 0, null );
-        checkVersionParsing( "1.2", 1, 2, 0, 0, null );
-        checkVersionParsing( "1.2.3", 1, 2, 3, 0, null );
-        checkVersionParsing( "1.2.3-1", 1, 2, 3, 1, null );
-        checkVersionParsing( "1.2.3-alpha-1", 1, 2, 3, 0, "alpha-1" );
-        checkVersionParsing( "1.2-alpha-1", 1, 2, 0, 0, "alpha-1" );
-        checkVersionParsing( "1.2-alpha-1-20050205.060708-1", 1, 2, 0, 0, "alpha-1-20050205.060708-1" );
-        checkVersionParsing( "RELEASE", 0, 0, 0, 0, "RELEASE" );
-        checkVersionParsing( "2.0-1", 2, 0, 0, 1, null );
+    void testVersionParsing() {
+        checkVersionParsing("1", 1, 0, 0, 0, null);
+        checkVersionParsing("1.2", 1, 2, 0, 0, null);
+        checkVersionParsing("1.2.3", 1, 2, 3, 0, null);
+        checkVersionParsing("1.2.3-1", 1, 2, 3, 1, null);
+        checkVersionParsing("1.2.3-alpha-1", 1, 2, 3, 0, "alpha-1");
+        checkVersionParsing("1.2-alpha-1", 1, 2, 0, 0, "alpha-1");
+        checkVersionParsing("1.2-alpha-1-20050205.060708-1", 1, 2, 0, 0, "alpha-1-20050205.060708-1");
+        checkVersionParsing("RELEASE", 0, 0, 0, 0, "RELEASE");
+        checkVersionParsing("2.0-1", 2, 0, 0, 1, null);
 
         // 0 at the beginning of a number has a special handling
-        checkVersionParsing( "02", 0, 0, 0, 0, "02" );
-        checkVersionParsing( "0.09", 0, 0, 0, 0, "0.09" );
-        checkVersionParsing( "0.2.09", 0, 0, 0, 0, "0.2.09" );
-        checkVersionParsing( "2.0-01", 2, 0, 0, 0, "01" );
+        checkVersionParsing("02", 0, 0, 0, 0, "02");
+        checkVersionParsing("0.09", 0, 0, 0, 0, "0.09");
+        checkVersionParsing("0.2.09", 0, 0, 0, 0, "0.2.09");
+        checkVersionParsing("2.0-01", 2, 0, 0, 0, "01");
 
         // version schemes not really supported: fully transformed as qualifier
-        checkVersionParsing( "1.0.1b", 0, 0, 0, 0, "1.0.1b" );
-        checkVersionParsing( "1.0M2", 0, 0, 0, 0, "1.0M2" );
-        checkVersionParsing( "1.0RC2", 0, 0, 0, 0, "1.0RC2" );
-        checkVersionParsing( "1.1.2.beta1", 1, 1, 2, 0, "beta1" );
-        checkVersionParsing( "1.7.3.beta1", 1, 7, 3, 0, "beta1" );
-        checkVersionParsing( "1.7.3.0", 0, 0, 0, 0, "1.7.3.0" );
-        checkVersionParsing( "1.7.3.0-1", 0, 0, 0, 0, "1.7.3.0-1" );
-        checkVersionParsing( "PATCH-1193602", 0, 0, 0, 0, "PATCH-1193602" );
-        checkVersionParsing( "5.0.0alpha-2006020117", 0, 0, 0, 0, "5.0.0alpha-2006020117" );
-        checkVersionParsing( "1.0.0.-SNAPSHOT", 0, 0, 0, 0, "1.0.0.-SNAPSHOT" );
-        checkVersionParsing( "1..0-SNAPSHOT", 0, 0, 0, 0, "1..0-SNAPSHOT" );
-        checkVersionParsing( "1.0.-SNAPSHOT", 0, 0, 0, 0, "1.0.-SNAPSHOT" );
-        checkVersionParsing( ".1.0-SNAPSHOT", 0, 0, 0, 0, ".1.0-SNAPSHOT" );
+        checkVersionParsing("1.0.1b", 0, 0, 0, 0, "1.0.1b");
+        checkVersionParsing("1.0M2", 0, 0, 0, 0, "1.0M2");
+        checkVersionParsing("1.0RC2", 0, 0, 0, 0, "1.0RC2");
+        checkVersionParsing("1.1.2.beta1", 1, 1, 2, 0, "beta1");
+        checkVersionParsing("1.7.3.beta1", 1, 7, 3, 0, "beta1");
+        checkVersionParsing("1.7.3.0", 0, 0, 0, 0, "1.7.3.0");
+        checkVersionParsing("1.7.3.0-1", 0, 0, 0, 0, "1.7.3.0-1");
+        checkVersionParsing("PATCH-1193602", 0, 0, 0, 0, "PATCH-1193602");
+        checkVersionParsing("5.0.0alpha-2006020117", 0, 0, 0, 0, "5.0.0alpha-2006020117");
+        checkVersionParsing("1.0.0.-SNAPSHOT", 0, 0, 0, 0, "1.0.0.-SNAPSHOT");
+        checkVersionParsing("1..0-SNAPSHOT", 0, 0, 0, 0, "1..0-SNAPSHOT");
+        checkVersionParsing("1.0.-SNAPSHOT", 0, 0, 0, 0, "1.0.-SNAPSHOT");
+        checkVersionParsing(".1.0-SNAPSHOT", 0, 0, 0, 0, ".1.0-SNAPSHOT");
 
-        checkVersionParsing( "1.2.3.200705301630", 0, 0, 0, 0, "1.2.3.200705301630" );
-        checkVersionParsing( "1.2.3-200705301630", 1, 2, 3, 0, "200705301630" );
+        checkVersionParsing("1.2.3.200705301630", 0, 0, 0, 0, "1.2.3.200705301630");
+        checkVersionParsing("1.2.3-200705301630", 1, 2, 3, 0, "200705301630");
     }
 
     @Test
-    public void testVersionComparing()
-    {
-        assertVersionEqual( "1", "1" );
-        assertVersionOlder( "1", "2" );
-        assertVersionOlder( "1.5", "2" );
-        assertVersionOlder( "1", "2.5" );
-        assertVersionEqual( "1", "1.0" );
-        assertVersionEqual( "1", "1.0.0" );
-        assertVersionOlder( "1.0", "1.1" );
-        assertVersionOlder( "1.1", "1.2" );
-        assertVersionOlder( "1.0.0", "1.1" );
-        assertVersionOlder( "1.1", "1.2.0" );
+    void testVersionComparing() {
+        assertVersionEqual("1", "1");
+        assertVersionOlder("1", "2");
+        assertVersionOlder("1.5", "2");
+        assertVersionOlder("1", "2.5");
+        assertVersionEqual("1", "1.0");
+        assertVersionEqual("1", "1.0.0");
+        assertVersionOlder("1.0", "1.1");
+        assertVersionOlder("1.1", "1.2");
+        assertVersionOlder("1.0.0", "1.1");
+        assertVersionOlder("1.1", "1.2.0");
 
-        assertVersionOlder( "1.1.2.alpha1", "1.1.2" );
-        assertVersionOlder( "1.1.2.alpha1", "1.1.2.beta1" );
-        assertVersionOlder( "1.1.2.beta1", "1.2" );
+        assertVersionOlder("1.1.2.alpha1", "1.1.2");
+        assertVersionOlder("1.1.2.alpha1", "1.1.2.beta1");
+        assertVersionOlder("1.1.2.beta1", "1.2");
 
-        assertVersionOlder( "1.0-alpha-1", "1.0" );
-        assertVersionOlder( "1.0-alpha-1", "1.0-alpha-2" );
-        assertVersionOlder( "1.0-alpha-2", "1.0-alpha-15" );
-        assertVersionOlder( "1.0-alpha-1", "1.0-beta-1" );
+        assertVersionOlder("1.0-alpha-1", "1.0");
+        assertVersionOlder("1.0-alpha-1", "1.0-alpha-2");
+        assertVersionOlder("1.0-alpha-2", "1.0-alpha-15");
+        assertVersionOlder("1.0-alpha-1", "1.0-beta-1");
 
-        assertVersionOlder( "1.0-beta-1", "1.0-SNAPSHOT" );
-        assertVersionOlder( "1.0-SNAPSHOT", "1.0" );
-        assertVersionOlder( "1.0-alpha-1-SNAPSHOT", "1.0-alpha-1" );
+        assertVersionOlder("1.0-beta-1", "1.0-SNAPSHOT");
+        assertVersionOlder("1.0-SNAPSHOT", "1.0");
+        assertVersionOlder("1.0-alpha-1-SNAPSHOT", "1.0-alpha-1");
 
-        assertVersionOlder( "1.0", "1.0-1" );
-        assertVersionOlder( "1.0-1", "1.0-2" );
-        assertVersionEqual( "2.0-0", "2.0" );
-        assertVersionOlder( "2.0", "2.0-1" );
-        assertVersionOlder( "2.0.0", "2.0-1" );
-        assertVersionOlder( "2.0-1", "2.0.1" );
+        assertVersionOlder("1.0", "1.0-1");
+        assertVersionOlder("1.0-1", "1.0-2");
+        assertVersionEqual("2.0-0", "2.0");
+        assertVersionOlder("2.0", "2.0-1");
+        assertVersionOlder("2.0.0", "2.0-1");
+        assertVersionOlder("2.0-1", "2.0.1");
 
-        assertVersionOlder( "2.0.1-klm", "2.0.1-lmn" );
-        assertVersionOlder( "2.0.1", "2.0.1-xyz" );
-        assertVersionOlder( "2.0.1-xyz-1", "2.0.1-1-xyz" );
+        assertVersionOlder("2.0.1-klm", "2.0.1-lmn");
+        assertVersionOlder("2.0.1", "2.0.1-xyz");
+        assertVersionOlder("2.0.1-xyz-1", "2.0.1-1-xyz");
 
-        assertVersionOlder( "2.0.1", "2.0.1-123" );
-        assertVersionOlder( "2.0.1-xyz", "2.0.1-123" );
+        assertVersionOlder("2.0.1", "2.0.1-123");
+        assertVersionOlder("2.0.1-xyz", "2.0.1-123");
 
-        assertVersionOlder( "1.2.3-10000000000", "1.2.3-10000000001" );
-        assertVersionOlder( "1.2.3-1", "1.2.3-10000000001" );
-        assertVersionOlder( "2.3.0-v200706262000", "2.3.0-v200706262130" ); // org.eclipse:emf:2.3.0-v200706262000
+        assertVersionOlder("1.2.3-10000000000", "1.2.3-10000000001");
+        assertVersionOlder("1.2.3-1", "1.2.3-10000000001");
+        assertVersionOlder("2.3.0-v200706262000", "2.3.0-v200706262130"); // org.eclipse:emf:2.3.0-v200706262000
         // org.eclipse.wst.common_core.feature_2.0.0.v200706041905-7C78EK9E_EkMNfNOd2d8qq
-        assertVersionOlder( "2.0.0.v200706041905-7C78EK9E_EkMNfNOd2d8qq", "2.0.0.v200706041906-7C78EK9E_EkMNfNOd2d8qq" );
+        assertVersionOlder("2.0.0.v200706041905-7C78EK9E_EkMNfNOd2d8qq", "2.0.0.v200706041906-7C78EK9E_EkMNfNOd2d8qq");
     }
 
     @Test
-    public void testVersionSnapshotComparing()
-    {
-        assertVersionEqual( "1-SNAPSHOT", "1-SNAPSHOT" );
-        assertVersionOlder( "1-SNAPSHOT", "2-SNAPSHOT" );
-        assertVersionOlder( "1.5-SNAPSHOT", "2-SNAPSHOT" );
-        assertVersionOlder( "1-SNAPSHOT", "2.5-SNAPSHOT" );
-        assertVersionEqual( "1-SNAPSHOT", "1.0-SNAPSHOT" );
-        assertVersionEqual( "1-SNAPSHOT", "1.0.0-SNAPSHOT" );
-        assertVersionOlder( "1.0-SNAPSHOT", "1.1-SNAPSHOT" );
-        assertVersionOlder( "1.1-SNAPSHOT", "1.2-SNAPSHOT" );
-        assertVersionOlder( "1.0.0-SNAPSHOT", "1.1-SNAPSHOT" );
-        assertVersionOlder( "1.1-SNAPSHOT", "1.2.0-SNAPSHOT" );
+    void testVersionSnapshotComparing() {
+        assertVersionEqual("1-SNAPSHOT", "1-SNAPSHOT");
+        assertVersionOlder("1-SNAPSHOT", "2-SNAPSHOT");
+        assertVersionOlder("1.5-SNAPSHOT", "2-SNAPSHOT");
+        assertVersionOlder("1-SNAPSHOT", "2.5-SNAPSHOT");
+        assertVersionEqual("1-SNAPSHOT", "1.0-SNAPSHOT");
+        assertVersionEqual("1-SNAPSHOT", "1.0.0-SNAPSHOT");
+        assertVersionOlder("1.0-SNAPSHOT", "1.1-SNAPSHOT");
+        assertVersionOlder("1.1-SNAPSHOT", "1.2-SNAPSHOT");
+        assertVersionOlder("1.0.0-SNAPSHOT", "1.1-SNAPSHOT");
+        assertVersionOlder("1.1-SNAPSHOT", "1.2.0-SNAPSHOT");
 
         // assertVersionOlder( "1.0-alpha-1-SNAPSHOT", "1.0-SNAPSHOT" );
-        assertVersionOlder( "1.0-alpha-1-SNAPSHOT", "1.0-alpha-2-SNAPSHOT" );
-        assertVersionOlder( "1.0-alpha-1-SNAPSHOT", "1.0-beta-1-SNAPSHOT" );
+        assertVersionOlder("1.0-alpha-1-SNAPSHOT", "1.0-alpha-2-SNAPSHOT");
+        assertVersionOlder("1.0-alpha-1-SNAPSHOT", "1.0-beta-1-SNAPSHOT");
 
-        assertVersionOlder( "1.0-beta-1-SNAPSHOT", "1.0-SNAPSHOT-SNAPSHOT" );
-        assertVersionOlder( "1.0-SNAPSHOT-SNAPSHOT", "1.0-SNAPSHOT" );
-        assertVersionOlder( "1.0-alpha-1-SNAPSHOT-SNAPSHOT", "1.0-alpha-1-SNAPSHOT" );
+        assertVersionOlder("1.0-beta-1-SNAPSHOT", "1.0-SNAPSHOT-SNAPSHOT");
+        assertVersionOlder("1.0-SNAPSHOT-SNAPSHOT", "1.0-SNAPSHOT");
+        assertVersionOlder("1.0-alpha-1-SNAPSHOT-SNAPSHOT", "1.0-alpha-1-SNAPSHOT");
 
-        assertVersionOlder( "1.0-SNAPSHOT", "1.0-1-SNAPSHOT" );
-        assertVersionOlder( "1.0-1-SNAPSHOT", "1.0-2-SNAPSHOT" );
+        assertVersionOlder("1.0-SNAPSHOT", "1.0-1-SNAPSHOT");
+        assertVersionOlder("1.0-1-SNAPSHOT", "1.0-2-SNAPSHOT");
         // assertVersionEqual( "2.0-0-SNAPSHOT", "2.0-SNAPSHOT" );
-        assertVersionOlder( "2.0-SNAPSHOT", "2.0-1-SNAPSHOT" );
-        assertVersionOlder( "2.0.0-SNAPSHOT", "2.0-1-SNAPSHOT" );
-        assertVersionOlder( "2.0-1-SNAPSHOT", "2.0.1-SNAPSHOT" );
+        assertVersionOlder("2.0-SNAPSHOT", "2.0-1-SNAPSHOT");
+        assertVersionOlder("2.0.0-SNAPSHOT", "2.0-1-SNAPSHOT");
+        assertVersionOlder("2.0-1-SNAPSHOT", "2.0.1-SNAPSHOT");
 
-        assertVersionOlder( "2.0.1-klm-SNAPSHOT", "2.0.1-lmn-SNAPSHOT" );
+        assertVersionOlder("2.0.1-klm-SNAPSHOT", "2.0.1-lmn-SNAPSHOT");
         // assertVersionOlder( "2.0.1-xyz-SNAPSHOT", "2.0.1-SNAPSHOT" );
-        assertVersionOlder( "2.0.1-SNAPSHOT", "2.0.1-123-SNAPSHOT" );
-        assertVersionOlder( "2.0.1-xyz-SNAPSHOT", "2.0.1-123-SNAPSHOT" );
+        assertVersionOlder("2.0.1-SNAPSHOT", "2.0.1-123-SNAPSHOT");
+        assertVersionOlder("2.0.1-xyz-SNAPSHOT", "2.0.1-123-SNAPSHOT");
     }
 
     @Test
-    public void testSnapshotVsReleases()
-    {
-        assertVersionOlder( "1.0-RC1", "1.0-SNAPSHOT" );
-        assertVersionOlder( "1.0-rc1", "1.0-SNAPSHOT" );
-        assertVersionOlder( "1.0-rc-1", "1.0-SNAPSHOT" );
+    void testSnapshotVsReleases() {
+        assertVersionOlder("1.0-RC1", "1.0-SNAPSHOT");
+        assertVersionOlder("1.0-rc1", "1.0-SNAPSHOT");
+        assertVersionOlder("1.0-rc-1", "1.0-SNAPSHOT");
     }
 
     @Test
-    public void testHashCode()
-    {
-        ArtifactVersion v1 = newArtifactVersion( "1" );
-        ArtifactVersion v2 = newArtifactVersion( "1.0" );
-        assertTrue( v1.equals( v2 ) );
-        assertEquals( v1.hashCode(), v2.hashCode() );
+    void testHashCode() {
+        ArtifactVersion v1 = newArtifactVersion("1");
+        ArtifactVersion v2 = newArtifactVersion("1.0");
+        assertTrue(v1.equals(v2));
+        assertEquals(v1.hashCode(), v2.hashCode());
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( newArtifactVersion( "1" ).equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(newArtifactVersion("1").equals(null));
     }
 
     @Test
-    public void testEqualsTypeSafe()
-    {
-        assertFalse( newArtifactVersion( "1" ).equals( "non-an-artifact-version-instance" ) );
+    void testEqualsTypeSafe() {
+        assertFalse(newArtifactVersion("1").equals("non-an-artifact-version-instance"));
     }
 
-    private void assertVersionOlder( String left, String right )
-    {
+    private void assertVersionOlder(String left, String right) {
         assertTrue(
-                newArtifactVersion( left ).compareTo( newArtifactVersion( right ) ) < 0,
-                left + " should be older than " + right );
+                newArtifactVersion(left).compareTo(newArtifactVersion(right)) < 0,
+                left + " should be older than " + right);
         assertTrue(
-                newArtifactVersion( right ).compareTo( newArtifactVersion( left ) ) > 0,
-                right + " should be newer than " + left );
+                newArtifactVersion(right).compareTo(newArtifactVersion(left)) > 0,
+                right + " should be newer than " + left);
     }
 
-    private void assertVersionEqual( String left, String right )
-    {
+    private void assertVersionEqual(String left, String right) {
         assertTrue(
-                newArtifactVersion( left ).compareTo( newArtifactVersion( right ) ) == 0,
-                left + " should be equal to " + right );
+                newArtifactVersion(left).compareTo(newArtifactVersion(right)) == 0,
+                left + " should be equal to " + right);
         assertTrue(
-                newArtifactVersion( right ).compareTo( newArtifactVersion( left ) ) == 0,
-                right + " should be equal to " + left );
+                newArtifactVersion(right).compareTo(newArtifactVersion(left)) == 0,
+                right + " should be equal to " + left);
     }
 }
diff --git a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/VersionRangeTest.java b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/VersionRangeTest.java
index 50270a0..ea8b240 100644
--- a/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/VersionRangeTest.java
+++ b/maven-artifact/src/test/java/org/apache/maven/artifact/versioning/VersionRangeTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import java.util.List;
 
@@ -34,10 +33,8 @@
 /**
  * Tests version range construction.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class VersionRangeTest
-{
+class VersionRangeTest {
     private static final String CHECK_NUM_RESTRICTIONS = "check number of restrictions";
 
     private static final String CHECK_UPPER_BOUND = "check upper bound";
@@ -55,704 +52,698 @@
     private static final String CHECK_SELECTED_VERSION = "check selected version";
 
     @Test
-    public void testRange()
-        throws InvalidVersionSpecificationException, OverConstrainedVersionException
-    {
+    void testRange() throws InvalidVersionSpecificationException, OverConstrainedVersionException {
         Artifact artifact = null;
 
-        VersionRange range = VersionRange.createFromVersionSpec( "(,1.0]" );
+        VersionRange range = VersionRange.createFromVersionSpec("(,1.0]");
         List<Restriction> restrictions = range.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        Restriction restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertNull( range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
-        assertFalse( range.isSelectedVersionKnown( artifact ), CHECK_SELECTED_VERSION_KNOWN );
-        assertNull( range.getSelectedVersion( artifact ), CHECK_SELECTED_VERSION );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        Restriction restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertNull(range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
+        assertFalse(range.isSelectedVersionKnown(artifact), CHECK_SELECTED_VERSION_KNOWN);
+        assertNull(range.getSelectedVersion(artifact), CHECK_SELECTED_VERSION);
 
-        range = VersionRange.createFromVersionSpec( "1.0" );
-        assertEquals( "1.0", range.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        range = VersionRange.createFromVersionSpec("1.0");
+        assertEquals("1.0", range.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = range.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertTrue( range.isSelectedVersionKnown( artifact ), CHECK_SELECTED_VERSION_KNOWN );
-        assertEquals( "1.0", range.getSelectedVersion( artifact ).toString(), CHECK_SELECTED_VERSION );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertTrue(range.isSelectedVersionKnown(artifact), CHECK_SELECTED_VERSION_KNOWN);
+        assertEquals("1.0", range.getSelectedVersion(artifact).toString(), CHECK_SELECTED_VERSION);
 
-        range = VersionRange.createFromVersionSpec( "[1.0]" );
+        range = VersionRange.createFromVersionSpec("[1.0]");
         restrictions = range.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.0", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertNull( range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
-        assertFalse( range.isSelectedVersionKnown( artifact ), CHECK_SELECTED_VERSION_KNOWN );
-        assertNull( range.getSelectedVersion( artifact ), CHECK_SELECTED_VERSION );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.0", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertNull(range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
+        assertFalse(range.isSelectedVersionKnown(artifact), CHECK_SELECTED_VERSION_KNOWN);
+        assertNull(range.getSelectedVersion(artifact), CHECK_SELECTED_VERSION);
 
-        range = VersionRange.createFromVersionSpec( "[1.2,1.3]" );
+        range = VersionRange.createFromVersionSpec("[1.2,1.3]");
         restrictions = range.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertNull( range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
-        assertFalse( range.isSelectedVersionKnown( artifact ), CHECK_SELECTED_VERSION_KNOWN );
-        assertNull( range.getSelectedVersion( artifact ), CHECK_SELECTED_VERSION );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertNull(range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
+        assertFalse(range.isSelectedVersionKnown(artifact), CHECK_SELECTED_VERSION_KNOWN);
+        assertNull(range.getSelectedVersion(artifact), CHECK_SELECTED_VERSION);
 
-        range = VersionRange.createFromVersionSpec( "[1.0,2.0)" );
+        range = VersionRange.createFromVersionSpec("[1.0,2.0)");
         restrictions = range.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.0", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "2.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertNull( range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
-        assertFalse( range.isSelectedVersionKnown( artifact ), CHECK_SELECTED_VERSION_KNOWN );
-        assertNull( range.getSelectedVersion( artifact ), CHECK_SELECTED_VERSION );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.0", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("2.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertNull(range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
+        assertFalse(range.isSelectedVersionKnown(artifact), CHECK_SELECTED_VERSION_KNOWN);
+        assertNull(range.getSelectedVersion(artifact), CHECK_SELECTED_VERSION);
 
-        range = VersionRange.createFromVersionSpec( "[1.5,)" );
+        range = VersionRange.createFromVersionSpec("[1.5,)");
         restrictions = range.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.5", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertNull( range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
-        assertFalse( range.isSelectedVersionKnown( artifact ), CHECK_SELECTED_VERSION_KNOWN );
-        assertNull( range.getSelectedVersion( artifact ), CHECK_SELECTED_VERSION );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.5", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertNull(range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
+        assertFalse(range.isSelectedVersionKnown(artifact), CHECK_SELECTED_VERSION_KNOWN);
+        assertNull(range.getSelectedVersion(artifact), CHECK_SELECTED_VERSION);
 
-        range = VersionRange.createFromVersionSpec( "(,1.0],[1.2,)" );
+        range = VersionRange.createFromVersionSpec("(,1.0],[1.2,)");
         restrictions = range.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertNull( range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        assertNull( range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
-        assertFalse( range.isSelectedVersionKnown( artifact ), CHECK_SELECTED_VERSION_KNOWN );
-        assertNull( range.getSelectedVersion( artifact ), CHECK_SELECTED_VERSION );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertNull(range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
+        restriction = restrictions.get(1);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        assertNull(range.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
+        assertFalse(range.isSelectedVersionKnown(artifact), CHECK_SELECTED_VERSION_KNOWN);
+        assertNull(range.getSelectedVersion(artifact), CHECK_SELECTED_VERSION);
 
-        range = VersionRange.createFromVersionSpec( "[1.0,)" );
-        assertFalse( range.containsVersion( new DefaultArtifactVersion( "1.0-SNAPSHOT" ) ) );
+        range = VersionRange.createFromVersionSpec("[1.0,)");
+        assertFalse(range.containsVersion(new DefaultArtifactVersion("1.0-SNAPSHOT")));
 
-        range = VersionRange.createFromVersionSpec( "[1.0,1.1-SNAPSHOT]" );
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.1-SNAPSHOT" ) ) );
+        range = VersionRange.createFromVersionSpec("[1.0,1.1-SNAPSHOT]");
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.1-SNAPSHOT")));
 
-        range = VersionRange.createFromVersionSpec( "[5.0.9.0,5.0.10.0)" );
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "5.0.9.0" ) ) );
+        range = VersionRange.createFromVersionSpec("[5.0.9.0,5.0.10.0)");
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("5.0.9.0")));
     }
 
     @Test
-    public void testInvalidRanges()
-    {
-        checkInvalidRange( "(1.0)" );
-        checkInvalidRange( "[1.0)" );
-        checkInvalidRange( "(1.0]" );
-        checkInvalidRange( "(1.0,1.0]" );
-        checkInvalidRange( "[1.0,1.0)" );
-        checkInvalidRange( "(1.0,1.0)" );
-        checkInvalidRange( "[1.1,1.0]" );
-        checkInvalidRange( "[1.0,1.2),1.3" );
+    void testSameUpperAndLowerBoundRoundtrip() throws InvalidVersionSpecificationException {
+        VersionRange range = VersionRange.createFromVersionSpec("[1.0]");
+        VersionRange range2 = VersionRange.createFromVersionSpec(range.toString());
+        assertEquals(range, range2);
+    }
+
+    @Test
+    void testInvalidRanges() {
+        checkInvalidRange("(1.0)");
+        checkInvalidRange("[1.0)");
+        checkInvalidRange("(1.0]");
+        checkInvalidRange("(1.0,1.0]");
+        checkInvalidRange("[1.0,1.0)");
+        checkInvalidRange("(1.0,1.0)");
+        checkInvalidRange("[1.1,1.0]");
+        checkInvalidRange("[1.0,1.2),1.3");
         // overlap
-        checkInvalidRange( "[1.0,1.2),(1.1,1.3]" );
+        checkInvalidRange("[1.0,1.2),(1.1,1.3]");
         // overlap
-        checkInvalidRange( "[1.1,1.3),(1.0,1.2]" );
+        checkInvalidRange("[1.1,1.3),(1.0,1.2]");
         // ordering
-        checkInvalidRange( "(1.1,1.2],[1.0,1.1)" );
+        checkInvalidRange("(1.1,1.2],[1.0,1.1)");
     }
 
     @Test
-    public void testIntersections()
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange range1 = VersionRange.createFromVersionSpec( "1.0" );
-        VersionRange range2 = VersionRange.createFromVersionSpec( "1.1" );
-        VersionRange mergedRange = range1.restrict( range2 );
-        // TODO current policy is to retain the original version - is this correct, do we need strategies or is that handled elsewhere?
-//        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
-        assertEquals( "1.0", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+    void testIntersections() throws InvalidVersionSpecificationException {
+        VersionRange range1 = VersionRange.createFromVersionSpec("1.0");
+        VersionRange range2 = VersionRange.createFromVersionSpec("1.1");
+        VersionRange mergedRange = range1.restrict(range2);
+        // TODO current policy is to retain the original version - is this correct, do we need strategies or is that
+        // handled elsewhere?
+        //        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        assertEquals("1.0", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         List<Restriction> restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        Restriction restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        Restriction restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        mergedRange = range2.restrict( range1 );
-        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        mergedRange = range2.restrict(range1);
+        assertEquals("1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
         // TODO test reversed restrictions on all below
-        range1 = VersionRange.createFromVersionSpec( "[1.0,)" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,)");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertEquals("1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.0", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.0", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.1,)" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.1,)");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertEquals("1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.1]" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.1]");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertEquals("1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(1.1,)" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(1.1,)");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.2,)" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.2,)");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.2]" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.2]");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertEquals("1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.1]" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertEquals( "1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.1]");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertEquals("1.1", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.1)" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.1)");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.0]" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.0]");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.0], [1.1,)" );
-        range2 = VersionRange.createFromVersionSpec( "1.2" );
-        mergedRange = range1.restrict( range2 );
-        assertEquals( "1.2", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.0], [1.1,)");
+        range2 = VersionRange.createFromVersionSpec("1.2");
+        mergedRange = range1.restrict(range2);
+        assertEquals("1.2", mergedRange.getRecommendedVersion().toString(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.0], [1.1,)" );
-        range2 = VersionRange.createFromVersionSpec( "1.0.5" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.0], [1.1,)");
+        range2 = VersionRange.createFromVersionSpec("1.0.5");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.0", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.1), (1.1,)" );
-        range2 = VersionRange.createFromVersionSpec( "1.1" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.1), (1.1,)");
+        range2 = VersionRange.createFromVersionSpec("1.1");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertNull( restriction.getLowerBound(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertNull( restriction.getUpperBound(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertNull(restriction.getLowerBound(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertNull(restriction.getUpperBound(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.1,1.3]" );
-        range2 = VersionRange.createFromVersionSpec( "(1.1,)" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.1,1.3]");
+        range2 = VersionRange.createFromVersionSpec("(1.1,)");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.3)" );
-        range2 = VersionRange.createFromVersionSpec( "[1.2,1.3]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.3)");
+        range2 = VersionRange.createFromVersionSpec("[1.2,1.3]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.1,1.3]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.2,)" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.1,1.3]");
+        range2 = VersionRange.createFromVersionSpec("[1.2,)");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.3]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.2,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.3]");
+        range2 = VersionRange.createFromVersionSpec("[1.2,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(1.2,1.3]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(1.2,1.3]");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(1.2,1.3)" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(1.2,1.3)");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.2,1.3)" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.2,1.3)");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.2", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.3", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.1]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.1]");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.1)" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.1)");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 0, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(0, restrictions.size(), CHECK_NUM_RESTRICTIONS);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2],[1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2],[1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("[1.1]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.1", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2],[1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2],[1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("[1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.4", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.4", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2],[1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2],[1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2),(1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2),(1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2],[1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "(1.1,1.4)" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2],[1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("(1.1,1.4)");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2),(1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "(1.1,1.4)" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2),(1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("(1.1,1.4)");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertFalse( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertFalse( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertFalse(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertFalse(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.1),(1.4,)" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.1),(1.4,)");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 0, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(0, restrictions.size(), CHECK_NUM_RESTRICTIONS);
 
-        range1 = VersionRange.createFromVersionSpec( "(,1.1],[1.4,)" );
-        range2 = VersionRange.createFromVersionSpec( "(1.1,1.4)" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("(,1.1],[1.4,)");
+        range2 = VersionRange.createFromVersionSpec("(1.1,1.4)");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 0, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(0, restrictions.size(), CHECK_NUM_RESTRICTIONS);
 
-        range1 = VersionRange.createFromVersionSpec( "[,1.1],[1.4,]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.2,1.3]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[,1.1],[1.4,]");
+        range2 = VersionRange.createFromVersionSpec("[1.2,1.3]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 0, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(0, restrictions.size(), CHECK_NUM_RESTRICTIONS);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2],[1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4],[1.6,]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2],[1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4],[1.6,]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 2, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(2, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2],[1.3,1.5]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4],[1.5,]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2],[1.3,1.5]");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4],[1.5,]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 3, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 2 );
-        assertEquals( "1.5", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.5", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(3, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(2);
+        assertEquals("1.5", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.5", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
-        range1 = VersionRange.createFromVersionSpec( "[1.0,1.2],[1.3,1.7]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.1,1.4],[1.5,1.6]" );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[1.0,1.2],[1.3,1.7]");
+        range2 = VersionRange.createFromVersionSpec("[1.1,1.4],[1.5,1.6]");
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 3, restrictions.size(), CHECK_NUM_RESTRICTIONS );
-        restriction = restrictions.get( 0 );
-        assertEquals( "1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 1 );
-        assertEquals( "1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
-        restriction = restrictions.get( 2 );
-        assertEquals( "1.5", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND );
-        assertTrue( restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE );
-        assertEquals( "1.6", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND );
-        assertTrue( restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE );
+        assertEquals(3, restrictions.size(), CHECK_NUM_RESTRICTIONS);
+        restriction = restrictions.get(0);
+        assertEquals("1.1", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.2", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(1);
+        assertEquals("1.3", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.4", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
+        restriction = restrictions.get(2);
+        assertEquals("1.5", restriction.getLowerBound().toString(), CHECK_LOWER_BOUND);
+        assertTrue(restriction.isLowerBoundInclusive(), CHECK_LOWER_BOUND_INCLUSIVE);
+        assertEquals("1.6", restriction.getUpperBound().toString(), CHECK_UPPER_BOUND);
+        assertTrue(restriction.isUpperBoundInclusive(), CHECK_UPPER_BOUND_INCLUSIVE);
 
         // test restricting empty sets
-        range1 = VersionRange.createFromVersionSpec( "[,1.1],[1.4,]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.2,1.3]" );
-        range1 = range1.restrict( range2 );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[,1.1],[1.4,]");
+        range2 = VersionRange.createFromVersionSpec("[1.2,1.3]");
+        range1 = range1.restrict(range2);
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 0, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(0, restrictions.size(), CHECK_NUM_RESTRICTIONS);
 
-        range1 = VersionRange.createFromVersionSpec( "[,1.1],[1.4,]" );
-        range2 = VersionRange.createFromVersionSpec( "[1.2,1.3]" );
-        range2 = range1.restrict( range2 );
-        mergedRange = range1.restrict( range2 );
-        assertNull( mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION );
+        range1 = VersionRange.createFromVersionSpec("[,1.1],[1.4,]");
+        range2 = VersionRange.createFromVersionSpec("[1.2,1.3]");
+        range2 = range1.restrict(range2);
+        mergedRange = range1.restrict(range2);
+        assertNull(mergedRange.getRecommendedVersion(), CHECK_VERSION_RECOMMENDATION);
         restrictions = mergedRange.getRestrictions();
-        assertEquals( 0, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(0, restrictions.size(), CHECK_NUM_RESTRICTIONS);
     }
 
     @Test
-    public void testReleaseRangeBoundsContainsSnapshots()
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange range = VersionRange.createFromVersionSpec( "[1.0,1.2]" );
+    void testReleaseRangeBoundsContainsSnapshots() throws InvalidVersionSpecificationException {
+        VersionRange range = VersionRange.createFromVersionSpec("[1.0,1.2]");
 
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.1-SNAPSHOT" ) ) );
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.2-SNAPSHOT" ) ) );
-        assertFalse( range.containsVersion( new DefaultArtifactVersion( "1.0-SNAPSHOT" ) ) );
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.1-SNAPSHOT")));
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.2-SNAPSHOT")));
+        assertFalse(range.containsVersion(new DefaultArtifactVersion("1.0-SNAPSHOT")));
     }
 
     @Test
-    public void testSnapshotRangeBoundsCanContainSnapshots()
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange range = VersionRange.createFromVersionSpec( "[1.0,1.2-SNAPSHOT]" );
+    void testSnapshotRangeBoundsCanContainSnapshots() throws InvalidVersionSpecificationException {
+        VersionRange range = VersionRange.createFromVersionSpec("[1.0,1.2-SNAPSHOT]");
 
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.1-SNAPSHOT" ) ) );
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.2-SNAPSHOT" ) ) );
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.1-SNAPSHOT")));
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.2-SNAPSHOT")));
 
-        range = VersionRange.createFromVersionSpec( "[1.0-SNAPSHOT,1.2]" );
+        range = VersionRange.createFromVersionSpec("[1.0-SNAPSHOT,1.2]");
 
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.0-SNAPSHOT" ) ) );
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.1-SNAPSHOT" ) ) );
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.0-SNAPSHOT")));
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.1-SNAPSHOT")));
     }
 
     @Test
-    public void testSnapshotSoftVersionCanContainSnapshot()
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange range = VersionRange.createFromVersionSpec( "1.0-SNAPSHOT" );
+    void testSnapshotSoftVersionCanContainSnapshot() throws InvalidVersionSpecificationException {
+        VersionRange range = VersionRange.createFromVersionSpec("1.0-SNAPSHOT");
 
-        assertTrue( range.containsVersion( new DefaultArtifactVersion( "1.0-SNAPSHOT" ) ) );
+        assertTrue(range.containsVersion(new DefaultArtifactVersion("1.0-SNAPSHOT")));
     }
 
-    private void checkInvalidRange( String version )
-    {
+    private void checkInvalidRange(String version) {
         assertThrows(
                 InvalidVersionSpecificationException.class,
-                () -> VersionRange.createFromVersionSpec( version ),
-                "Version " + version + " should have failed to construct" );
+                () -> VersionRange.createFromVersionSpec(version),
+                "Version " + version + " should have failed to construct");
     }
 
     @Test
-    public void testContains() throws InvalidVersionSpecificationException
-    {
-        ArtifactVersion actualVersion = new DefaultArtifactVersion( "2.0.5" );
-        assertTrue( enforceVersion( "2.0.5", actualVersion ) );
-        assertTrue( enforceVersion( "2.0.4", actualVersion ) );
-        assertTrue( enforceVersion( "[2.0.5]", actualVersion ) );
-        assertFalse( enforceVersion( "[2.0.6,)", actualVersion ) );
-        assertFalse( enforceVersion( "[2.0.6]", actualVersion ) );
-        assertTrue( enforceVersion( "[2.0,2.1]", actualVersion ) );
-        assertFalse( enforceVersion( "[2.0,2.0.3]", actualVersion ) );
-        assertTrue( enforceVersion( "[2.0,2.0.5]", actualVersion ) );
-        assertFalse( enforceVersion( "[2.0,2.0.5)", actualVersion ) );
+    void testContains() throws InvalidVersionSpecificationException {
+        ArtifactVersion actualVersion = new DefaultArtifactVersion("2.0.5");
+        assertTrue(enforceVersion("2.0.5", actualVersion));
+        assertTrue(enforceVersion("2.0.4", actualVersion));
+        assertTrue(enforceVersion("[2.0.5]", actualVersion));
+        assertFalse(enforceVersion("[2.0.6,)", actualVersion));
+        assertFalse(enforceVersion("[2.0.6]", actualVersion));
+        assertTrue(enforceVersion("[2.0,2.1]", actualVersion));
+        assertFalse(enforceVersion("[2.0,2.0.3]", actualVersion));
+        assertTrue(enforceVersion("[2.0,2.0.5]", actualVersion));
+        assertFalse(enforceVersion("[2.0,2.0.5)", actualVersion));
     }
 
-    public boolean enforceVersion( String requiredVersionRange, ArtifactVersion actualVersion )
-        throws InvalidVersionSpecificationException
-    {
+    public boolean enforceVersion(String requiredVersionRange, ArtifactVersion actualVersion)
+            throws InvalidVersionSpecificationException {
         VersionRange vr = null;
 
-        vr = VersionRange.createFromVersionSpec( requiredVersionRange );
+        vr = VersionRange.createFromVersionSpec(requiredVersionRange);
 
-        return vr.containsVersion( actualVersion );
+        return vr.containsVersion(actualVersion);
     }
 
     @Test
-    public void testOrder0()
-    {
-        // assertTrue( new DefaultArtifactVersion( "1.0-alpha10" ).compareTo( new DefaultArtifactVersion( "1.0-alpha1" ) ) > 0 );
+    void testOrder0() {
+        // assertTrue( new DefaultArtifactVersion( "1.0-alpha10" ).compareTo( new DefaultArtifactVersion( "1.0-alpha1" )
+        // ) > 0 );
     }
 
     @Test
-    public void testCache()
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange range = VersionRange.createFromVersionSpec( "[1.0,1.2]" );
-        assertSame( range, VersionRange.createFromVersionSpec( "[1.0,1.2]" ) ); // same instance from spec cache
+    void testCache() throws InvalidVersionSpecificationException {
+        VersionRange range = VersionRange.createFromVersionSpec("[1.0,1.2]");
+        assertSame(range, VersionRange.createFromVersionSpec("[1.0,1.2]")); // same instance from spec cache
 
-        VersionRange spec = VersionRange.createFromVersionSpec( "1.0" );
-        assertSame( spec, VersionRange.createFromVersionSpec( "1.0" ) ); // same instance from spec cache
+        VersionRange spec = VersionRange.createFromVersionSpec("1.0");
+        assertSame(spec, VersionRange.createFromVersionSpec("1.0")); // same instance from spec cache
         List<Restriction> restrictions = spec.getRestrictions();
-        assertEquals( 1, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(1, restrictions.size(), CHECK_NUM_RESTRICTIONS);
 
-        VersionRange version = VersionRange.createFromVersion( "1.0" );
-        assertSame( version, VersionRange.createFromVersion( "1.0" ) ); // same instance from version cache
+        VersionRange version = VersionRange.createFromVersion("1.0");
+        assertSame(version, VersionRange.createFromVersion("1.0")); // same instance from version cache
         restrictions = version.getRestrictions();
-        assertEquals( 0, restrictions.size(), CHECK_NUM_RESTRICTIONS );
+        assertEquals(0, restrictions.size(), CHECK_NUM_RESTRICTIONS);
 
-        assertFalse( spec.equals( version ), "check !VersionRange.createFromVersionSpec(x).equals(VersionRange.createFromVersion(x))" );
+        assertFalse(
+                spec.equals(version),
+                "check !VersionRange.createFromVersionSpec(x).equals(VersionRange.createFromVersion(x))");
     }
 }
diff --git a/maven-bom/pom.xml b/maven-bom/pom.xml
index 4f9b6e3..e650392 100644
--- a/maven-bom/pom.xml
+++ b/maven-bom/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,33 +17,28 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven-parent</artifactId>
-    <version>35</version>
+    <version>41</version>
     <relativePath />
   </parent>
 
   <artifactId>maven-bom</artifactId>
-  <version>4.0.0-alpha-1-SNAPSHOT</version>
+  <version>4.0.0-alpha-9-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>Maven Dependencies BOM</name>
   <description>Bill Of Materials for Apache Maven dependencies</description>
   <url>https://maven.apache.org/ref/${project.version}/${project.artifactId}</url>
 
-  <properties>
-    <maven.site.path>ref/4-LATEST/${project.artifactId}</maven.site.path>
-  </properties>
-
   <scm>
     <connection>scm:git:https://gitbox.apache.org/repos/asf/maven.git</connection>
     <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/maven.git</developerConnection>
+    <tag>maven-4.0.0-alpha-3</tag>
     <url>https://github.com/apache/maven/tree/${project.scm.tag}/${project.artifactId}</url>
-    <tag>master</tag>
   </scm>
   <issueManagement>
     <system>jira</system>
@@ -55,13 +49,17 @@
     <url>https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven/</url>
   </ciManagement>
   <distributionManagement>
-    <downloadUrl>https://maven.apache.org/download.html</downloadUrl>
     <site>
       <id>apache.website</id>
       <url>scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path}</url>
     </site>
+    <downloadUrl>https://maven.apache.org/download.html</downloadUrl>
   </distributionManagement>
 
+  <properties>
+    <maven.site.path>ref/4-LATEST/${project.artifactId}</maven.site.path>
+  </properties>
+
   <dependencyManagement>
     <!-- Not included:
          - apache-maven, as it delivers the binaries
@@ -96,12 +94,47 @@
       </dependency>
       <dependency>
         <groupId>org.apache.maven</groupId>
-        <artifactId>maven-model-builder</artifactId>
+        <artifactId>maven-api-core</artifactId>
         <version>${project.version}</version>
       </dependency>
       <dependency>
         <groupId>org.apache.maven</groupId>
-        <artifactId>maven-model-transform</artifactId>
+        <artifactId>maven-api-meta</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-api-model</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-api-settings</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-api-spi</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-api-toolchain</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-api-plugin</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-api-xml</artifactId>
+        <version>${project.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-model-builder</artifactId>
         <version>${project.version}</version>
       </dependency>
       <dependency>
@@ -144,6 +177,11 @@
         <artifactId>maven-slf4j-wrapper</artifactId>
         <version>${project.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>maven-xml-impl</artifactId>
+        <version>${project.version}</version>
+      </dependency>
     </dependencies>
   </dependencyManagement>
 
@@ -155,6 +193,16 @@
           <topSiteURL>${project.distributionManagement.site.url}/..</topSiteURL>
         </configuration>
       </plugin>
+      <plugin>
+        <groupId>org.apache.rat</groupId>
+        <artifactId>apache-rat-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>rat-check</id>
+            <phase>none</phase>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/maven-bom/src/site/site.xml b/maven-bom/src/site/site.xml
index 7f2adda..e6ace57 100644
--- a/maven-bom/src/site/site.xml
+++ b/maven-bom/src/site/site.xml
@@ -39,7 +39,7 @@
 
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <!--item name="JavaDocs" href="apidocs/index.html"/>
+      <!--item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-builder-support/pom.xml b/maven-builder-support/pom.xml
index edaf5f4..6941142 100644
--- a/maven-builder-support/pom.xml
+++ b/maven-builder-support/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-builder-support</artifactId>
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblem.java b/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblem.java
index 212eaa1..8c628a4 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblem.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 /**
  * Describes a problem that was encountered during settings building. A problem can either be an exception that was
  * thrown or a simple string message. In addition, a problem carries a hint about its source, e.g. the settings file
  * that exhibits the problem.
  *
- * @author Benjamin Bentmann
- * @author Robert Scholte
  */
-class DefaultProblem
-    implements Problem
-{
+class DefaultProblem implements Problem {
 
     private final String source;
 
@@ -55,85 +50,68 @@
      * @param columnNumber The one-based index of the column containing the problem or {@code -1} if unknown.
      * @param exception The exception that caused this problem, may be {@code null}.
      */
-    DefaultProblem( String message, Severity severity, String source, int lineNumber, int columnNumber,
-                                   Exception exception )
-    {
+    DefaultProblem(
+            String message, Severity severity, String source, int lineNumber, int columnNumber, Exception exception) {
         this.message = message;
-        this.severity = ( severity != null ) ? severity : Severity.ERROR;
-        this.source = ( source != null ) ? source : "";
+        this.severity = (severity != null) ? severity : Severity.ERROR;
+        this.source = (source != null) ? source : "";
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
         this.exception = exception;
     }
 
-    public String getSource()
-    {
+    public String getSource() {
         return source;
     }
 
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
 
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
 
-    public String getLocation()
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
+    public String getLocation() {
+        StringBuilder buffer = new StringBuilder(256);
 
-        if ( getSource().length() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (getSource().length() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( getSource() );
+            buffer.append(getSource());
         }
 
-        if ( getLineNumber() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (getLineNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( "line " ).append( getLineNumber() );
+            buffer.append("line ").append(getLineNumber());
         }
 
-        if ( getColumnNumber() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (getColumnNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( "column " ).append( getColumnNumber() );
+            buffer.append("column ").append(getColumnNumber());
         }
 
         return buffer.toString();
     }
 
-    public Exception getException()
-    {
+    public Exception getException() {
         return exception;
     }
 
-    public String getMessage()
-    {
+    public String getMessage() {
         String msg;
 
-        if ( message != null && message.length() > 0 )
-        {
+        if (message != null && message.length() > 0) {
             msg = message;
-        }
-        else
-        {
+        } else {
             msg = exception.getMessage();
 
-            if ( msg == null )
-            {
+            if (msg == null) {
                 msg = "";
             }
         }
@@ -141,27 +119,22 @@
         return msg;
     }
 
-    public Severity getSeverity()
-    {
+    public Severity getSeverity() {
         return severity;
     }
 
     @Override
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder( 128 );
+    public String toString() {
+        StringBuilder buffer = new StringBuilder(128);
 
-        buffer.append( '[' ).append( getSeverity() ).append( "] " );
-        buffer.append( getMessage() );
+        buffer.append('[').append(getSeverity()).append("] ");
+        buffer.append(getMessage());
         String location = getLocation();
-        if ( !location.isEmpty() )
-        {
-             buffer.append( " @ " );
-             buffer.append( location );
+        if (!location.isEmpty()) {
+            buffer.append(" @ ");
+            buffer.append(location);
         }
 
-
         return buffer.toString();
     }
-
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblemCollector.java b/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblemCollector.java
index 2c09df6..3274516 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblemCollector.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/DefaultProblemCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -25,40 +24,31 @@
 /**
  * Collects problems that are encountered during settings building.
  *
- * @author Benjamin Bentmann
- * @author Robert Scholte
  */
-class DefaultProblemCollector
-    implements ProblemCollector
-{
+class DefaultProblemCollector implements ProblemCollector {
 
     private List<Problem> problems;
 
     private String source;
 
-    DefaultProblemCollector( List<Problem> problems )
-    {
-        this.problems = ( problems != null ) ? problems : new ArrayList<>();
+    DefaultProblemCollector(List<Problem> problems) {
+        this.problems = (problems != null) ? problems : new ArrayList<>();
     }
 
     @Override
-    public List<Problem> getProblems()
-    {
+    public List<Problem> getProblems() {
         return problems;
     }
 
     @Override
-    public void setSource( String source )
-    {
+    public void setSource(String source) {
         this.source = source;
     }
 
     @Override
-    public void add( Problem.Severity severity, String message, int line, int column, Exception cause )
-    {
-        Problem problem = new DefaultProblem( message, severity, source, line, column, cause );
+    public void add(Problem.Severity severity, String message, int line, int column, Exception cause) {
+        Problem problem = new DefaultProblem(message, severity, source, line, column, cause);
 
-        problems.add( problem );
+        problems.add(problem);
     }
-
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java b/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java
index db1b2b2..d75f837 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/FileSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,21 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
 import java.util.Objects;
 
 /**
  * Wraps an ordinary {@link File} as a source.
  *
- * @author Benjamin Bentmann
  */
-public class FileSource
-    implements Source
-{
+public class FileSource implements Source {
     private final File file;
 
     private final int hashCode;
@@ -42,22 +38,18 @@
      *
      * @param file The file, must not be {@code null}.
      */
-    public FileSource( File file )
-    {
-        this.file = Objects.requireNonNull( file, "file cannot be null" ).getAbsoluteFile();
-        this.hashCode = Objects.hash( file );
+    public FileSource(File file) {
+        this.file = Objects.requireNonNull(file, "file cannot be null").getAbsoluteFile();
+        this.hashCode = Objects.hash(file);
     }
 
     @Override
-    public InputStream getInputStream()
-        throws IOException
-    {
-        return new FileInputStream( file );
+    public InputStream getInputStream() throws IOException {
+        return Files.newInputStream(file.toPath());
     }
 
     @Override
-    public String getLocation()
-    {
+    public String getLocation() {
         return file.getPath();
     }
 
@@ -66,42 +58,35 @@
      *
      * @return The underlying file, never {@code null}.
      */
-    public File getFile()
-    {
+    public File getFile() {
         return file;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getLocation();
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         return hashCode;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( obj == null )
-        {
+        if (obj == null) {
             return false;
         }
 
-        if ( !FileSource.class.equals( obj.getClass() ) )
-        {
+        if (!FileSource.class.equals(obj.getClass())) {
             return false;
         }
 
         FileSource other = (FileSource) obj;
-        return this.file.equals( other.file );
+        return this.file.equals(other.file);
     }
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/Problem.java b/maven-builder-support/src/main/java/org/apache/maven/building/Problem.java
index 9ab9b3a..7e31586 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/Problem.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/Problem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,28 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 /**
  * Describes a problem that was encountered during settings building. A problem can either be an exception that was
  * thrown or a simple string message. In addition, a problem carries a hint about its source, e.g. the settings file
  * that exhibits the problem.
  *
- * @author Benjamin Bentmann
- * @author Robert Scholte
  */
-public interface Problem
-{
+public interface Problem {
 
     /**
      * The different severity levels for a problem, in decreasing order.
      */
-    enum Severity
-    {
-
+    enum Severity {
         FATAL, //
         ERROR, //
         WARNING //
-
     }
 
     /**
@@ -97,5 +90,4 @@
      * @return The severity level of this problem, never {@code null}.
      */
     Severity getSeverity();
-
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollector.java b/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollector.java
index 6e61256..89cee19 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollector.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.util.List;
 
 /**
  * Collects problems that are encountered during settings building.
  *
- * @author Benjamin Bentmann
- * @author Robert Scholte
  */
-public interface ProblemCollector
-{
+public interface ProblemCollector {
 
     /**
      * Adds the specified problem.
@@ -40,7 +36,7 @@
      * @param column The one-based index of the column containing the problem or {@code -1} if unknown.
      * @param cause The cause of the problem, may be {@code null}.
      */
-    void add( Problem.Severity severity, String message, int line, int column, Exception cause );
+    void add(Problem.Severity severity, String message, int line, int column, Exception cause);
 
     /**
      * The next messages will be bound to this source. When calling this method again, previous messages keep
@@ -48,12 +44,11 @@
      *
      * @param source a source
      */
-    void setSource( String source );
+    void setSource(String source);
 
     /**
      *
      * @return the collected Problems, never {@code null}
      */
     List<Problem> getProblems();
-
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollectorFactory.java b/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollectorFactory.java
index 43c9bd3..f169b5b 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollectorFactory.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/ProblemCollectorFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.util.List;
 
 /**
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public class ProblemCollectorFactory
-{
+public class ProblemCollectorFactory {
 
     /**
      * The default implementation is not visible, create it with this factory
@@ -35,9 +32,7 @@
      * @param problems starting set of problems, may be {@code null}
      * @return a new instance of a ProblemCollector
      */
-    public static ProblemCollector newInstance( List<Problem> problems )
-    {
-        return new DefaultProblemCollector( problems );
+    public static ProblemCollector newInstance(List<Problem> problems) {
+        return new DefaultProblemCollector(problems);
     }
-
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/Source.java b/maven-builder-support/src/main/java/org/apache/maven/building/Source.java
index 948a557..ed1a38c 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/Source.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/Source.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -25,10 +24,8 @@
 /**
  * Provides access to the contents of a source independently of the backing store (e.g. file system, database, memory).
  *
- * @author Benjamin Bentmann
  */
-public interface Source
-{
+public interface Source {
 
     /**
      * Gets a byte stream to the source contents. Closing the returned stream is the responsibility of the caller.
@@ -36,8 +33,7 @@
      * @return A byte stream to the source contents, never {@code null}.
      * @throws IOException in case of IO issue
      */
-    InputStream getInputStream()
-        throws IOException;
+    InputStream getInputStream() throws IOException;
 
     /**
      * Provides a user-friendly hint about the location of the source. This could be a local file path, a URI or just an
@@ -46,5 +42,4 @@
      * @return A user-friendly hint about the location of the source, never {@code null}.
      */
     String getLocation();
-
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java b/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java
index d305899..12e6488 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/StringSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -27,11 +26,8 @@
 /**
  * Wraps an ordinary {@link CharSequence} as a source.
  *
- * @author Benjamin Bentmann
  */
-public class StringSource
-    implements Source
-{
+public class StringSource implements Source {
     private final String content;
 
     private final String location;
@@ -43,9 +39,8 @@
      *
      * @param content The String representation, may be empty or {@code null}.
      */
-    public StringSource( CharSequence content )
-    {
-        this( content, null );
+    public StringSource(CharSequence content) {
+        this(content, null);
     }
 
     /**
@@ -54,23 +49,19 @@
      * @param content The String representation, may be empty or {@code null}.
      * @param location The location to report for this use, may be {@code null}.
      */
-    public StringSource( CharSequence content, String location )
-    {
-        this.content = ( content != null ) ? content.toString() : "";
-        this.location = ( location != null ) ? location : "(memory)";
+    public StringSource(CharSequence content, String location) {
+        this.content = (content != null) ? content.toString() : "";
+        this.location = (location != null) ? location : "(memory)";
         this.hashCode = this.content.hashCode();
     }
 
     @Override
-    public InputStream getInputStream()
-        throws IOException
-    {
-        return new ByteArrayInputStream( content.getBytes( StandardCharsets.UTF_8 ) );
+    public InputStream getInputStream() throws IOException {
+        return new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8));
     }
 
     @Override
-    public String getLocation()
-    {
+    public String getLocation() {
         return location;
     }
 
@@ -79,42 +70,35 @@
      *
      * @return The underlying character stream, never {@code null}.
      */
-    public String getContent()
-    {
+    public String getContent() {
         return content;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getLocation();
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         return hashCode;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( obj == null )
-        {
+        if (obj == null) {
             return false;
         }
 
-        if ( !StringSource.class.equals( obj.getClass() ) )
-        {
+        if (!StringSource.class.equals(obj.getClass())) {
             return false;
         }
 
         StringSource other = (StringSource) obj;
-        return this.content.equals( other.content );
+        return this.content.equals(other.content);
     }
 }
diff --git a/maven-builder-support/src/main/java/org/apache/maven/building/UrlSource.java b/maven-builder-support/src/main/java/org/apache/maven/building/UrlSource.java
index 7226293..7cd2651 100644
--- a/maven-builder-support/src/main/java/org/apache/maven/building/UrlSource.java
+++ b/maven-builder-support/src/main/java/org/apache/maven/building/UrlSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -27,11 +26,8 @@
 /**
  * Wraps an ordinary {@link URL} as a source.
  *
- * @author Benjamin Bentmann
  */
-public class UrlSource
-    implements Source
-{
+public class UrlSource implements Source {
 
     private final URL url;
 
@@ -42,22 +38,18 @@
      *
      * @param url The file, must not be {@code null}.
      */
-    public UrlSource( URL url )
-    {
-        this.url = Objects.requireNonNull( url, "url cannot be null" );
-        this.hashCode = Objects.hashCode( url );
+    public UrlSource(URL url) {
+        this.url = Objects.requireNonNull(url, "url cannot be null");
+        this.hashCode = Objects.hashCode(url);
     }
 
     @Override
-    public InputStream getInputStream()
-        throws IOException
-    {
+    public InputStream getInputStream() throws IOException {
         return url.openStream();
     }
 
     @Override
-    public String getLocation()
-    {
+    public String getLocation() {
         return url.toString();
     }
 
@@ -66,42 +58,35 @@
      *
      * @return The underlying URL, never {@code null}.
      */
-    public URL getUrl()
-    {
+    public URL getUrl() {
         return url;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getLocation();
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         return hashCode;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( obj == null )
-        {
+        if (obj == null) {
             return false;
         }
 
-        if ( !UrlSource.class.equals( obj.getClass() ) )
-        {
+        if (!UrlSource.class.equals(obj.getClass())) {
             return false;
         }
 
         UrlSource other = (UrlSource) obj;
-        return this.url.equals( other.url );
+        return this.url.equals(other.url);
     }
 }
diff --git a/maven-builder-support/src/site/site.xml b/maven-builder-support/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-builder-support/src/site/site.xml
+++ b/maven-builder-support/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemCollectorTest.java b/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemCollectorTest.java
index a8b85d8..4ff6750 100644
--- a/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemCollectorTest.java
+++ b/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemCollectorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import org.apache.maven.building.Problem.Severity;
 import org.junit.jupiter.api.Test;
@@ -26,53 +25,50 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
-public class DefaultProblemCollectorTest
-{
+class DefaultProblemCollectorTest {
 
     @Test
-    public void testGetProblems()
-    {
-        DefaultProblemCollector collector = new DefaultProblemCollector( null );
-        assertNotNull( collector.getProblems() );
-        assertEquals( 0, collector.getProblems().size() );
+    void testGetProblems() {
+        DefaultProblemCollector collector = new DefaultProblemCollector(null);
+        assertNotNull(collector.getProblems());
+        assertEquals(0, collector.getProblems().size());
 
-        collector.add( null, "MESSAGE1", -1, -1, null );
+        collector.add(null, "MESSAGE1", -1, -1, null);
 
         Exception e2 = new Exception();
-        collector.add( Severity.WARNING, null, 42, 127, e2 );
+        collector.add(Severity.WARNING, null, 42, 127, e2);
 
-        assertEquals( 2, collector.getProblems().size() );
+        assertEquals(2, collector.getProblems().size());
 
         Problem p1 = collector.getProblems().get(0);
-        assertEquals( Severity.ERROR, p1.getSeverity() );
-        assertEquals( "MESSAGE1",p1.getMessage() );
-        assertEquals( -1, p1.getLineNumber() );
-        assertEquals( -1, p1.getColumnNumber() );
-        assertNull( p1.getException() );
+        assertEquals(Severity.ERROR, p1.getSeverity());
+        assertEquals("MESSAGE1", p1.getMessage());
+        assertEquals(-1, p1.getLineNumber());
+        assertEquals(-1, p1.getColumnNumber());
+        assertNull(p1.getException());
 
         Problem p2 = collector.getProblems().get(1);
-        assertEquals( Severity.WARNING, p2.getSeverity() );
-        assertEquals( "",p2.getMessage() );
-        assertEquals( 42, p2.getLineNumber() );
-        assertEquals( 127, p2.getColumnNumber() );
-        assertEquals( e2, p2.getException() );
+        assertEquals(Severity.WARNING, p2.getSeverity());
+        assertEquals("", p2.getMessage());
+        assertEquals(42, p2.getLineNumber());
+        assertEquals(127, p2.getColumnNumber());
+        assertEquals(e2, p2.getException());
     }
 
     @Test
-    public void testSetSource()
-    {
-        DefaultProblemCollector collector = new DefaultProblemCollector( null );
+    void testSetSource() {
+        DefaultProblemCollector collector = new DefaultProblemCollector(null);
 
-        collector.add( null, "PROBLEM1", -1, -1, null );
+        collector.add(null, "PROBLEM1", -1, -1, null);
 
-        collector.setSource( "SOURCE_PROBLEM2" );
-        collector.add( null, "PROBLEM2", -1, -1, null );
+        collector.setSource("SOURCE_PROBLEM2");
+        collector.add(null, "PROBLEM2", -1, -1, null);
 
-        collector.setSource( "SOURCE_PROBLEM3" );
-        collector.add( null, "PROBLEM3", -1, -1, null );
+        collector.setSource("SOURCE_PROBLEM3");
+        collector.add(null, "PROBLEM3", -1, -1, null);
 
-        assertEquals( "", collector.getProblems().get( 0 ).getSource() );
-        assertEquals( "SOURCE_PROBLEM2", collector.getProblems().get( 1 ).getSource() );
-        assertEquals( "SOURCE_PROBLEM3", collector.getProblems().get( 2 ).getSource() );
+        assertEquals("", collector.getProblems().get(0).getSource());
+        assertEquals("SOURCE_PROBLEM2", collector.getProblems().get(1).getSource());
+        assertEquals("SOURCE_PROBLEM3", collector.getProblems().get(2).getSource());
     }
 }
diff --git a/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemTest.java b/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemTest.java
index 6182f99..3bd8a9a 100644
--- a/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemTest.java
+++ b/maven-builder-support/src/test/java/org/apache/maven/building/DefaultProblemTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import org.apache.maven.building.Problem.Severity;
 import org.junit.jupiter.api.Test;
@@ -26,112 +25,104 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
 
-public class DefaultProblemTest
-{
+class DefaultProblemTest {
 
     @Test
-    public void testGetSeverity()
-    {
-        DefaultProblem problem = new DefaultProblem( null, null, null, -1, -1, null );
-        assertEquals( Severity.ERROR, problem.getSeverity() );
+    void testGetSeverity() {
+        DefaultProblem problem = new DefaultProblem(null, null, null, -1, -1, null);
+        assertEquals(Severity.ERROR, problem.getSeverity());
 
-        problem = new DefaultProblem( null, Severity.FATAL, null, -1, -1, null );
-        assertEquals( Severity.FATAL, problem.getSeverity() );
+        problem = new DefaultProblem(null, Severity.FATAL, null, -1, -1, null);
+        assertEquals(Severity.FATAL, problem.getSeverity());
 
-        problem = new DefaultProblem( null, Severity.ERROR, null, -1, -1, null );
-        assertEquals( Severity.ERROR, problem.getSeverity() );
+        problem = new DefaultProblem(null, Severity.ERROR, null, -1, -1, null);
+        assertEquals(Severity.ERROR, problem.getSeverity());
 
-        problem = new DefaultProblem( null, Severity.WARNING, null, -1, -1, null );
-        assertEquals( Severity.WARNING, problem.getSeverity() );
+        problem = new DefaultProblem(null, Severity.WARNING, null, -1, -1, null);
+        assertEquals(Severity.WARNING, problem.getSeverity());
     }
 
     @Test
-    public void testGetLineNumber()
-    {
-        DefaultProblem problem = new DefaultProblem( null, null, null, -1, -1, null );
-        assertEquals( -1, problem.getLineNumber() );
+    void testGetLineNumber() {
+        DefaultProblem problem = new DefaultProblem(null, null, null, -1, -1, null);
+        assertEquals(-1, problem.getLineNumber());
 
-        problem = new DefaultProblem( null, null, null, 42, -1, null );
-        assertEquals( 42, problem.getLineNumber() );
+        problem = new DefaultProblem(null, null, null, 42, -1, null);
+        assertEquals(42, problem.getLineNumber());
 
-        problem = new DefaultProblem( null, null, null, Integer.MAX_VALUE, -1, null );
-        assertEquals( Integer.MAX_VALUE, problem.getLineNumber() );
+        problem = new DefaultProblem(null, null, null, Integer.MAX_VALUE, -1, null);
+        assertEquals(Integer.MAX_VALUE, problem.getLineNumber());
 
         // this case is not specified, might also return -1
-        problem = new DefaultProblem( null, null, null, Integer.MIN_VALUE, -1, null );
-        assertEquals( Integer.MIN_VALUE, problem.getLineNumber() );
+        problem = new DefaultProblem(null, null, null, Integer.MIN_VALUE, -1, null);
+        assertEquals(Integer.MIN_VALUE, problem.getLineNumber());
     }
 
     @Test
-    public void testGetColumnNumber()
-    {
-        DefaultProblem problem = new DefaultProblem( null, null, null, -1, -1, null );
-        assertEquals( -1, problem.getColumnNumber() );
+    void testGetColumnNumber() {
+        DefaultProblem problem = new DefaultProblem(null, null, null, -1, -1, null);
+        assertEquals(-1, problem.getColumnNumber());
 
-        problem = new DefaultProblem( null, null, null, -1, 42, null );
-        assertEquals( 42, problem.getColumnNumber() );
+        problem = new DefaultProblem(null, null, null, -1, 42, null);
+        assertEquals(42, problem.getColumnNumber());
 
-        problem = new DefaultProblem( null, null, null, -1, Integer.MAX_VALUE, null );
-        assertEquals( Integer.MAX_VALUE, problem.getColumnNumber() );
+        problem = new DefaultProblem(null, null, null, -1, Integer.MAX_VALUE, null);
+        assertEquals(Integer.MAX_VALUE, problem.getColumnNumber());
 
         // this case is not specified, might also return -1
-        problem = new DefaultProblem( null, null, null, -1, Integer.MIN_VALUE, null );
-        assertEquals( Integer.MIN_VALUE, problem.getColumnNumber() );
+        problem = new DefaultProblem(null, null, null, -1, Integer.MIN_VALUE, null);
+        assertEquals(Integer.MIN_VALUE, problem.getColumnNumber());
     }
 
     @Test
-    public void testGetException()
-    {
-        DefaultProblem problem = new DefaultProblem( null, null, null, -1, -1, null );
-        assertNull( problem.getException() );
+    void testGetException() {
+        DefaultProblem problem = new DefaultProblem(null, null, null, -1, -1, null);
+        assertNull(problem.getException());
 
         Exception e = new Exception();
-        problem = new DefaultProblem( null, null, null, -1, -1, e );
-        assertSame( e, problem.getException() );
+        problem = new DefaultProblem(null, null, null, -1, -1, e);
+        assertSame(e, problem.getException());
     }
 
     @Test
-    public void testGetSource()
-    {
-        DefaultProblem problem = new DefaultProblem( null, null, null, -1, -1, null );
-        assertEquals( "", problem.getSource() );
+    void testGetSource() {
+        DefaultProblem problem = new DefaultProblem(null, null, null, -1, -1, null);
+        assertEquals("", problem.getSource());
 
-        problem = new DefaultProblem( null, null, "", -1, -1, null );
-        assertEquals( "", problem.getSource() );
+        problem = new DefaultProblem(null, null, "", -1, -1, null);
+        assertEquals("", problem.getSource());
 
-        problem = new DefaultProblem( null, null, "SOURCE", -1, -1, null );
-        assertEquals( "SOURCE", problem.getSource() );
+        problem = new DefaultProblem(null, null, "SOURCE", -1, -1, null);
+        assertEquals("SOURCE", problem.getSource());
     }
 
     @Test
-    public void testGetLocation()
-    {
-        DefaultProblem problem = new DefaultProblem( null, null, null, -1, -1, null );
-        assertEquals( "", problem.getLocation() );
+    void testGetLocation() {
+        DefaultProblem problem = new DefaultProblem(null, null, null, -1, -1, null);
+        assertEquals("", problem.getLocation());
 
-        problem = new DefaultProblem( null, null, "SOURCE", -1, -1, null );
-        assertEquals( "SOURCE", problem.getLocation() );
+        problem = new DefaultProblem(null, null, "SOURCE", -1, -1, null);
+        assertEquals("SOURCE", problem.getLocation());
 
-        problem = new DefaultProblem( null, null, null, 42, -1, null );
-        assertEquals( "line 42", problem.getLocation() );
+        problem = new DefaultProblem(null, null, null, 42, -1, null);
+        assertEquals("line 42", problem.getLocation());
 
-        problem = new DefaultProblem( null, null, null, -1, 127, null );
-        assertEquals( "column 127", problem.getLocation() );
+        problem = new DefaultProblem(null, null, null, -1, 127, null);
+        assertEquals("column 127", problem.getLocation());
 
-        problem = new DefaultProblem( null, null, "SOURCE", 42, 127, null );
-        assertEquals( "SOURCE, line 42, column 127", problem.getLocation() );
+        problem = new DefaultProblem(null, null, "SOURCE", 42, 127, null);
+        assertEquals("SOURCE, line 42, column 127", problem.getLocation());
     }
 
     @Test
-    public void testGetMessage()
-    {
-        DefaultProblem problem = new DefaultProblem( "MESSAGE", null, null, -1, -1, null );
-        assertEquals( "MESSAGE", problem.getMessage() );
+    void testGetMessage() {
+        DefaultProblem problem = new DefaultProblem("MESSAGE", null, null, -1, -1, null);
+        assertEquals("MESSAGE", problem.getMessage());
 
-        problem = new DefaultProblem( null, null, null, -1, -1, new Exception() );
-        assertEquals( "", problem.getMessage() );
+        problem = new DefaultProblem(null, null, null, -1, -1, new Exception());
+        assertEquals("", problem.getMessage());
 
-        problem = new DefaultProblem( null, null, null, -1, -1, new Exception( "EXCEPTION MESSAGE" ) );
-        assertEquals( "EXCEPTION MESSAGE", problem.getMessage() );
+        problem = new DefaultProblem(null, null, null, -1, -1, new Exception("EXCEPTION MESSAGE"));
+        assertEquals("EXCEPTION MESSAGE", problem.getMessage());
     }
 }
diff --git a/maven-builder-support/src/test/java/org/apache/maven/building/FileSourceTest.java b/maven-builder-support/src/test/java/org/apache/maven/building/FileSourceTest.java
index 9373c01..cfdc9d7 100644
--- a/maven-builder-support/src/test/java/org/apache/maven/building/FileSourceTest.java
+++ b/maven-builder-support/src/test/java/org/apache/maven/building/FileSourceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.io.File;
 import java.io.InputStream;
@@ -28,48 +27,38 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-public class FileSourceTest
-{
+class FileSourceTest {
 
     @Test
-    public void testFileSource()
-    {
+    void testFileSource() {
         NullPointerException e = assertThrows(
-                NullPointerException.class,
-                () -> new FileSource( null ),
-                "Should fail, since you must specify a file" );
-        assertEquals( "file cannot be null", e.getMessage() );
+                NullPointerException.class, () -> new FileSource(null), "Should fail, since you must specify a file");
+        assertEquals("file cannot be null", e.getMessage());
     }
 
     @Test
-    public void testGetInputStream()
-        throws Exception
-    {
-        File txtFile = new File( "target/test-classes/source.txt" );
-        FileSource source = new FileSource( txtFile );
+    void testGetInputStream() throws Exception {
+        File txtFile = new File("target/test-classes/source.txt");
+        FileSource source = new FileSource(txtFile);
 
-        try ( InputStream is = source.getInputStream();
-              Scanner scanner = new Scanner( is ) )
-        {
+        try (InputStream is = source.getInputStream();
+                Scanner scanner = new Scanner(is)) {
 
-            assertEquals( "Hello World!", scanner.nextLine() );
+            assertEquals("Hello World!", scanner.nextLine());
         }
     }
 
     @Test
-    public void testGetLocation()
-    {
-        File txtFile = new File( "target/test-classes/source.txt" );
-        FileSource source = new FileSource( txtFile );
-        assertEquals( txtFile.getAbsolutePath(), source.getLocation() );
+    void testGetLocation() {
+        File txtFile = new File("target/test-classes/source.txt");
+        FileSource source = new FileSource(txtFile);
+        assertEquals(txtFile.getAbsolutePath(), source.getLocation());
     }
 
     @Test
-    public void testGetFile()
-    {
-        File txtFile = new File( "target/test-classes/source.txt" );
-        FileSource source = new FileSource( txtFile );
-        assertEquals( txtFile.getAbsoluteFile(), source.getFile() );
+    void testGetFile() {
+        File txtFile = new File("target/test-classes/source.txt");
+        FileSource source = new FileSource(txtFile);
+        assertEquals(txtFile.getAbsoluteFile(), source.getFile());
     }
-
 }
diff --git a/maven-builder-support/src/test/java/org/apache/maven/building/ProblemCollectorFactoryTest.java b/maven-builder-support/src/test/java/org/apache/maven/building/ProblemCollectorFactoryTest.java
index ee2575b..6705992 100644
--- a/maven-builder-support/src/test/java/org/apache/maven/building/ProblemCollectorFactoryTest.java
+++ b/maven-builder-support/src/test/java/org/apache/maven/building/ProblemCollectorFactoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.util.Collections;
 
@@ -26,20 +25,17 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotSame;
 
-public class ProblemCollectorFactoryTest
-{
+class ProblemCollectorFactoryTest {
 
     @Test
-    public void testNewInstance()
-    {
-        ProblemCollector collector1 = ProblemCollectorFactory.newInstance( null );
+    void testNewInstance() {
+        ProblemCollector collector1 = ProblemCollectorFactory.newInstance(null);
 
-        Problem problem = new DefaultProblem( "MESSAGE1", null, null, -1, -1, null );
-        ProblemCollector collector2 = ProblemCollectorFactory.newInstance( Collections.singletonList( problem ) );
+        Problem problem = new DefaultProblem("MESSAGE1", null, null, -1, -1, null);
+        ProblemCollector collector2 = ProblemCollectorFactory.newInstance(Collections.singletonList(problem));
 
-        assertNotSame( collector1, collector2 );
-        assertEquals( 0, collector1.getProblems().size() );
-        assertEquals( 1, collector2.getProblems().size() );
+        assertNotSame(collector1, collector2);
+        assertEquals(0, collector1.getProblems().size());
+        assertEquals(1, collector2.getProblems().size());
     }
-
 }
diff --git a/maven-builder-support/src/test/java/org/apache/maven/building/StringSourceTest.java b/maven-builder-support/src/test/java/org/apache/maven/building/StringSourceTest.java
index 85309aa..8bd2a41 100644
--- a/maven-builder-support/src/test/java/org/apache/maven/building/StringSourceTest.java
+++ b/maven-builder-support/src/test/java/org/apache/maven/building/StringSourceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.io.InputStream;
 import java.util.Scanner;
@@ -26,39 +25,32 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class StringSourceTest
-{
+class StringSourceTest {
     @Test
-    public void testGetInputStream()
-        throws Exception
-    {
-        StringSource source = new StringSource( "Hello World!" );
+    void testGetInputStream() throws Exception {
+        StringSource source = new StringSource("Hello World!");
 
-        try ( InputStream is = source.getInputStream();
-              Scanner scanner = new Scanner( is ) )
-        {
-            assertEquals( "Hello World!", scanner.nextLine() );
+        try (InputStream is = source.getInputStream();
+                Scanner scanner = new Scanner(is)) {
+            assertEquals("Hello World!", scanner.nextLine());
         }
     }
 
     @Test
-    public void testGetLocation()
-    {
-        StringSource source = new StringSource( "Hello World!" );
-        assertEquals( "(memory)", source.getLocation() );
+    void testGetLocation() {
+        StringSource source = new StringSource("Hello World!");
+        assertEquals("(memory)", source.getLocation());
 
-        source = new StringSource( "Hello World!", "LOCATION" );
-        assertEquals( "LOCATION", source.getLocation() );
+        source = new StringSource("Hello World!", "LOCATION");
+        assertEquals("LOCATION", source.getLocation());
     }
 
     @Test
-    public void testGetContent()
-    {
-        StringSource source = new StringSource( null );
-        assertEquals( "", source.getContent() );
+    void testGetContent() {
+        StringSource source = new StringSource(null);
+        assertEquals("", source.getContent());
 
-        source = new StringSource( "Hello World!", "LOCATION" );
-        assertEquals( "Hello World!", source.getContent() );
+        source = new StringSource("Hello World!", "LOCATION");
+        assertEquals("Hello World!", source.getContent());
     }
-
 }
diff --git a/maven-builder-support/src/test/java/org/apache/maven/building/UrlSourceTest.java b/maven-builder-support/src/test/java/org/apache/maven/building/UrlSourceTest.java
index efdb9bb..216c5d7 100644
--- a/maven-builder-support/src/test/java/org/apache/maven/building/UrlSourceTest.java
+++ b/maven-builder-support/src/test/java/org/apache/maven/building/UrlSourceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.building;
 
 import java.io.File;
 import java.io.InputStream;
@@ -29,39 +28,29 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-public class UrlSourceTest
-{
+class UrlSourceTest {
 
     @Test
-    public void testUrlSource()
-    {
+    void testUrlSource() {
         NullPointerException e = assertThrows(
-                NullPointerException.class,
-                () -> new UrlSource( null ),
-                "Should fail, since you must specify a url" );
-        assertEquals( "url cannot be null", e.getMessage() );
+                NullPointerException.class, () -> new UrlSource(null), "Should fail, since you must specify a url");
+        assertEquals("url cannot be null", e.getMessage());
     }
 
     @Test
-    public void testGetInputStream()
-        throws Exception
-    {
-        URL txtFile = new File( "target/test-classes/source.txt" ).toURI().toURL();
-        UrlSource source = new UrlSource( txtFile );
-        try ( InputStream is = source.getInputStream();
-              Scanner scanner = new Scanner( is ) )
-        {
-            assertEquals( "Hello World!", scanner.nextLine() );
+    void testGetInputStream() throws Exception {
+        URL txtFile = new File("target/test-classes/source.txt").toURI().toURL();
+        UrlSource source = new UrlSource(txtFile);
+        try (InputStream is = source.getInputStream();
+                Scanner scanner = new Scanner(is)) {
+            assertEquals("Hello World!", scanner.nextLine());
         }
     }
 
     @Test
-    public void testGetLocation()
-        throws Exception
-    {
-        URL txtFile = new File( "target/test-classes/source.txt" ).toURI().toURL();
-        UrlSource source = new UrlSource( txtFile );
-        assertEquals( txtFile.toExternalForm(), source.getLocation() );
+    void testGetLocation() throws Exception {
+        URL txtFile = new File("target/test-classes/source.txt").toURI().toURL();
+        UrlSource source = new UrlSource(txtFile);
+        assertEquals(txtFile.toExternalForm(), source.getLocation());
     }
-
 }
diff --git a/maven-compat/pom.xml b/maven-compat/pom.xml
index 7f8d4a3..8ae5966 100644
--- a/maven-compat/pom.xml
+++ b/maven-compat/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,20 +17,19 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-compat</artifactId>
 
-  <name>Maven Compat</name>
-  <description>Maven2 classes maintained as compatibility layer.</description>
+  <name>Maven Compat (deprecated)</name>
+  <description>Deprecated Maven2 classes maintained as compatibility layer.</description>
 
   <dependencies>
     <dependency>
@@ -84,10 +82,6 @@
     </dependency>
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-interpolation</artifactId>
     </dependency>
     <dependency>
@@ -95,10 +89,6 @@
       <artifactId>org.eclipse.sisu.plexus</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-component-annotations</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven.wagon</groupId>
       <artifactId>wagon-provider-api</artifactId>
     </dependency>
@@ -133,8 +123,8 @@
   <build>
     <plugins>
       <plugin>
-        <groupId>org.codehaus.plexus</groupId>
-        <artifactId>plexus-component-metadata</artifactId>
+        <groupId>org.eclipse.sisu</groupId>
+        <artifactId>sisu-maven-plugin</artifactId>
       </plugin>
       <plugin>
         <groupId>org.codehaus.modello</groupId>
@@ -146,6 +136,16 @@
             <model>src/main/mdo/paramdoc.mdo</model>
           </models>
         </configuration>
+        <executions>
+          <execution>
+            <id>modello</id>
+            <goals>
+              <goal>java</goal>
+              <goal>xpp3-reader</goal>
+              <goal>xpp3-writer</goal>
+            </goals>
+          </execution>
+        </executions>
       </plugin>
     </plugins>
   </build>
diff --git a/maven-compat/src/main/java/org/apache/maven/ArtifactFilterManager.java b/maven-compat/src/main/java/org/apache/maven/ArtifactFilterManager.java
new file mode 100644
index 0000000..e756a9c
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/ArtifactFilterManager.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven;
+
+import java.util.Set;
+
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+
+/**
+ * ArtifactFilterManager
+ */
+@Deprecated
+public interface ArtifactFilterManager {
+    /**
+     * Returns a filter for core + extension artifacts.
+     *
+     * @return the artifact filter
+     * @deprecated use {@code META-INF/maven/extension.xml} to define artifacts exported by Maven core and plugin
+     *             extensions.
+     */
+    ArtifactFilter getArtifactFilter();
+
+    /**
+     * Returns a filter for only the core artifacts.
+     *
+     * @return the artifact filter
+     */
+    ArtifactFilter getCoreArtifactFilter();
+
+    /**
+     * Exclude an extension artifact (doesn't affect getArtifactFilter's result, only getExtensionArtifactFilter).
+     *
+     * @param artifactId an artifact id
+     * @deprecated use {@code META-INF/maven/extension.xml} to define artifacts exported by Maven core and plugin
+     *             extensions.
+     */
+    void excludeArtifact(String artifactId);
+
+    Set<String> getCoreArtifactExcludes();
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/ArtifactFilterManagerDelegate.java b/maven-compat/src/main/java/org/apache/maven/ArtifactFilterManagerDelegate.java
new file mode 100644
index 0000000..c9e752e
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/ArtifactFilterManagerDelegate.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven;
+
+import java.util.Set;
+
+/**
+ * @deprecated use {@code META-INF/maven/extension.xml} to define artifacts exported by Maven core extensions.
+ */
+@Deprecated
+public interface ArtifactFilterManagerDelegate {
+
+    void addExcludes(Set<String> excludes);
+
+    void addCoreExcludes(Set<String> excludes);
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java b/maven-compat/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
new file mode 100644
index 0000000..f698d53
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter;
+import org.apache.maven.extension.internal.CoreExports;
+
+/**
+ */
+@Named
+@Singleton
+@Deprecated
+public class DefaultArtifactFilterManager implements ArtifactFilterManager {
+
+    // this is a live injected collection
+    protected final List<ArtifactFilterManagerDelegate> delegates;
+
+    protected Set<String> excludedArtifacts;
+
+    private final Set<String> coreArtifacts;
+
+    @Inject
+    public DefaultArtifactFilterManager(List<ArtifactFilterManagerDelegate> delegates, CoreExports coreExports) {
+        this.delegates = delegates;
+        this.coreArtifacts = coreExports.getExportedArtifacts();
+    }
+
+    private synchronized Set<String> getExcludedArtifacts() {
+        if (excludedArtifacts == null) {
+            excludedArtifacts = new LinkedHashSet<>(coreArtifacts);
+        }
+        return excludedArtifacts;
+    }
+
+    /**
+     * Returns the artifact filter for the core + extension artifacts.
+     *
+     * @see org.apache.maven.ArtifactFilterManager#getArtifactFilter()
+     */
+    public ArtifactFilter getArtifactFilter() {
+        Set<String> excludes = new LinkedHashSet<>(getExcludedArtifacts());
+
+        for (ArtifactFilterManagerDelegate delegate : delegates) {
+            delegate.addExcludes(excludes);
+        }
+
+        return new ExclusionSetFilter(excludes);
+    }
+
+    /**
+     * Returns the artifact filter for the standard core artifacts.
+     *
+     * @see org.apache.maven.ArtifactFilterManager#getCoreArtifactFilter()
+     */
+    public ArtifactFilter getCoreArtifactFilter() {
+        return new ExclusionSetFilter(getCoreArtifactExcludes());
+    }
+
+    public void excludeArtifact(String artifactId) {
+        getExcludedArtifacts().add(artifactId);
+    }
+
+    public Set<String> getCoreArtifactExcludes() {
+        Set<String> excludes = new LinkedHashSet<>(coreArtifacts);
+
+        for (ArtifactFilterManagerDelegate delegate : delegates) {
+            delegate.addCoreExcludes(excludes);
+        }
+
+        return excludes;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/DefaultProjectDependenciesResolver.java b/maven-compat/src/main/java/org/apache/maven/DefaultProjectDependenciesResolver.java
new file mode 100644
index 0000000..ce24588
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/DefaultProjectDependenciesResolver.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
+import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
+import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.ProjectArtifact;
+import org.apache.maven.repository.RepositorySystem;
+
+/**
+ * @deprecated As of 3.2.2, and there is no direct replacement. This is an internal class which was not marked as such,
+ *             but should have been.
+ *
+ */
+@Named
+@Singleton
+@Deprecated
+public class DefaultProjectDependenciesResolver implements ProjectDependenciesResolver {
+
+    private final RepositorySystem repositorySystem;
+
+    private final ResolutionErrorHandler resolutionErrorHandler;
+
+    @Inject
+    public DefaultProjectDependenciesResolver(
+            RepositorySystem repositorySystem, ResolutionErrorHandler resolutionErrorHandler) {
+        this.repositorySystem = repositorySystem;
+        this.resolutionErrorHandler = resolutionErrorHandler;
+    }
+
+    public Set<Artifact> resolve(MavenProject project, Collection<String> scopesToResolve, MavenSession session)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        return resolve(Collections.singleton(project), scopesToResolve, session);
+    }
+
+    public Set<Artifact> resolve(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        Set<MavenProject> mavenProjects = Collections.singleton(project);
+        return resolveImpl(
+                mavenProjects, scopesToCollect, scopesToResolve, session, getIgnorableArtifacts(mavenProjects));
+    }
+
+    public Set<Artifact> resolve(
+            Collection<? extends MavenProject> projects, Collection<String> scopesToResolve, MavenSession session)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        return resolveImpl(projects, null, scopesToResolve, session, getIgnorableArtifacts(projects));
+    }
+
+    public Set<Artifact> resolve(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session,
+            Set<Artifact> ignorableArtifacts)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        return resolveImpl(
+                Collections.singleton(project),
+                scopesToCollect,
+                scopesToResolve,
+                session,
+                getIgnorableArtifacts(ignorableArtifacts));
+    }
+
+    private Set<Artifact> resolveImpl(
+            Collection<? extends MavenProject> projects,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session,
+            Set<String> projectIds)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        Set<Artifact> resolved = new LinkedHashSet<>();
+
+        if (projects == null || projects.isEmpty()) {
+            return resolved;
+        }
+
+        if ((scopesToCollect == null || scopesToCollect.isEmpty())
+                && (scopesToResolve == null || scopesToResolve.isEmpty())) {
+            return resolved;
+        }
+
+        /*
+
+        Logic for transitive global exclusions
+
+        List<String> exclusions = new ArrayList<String>();
+
+        for ( Dependency d : project.getDependencies() )
+        {
+            if ( d.getExclusions() != null )
+            {
+                for ( Exclusion e : d.getExclusions() )
+                {
+                    exclusions.add(  e.getGroupId() + ":" + e.getArtifactId() );
+                }
+            }
+        }
+
+        ArtifactFilter scopeFilter = new ScopeArtifactFilter( scope );
+
+        ArtifactFilter filter;
+
+        if ( ! exclusions.isEmpty() )
+        {
+            filter = new AndArtifactFilter( Arrays.asList( new ArtifactFilter[]{
+                new ExcludesArtifactFilter( exclusions ), scopeFilter } ) );
+        }
+        else
+        {
+            filter = scopeFilter;
+        }
+        */
+
+        CumulativeScopeArtifactFilter resolutionScopeFilter = new CumulativeScopeArtifactFilter(scopesToResolve);
+
+        CumulativeScopeArtifactFilter collectionScopeFilter = new CumulativeScopeArtifactFilter(scopesToCollect);
+        collectionScopeFilter = new CumulativeScopeArtifactFilter(collectionScopeFilter, resolutionScopeFilter);
+
+        ArtifactResolutionRequest request = new ArtifactResolutionRequest()
+                .setResolveRoot(false)
+                .setResolveTransitively(true)
+                .setCollectionFilter(collectionScopeFilter)
+                .setResolutionFilter(resolutionScopeFilter)
+                .setLocalRepository(session.getLocalRepository())
+                .setOffline(session.isOffline())
+                .setForceUpdate(session.getRequest().isUpdateSnapshots());
+        request.setServers(session.getRequest().getServers());
+        request.setMirrors(session.getRequest().getMirrors());
+        request.setProxies(session.getRequest().getProxies());
+
+        for (MavenProject project : projects) {
+            request.setArtifact(new ProjectArtifact(project));
+            request.setArtifactDependencies(project.getDependencyArtifacts());
+            request.setManagedVersionMap(project.getManagedVersionMap());
+            request.setRemoteRepositories(project.getRemoteArtifactRepositories());
+
+            ArtifactResolutionResult result = repositorySystem.resolve(request);
+
+            try {
+                resolutionErrorHandler.throwErrors(request, result);
+            } catch (MultipleArtifactsNotFoundException e) {
+
+                Collection<Artifact> missing = new HashSet<>(e.getMissingArtifacts());
+
+                for (Iterator<Artifact> it = missing.iterator(); it.hasNext(); ) {
+                    String key = ArtifactUtils.key(it.next());
+                    if (projectIds.contains(key)) {
+                        it.remove();
+                    }
+                }
+
+                if (!missing.isEmpty()) {
+                    throw e;
+                }
+            }
+
+            resolved.addAll(result.getArtifacts());
+        }
+
+        return resolved;
+    }
+
+    private Set<String> getIgnorableArtifacts(Collection<? extends MavenProject> projects) {
+        Set<String> projectIds = new HashSet<>(projects.size() * 2);
+
+        for (MavenProject p : projects) {
+            String key = ArtifactUtils.key(p.getGroupId(), p.getArtifactId(), p.getVersion());
+            projectIds.add(key);
+        }
+        return projectIds;
+    }
+
+    private Set<String> getIgnorableArtifacts(Iterable<Artifact> artifactIterable) {
+        Set<String> projectIds = new HashSet<>();
+
+        for (Artifact artifact : artifactIterable) {
+            String key = ArtifactUtils.key(artifact);
+            projectIds.add(key);
+        }
+        return projectIds;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/ProjectDependenciesResolver.java b/maven-compat/src/main/java/org/apache/maven/ProjectDependenciesResolver.java
new file mode 100644
index 0000000..509ee5e
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/ProjectDependenciesResolver.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven;
+
+import java.util.Collection;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * @deprecated As of 3.2.2, and there is no direct replacement. This is an internal class which was not marked as such,
+ *             but should have been.
+ *
+ */
+@Deprecated
+public interface ProjectDependenciesResolver {
+
+    /**
+     * Resolves the transitive dependencies of the specified project.
+     *
+     * @param project         The project whose dependencies should be resolved, must not be {@code null}.
+     * @param scopesToResolve The dependency scopes that should be resolved, may be {@code null}.
+     * @param session         The current build session, must not be {@code null}.
+     * @return The transitive dependencies of the specified project that match the requested scopes, never {@code null}.
+     * @throws ArtifactResolutionException in case of resolution issue
+     * @throws ArtifactNotFoundException if an artifact is not found
+     */
+    Set<Artifact> resolve(MavenProject project, Collection<String> scopesToResolve, MavenSession session)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
+
+    /**
+     * Resolves the transitive dependencies of the specified project.
+     *
+     * @param project         The project whose dependencies should be resolved, must not be {@code null}.
+     * @param scopesToCollect The dependency scopes that should be collected, may be {@code null}.
+     * @param scopesToResolve The dependency scopes that should be collected and also resolved, may be {@code null}.
+     * @param session         The current build session, must not be {@code null}.
+     * @return The transitive dependencies of the specified project that match the requested scopes, never {@code null}.
+     * @throws ArtifactResolutionException in case of resolution issue
+     * @throws ArtifactNotFoundException if an artifact is not found
+     */
+    Set<Artifact> resolve(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
+
+    /**
+     * Resolves the transitive dependencies of the specified project.
+     *
+     * @param project            The project whose dependencies should be resolved, must not be {@code null}.
+     * @param scopesToCollect    The dependency scopes that should be collected, may be {@code null}.
+     * @param scopesToResolve    The dependency scopes that should be collected and also resolved, may be {@code null}.
+     * @param session            The current build session, must not be {@code null}.
+     * @param ignorableArtifacts Artifacts that need not be resolved
+     * @return The transitive dependencies of the specified project that match the requested scopes, never {@code null}.
+     * @throws ArtifactResolutionException in case of resolution issue
+     * @throws ArtifactNotFoundException if an artifact is not found
+     */
+    Set<Artifact> resolve(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session,
+            Set<Artifact> ignorableArtifacts)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
+
+    /**
+     * Resolves the transitive dependencies of the specified projects. Note that dependencies which can't be resolved
+     * from any repository but are present among the set of specified projects will not cause an exception. Instead,
+     * those unresolved artifacts will be returned in the result set, allowing the caller to take special care of
+     * artifacts that haven't been build yet.
+     *
+     * @param projects The projects whose dependencies should be resolved, may be {@code null}.
+     * @param scopes   The dependency scopes that should be resolved, may be {@code null}.
+     * @param session  The current build session, must not be {@code null}.
+     * @return The transitive dependencies of the specified projects that match the requested scopes, never
+     *         {@code null}.
+     * @throws ArtifactResolutionException in case of resolution issue
+     * @throws ArtifactNotFoundException if an artifact is not found
+     */
+    Set<Artifact> resolve(Collection<? extends MavenProject> projects, Collection<String> scopes, MavenSession session)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactScopeEnum.java b/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactScopeEnum.java
index 4745467..34178d5 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactScopeEnum.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactScopeEnum.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,43 +16,43 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 /**
  * Type safe reincarnation of Artifact scope. Also supplies the {@code DEFAULT_SCOPE} as well
  * as convenience method to deal with scope relationships.
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-
-public enum ArtifactScopeEnum
-{
-    compile( 1 ), test( 2 ), runtime( 3 ), provided( 4 ), system( 5 ), runtime_plus_system( 6 );
+@Deprecated
+public enum ArtifactScopeEnum {
+    compile(1),
+    test(2),
+    runtime(3),
+    provided(4),
+    system(5),
+    runtime_plus_system(6);
 
     public static final ArtifactScopeEnum DEFAULT_SCOPE = compile;
 
     private int id;
 
     // Constructor
-    ArtifactScopeEnum( int id )
-    {
+    ArtifactScopeEnum(int id) {
         this.id = id;
     }
 
-    int getId()
-    {
+    int getId() {
         return id;
     }
 
-
     /**
      * Helper method to simplify null processing
      *
      * @param scope a scope or {@code null}
      * @return the provided scope or DEFAULT_SCOPE
      */
-    public static ArtifactScopeEnum checkScope( ArtifactScopeEnum scope )
-    {
+    public static ArtifactScopeEnum checkScope(ArtifactScopeEnum scope) {
         return scope == null ? DEFAULT_SCOPE : scope;
     }
 
@@ -62,41 +60,29 @@
      *
      * @return unsafe String representation of this scope.
      */
-    public String getScope()
-    {
-        if ( id == 1 )
-        {
+    public String getScope() {
+        if (id == 1) {
             return Artifact.SCOPE_COMPILE;
-        }
-        else if ( id == 2 )
-        {
+        } else if (id == 2) {
             return Artifact.SCOPE_TEST;
 
-        }
-        else if ( id == 3 )
-        {
+        } else if (id == 3) {
             return Artifact.SCOPE_RUNTIME;
 
-        }
-        else if ( id == 4 )
-        {
+        } else if (id == 4) {
             return Artifact.SCOPE_PROVIDED;
-        }
-        else if ( id == 5 )
-        {
+        } else if (id == 5) {
             return Artifact.SCOPE_SYSTEM;
-        }
-        else
-        {
+        } else {
             return Artifact.SCOPE_RUNTIME_PLUS_SYSTEM;
         }
     }
 
-    private static final ArtifactScopeEnum [][][] COMPLIANCY_SETS = {
-          { { compile  }, { compile,                provided, system } }
-        , { { test     }, { compile, test,          provided, system } }
-        , { { runtime  }, { compile,       runtime,           system } }
-        , { { provided }, { compile, test,          provided         } }
+    private static final ArtifactScopeEnum[][][] COMPLIANCY_SETS = {
+        {{compile}, {compile, provided, system}},
+        {{test}, {compile, test, provided, system}},
+        {{runtime}, {compile, runtime, system}},
+        {{provided}, {compile, test, provided}}
     };
 
     /**
@@ -105,24 +91,18 @@
      * @param scope a scope
      * @return true is supplied scope is an inclusive sub-scope of current one.
      */
-    public boolean encloses( ArtifactScopeEnum scope )
-    {
-        final ArtifactScopeEnum s = checkScope( scope );
+    public boolean encloses(ArtifactScopeEnum scope) {
+        final ArtifactScopeEnum s = checkScope(scope);
 
         // system scope is historic only - and simple
-        if ( id == system.id )
-        {
+        if (id == system.id) {
             return scope.id == system.id;
         }
 
-        for ( ArtifactScopeEnum[][] set : COMPLIANCY_SETS )
-        {
-            if ( id == set[0][0].id )
-            {
-                for ( ArtifactScopeEnum ase : set[1] )
-                {
-                    if ( s.id == ase.id )
-                    {
+        for (ArtifactScopeEnum[][] set : COMPLIANCY_SETS) {
+            if (id == set[0][0].id) {
+                for (ArtifactScopeEnum ase : set[1]) {
+                    if (s.id == ase.id) {
                         return true;
                     }
                 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactStatus.java b/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactStatus.java
index 1705d66..3a6a2bd 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactStatus.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/ArtifactStatus.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -25,40 +24,38 @@
 /**
  * Type safe enumeration for the artifact status field.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public final class ArtifactStatus
-    implements Comparable<ArtifactStatus>
-{
+@Deprecated
+public final class ArtifactStatus implements Comparable<ArtifactStatus> {
     /**
      * No trust - no information about status.
      */
-    public static final ArtifactStatus NONE = new ArtifactStatus( "none", 0 );
+    public static final ArtifactStatus NONE = new ArtifactStatus("none", 0);
 
     /**
      * No trust - information was generated with defaults.
      */
-    public static final ArtifactStatus GENERATED = new ArtifactStatus( "generated", 1 );
+    public static final ArtifactStatus GENERATED = new ArtifactStatus("generated", 1);
 
     /**
      * Low trust - was converted from the Maven 1.x repository.
      */
-    public static final ArtifactStatus CONVERTED = new ArtifactStatus( "converted", 2 );
+    public static final ArtifactStatus CONVERTED = new ArtifactStatus("converted", 2);
 
     /**
      * Moderate trust - it was deployed directly from a partner.
      */
-    public static final ArtifactStatus PARTNER = new ArtifactStatus( "partner", 3 );
+    public static final ArtifactStatus PARTNER = new ArtifactStatus("partner", 3);
 
     /**
      * Moderate trust - it was deployed directly by a user.
      */
-    public static final ArtifactStatus DEPLOYED = new ArtifactStatus( "deployed", 4 );
+    public static final ArtifactStatus DEPLOYED = new ArtifactStatus("deployed", 4);
 
     /**
      * Trusted, as it has had its data verified by hand.
      */
-    public static final ArtifactStatus VERIFIED = new ArtifactStatus( "verified", 5 );
+    public static final ArtifactStatus VERIFIED = new ArtifactStatus("verified", 5);
 
     private final int rank;
 
@@ -66,59 +63,48 @@
 
     private static Map<String, ArtifactStatus> map;
 
-    private ArtifactStatus( String key, int rank )
-    {
+    private ArtifactStatus(String key, int rank) {
         this.rank = rank;
         this.key = key;
 
-        if ( map == null )
-        {
+        if (map == null) {
             map = new HashMap<>();
         }
-        map.put( key, this );
+        map.put(key, this);
     }
 
-    public static ArtifactStatus valueOf( String status )
-    {
+    public static ArtifactStatus valueOf(String status) {
         ArtifactStatus retVal = null;
 
-        if ( status != null )
-        {
-            retVal = map.get( status );
+        if (status != null) {
+            retVal = map.get(status);
         }
 
         return retVal != null ? retVal : NONE;
     }
 
-    public boolean equals( Object o )
-    {
-        if ( this == o )
-        {
+    public boolean equals(Object o) {
+        if (this == o) {
             return true;
         }
-        if ( o == null || getClass() != o.getClass() )
-        {
+        if (o == null || getClass() != o.getClass()) {
             return false;
         }
 
         final ArtifactStatus that = (ArtifactStatus) o;
 
         return rank == that.rank;
-
     }
 
-    public int hashCode()
-    {
+    public int hashCode() {
         return rank;
     }
 
-    public String toString()
-    {
+    public String toString() {
         return key;
     }
 
-    public int compareTo( ArtifactStatus s )
-    {
+    public int compareTo(ArtifactStatus s) {
         return rank - s.rank;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/UnknownRepositoryLayoutException.java b/maven-compat/src/main/java/org/apache/maven/artifact/UnknownRepositoryLayoutException.java
index e23bea9..dcaa874 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/UnknownRepositoryLayoutException.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/UnknownRepositoryLayoutException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 
@@ -26,29 +25,23 @@
  * repository doesn't have a corresponding {@link org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout}
  * component in the current container.
  *
- * @author jdcasey
  */
-public class UnknownRepositoryLayoutException
-    extends InvalidRepositoryException
-{
+@Deprecated
+public class UnknownRepositoryLayoutException extends InvalidRepositoryException {
 
     private final String layoutId;
 
-    public UnknownRepositoryLayoutException( String repositoryId, String layoutId )
-    {
-        super( "Cannot find ArtifactRepositoryLayout instance for: " + layoutId, repositoryId );
+    public UnknownRepositoryLayoutException(String repositoryId, String layoutId) {
+        super("Cannot find ArtifactRepositoryLayout instance for: " + layoutId, repositoryId);
         this.layoutId = layoutId;
     }
 
-    public UnknownRepositoryLayoutException( String repositoryId, String layoutId, ComponentLookupException e )
-    {
-        super( "Cannot find ArtifactRepositoryLayout instance for: " + layoutId, repositoryId, e );
+    public UnknownRepositoryLayoutException(String repositoryId, String layoutId, ComponentLookupException e) {
+        super("Cannot find ArtifactRepositoryLayout instance for: " + layoutId, repositoryId, e);
         this.layoutId = layoutId;
     }
 
-    public String getLayoutId()
-    {
+    public String getLayoutId() {
         return layoutId;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeployer.java b/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeployer.java
index bf15206..43dbd13 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeployer.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeployer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.deployer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.deployer;
 
 import java.io.File;
 
@@ -27,8 +26,8 @@
 /**
  * ArtifactDeployer
  */
-public interface ArtifactDeployer
-{
+@Deprecated
+public interface ArtifactDeployer {
     String ROLE = ArtifactDeployer.class.getName();
 
     /**
@@ -45,9 +44,13 @@
      *             method
      */
     @Deprecated
-    void deploy( String basedir, String finalName, Artifact artifact, ArtifactRepository deploymentRepository,
-                 ArtifactRepository localRepository )
-        throws ArtifactDeploymentException;
+    void deploy(
+            String basedir,
+            String finalName,
+            Artifact artifact,
+            ArtifactRepository deploymentRepository,
+            ArtifactRepository localRepository)
+            throws ArtifactDeploymentException;
 
     /**
      * Deploy an artifact from a particular file.
@@ -58,7 +61,7 @@
      * @param localRepository the local repository to install into
      * @throws ArtifactDeploymentException if an error occurred deploying the artifact
      */
-    void deploy( File source, Artifact artifact, ArtifactRepository deploymentRepository,
-                 ArtifactRepository localRepository )
-        throws ArtifactDeploymentException;
+    void deploy(
+            File source, Artifact artifact, ArtifactRepository deploymentRepository, ArtifactRepository localRepository)
+            throws ArtifactDeploymentException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeploymentException.java b/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeploymentException.java
index 6e44ed3..6351873 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeploymentException.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/deployer/ArtifactDeploymentException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.deployer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,26 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.deployer;
 
 /**
- * @author Jason van Zyl
  */
-public class ArtifactDeploymentException
-    extends Exception
-{
-    public ArtifactDeploymentException( String message )
-    {
-        super( message );
+@Deprecated
+public class ArtifactDeploymentException extends Exception {
+    public ArtifactDeploymentException(String message) {
+        super(message);
     }
 
-    public ArtifactDeploymentException( Throwable cause )
-    {
-        super( cause );
+    public ArtifactDeploymentException(Throwable cause) {
+        super(cause);
     }
 
-    public ArtifactDeploymentException( String message,
-                                        Throwable cause )
-    {
-        super( message, cause );
+    public ArtifactDeploymentException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/deployer/DefaultArtifactDeployer.java b/maven-compat/src/main/java/org/apache/maven/artifact/deployer/DefaultArtifactDeployer.java
index 87d9c46..3ecc9ab 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/deployer/DefaultArtifactDeployer.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/deployer/DefaultArtifactDeployer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.deployer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.deployer;
+
+import javax.inject.Inject;
+import javax.inject.Named;
 
 import java.io.File;
 import java.util.Map;
@@ -34,8 +36,6 @@
 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
 import org.apache.maven.plugin.LegacySupport;
 import org.apache.maven.project.artifact.ProjectArtifactMetadata;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
@@ -50,16 +50,14 @@
 /**
  * DefaultArtifactDeployer
  */
-@Component( role = ArtifactDeployer.class, instantiationStrategy = "per-lookup" )
-public class DefaultArtifactDeployer
-    extends AbstractLogEnabled
-    implements ArtifactDeployer
-{
+@Named
+@Deprecated
+public class DefaultArtifactDeployer extends AbstractLogEnabled implements ArtifactDeployer {
 
-    @Requirement
+    @Inject
     private RepositorySystem repoSystem;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
     private Map<Object, MergeableMetadata> relatedMetadata = new ConcurrentHashMap<>();
@@ -69,96 +67,83 @@
      *             correctly.
      */
     @Deprecated
-    public void deploy( String basedir, String finalName, Artifact artifact, ArtifactRepository deploymentRepository,
-                        ArtifactRepository localRepository )
-        throws ArtifactDeploymentException
-    {
+    public void deploy(
+            String basedir,
+            String finalName,
+            Artifact artifact,
+            ArtifactRepository deploymentRepository,
+            ArtifactRepository localRepository)
+            throws ArtifactDeploymentException {
         String extension = artifact.getArtifactHandler().getExtension();
-        File source = new File( basedir, finalName + "." + extension );
-        deploy( source, artifact, deploymentRepository, localRepository );
+        File source = new File(basedir, finalName + "." + extension);
+        deploy(source, artifact, deploymentRepository, localRepository);
     }
 
-    public void deploy( File source, Artifact artifact, ArtifactRepository deploymentRepository,
-                        ArtifactRepository localRepository )
-        throws ArtifactDeploymentException
-    {
+    public void deploy(
+            File source, Artifact artifact, ArtifactRepository deploymentRepository, ArtifactRepository localRepository)
+            throws ArtifactDeploymentException {
         RepositorySystemSession session =
-            LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(), repoSystem );
+                LegacyLocalRepositoryManager.overlay(localRepository, legacySupport.getRepositorySession(), repoSystem);
 
         DeployRequest request = new DeployRequest();
 
-        request.setTrace( RequestTrace.newChild( null, legacySupport.getSession().getCurrentProject() ) );
+        request.setTrace(RequestTrace.newChild(null, legacySupport.getSession().getCurrentProject()));
 
-        org.eclipse.aether.artifact.Artifact mainArtifact = RepositoryUtils.toArtifact( artifact );
-        mainArtifact = mainArtifact.setFile( source );
-        request.addArtifact( mainArtifact );
+        org.eclipse.aether.artifact.Artifact mainArtifact = RepositoryUtils.toArtifact(artifact);
+        mainArtifact = mainArtifact.setFile(source);
+        request.addArtifact(mainArtifact);
 
         String versionKey = artifact.getGroupId() + ':' + artifact.getArtifactId();
         String snapshotKey = null;
-        if ( artifact.isSnapshot() )
-        {
+        if (artifact.isSnapshot()) {
             snapshotKey = versionKey + ':' + artifact.getBaseVersion();
-            request.addMetadata( relatedMetadata.get( snapshotKey ) );
+            request.addMetadata(relatedMetadata.get(snapshotKey));
         }
-        request.addMetadata( relatedMetadata.get( versionKey ) );
+        request.addMetadata(relatedMetadata.get(versionKey));
 
-        for ( ArtifactMetadata metadata : artifact.getMetadataList() )
-        {
-            if ( metadata instanceof ProjectArtifactMetadata )
-            {
-                org.eclipse.aether.artifact.Artifact pomArtifact = new SubArtifact( mainArtifact, "", "pom" );
-                pomArtifact = pomArtifact.setFile( ( (ProjectArtifactMetadata) metadata ).getFile() );
-                request.addArtifact( pomArtifact );
-            }
-            else if ( metadata instanceof SnapshotArtifactRepositoryMetadata
-                || metadata instanceof ArtifactRepositoryMetadata )
-            {
+        for (ArtifactMetadata metadata : artifact.getMetadataList()) {
+            if (metadata instanceof ProjectArtifactMetadata) {
+                org.eclipse.aether.artifact.Artifact pomArtifact = new SubArtifact(mainArtifact, "", "pom");
+                pomArtifact = pomArtifact.setFile(((ProjectArtifactMetadata) metadata).getFile());
+                request.addArtifact(pomArtifact);
+            } else if (metadata instanceof SnapshotArtifactRepositoryMetadata
+                    || metadata instanceof ArtifactRepositoryMetadata) {
                 // eaten, handled by repo system
-            }
-            else
-            {
-                request.addMetadata( new MetadataBridge( metadata ) );
+            } else {
+                request.addMetadata(new MetadataBridge(metadata));
             }
         }
 
-        RemoteRepository remoteRepo = RepositoryUtils.toRepo( deploymentRepository );
+        RemoteRepository remoteRepo = RepositoryUtils.toRepo(deploymentRepository);
         /*
          * NOTE: This provides backward-compat with maven-deploy-plugin:2.4 which bypasses the repository factory when
          * using an alternative deployment location.
          */
-        if ( deploymentRepository instanceof DefaultArtifactRepository
-            && deploymentRepository.getAuthentication() == null )
-        {
-            RemoteRepository.Builder builder = new RemoteRepository.Builder( remoteRepo );
-            builder.setAuthentication( session.getAuthenticationSelector().getAuthentication( remoteRepo ) );
-            builder.setProxy( session.getProxySelector().getProxy( remoteRepo ) );
+        if (deploymentRepository instanceof DefaultArtifactRepository
+                && deploymentRepository.getAuthentication() == null) {
+            RemoteRepository.Builder builder = new RemoteRepository.Builder(remoteRepo);
+            builder.setAuthentication(session.getAuthenticationSelector().getAuthentication(remoteRepo));
+            builder.setProxy(session.getProxySelector().getProxy(remoteRepo));
             remoteRepo = builder.build();
         }
-        request.setRepository( remoteRepo );
+        request.setRepository(remoteRepo);
 
         DeployResult result;
-        try
-        {
-            result = repoSystem.deploy( session, request );
-        }
-        catch ( DeploymentException e )
-        {
-            throw new ArtifactDeploymentException( e.getMessage(), e );
+        try {
+            result = repoSystem.deploy(session, request);
+        } catch (DeploymentException e) {
+            throw new ArtifactDeploymentException(e.getMessage(), e);
         }
 
-        for ( Object metadata : result.getMetadata() )
-        {
-            if ( metadata.getClass().getName().endsWith( ".internal.VersionsMetadata" ) )
-            {
-                relatedMetadata.put( versionKey, (MergeableMetadata) metadata );
+        for (Object metadata : result.getMetadata()) {
+            if (metadata.getClass().getName().endsWith(".internal.VersionsMetadata")) {
+                relatedMetadata.put(versionKey, (MergeableMetadata) metadata);
             }
-            if ( snapshotKey != null && metadata.getClass().getName().endsWith( ".internal.RemoteSnapshotMetadata" ) )
-            {
-                relatedMetadata.put( snapshotKey, (MergeableMetadata) metadata );
+            if (snapshotKey != null && metadata.getClass().getName().endsWith(".internal.RemoteSnapshotMetadata")) {
+                relatedMetadata.put(snapshotKey, (MergeableMetadata) metadata);
             }
         }
 
-        artifact.setResolvedVersion( result.getArtifacts().iterator().next().getVersion() );
+        artifact.setResolvedVersion(result.getArtifacts().iterator().next().getVersion());
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstallationException.java b/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstallationException.java
index 9f1e45b..830a90b 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstallationException.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstallationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.installer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,26 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.installer;
 
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-public class ArtifactInstallationException
-    extends Exception
-{
-    public ArtifactInstallationException( String message )
-    {
-        super( message );
+@Deprecated
+public class ArtifactInstallationException extends Exception {
+    public ArtifactInstallationException(String message) {
+        super(message);
     }
 
-    public ArtifactInstallationException( Throwable cause )
-    {
-        super( cause );
+    public ArtifactInstallationException(Throwable cause) {
+        super(cause);
     }
 
-    public ArtifactInstallationException( String message,
-                                          Throwable cause )
-    {
-        super( message, cause );
+    public ArtifactInstallationException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstaller.java b/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstaller.java
index ca6bb20..f9f4c12 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstaller.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/installer/ArtifactInstaller.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.installer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.installer;
 
 import java.io.File;
 
@@ -25,10 +24,9 @@
 import org.apache.maven.artifact.repository.ArtifactRepository;
 
 /**
- * @author <a href="michal@codehaus.org">Michal Maczka</a>
  */
-public interface ArtifactInstaller
-{
+@Deprecated
+public interface ArtifactInstaller {
     String ROLE = ArtifactInstaller.class.getName();
 
     /**
@@ -44,8 +42,8 @@
      *             method
      */
     @Deprecated
-    void install( String basedir, String finalName, Artifact artifact, ArtifactRepository localRepository )
-        throws ArtifactInstallationException;
+    void install(String basedir, String finalName, Artifact artifact, ArtifactRepository localRepository)
+            throws ArtifactInstallationException;
 
     /**
      * Install an artifact from a particular file.
@@ -55,6 +53,6 @@
      * @param localRepository the local repository to install into
      * @throws ArtifactInstallationException if an error occurred installing the artifact
      */
-    void install( File source, Artifact artifact, ArtifactRepository localRepository )
-        throws ArtifactInstallationException;
+    void install(File source, Artifact artifact, ArtifactRepository localRepository)
+            throws ArtifactInstallationException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java b/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java
index 5deee38..4adf578 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/installer/DefaultArtifactInstaller.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.installer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.installer;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 
@@ -33,8 +36,6 @@
 import org.apache.maven.artifact.repository.metadata.Versioning;
 import org.apache.maven.plugin.LegacySupport;
 import org.apache.maven.project.artifact.ProjectArtifactMetadata;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
@@ -44,93 +45,77 @@
 import org.eclipse.aether.util.artifact.SubArtifact;
 
 /**
- * @author Jason van Zyl
  */
-@Component( role = ArtifactInstaller.class )
-public class DefaultArtifactInstaller
-    extends AbstractLogEnabled
-    implements ArtifactInstaller
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultArtifactInstaller extends AbstractLogEnabled implements ArtifactInstaller {
 
-    @Requirement
+    @Inject
     private RepositorySystem repoSystem;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
     /** @deprecated we want to use the artifact method only, and ensure artifact.file is set correctly. */
     @Deprecated
-    public void install( String basedir, String finalName, Artifact artifact, ArtifactRepository localRepository )
-        throws ArtifactInstallationException
-    {
+    public void install(String basedir, String finalName, Artifact artifact, ArtifactRepository localRepository)
+            throws ArtifactInstallationException {
         String extension = artifact.getArtifactHandler().getExtension();
-        File source = new File( basedir, finalName + "." + extension );
+        File source = new File(basedir, finalName + "." + extension);
 
-        install( source, artifact, localRepository );
+        install(source, artifact, localRepository);
     }
 
-    public void install( File source, Artifact artifact, ArtifactRepository localRepository )
-        throws ArtifactInstallationException
-    {
+    public void install(File source, Artifact artifact, ArtifactRepository localRepository)
+            throws ArtifactInstallationException {
         RepositorySystemSession session =
-            LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(), repoSystem );
+                LegacyLocalRepositoryManager.overlay(localRepository, legacySupport.getRepositorySession(), repoSystem);
 
         InstallRequest request = new InstallRequest();
 
-        request.setTrace( RequestTrace.newChild( null, legacySupport.getSession().getCurrentProject() ) );
+        request.setTrace(RequestTrace.newChild(null, legacySupport.getSession().getCurrentProject()));
 
-        org.eclipse.aether.artifact.Artifact mainArtifact = RepositoryUtils.toArtifact( artifact );
-        mainArtifact = mainArtifact.setFile( source );
-        request.addArtifact( mainArtifact );
+        org.eclipse.aether.artifact.Artifact mainArtifact = RepositoryUtils.toArtifact(artifact);
+        mainArtifact = mainArtifact.setFile(source);
+        request.addArtifact(mainArtifact);
 
-        for ( ArtifactMetadata metadata : artifact.getMetadataList() )
-        {
-            if ( metadata instanceof ProjectArtifactMetadata )
-            {
-                org.eclipse.aether.artifact.Artifact pomArtifact = new SubArtifact( mainArtifact, "", "pom" );
-                pomArtifact = pomArtifact.setFile( ( (ProjectArtifactMetadata) metadata ).getFile() );
-                request.addArtifact( pomArtifact );
-            }
-            else if ( metadata instanceof SnapshotArtifactRepositoryMetadata
-                || metadata instanceof ArtifactRepositoryMetadata )
-            {
+        for (ArtifactMetadata metadata : artifact.getMetadataList()) {
+            if (metadata instanceof ProjectArtifactMetadata) {
+                org.eclipse.aether.artifact.Artifact pomArtifact = new SubArtifact(mainArtifact, "", "pom");
+                pomArtifact = pomArtifact.setFile(((ProjectArtifactMetadata) metadata).getFile());
+                request.addArtifact(pomArtifact);
+            } else if (metadata instanceof SnapshotArtifactRepositoryMetadata
+                    || metadata instanceof ArtifactRepositoryMetadata) {
                 // eaten, handled by repo system
-            }
-            else
-            {
-                request.addMetadata( new MetadataBridge( metadata ) );
+            } else {
+                request.addMetadata(new MetadataBridge(metadata));
             }
         }
 
-        try
-        {
-            repoSystem.install( session, request );
-        }
-        catch ( InstallationException e )
-        {
-            throw new ArtifactInstallationException( e.getMessage(), e );
+        try {
+            repoSystem.install(session, request);
+        } catch (InstallationException e) {
+            throw new ArtifactInstallationException(e.getMessage(), e);
         }
 
         /*
          * NOTE: Not used by Maven core, only here to provide backward-compat with plugins like the Install Plugin.
          */
 
-        if ( artifact.isSnapshot() )
-        {
+        if (artifact.isSnapshot()) {
             Snapshot snapshot = new Snapshot();
-            snapshot.setLocalCopy( true );
-            artifact.addMetadata( new SnapshotArtifactRepositoryMetadata( artifact, snapshot ) );
+            snapshot.setLocalCopy(true);
+            artifact.addMetadata(new SnapshotArtifactRepositoryMetadata(artifact, snapshot));
         }
 
         Versioning versioning = new Versioning();
         // TODO Should this be changed for MNG-6754 too?
         versioning.updateTimestamp();
-        versioning.addVersion( artifact.getBaseVersion() );
-        if ( artifact.isRelease() )
-        {
-            versioning.setRelease( artifact.getBaseVersion() );
+        versioning.addVersion(artifact.getBaseVersion());
+        if (artifact.isRelease()) {
+            versioning.setRelease(artifact.getBaseVersion());
         }
-        artifact.addMetadata( new ArtifactRepositoryMetadata( artifact, versioning ) );
+        artifact.addMetadata(new ArtifactRepositoryMetadata(artifact, versioning));
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java b/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
index 5f7957e..ee2ff72 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/manager/DefaultWagonManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.manager;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.manager;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.List;
 
@@ -38,62 +41,54 @@
 import org.apache.maven.wagon.TransferFailedException;
 import org.apache.maven.wagon.authentication.AuthenticationInfo;
 import org.apache.maven.wagon.proxy.ProxyInfo;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.logging.Logger;
 
 /**
  * Manages <a href="https://maven.apache.org/wagon">Wagon</a> related operations in Maven.
  */
-@Component( role = WagonManager.class )
-public class DefaultWagonManager
-    extends org.apache.maven.repository.legacy.DefaultWagonManager
-    implements WagonManager
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultWagonManager extends org.apache.maven.repository.legacy.DefaultWagonManager
+        implements WagonManager {
 
     // NOTE: This must use a different field name than in the super class or IoC has no chance to inject the loggers
-    @Requirement
+    @Inject
     private Logger log;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
-    @Requirement
+    @Inject
     private SettingsDecrypter settingsDecrypter;
 
-    @Requirement
+    @Inject
     private MirrorSelector mirrorSelector;
 
-    @Requirement
+    @Inject
     private ArtifactRepositoryFactory artifactRepositoryFactory;
 
-    public AuthenticationInfo getAuthenticationInfo( String id )
-    {
+    public AuthenticationInfo getAuthenticationInfo(String id) {
         MavenSession session = legacySupport.getSession();
 
-        if ( session != null && id != null )
-        {
+        if (session != null && id != null) {
             MavenExecutionRequest request = session.getRequest();
 
-            if ( request != null )
-            {
+            if (request != null) {
                 List<Server> servers = request.getServers();
 
-                if ( servers != null )
-                {
-                    for ( Server server : servers )
-                    {
-                        if ( id.equalsIgnoreCase( server.getId() ) )
-                        {
+                if (servers != null) {
+                    for (Server server : servers) {
+                        if (id.equalsIgnoreCase(server.getId())) {
                             SettingsDecryptionResult result =
-                                settingsDecrypter.decrypt( new DefaultSettingsDecryptionRequest( server ) );
+                                    settingsDecrypter.decrypt(new DefaultSettingsDecryptionRequest(server));
                             server = result.getServer();
 
                             AuthenticationInfo authInfo = new AuthenticationInfo();
-                            authInfo.setUserName( server.getUsername() );
-                            authInfo.setPassword( server.getPassword() );
-                            authInfo.setPrivateKey( server.getPrivateKey() );
-                            authInfo.setPassphrase( server.getPassphrase() );
+                            authInfo.setUserName(server.getUsername());
+                            authInfo.setPassword(server.getPassword());
+                            authInfo.setPrivateKey(server.getPrivateKey());
+                            authInfo.setPassphrase(server.getPassphrase());
 
                             return authInfo;
                         }
@@ -103,38 +98,32 @@
         }
 
         // empty one to prevent NPE
-       return new AuthenticationInfo();
+        return new AuthenticationInfo();
     }
 
-    public ProxyInfo getProxy( String protocol )
-    {
+    public ProxyInfo getProxy(String protocol) {
         MavenSession session = legacySupport.getSession();
 
-        if ( session != null && protocol != null )
-        {
+        if (session != null && protocol != null) {
             MavenExecutionRequest request = session.getRequest();
 
-            if ( request != null )
-            {
+            if (request != null) {
                 List<Proxy> proxies = request.getProxies();
 
-                if ( proxies != null )
-                {
-                    for ( Proxy proxy : proxies )
-                    {
-                        if ( proxy.isActive() && protocol.equalsIgnoreCase( proxy.getProtocol() ) )
-                        {
+                if (proxies != null) {
+                    for (Proxy proxy : proxies) {
+                        if (proxy.isActive() && protocol.equalsIgnoreCase(proxy.getProtocol())) {
                             SettingsDecryptionResult result =
-                                settingsDecrypter.decrypt( new DefaultSettingsDecryptionRequest( proxy ) );
+                                    settingsDecrypter.decrypt(new DefaultSettingsDecryptionRequest(proxy));
                             proxy = result.getProxy();
 
                             ProxyInfo proxyInfo = new ProxyInfo();
-                            proxyInfo.setHost( proxy.getHost() );
-                            proxyInfo.setType( proxy.getProtocol() );
-                            proxyInfo.setPort( proxy.getPort() );
-                            proxyInfo.setNonProxyHosts( proxy.getNonProxyHosts() );
-                            proxyInfo.setUserName( proxy.getUsername() );
-                            proxyInfo.setPassword( proxy.getPassword() );
+                            proxyInfo.setHost(proxy.getHost());
+                            proxyInfo.setType(proxy.getProtocol());
+                            proxyInfo.setPort(proxy.getPort());
+                            proxyInfo.setNonProxyHosts(proxy.getNonProxyHosts());
+                            proxyInfo.setUserName(proxy.getUsername());
+                            proxyInfo.setPassword(proxy.getPassword());
 
                             return proxyInfo;
                         }
@@ -146,40 +135,34 @@
         return null;
     }
 
-    public void getArtifact( Artifact artifact, ArtifactRepository repository )
-        throws TransferFailedException, ResourceDoesNotExistException
-    {
-        getArtifact( artifact, repository, null, false );
+    public void getArtifact(Artifact artifact, ArtifactRepository repository)
+            throws TransferFailedException, ResourceDoesNotExistException {
+        getArtifact(artifact, repository, null, false);
     }
 
-    public void getArtifact( Artifact artifact, List<ArtifactRepository> remoteRepositories )
-        throws TransferFailedException, ResourceDoesNotExistException
-    {
-        getArtifact( artifact, remoteRepositories, null, false );
+    public void getArtifact(Artifact artifact, List<ArtifactRepository> remoteRepositories)
+            throws TransferFailedException, ResourceDoesNotExistException {
+        getArtifact(artifact, remoteRepositories, null, false);
     }
 
     @Deprecated
-    public ArtifactRepository getMirrorRepository( ArtifactRepository repository )
-    {
+    public ArtifactRepository getMirrorRepository(ArtifactRepository repository) {
 
-        Mirror mirror = mirrorSelector.getMirror( repository, legacySupport.getSession().getSettings().getMirrors() );
+        Mirror mirror = mirrorSelector.getMirror(
+                repository, legacySupport.getSession().getSettings().getMirrors());
 
-        if ( mirror != null )
-        {
+        if (mirror != null) {
             String id = mirror.getId();
-            if ( id == null )
-            {
+            if (id == null) {
                 // TODO this should be illegal in settings.xml
                 id = repository.getId();
             }
 
-            log.debug( "Using mirror: " + mirror.getUrl() + " (id: " + id + ")" );
+            log.debug("Using mirror: " + mirror.getUrl() + " (id: " + id + ")");
 
-            repository = artifactRepositoryFactory.createArtifactRepository( id, mirror.getUrl(),
-                                                                     repository.getLayout(), repository.getSnapshots(),
-                                                                     repository.getReleases() );
+            repository = artifactRepositoryFactory.createArtifactRepository(
+                    id, mirror.getUrl(), repository.getLayout(), repository.getSnapshots(), repository.getReleases());
         }
         return repository;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonConfigurationException.java b/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonConfigurationException.java
index 8065116..923ab3c 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonConfigurationException.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonConfigurationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.manager;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,21 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.manager;
 
 /**
- * @author Olivier Lamy
  */
 @Deprecated
-public class WagonConfigurationException
-    extends org.apache.maven.repository.legacy.WagonConfigurationException
-{
-    public WagonConfigurationException( String repositoryId, String message, Throwable cause )
-    {
-        super( repositoryId, message, cause );
+public class WagonConfigurationException extends org.apache.maven.repository.legacy.WagonConfigurationException {
+    public WagonConfigurationException(String repositoryId, String message, Throwable cause) {
+        super(repositoryId, message, cause);
     }
 
-    public WagonConfigurationException( String repositoryId, String message )
-    {
-        super( repositoryId, message );
+    public WagonConfigurationException(String repositoryId, String message) {
+        super(repositoryId, message);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonManager.java b/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonManager.java
index 3f9c0bd..8ae5e50 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/manager/WagonManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.manager;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.manager;
 
 import java.util.List;
 
@@ -31,12 +30,9 @@
 /**
  * Manages <a href="https://maven.apache.org/wagon">Wagon</a> related operations in Maven.
  *
- * @author <a href="michal.maczka@dimatics.com">Michal Maczka </a>
  */
 @Deprecated
-public interface WagonManager
-    extends org.apache.maven.repository.legacy.WagonManager
-{
+public interface WagonManager extends org.apache.maven.repository.legacy.WagonManager {
     /**
      * this method is only here for backward compat (project-info-reports:dependencies)
      * the default implementation will return an empty AuthenticationInfo
@@ -44,16 +40,15 @@
      * @param id an id
      * @return corresponding authentication info
      */
-    AuthenticationInfo getAuthenticationInfo( String id );
+    AuthenticationInfo getAuthenticationInfo(String id);
 
-    ProxyInfo getProxy( String protocol );
+    ProxyInfo getProxy(String protocol);
 
-    void getArtifact( Artifact artifact, ArtifactRepository repository )
-        throws TransferFailedException, ResourceDoesNotExistException;
+    void getArtifact(Artifact artifact, ArtifactRepository repository)
+            throws TransferFailedException, ResourceDoesNotExistException;
 
-    void getArtifact( Artifact artifact, List<ArtifactRepository> remoteRepositories )
-        throws TransferFailedException, ResourceDoesNotExistException;
+    void getArtifact(Artifact artifact, List<ArtifactRepository> remoteRepositories)
+            throws TransferFailedException, ResourceDoesNotExistException;
 
-    ArtifactRepository getMirrorRepository( ArtifactRepository repository );
-
+    ArtifactRepository getMirrorRepository(ArtifactRepository repository);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/metadata/AbstractArtifactMetadata.java b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/AbstractArtifactMetadata.java
new file mode 100644
index 0000000..1562d19
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/AbstractArtifactMetadata.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.metadata;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * AbstractArtifactMetadata
+ */
+@Deprecated
+public abstract class AbstractArtifactMetadata
+        extends org.apache.maven.repository.legacy.metadata.AbstractArtifactMetadata
+        implements org.apache.maven.artifact.metadata.ArtifactMetadata {
+    protected AbstractArtifactMetadata(Artifact artifact) {
+        super(artifact);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataRetrievalException.java b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataRetrievalException.java
new file mode 100644
index 0000000..5330f7e
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataRetrievalException.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.metadata;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * Error while retrieving repository metadata from the repository - deprecated
+ */
+@Deprecated
+public class ArtifactMetadataRetrievalException
+        extends org.apache.maven.repository.legacy.metadata.ArtifactMetadataRetrievalException {
+
+    /**
+     * @param message a message
+     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
+     */
+    @Deprecated
+    public ArtifactMetadataRetrievalException(String message) {
+        super(message, null, null);
+    }
+
+    /**
+     * @param cause a cause
+     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
+     */
+    @Deprecated
+    public ArtifactMetadataRetrievalException(Throwable cause) {
+        super(null, cause, null);
+    }
+
+    /**
+     * @param message a message
+     * @param cause a cause
+     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
+     */
+    @Deprecated
+    public ArtifactMetadataRetrievalException(String message, Throwable cause) {
+        super(message, cause, null);
+    }
+
+    public ArtifactMetadataRetrievalException(String message, Throwable cause, Artifact artifact) {
+        super(message, cause, artifact);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataSource.java b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataSource.java
new file mode 100644
index 0000000..771e496
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataSource.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.metadata;
+
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
+
+/**
+ * Provides some metadata operations, like querying the remote repository for a list of versions available for an
+ * artifact - deprecated
+ */
+@Deprecated
+public interface ArtifactMetadataSource extends org.apache.maven.repository.legacy.metadata.ArtifactMetadataSource {
+
+    ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException;
+
+    ResolutionGroup retrieve(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException;
+
+    List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request)
+            throws ArtifactMetadataRetrievalException;
+
+    List<ArtifactVersion> retrieveAvailableVersions(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException;
+
+    List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws ArtifactMetadataRetrievalException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ResolutionGroup.java b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ResolutionGroup.java
new file mode 100644
index 0000000..25b5b65
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/metadata/ResolutionGroup.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.metadata;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
+/**
+ * ResolutionGroup
+ */
+@Deprecated
+public class ResolutionGroup extends org.apache.maven.repository.legacy.metadata.ResolutionGroup {
+
+    public ResolutionGroup(
+            Artifact pomArtifact, Set<Artifact> artifacts, List<ArtifactRepository> resolutionRepositories) {
+        super(pomArtifact, artifacts, resolutionRepositories);
+    }
+
+    public ResolutionGroup(
+            Artifact pomArtifact,
+            Artifact relocatedArtifact,
+            Set<Artifact> artifacts,
+            Map<String, Artifact> managedVersions,
+            List<ArtifactRepository> resolutionRepositories) {
+        super(pomArtifact, relocatedArtifact, artifacts, managedVersions, resolutionRepositories);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryFactory.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryFactory.java
index 446ec49..85a2f24 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryFactory.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/ArtifactRepositoryFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 import org.apache.maven.artifact.UnknownRepositoryLayoutException;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
 
 /**
- * @author jdcasey
  */
-public interface ArtifactRepositoryFactory
-{
+@Deprecated
+public interface ArtifactRepositoryFactory {
     String ROLE = ArtifactRepositoryFactory.class.getName();
 
     String DEFAULT_LAYOUT_ID = "default";
@@ -34,26 +32,31 @@
     String LOCAL_REPOSITORY_ID = "local";
 
     @Deprecated
-    ArtifactRepositoryLayout getLayout( String layoutId )
-        throws UnknownRepositoryLayoutException;
+    ArtifactRepositoryLayout getLayout(String layoutId) throws UnknownRepositoryLayoutException;
 
     @Deprecated
-    ArtifactRepository createDeploymentArtifactRepository( String id, String url, String layoutId,
-                                                           boolean uniqueVersion )
-                                                               throws UnknownRepositoryLayoutException;
+    ArtifactRepository createDeploymentArtifactRepository(String id, String url, String layoutId, boolean uniqueVersion)
+            throws UnknownRepositoryLayoutException;
 
-    ArtifactRepository createDeploymentArtifactRepository( String id, String url, ArtifactRepositoryLayout layout,
-                                                           boolean uniqueVersion );
+    ArtifactRepository createDeploymentArtifactRepository(
+            String id, String url, ArtifactRepositoryLayout layout, boolean uniqueVersion);
 
-    ArtifactRepository createArtifactRepository( String id, String url, String layoutId,
-                                                 ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases )
-                                                     throws UnknownRepositoryLayoutException;
+    ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            String layoutId,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases)
+            throws UnknownRepositoryLayoutException;
 
-    ArtifactRepository createArtifactRepository( String id, String url, ArtifactRepositoryLayout repositoryLayout,
-                                                 ArtifactRepositoryPolicy snapshots,
-                                                 ArtifactRepositoryPolicy releases );
+    ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases);
 
-    void setGlobalUpdatePolicy( String snapshotPolicy );
+    void setGlobalUpdatePolicy(String snapshotPolicy);
 
-    void setGlobalChecksumPolicy( String checksumPolicy );
+    void setGlobalChecksumPolicy(String checksumPolicy);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java
index 4c9da38..1566890 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepository.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 import java.io.File;
 import java.util.Collections;
@@ -33,13 +32,9 @@
  * This class is an abstraction of the location from/to resources can be
  * transferred.
  *
- * @author <a href="michal.maczka@dimatics.com">Michal Maczka </a>
  */
 @Deprecated
-public class DefaultArtifactRepository
-    extends Repository
-    implements ArtifactRepository
-{
+public class DefaultArtifactRepository extends Repository implements ArtifactRepository {
     private ArtifactRepositoryLayout layout;
 
     private ArtifactRepositoryPolicy snapshots;
@@ -63,9 +58,8 @@
      * @param url    the URL of the repository
      * @param layout the layout of the repository
      */
-    public DefaultArtifactRepository( String id, String url, ArtifactRepositoryLayout layout )
-    {
-        this( id, url, layout, null, null );
+    public DefaultArtifactRepository(String id, String url, ArtifactRepositoryLayout layout) {
+        this(id, url, layout, null, null);
     }
 
     /**
@@ -76,9 +70,8 @@
      * @param layout        the layout of the repository
      * @param uniqueVersion whether to assign each snapshot a unique version
      */
-    public DefaultArtifactRepository( String id, String url, ArtifactRepositoryLayout layout, boolean uniqueVersion )
-    {
-        super( id, url );
+    public DefaultArtifactRepository(String id, String url, ArtifactRepositoryLayout layout, boolean uniqueVersion) {
+        super(id, url);
         this.layout = layout;
     }
 
@@ -91,189 +84,162 @@
      * @param snapshots the policies to use for snapshots
      * @param releases  the policies to use for releases
      */
-    public DefaultArtifactRepository( String id, String url, ArtifactRepositoryLayout layout,
-                                      ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases )
-    {
-        super( id, url );
+    public DefaultArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout layout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases) {
+        super(id, url);
 
         this.layout = layout;
 
-        if ( snapshots == null )
-        {
-            snapshots = new ArtifactRepositoryPolicy( true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
-                ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
+        if (snapshots == null) {
+            snapshots = new ArtifactRepositoryPolicy(
+                    true,
+                    ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                    ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
         }
 
         this.snapshots = snapshots;
 
-        if ( releases == null )
-        {
-            releases = new ArtifactRepositoryPolicy( true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
-                ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
+        if (releases == null) {
+            releases = new ArtifactRepositoryPolicy(
+                    true,
+                    ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                    ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
         }
 
         this.releases = releases;
     }
 
-    public String pathOf( Artifact artifact )
-    {
-        return layout.pathOf( artifact );
+    public String pathOf(Artifact artifact) {
+        return layout.pathOf(artifact);
     }
 
-    public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
-    {
-        return layout.pathOfRemoteRepositoryMetadata( artifactMetadata );
+    public String pathOfRemoteRepositoryMetadata(ArtifactMetadata artifactMetadata) {
+        return layout.pathOfRemoteRepositoryMetadata(artifactMetadata);
     }
 
-    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-    {
-        return layout.pathOfLocalRepositoryMetadata( metadata, repository );
+    public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+        return layout.pathOfLocalRepositoryMetadata(metadata, repository);
     }
 
-    public void setLayout( ArtifactRepositoryLayout layout )
-    {
+    public void setLayout(ArtifactRepositoryLayout layout) {
         this.layout = layout;
     }
 
-    public ArtifactRepositoryLayout getLayout()
-    {
+    public ArtifactRepositoryLayout getLayout() {
         return layout;
     }
 
-    public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy snapshots )
-    {
+    public void setSnapshotUpdatePolicy(ArtifactRepositoryPolicy snapshots) {
         this.snapshots = snapshots;
     }
 
-    public ArtifactRepositoryPolicy getSnapshots()
-    {
+    public ArtifactRepositoryPolicy getSnapshots() {
         return snapshots;
     }
 
-    public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy releases )
-    {
+    public void setReleaseUpdatePolicy(ArtifactRepositoryPolicy releases) {
         this.releases = releases;
     }
 
-    public ArtifactRepositoryPolicy getReleases()
-    {
+    public ArtifactRepositoryPolicy getReleases() {
         return releases;
     }
 
-    public String getKey()
-    {
+    public String getKey() {
         return getId();
     }
 
-    public boolean isBlacklisted()
-    {
+    public boolean isBlacklisted() {
         return blacklisted;
     }
 
-    public void setBlacklisted( boolean blacklisted )
-    {
+    public void setBlacklisted(boolean blacklisted) {
         this.blacklisted = blacklisted;
     }
 
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 256 );
+    public String toString() {
+        StringBuilder sb = new StringBuilder(256);
 
-        sb.append( "       id: " ).append( getId() ).append( '\n' );
-        sb.append( "      url: " ).append( getUrl() ).append( '\n' );
-        sb.append( "   layout: " ).append( layout != null ? layout : "none" ).append( '\n' );
+        sb.append("       id: ").append(getId()).append('\n');
+        sb.append("      url: ").append(getUrl()).append('\n');
+        sb.append("   layout: ").append(layout != null ? layout : "none").append('\n');
 
-        if ( snapshots != null )
-        {
-            sb.append( "snapshots: [enabled => " ).append( snapshots.isEnabled() );
-            sb.append( ", update => " ).append( snapshots.getUpdatePolicy() ).append( "]\n" );
+        if (snapshots != null) {
+            sb.append("snapshots: [enabled => ").append(snapshots.isEnabled());
+            sb.append(", update => ").append(snapshots.getUpdatePolicy()).append("]\n");
         }
 
-        if ( releases != null )
-        {
-            sb.append( " releases: [enabled => " ).append( releases.isEnabled() );
-            sb.append( ", update => " ).append( releases.getUpdatePolicy() ).append( "]\n" );
+        if (releases != null) {
+            sb.append(" releases: [enabled => ").append(releases.isEnabled());
+            sb.append(", update => ").append(releases.getUpdatePolicy()).append("]\n");
         }
 
         return sb.toString();
     }
 
-    public Artifact find( Artifact artifact )
-    {
-        File artifactFile = new File( getBasedir(), pathOf( artifact ) );
+    public Artifact find(Artifact artifact) {
+        File artifactFile = new File(getBasedir(), pathOf(artifact));
 
         // We need to set the file here or the resolver will fail with an NPE, not fully equipped to deal
         // with multiple local repository implementations yet.
-        artifact.setFile( artifactFile );
+        artifact.setFile(artifactFile);
 
-        if ( artifactFile.exists() )
-        {
-            artifact.setResolved( true );
+        if (artifactFile.exists()) {
+            artifact.setResolved(true);
         }
 
         return artifact;
     }
 
-    public List<String> findVersions( Artifact artifact )
-    {
+    public List<String> findVersions(Artifact artifact) {
         return Collections.emptyList();
     }
 
-    public boolean isProjectAware()
-    {
+    public boolean isProjectAware() {
         return false;
     }
 
-    public Authentication getAuthentication()
-    {
+    public Authentication getAuthentication() {
         return authentication;
     }
 
-    public void setAuthentication( Authentication authentication )
-    {
+    public void setAuthentication(Authentication authentication) {
         this.authentication = authentication;
     }
 
-    public Proxy getProxy()
-    {
+    public Proxy getProxy() {
         return proxy;
     }
 
-    public void setProxy( Proxy proxy )
-    {
+    public void setProxy(Proxy proxy) {
         this.proxy = proxy;
     }
 
-    public boolean isUniqueVersion()
-    {
+    public boolean isUniqueVersion() {
         return true;
     }
 
-    public List<ArtifactRepository> getMirroredRepositories()
-    {
+    public List<ArtifactRepository> getMirroredRepositories() {
         return mirroredRepositories;
     }
 
-    public void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories )
-    {
-        if ( mirroredRepositories != null )
-        {
-            this.mirroredRepositories = Collections.unmodifiableList( mirroredRepositories );
-        }
-        else
-        {
+    public void setMirroredRepositories(List<ArtifactRepository> mirroredRepositories) {
+        if (mirroredRepositories != null) {
+            this.mirroredRepositories = Collections.unmodifiableList(mirroredRepositories);
+        } else {
             this.mirroredRepositories = Collections.emptyList();
         }
     }
 
-    public boolean isBlocked()
-    {
+    public boolean isBlocked() {
         return blocked;
     }
 
-    public void setBlocked( boolean blocked )
-    {
+    public void setBlocked(boolean blocked) {
         this.blocked = blocked;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepositoryFactory.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepositoryFactory.java
index 0f69835..8ddb073 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepositoryFactory.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/DefaultArtifactRepositoryFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Arrays;
 import java.util.List;
@@ -26,101 +29,95 @@
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
 import org.apache.maven.plugin.LegacySupport;
 import org.apache.maven.repository.RepositorySystem;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.eclipse.aether.RepositorySystemSession;
 
 /**
- * @author jdcasey
  */
-@Component( role = ArtifactRepositoryFactory.class )
-public class DefaultArtifactRepositoryFactory
-    implements ArtifactRepositoryFactory
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultArtifactRepositoryFactory implements ArtifactRepositoryFactory {
 
-    @Requirement
+    @Inject
     private org.apache.maven.repository.legacy.repository.ArtifactRepositoryFactory factory;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
-    @Requirement
-    private RepositorySystem repositorySystem;
+    @Inject
+    private PlexusContainer container;
 
-    public ArtifactRepositoryLayout getLayout( String layoutId )
-        throws UnknownRepositoryLayoutException
-    {
-        return factory.getLayout( layoutId );
+    public ArtifactRepositoryLayout getLayout(String layoutId) throws UnknownRepositoryLayoutException {
+        return factory.getLayout(layoutId);
     }
 
-    public ArtifactRepository createDeploymentArtifactRepository( String id, String url, String layoutId,
-                                                                  boolean uniqueVersion )
-        throws UnknownRepositoryLayoutException
-    {
-        return injectSession( factory.createDeploymentArtifactRepository( id, url, layoutId, uniqueVersion ), false );
+    public ArtifactRepository createDeploymentArtifactRepository(
+            String id, String url, String layoutId, boolean uniqueVersion) throws UnknownRepositoryLayoutException {
+        return injectSession(factory.createDeploymentArtifactRepository(id, url, layoutId, uniqueVersion), false);
     }
 
-    public ArtifactRepository createDeploymentArtifactRepository( String id, String url,
-                                                                  ArtifactRepositoryLayout repositoryLayout,
-                                                                  boolean uniqueVersion )
-    {
-        return injectSession( factory.createDeploymentArtifactRepository( id, url, repositoryLayout, uniqueVersion ),
-                              false );
+    public ArtifactRepository createDeploymentArtifactRepository(
+            String id, String url, ArtifactRepositoryLayout repositoryLayout, boolean uniqueVersion) {
+        return injectSession(
+                factory.createDeploymentArtifactRepository(id, url, repositoryLayout, uniqueVersion), false);
     }
 
-    public ArtifactRepository createArtifactRepository( String id, String url, String layoutId,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-        throws UnknownRepositoryLayoutException
-    {
-        return injectSession( factory.createArtifactRepository( id, url, layoutId, snapshots, releases ), true );
+    public ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            String layoutId,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases)
+            throws UnknownRepositoryLayoutException {
+        return injectSession(factory.createArtifactRepository(id, url, layoutId, snapshots, releases), true);
     }
 
-    public ArtifactRepository createArtifactRepository( String id, String url,
-                                                        ArtifactRepositoryLayout repositoryLayout,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-    {
-        return injectSession( factory.createArtifactRepository( id, url, repositoryLayout, snapshots, releases ),
-                              true );
-
+    public ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases) {
+        return injectSession(factory.createArtifactRepository(id, url, repositoryLayout, snapshots, releases), true);
     }
 
-    public void setGlobalUpdatePolicy( String updatePolicy )
-    {
-        factory.setGlobalUpdatePolicy( updatePolicy );
+    public void setGlobalUpdatePolicy(String updatePolicy) {
+        factory.setGlobalUpdatePolicy(updatePolicy);
     }
 
-    public void setGlobalChecksumPolicy( String checksumPolicy )
-    {
-        factory.setGlobalChecksumPolicy( checksumPolicy );
+    public void setGlobalChecksumPolicy(String checksumPolicy) {
+        factory.setGlobalChecksumPolicy(checksumPolicy);
     }
 
-    private ArtifactRepository injectSession( ArtifactRepository repository, boolean mirrors )
-    {
+    private ArtifactRepository injectSession(ArtifactRepository repository, boolean mirrors) {
         RepositorySystemSession session = legacySupport.getRepositorySession();
 
-        if ( session != null && repository != null && !isLocalRepository( repository ) )
-        {
-            List<ArtifactRepository> repositories = Arrays.asList( repository );
+        if (session != null && repository != null && !isLocalRepository(repository)) {
+            List<ArtifactRepository> repositories = Arrays.asList(repository);
 
-            if ( mirrors )
-            {
-                repositorySystem.injectMirror( session, repositories );
+            RepositorySystem repositorySystem;
+            try {
+                repositorySystem = container.lookup(RepositorySystem.class);
+            } catch (ComponentLookupException e) {
+                throw new IllegalStateException("Unable to lookup " + RepositorySystem.class.getName());
             }
 
-            repositorySystem.injectProxy( session, repositories );
+            if (mirrors) {
+                repositorySystem.injectMirror(session, repositories);
+            }
 
-            repositorySystem.injectAuthentication( session, repositories );
+            repositorySystem.injectProxy(session, repositories);
+
+            repositorySystem.injectAuthentication(session, repositories);
         }
 
         return repository;
     }
 
-    private boolean isLocalRepository( ArtifactRepository repository )
-    {
+    private boolean isLocalRepository(ArtifactRepository repository) {
         // unfortunately, the API doesn't allow to tell a remote repo and the local repo apart...
-        return "local".equals( repository.getId() );
+        return "local".equals(repository.getId());
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java
new file mode 100644
index 0000000..6034d84
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java
@@ -0,0 +1,354 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadataStoreException;
+import org.apache.maven.repository.Proxy;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.metadata.Metadata;
+import org.eclipse.aether.repository.LocalArtifactRegistration;
+import org.eclipse.aether.repository.LocalArtifactRequest;
+import org.eclipse.aether.repository.LocalArtifactResult;
+import org.eclipse.aether.repository.LocalMetadataRegistration;
+import org.eclipse.aether.repository.LocalMetadataRequest;
+import org.eclipse.aether.repository.LocalMetadataResult;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.LocalRepositoryManager;
+import org.eclipse.aether.repository.RemoteRepository;
+
+/**
+ * <strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
+ * of the public API. In particular, this class can be changed or deleted without prior notice.
+ *
+ */
+@Deprecated
+public class LegacyLocalRepositoryManager implements LocalRepositoryManager {
+
+    private final ArtifactRepository delegate;
+
+    private final LocalRepository repo;
+
+    private final boolean realLocalRepo;
+
+    public static RepositorySystemSession overlay(
+            ArtifactRepository repository, RepositorySystemSession session, RepositorySystem system) {
+        return overlay(repository, session);
+    }
+
+    public static RepositorySystemSession overlay(ArtifactRepository repository, RepositorySystemSession session) {
+        if (repository == null || repository.getBasedir() == null) {
+            return session;
+        }
+
+        if (session != null) {
+            LocalRepositoryManager lrm = session.getLocalRepositoryManager();
+            if (lrm != null && lrm.getRepository().getBasedir().equals(new File(repository.getBasedir()))) {
+                return session;
+            }
+        } else {
+            session = new DefaultRepositorySystemSession();
+        }
+
+        final LocalRepositoryManager llrm = new LegacyLocalRepositoryManager(repository);
+
+        return new DefaultRepositorySystemSession(session).setLocalRepositoryManager(llrm);
+    }
+
+    private LegacyLocalRepositoryManager(ArtifactRepository delegate) {
+        this.delegate = Objects.requireNonNull(delegate, "delegate cannot be null");
+
+        ArtifactRepositoryLayout layout = delegate.getLayout();
+        repo = new LocalRepository(
+                new File(delegate.getBasedir()),
+                (layout != null) ? layout.getClass().getSimpleName() : "legacy");
+
+        /*
+         * NOTE: "invoker:install" vs "appassembler:assemble": Both mojos use the artifact installer to put an artifact
+         * into a repository. In the first case, the result needs to be a proper local repository that one can use for
+         * local artifact resolution. In the second case, the result needs to precisely obey the path information of the
+         * repository's layout to allow pointing at artifacts within the repository. Unfortunately,
+         * DefaultRepositoryLayout does not correctly describe the layout of a local repository which unlike a remote
+         * repository never uses timestamps in the filename of a snapshot artifact. The discrepancy gets notable when a
+         * remotely resolved snapshot artifact gets passed into pathOf(). So producing a proper local artifact path
+         * using DefaultRepositoryLayout requires us to enforce usage of the artifact's base version. This
+         * transformation however contradicts the other use case of precisely obeying the repository's layout. The below
+         * flag tries to detect which use case applies to make both plugins happy.
+         */
+        realLocalRepo = (layout instanceof DefaultRepositoryLayout) && "local".equals(delegate.getId());
+    }
+
+    public LocalRepository getRepository() {
+        return repo;
+    }
+
+    public String getPathForLocalArtifact(Artifact artifact) {
+        if (realLocalRepo) {
+            return delegate.pathOf(RepositoryUtils.toArtifact(artifact.setVersion(artifact.getBaseVersion())));
+        }
+        return delegate.pathOf(RepositoryUtils.toArtifact(artifact));
+    }
+
+    public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) {
+        return delegate.pathOf(RepositoryUtils.toArtifact(artifact));
+    }
+
+    public String getPathForLocalMetadata(Metadata metadata) {
+        return delegate.pathOfLocalRepositoryMetadata(new ArtifactMetadataAdapter(metadata), delegate);
+    }
+
+    public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) {
+        return delegate.pathOfLocalRepositoryMetadata(
+                new ArtifactMetadataAdapter(metadata), new ArtifactRepositoryAdapter(repository));
+    }
+
+    public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) {
+        String path = getPathForLocalArtifact(request.getArtifact());
+        File file = new File(getRepository().getBasedir(), path);
+
+        LocalArtifactResult result = new LocalArtifactResult(request);
+        if (file.isFile()) {
+            result.setFile(file);
+            result.setAvailable(true);
+        }
+
+        return result;
+    }
+
+    public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) {
+        Metadata metadata = request.getMetadata();
+
+        String path;
+        if (request.getRepository() == null) {
+            path = getPathForLocalMetadata(metadata);
+        } else {
+            path = getPathForRemoteMetadata(metadata, request.getRepository(), request.getContext());
+        }
+
+        File file = new File(getRepository().getBasedir(), path);
+
+        LocalMetadataResult result = new LocalMetadataResult(request);
+        if (file.isFile()) {
+            result.setFile(file);
+        }
+
+        return result;
+    }
+
+    public void add(RepositorySystemSession session, LocalArtifactRegistration request) {
+        // noop
+    }
+
+    public void add(RepositorySystemSession session, LocalMetadataRegistration request) {
+        // noop
+    }
+
+    static class ArtifactMetadataAdapter implements ArtifactMetadata {
+
+        private final Metadata metadata;
+
+        ArtifactMetadataAdapter(Metadata metadata) {
+            this.metadata = metadata;
+        }
+
+        public boolean storedInArtifactVersionDirectory() {
+            return metadata.getVersion().length() > 0;
+        }
+
+        public boolean storedInGroupDirectory() {
+            return metadata.getArtifactId().length() <= 0;
+        }
+
+        public String getGroupId() {
+            return nullify(metadata.getGroupId());
+        }
+
+        public String getArtifactId() {
+            return nullify(metadata.getArtifactId());
+        }
+
+        public String getBaseVersion() {
+            return nullify(metadata.getVersion());
+        }
+
+        private String nullify(String str) {
+            return (str == null || str.length() <= 0) ? null : str;
+        }
+
+        public Object getKey() {
+            return metadata.toString();
+        }
+
+        public String getRemoteFilename() {
+            return metadata.getType();
+        }
+
+        public String getLocalFilename(ArtifactRepository repository) {
+            return insertRepositoryKey(getRemoteFilename(), repository.getKey());
+        }
+
+        private String insertRepositoryKey(String filename, String repositoryKey) {
+            String result;
+            int idx = filename.indexOf('.');
+            if (idx < 0) {
+                result = filename + '-' + repositoryKey;
+            } else {
+                result = filename.substring(0, idx) + '-' + repositoryKey + filename.substring(idx);
+            }
+            return result;
+        }
+
+        public void merge(org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata) {
+            // not used
+        }
+
+        public void merge(ArtifactMetadata metadata) {
+            // not used
+        }
+
+        public void storeInLocalRepository(ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+                throws RepositoryMetadataStoreException {
+            // not used
+        }
+
+        public String extendedToString() {
+            return metadata.toString();
+        }
+    }
+
+    static class ArtifactRepositoryAdapter implements ArtifactRepository {
+
+        private final RemoteRepository repository;
+
+        ArtifactRepositoryAdapter(RemoteRepository repository) {
+            this.repository = repository;
+        }
+
+        public String pathOf(org.apache.maven.artifact.Artifact artifact) {
+            return null;
+        }
+
+        public String pathOfRemoteRepositoryMetadata(ArtifactMetadata artifactMetadata) {
+            return null;
+        }
+
+        public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+            return null;
+        }
+
+        public String getUrl() {
+            return repository.getUrl();
+        }
+
+        public void setUrl(String url) {}
+
+        public String getBasedir() {
+            return null;
+        }
+
+        public String getProtocol() {
+            return repository.getProtocol();
+        }
+
+        public String getId() {
+            return repository.getId();
+        }
+
+        public void setId(String id) {}
+
+        public ArtifactRepositoryPolicy getSnapshots() {
+            return null;
+        }
+
+        public void setSnapshotUpdatePolicy(ArtifactRepositoryPolicy policy) {}
+
+        public ArtifactRepositoryPolicy getReleases() {
+            return null;
+        }
+
+        public void setReleaseUpdatePolicy(ArtifactRepositoryPolicy policy) {}
+
+        public ArtifactRepositoryLayout getLayout() {
+            return null;
+        }
+
+        public void setLayout(ArtifactRepositoryLayout layout) {}
+
+        public String getKey() {
+            return getId();
+        }
+
+        public boolean isUniqueVersion() {
+            return true;
+        }
+
+        public boolean isBlacklisted() {
+            return false;
+        }
+
+        public void setBlacklisted(boolean blackListed) {}
+
+        public org.apache.maven.artifact.Artifact find(org.apache.maven.artifact.Artifact artifact) {
+            return null;
+        }
+
+        public List<String> findVersions(org.apache.maven.artifact.Artifact artifact) {
+            return Collections.emptyList();
+        }
+
+        public boolean isProjectAware() {
+            return false;
+        }
+
+        public void setAuthentication(Authentication authentication) {}
+
+        public Authentication getAuthentication() {
+            return null;
+        }
+
+        public void setProxy(Proxy proxy) {}
+
+        public Proxy getProxy() {
+            return null;
+        }
+
+        public List<ArtifactRepository> getMirroredRepositories() {
+            return Collections.emptyList();
+        }
+
+        public void setMirroredRepositories(List<ArtifactRepository> mirroredRepositories) {}
+
+        public boolean isBlocked() {
+            return false;
+        }
+
+        public void setBlocked(boolean blocked) {}
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/layout/FlatRepositoryLayout.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/layout/FlatRepositoryLayout.java
index 4426611..3dd264b 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/layout/FlatRepositoryLayout.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/layout/FlatRepositoryLayout.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.layout;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,74 +16,69 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.layout;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.handler.ArtifactHandler;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * FlatRepositoryLayout
  */
-@Component( role = ArtifactRepositoryLayout.class, hint = "flat" )
-public class FlatRepositoryLayout
-    implements ArtifactRepositoryLayout
-{
+@Named("flat")
+@Singleton
+@Deprecated
+public class FlatRepositoryLayout implements ArtifactRepositoryLayout {
 
     private static final char ARTIFACT_SEPARATOR = '-';
 
     private static final char GROUP_SEPARATOR = '.';
 
-    public String getId()
-    {
+    public String getId() {
         return "flat";
     }
 
-    public String pathOf( Artifact artifact )
-    {
+    public String pathOf(Artifact artifact) {
         ArtifactHandler artifactHandler = artifact.getArtifactHandler();
 
-        StringBuilder path = new StringBuilder( 128 );
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( artifact.getArtifactId() ).append( ARTIFACT_SEPARATOR ).append( artifact.getVersion() );
+        path.append(artifact.getArtifactId()).append(ARTIFACT_SEPARATOR).append(artifact.getVersion());
 
-        if ( artifact.hasClassifier() )
-        {
-            path.append( ARTIFACT_SEPARATOR ).append( artifact.getClassifier() );
+        if (artifact.hasClassifier()) {
+            path.append(ARTIFACT_SEPARATOR).append(artifact.getClassifier());
         }
 
-        if ( artifactHandler.getExtension() != null && artifactHandler.getExtension().length() > 0 )
-        {
-            path.append( GROUP_SEPARATOR ).append( artifactHandler.getExtension() );
+        if (artifactHandler.getExtension() != null
+                && artifactHandler.getExtension().length() > 0) {
+            path.append(GROUP_SEPARATOR).append(artifactHandler.getExtension());
         }
 
         return path.toString();
     }
 
-    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-    {
-        return pathOfRepositoryMetadata( metadata.getLocalFilename( repository ) );
+    public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+        return pathOfRepositoryMetadata(metadata.getLocalFilename(repository));
     }
 
-    private String pathOfRepositoryMetadata( String filename )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    private String pathOfRepositoryMetadata(String filename) {
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( filename );
+        path.append(filename);
 
         return path.toString();
     }
 
-    public String pathOfRemoteRepositoryMetadata( ArtifactMetadata metadata )
-    {
-        return pathOfRepositoryMetadata( metadata.getRemoteFilename() );
+    public String pathOfRemoteRepositoryMetadata(ArtifactMetadata metadata) {
+        return pathOfRepositoryMetadata(metadata.getRemoteFilename());
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getId();
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
new file mode 100644
index 0000000..9e30f10
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
@@ -0,0 +1,188 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxWriter;
+
+/**
+ * Shared methods of the repository metadata handling.
+ *
+ */
+@Deprecated
+public abstract class AbstractRepositoryMetadata implements RepositoryMetadata {
+    private static final String LS = System.lineSeparator();
+
+    private Metadata metadata;
+
+    protected AbstractRepositoryMetadata(Metadata metadata) {
+        this.metadata = metadata;
+    }
+
+    public String getRemoteFilename() {
+        return "maven-metadata.xml";
+    }
+
+    public String getLocalFilename(ArtifactRepository repository) {
+        return "maven-metadata-" + repository.getKey() + ".xml";
+    }
+
+    public void storeInLocalRepository(ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws RepositoryMetadataStoreException {
+        try {
+            updateRepositoryMetadata(localRepository, remoteRepository);
+        } catch (IOException | XMLStreamException e) {
+            throw new RepositoryMetadataStoreException("Error updating group repository metadata", e);
+        }
+    }
+
+    protected void updateRepositoryMetadata(ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws IOException, XMLStreamException {
+        Metadata metadata = null;
+
+        File metadataFile = new File(
+                localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata(this, remoteRepository));
+
+        if (metadataFile.length() == 0) {
+            if (!metadataFile.delete()) {
+                // sleep for 10ms just in case this is windows holding a file lock
+                try {
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+                metadataFile.delete(); // if this fails, forget about it, we'll try to overwrite it anyway so no need
+                // to delete on exit
+            }
+        } else if (metadataFile.exists()) {
+            try (InputStream input = Files.newInputStream(metadataFile.toPath())) {
+                metadata = new Metadata(new MetadataStaxReader().read(input, false));
+            }
+        }
+
+        boolean changed;
+
+        // If file could not be found or was not valid, start from scratch
+        if (metadata == null) {
+            metadata = this.metadata;
+
+            changed = true;
+        } else {
+            changed = metadata.merge(this.metadata);
+        }
+
+        // beware meta-versions!
+        String version = metadata.getVersion();
+        if (Artifact.LATEST_VERSION.equals(version) || Artifact.RELEASE_VERSION.equals(version)) {
+            // meta-versions are not valid <version/> values...don't write them.
+            metadata.setVersion(null);
+        }
+
+        if (changed || !metadataFile.exists()) {
+            metadataFile.getParentFile().mkdirs();
+            try (OutputStream output = Files.newOutputStream(metadataFile.toPath())) {
+                MetadataStaxWriter mappingWriter = new MetadataStaxWriter();
+                mappingWriter.write(output, metadata.getDelegate());
+            }
+        } else {
+            metadataFile.setLastModified(System.currentTimeMillis());
+        }
+    }
+
+    public String toString() {
+        return "repository metadata for: '" + getKey() + "'";
+    }
+
+    protected static Metadata createMetadata(Artifact artifact, Versioning versioning) {
+        Metadata metadata = new Metadata();
+        metadata.setGroupId(artifact.getGroupId());
+        metadata.setArtifactId(artifact.getArtifactId());
+        metadata.setVersion(artifact.getVersion());
+        metadata.setVersioning(versioning);
+        return metadata;
+    }
+
+    protected static Versioning createVersioning(Snapshot snapshot) {
+        Versioning versioning = new Versioning();
+        versioning.setSnapshot(snapshot);
+        return versioning;
+    }
+
+    public void setMetadata(Metadata metadata) {
+        this.metadata = metadata;
+    }
+
+    public Metadata getMetadata() {
+        return metadata;
+    }
+
+    public void merge(org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata) {
+        // TODO not sure that it should assume this, maybe the calls to addMetadata should pre-merge, then artifact
+        // replaces?
+        AbstractRepositoryMetadata repoMetadata = (AbstractRepositoryMetadata) metadata;
+        this.metadata.merge(repoMetadata.getMetadata());
+    }
+
+    public void merge(ArtifactMetadata metadata) {
+        // TODO not sure that it should assume this, maybe the calls to addMetadata should pre-merge, then artifact
+        // replaces?
+        AbstractRepositoryMetadata repoMetadata = (AbstractRepositoryMetadata) metadata;
+        this.metadata.merge(repoMetadata.getMetadata());
+    }
+
+    public String extendedToString() {
+        StringBuilder buffer = new StringBuilder(256);
+
+        buffer.append(LS).append("Repository Metadata").append(LS).append("--------------------------");
+        buffer.append(LS).append("GroupId: ").append(getGroupId());
+        buffer.append(LS).append("ArtifactId: ").append(getArtifactId());
+        buffer.append(LS).append("Metadata Type: ").append(getClass().getName());
+
+        return buffer.toString();
+    }
+
+    public int getNature() {
+        return RELEASE;
+    }
+
+    public ArtifactRepositoryPolicy getPolicy(ArtifactRepository repository) {
+        int nature = getNature();
+        if ((nature & RepositoryMetadata.RELEASE_OR_SNAPSHOT) == RepositoryMetadata.RELEASE_OR_SNAPSHOT) {
+            ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy(repository.getReleases());
+            policy.merge(repository.getSnapshots());
+            return policy;
+        } else if ((nature & RepositoryMetadata.SNAPSHOT) != 0) {
+            return repository.getSnapshots();
+        } else {
+            return repository.getReleases();
+        }
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/ArtifactRepositoryMetadata.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/ArtifactRepositoryMetadata.java
new file mode 100644
index 0000000..3038cc1
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/ArtifactRepositoryMetadata.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.Restriction;
+import org.apache.maven.artifact.versioning.VersionRange;
+
+/**
+ * Metadata for the artifact directory of the repository.
+ *
+ */
+@Deprecated
+public class ArtifactRepositoryMetadata extends AbstractRepositoryMetadata {
+    private Artifact artifact;
+
+    public ArtifactRepositoryMetadata(Artifact artifact) {
+        this(artifact, null);
+    }
+
+    public ArtifactRepositoryMetadata(Artifact artifact, Versioning versioning) {
+        super(createMetadata(artifact, versioning));
+        this.artifact = artifact;
+    }
+
+    public boolean storedInGroupDirectory() {
+        return false;
+    }
+
+    public boolean storedInArtifactVersionDirectory() {
+        return false;
+    }
+
+    public String getGroupId() {
+        return artifact.getGroupId();
+    }
+
+    public String getArtifactId() {
+        return artifact.getArtifactId();
+    }
+
+    public String getBaseVersion() {
+        // Don't want the artifact's version in here, as this is stored in the directory above that
+        return null;
+    }
+
+    public Object getKey() {
+        return "artifact " + artifact.getGroupId() + ":" + artifact.getArtifactId();
+    }
+
+    public boolean isSnapshot() {
+        // Don't consider the artifact's version in here, as this is stored in the directory above that
+        return false;
+    }
+
+    public int getNature() {
+        if (artifact.getVersion() != null) {
+            return artifact.isSnapshot() ? SNAPSHOT : RELEASE;
+        }
+
+        VersionRange range = artifact.getVersionRange();
+        if (range != null) {
+            for (Restriction restriction : range.getRestrictions()) {
+                if (isSnapshot(restriction.getLowerBound()) || isSnapshot(restriction.getUpperBound())) {
+                    return RELEASE_OR_SNAPSHOT;
+                }
+            }
+        }
+
+        return RELEASE;
+    }
+
+    private boolean isSnapshot(ArtifactVersion version) {
+        return version != null && ArtifactUtils.isSnapshot(version.getQualifier());
+    }
+
+    public ArtifactRepository getRepository() {
+        return null;
+    }
+
+    public void setRepository(ArtifactRepository remoteRepository) {
+        /*
+         * NOTE: Metadata at the g:a level contains a collection of available versions. After merging, we can't tell
+         * which repository provides which version so the metadata manager must not restrict the artifact resolution to
+         * the repository with the most recent updates.
+         */
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
index 8ade23f..a7136ae 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/DefaultRepositoryMetadataManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,184 +16,158 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
 import org.apache.maven.artifact.repository.RepositoryRequest;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxWriter;
 import org.apache.maven.repository.legacy.UpdateCheckManager;
 import org.apache.maven.repository.legacy.WagonManager;
 import org.apache.maven.wagon.ResourceDoesNotExistException;
 import org.apache.maven.wagon.TransferFailedException;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.WriterFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 
 /**
- * @author Jason van Zyl
  */
-@Component( role = RepositoryMetadataManager.class )
-public class DefaultRepositoryMetadataManager
-    extends AbstractLogEnabled
-    implements RepositoryMetadataManager
-{
-    @Requirement
+@Named
+@Singleton
+@Deprecated
+public class DefaultRepositoryMetadataManager extends AbstractLogEnabled implements RepositoryMetadataManager {
+    @Inject
     private WagonManager wagonManager;
 
-    @Requirement
+    @Inject
     private UpdateCheckManager updateCheckManager;
 
-    public void resolve( RepositoryMetadata metadata, List<ArtifactRepository> remoteRepositories,
-                         ArtifactRepository localRepository )
-        throws RepositoryMetadataResolutionException
-    {
+    public void resolve(
+            RepositoryMetadata metadata,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository)
+            throws RepositoryMetadataResolutionException {
         RepositoryRequest request = new DefaultRepositoryRequest();
-        request.setLocalRepository( localRepository );
-        request.setRemoteRepositories( remoteRepositories );
-        resolve( metadata, request );
+        request.setLocalRepository(localRepository);
+        request.setRemoteRepositories(remoteRepositories);
+        resolve(metadata, request);
     }
 
-    public void resolve( RepositoryMetadata metadata, RepositoryRequest request )
-        throws RepositoryMetadataResolutionException
-    {
+    public void resolve(RepositoryMetadata metadata, RepositoryRequest request)
+            throws RepositoryMetadataResolutionException {
         ArtifactRepository localRepo = request.getLocalRepository();
         List<ArtifactRepository> remoteRepositories = request.getRemoteRepositories();
 
-        if ( !request.isOffline() )
-        {
+        if (!request.isOffline()) {
             Date localCopyLastModified = null;
-            if ( metadata.getBaseVersion() != null )
-            {
-                localCopyLastModified = getLocalCopyLastModified( localRepo, metadata );
+            if (metadata.getBaseVersion() != null) {
+                localCopyLastModified = getLocalCopyLastModified(localRepo, metadata);
             }
 
-            for ( ArtifactRepository repository : remoteRepositories )
-            {
-                ArtifactRepositoryPolicy policy = metadata.getPolicy( repository );
+            for (ArtifactRepository repository : remoteRepositories) {
+                ArtifactRepositoryPolicy policy = metadata.getPolicy(repository);
 
                 File file =
-                    new File( localRepo.getBasedir(), localRepo.pathOfLocalRepositoryMetadata( metadata, repository ) );
+                        new File(localRepo.getBasedir(), localRepo.pathOfLocalRepositoryMetadata(metadata, repository));
                 boolean update;
 
-                if ( !policy.isEnabled() )
-                {
+                if (!policy.isEnabled()) {
                     update = false;
 
-                    if ( getLogger().isDebugEnabled() )
-                    {
-                        getLogger().debug( "Skipping update check for " + metadata.getKey() + " (" + file
-                                               + ") from disabled repository " + repository.getId() + " ("
-                                               + repository.getUrl() + ")" );
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger()
+                                .debug("Skipping update check for " + metadata.getKey() + " (" + file
+                                        + ") from disabled repository " + repository.getId() + " ("
+                                        + repository.getUrl() + ")");
                     }
-                }
-                else if ( request.isForceUpdate() )
-                {
+                } else if (request.isForceUpdate()) {
                     update = true;
-                }
-                else if ( localCopyLastModified != null && !policy.checkOutOfDate( localCopyLastModified ) )
-                {
+                } else if (localCopyLastModified != null && !policy.checkOutOfDate(localCopyLastModified)) {
                     update = false;
 
-                    if ( getLogger().isDebugEnabled() )
-                    {
-                        getLogger().debug(
-                            "Skipping update check for " + metadata.getKey() + " (" + file + ") from repository "
-                                + repository.getId() + " (" + repository.getUrl() + ") in favor of local copy" );
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger()
+                                .debug("Skipping update check for " + metadata.getKey() + " (" + file
+                                        + ") from repository " + repository.getId() + " (" + repository.getUrl()
+                                        + ") in favor of local copy");
                     }
-                }
-                else
-                {
-                    update = updateCheckManager.isUpdateRequired( metadata, repository, file );
+                } else {
+                    update = updateCheckManager.isUpdateRequired(metadata, repository, file);
                 }
 
-                if ( update )
-                {
-                    getLogger().info( metadata.getKey() + ": checking for updates from " + repository.getId() );
-                    try
-                    {
-                        wagonManager.getArtifactMetadata( metadata, repository, file, policy.getChecksumPolicy() );
-                    }
-                    catch ( ResourceDoesNotExistException e )
-                    {
-                        getLogger().debug( metadata + " could not be found on repository: " + repository.getId() );
+                if (update) {
+                    getLogger().info(metadata.getKey() + ": checking for updates from " + repository.getId());
+                    try {
+                        wagonManager.getArtifactMetadata(metadata, repository, file, policy.getChecksumPolicy());
+                    } catch (ResourceDoesNotExistException e) {
+                        getLogger().debug(metadata + " could not be found on repository: " + repository.getId());
 
                         // delete the local copy so the old details aren't used.
-                        if ( file.exists() )
-                        {
-                            if ( !file.delete() )
-                            {
+                        if (file.exists()) {
+                            if (!file.delete()) {
                                 // sleep for 10ms just in case this is windows holding a file lock
-                                try
-                                {
-                                    Thread.sleep( 10 );
-                                }
-                                catch ( InterruptedException ie )
-                                {
+                                try {
+                                    Thread.sleep(10);
+                                } catch (InterruptedException ie) {
                                     // ignore
                                 }
                                 file.delete(); // if this fails, forget about it
                             }
                         }
-                    }
-                    catch ( TransferFailedException e )
-                    {
-                        getLogger().warn( metadata + " could not be retrieved from repository: " + repository.getId()
-                                              + " due to an error: " + e.getMessage() );
-                        getLogger().debug( "Exception", e );
-                    }
-                    finally
-                    {
-                        updateCheckManager.touch( metadata, repository, file );
+                    } catch (TransferFailedException e) {
+                        getLogger()
+                                .warn(metadata + " could not be retrieved from repository: " + repository.getId()
+                                        + " due to an error: " + e.getMessage());
+                        getLogger().debug("Exception", e);
+                    } finally {
+                        updateCheckManager.touch(metadata, repository, file);
                     }
                 }
 
                 // TODO should this be inside the above check?
                 // touch file so that this is not checked again until interval has passed
-                if ( file.exists() )
-                {
-                    file.setLastModified( System.currentTimeMillis() );
+                if (file.exists()) {
+                    file.setLastModified(System.currentTimeMillis());
                 }
             }
         }
 
-        try
-        {
-            mergeMetadata( metadata, remoteRepositories, localRepo );
-        }
-        catch ( RepositoryMetadataStoreException e )
-        {
+        try {
+            mergeMetadata(metadata, remoteRepositories, localRepo);
+        } catch (RepositoryMetadataStoreException e) {
             throw new RepositoryMetadataResolutionException(
-                "Unable to store local copy of metadata: " + e.getMessage(), e );
+                    "Unable to store local copy of metadata: " + e.getMessage(), e);
         }
     }
 
-    private Date getLocalCopyLastModified( ArtifactRepository localRepository, RepositoryMetadata metadata )
-    {
-        String metadataPath = localRepository.pathOfLocalRepositoryMetadata( metadata, localRepository );
-        File metadataFile = new File( localRepository.getBasedir(), metadataPath );
-        return metadataFile.isFile() ? new Date( metadataFile.lastModified() ) : null;
+    private Date getLocalCopyLastModified(ArtifactRepository localRepository, RepositoryMetadata metadata) {
+        String metadataPath = localRepository.pathOfLocalRepositoryMetadata(metadata, localRepository);
+        File metadataFile = new File(localRepository.getBasedir(), metadataPath);
+        return metadataFile.isFile() ? new Date(metadataFile.lastModified()) : null;
     }
 
-    private void mergeMetadata( RepositoryMetadata metadata, List<ArtifactRepository> remoteRepositories,
-                                ArtifactRepository localRepository )
-        throws RepositoryMetadataStoreException
-    {
+    private void mergeMetadata(
+            RepositoryMetadata metadata,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository)
+            throws RepositoryMetadataStoreException {
         // TODO currently this is first wins, but really we should take the latest by comparing either the
         // snapshot timestamp, or some other timestamp later encoded into the metadata.
         // TODO this needs to be repeated here so the merging doesn't interfere with the written metadata
@@ -203,108 +175,90 @@
 
         Map<ArtifactRepository, Metadata> previousMetadata = new HashMap<>();
         ArtifactRepository selected = null;
-        for ( ArtifactRepository repository : remoteRepositories )
-        {
-            ArtifactRepositoryPolicy policy = metadata.getPolicy( repository );
+        for (ArtifactRepository repository : remoteRepositories) {
+            ArtifactRepositoryPolicy policy = metadata.getPolicy(repository);
 
-            if ( policy.isEnabled() && loadMetadata( metadata, repository, localRepository, previousMetadata ) )
-            {
-                metadata.setRepository( repository );
+            if (policy.isEnabled() && loadMetadata(metadata, repository, localRepository, previousMetadata)) {
+                metadata.setRepository(repository);
                 selected = repository;
             }
         }
-        if ( loadMetadata( metadata, localRepository, localRepository, previousMetadata ) )
-        {
-            metadata.setRepository( null );
+        if (loadMetadata(metadata, localRepository, localRepository, previousMetadata)) {
+            metadata.setRepository(null);
             selected = localRepository;
         }
 
-        updateSnapshotMetadata( metadata, previousMetadata, selected, localRepository );
+        updateSnapshotMetadata(metadata, previousMetadata, selected, localRepository);
     }
 
-    private void updateSnapshotMetadata( RepositoryMetadata metadata,
-                                         Map<ArtifactRepository, Metadata> previousMetadata,
-                                         ArtifactRepository selected, ArtifactRepository localRepository )
-        throws RepositoryMetadataStoreException
-    {
+    private void updateSnapshotMetadata(
+            RepositoryMetadata metadata,
+            Map<ArtifactRepository, Metadata> previousMetadata,
+            ArtifactRepository selected,
+            ArtifactRepository localRepository)
+            throws RepositoryMetadataStoreException {
         // TODO this could be a lot nicer... should really be in the snapshot transformation?
-        if ( metadata.isSnapshot() )
-        {
+        if (metadata.isSnapshot()) {
             Metadata prevMetadata = metadata.getMetadata();
 
-            for ( ArtifactRepository repository : previousMetadata.keySet() )
-            {
-                Metadata m = previousMetadata.get( repository );
-                if ( repository.equals( selected ) )
-                {
-                    if ( m.getVersioning() == null )
-                    {
-                        m.setVersioning( new Versioning() );
+            for (ArtifactRepository repository : previousMetadata.keySet()) {
+                Metadata m = previousMetadata.get(repository);
+                if (repository.equals(selected)) {
+                    if (m.getVersioning() == null) {
+                        m.setVersioning(new Versioning());
                     }
 
-                    if ( m.getVersioning().getSnapshot() == null )
-                    {
-                        m.getVersioning().setSnapshot( new Snapshot() );
+                    if (m.getVersioning().getSnapshot() == null) {
+                        m.getVersioning().setSnapshot(new Snapshot());
                     }
-                }
-                else
-                {
-                    if ( ( m.getVersioning() != null ) && ( m.getVersioning().getSnapshot() != null )
-                        && m.getVersioning().getSnapshot().isLocalCopy() )
-                    {
-                        m.getVersioning().getSnapshot().setLocalCopy( false );
-                        metadata.setMetadata( m );
-                        metadata.storeInLocalRepository( localRepository, repository );
+                } else {
+                    if ((m.getVersioning() != null)
+                            && (m.getVersioning().getSnapshot() != null)
+                            && m.getVersioning().getSnapshot().isLocalCopy()) {
+                        m.getVersioning().getSnapshot().setLocalCopy(false);
+                        metadata.setMetadata(m);
+                        metadata.storeInLocalRepository(localRepository, repository);
                     }
                 }
             }
 
-            metadata.setMetadata( prevMetadata );
+            metadata.setMetadata(prevMetadata);
         }
     }
 
-    private boolean loadMetadata( RepositoryMetadata repoMetadata, ArtifactRepository remoteRepository,
-                                  ArtifactRepository localRepository,
-                                  Map<ArtifactRepository, Metadata> previousMetadata )
-    {
+    private boolean loadMetadata(
+            RepositoryMetadata repoMetadata,
+            ArtifactRepository remoteRepository,
+            ArtifactRepository localRepository,
+            Map<ArtifactRepository, Metadata> previousMetadata) {
         boolean setRepository = false;
 
-        File metadataFile = new File( localRepository.getBasedir(),
-                                      localRepository.pathOfLocalRepositoryMetadata( repoMetadata, remoteRepository ) );
+        File metadataFile = new File(
+                localRepository.getBasedir(),
+                localRepository.pathOfLocalRepositoryMetadata(repoMetadata, remoteRepository));
 
-        if ( metadataFile.exists() )
-        {
+        if (metadataFile.exists()) {
             Metadata metadata;
 
-            try
-            {
-                metadata = readMetadata( metadataFile );
-            }
-            catch ( RepositoryMetadataReadException e )
-            {
-                if ( getLogger().isDebugEnabled() )
-                {
-                    getLogger().warn( e.getMessage(), e );
-                }
-                else
-                {
-                    getLogger().warn( e.getMessage() );
+            try {
+                metadata = readMetadata(metadataFile);
+            } catch (RepositoryMetadataReadException e) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().warn(e.getMessage(), e);
+                } else {
+                    getLogger().warn(e.getMessage());
                 }
                 return setRepository;
             }
 
-            if ( repoMetadata.isSnapshot() && ( previousMetadata != null ) )
-            {
-                previousMetadata.put( remoteRepository, metadata );
+            if (repoMetadata.isSnapshot() && (previousMetadata != null)) {
+                previousMetadata.put(remoteRepository, metadata);
             }
 
-            if ( repoMetadata.getMetadata() != null )
-            {
-                setRepository = repoMetadata.getMetadata().merge( metadata );
-            }
-            else
-            {
-                repoMetadata.setMetadata( metadata );
+            if (repoMetadata.getMetadata() != null) {
+                setRepository = repoMetadata.getMetadata().merge(metadata);
+            } else {
+                repoMetadata.setMetadata(metadata);
                 setRepository = true;
             }
         }
@@ -314,223 +268,164 @@
     /*
      * TODO share with DefaultPluginMappingManager.
      */
-    protected Metadata readMetadata( File mappingFile )
-        throws RepositoryMetadataReadException
-    {
-        Metadata result;
+    protected Metadata readMetadata(File mappingFile) throws RepositoryMetadataReadException {
 
-        try ( Reader reader = ReaderFactory.newXmlReader( mappingFile ) )
-        {
-            MetadataXpp3Reader mappingReader = new MetadataXpp3Reader();
-
-            result = mappingReader.read( reader, false );
-        }
-        catch ( FileNotFoundException e )
-        {
-            throw new RepositoryMetadataReadException( "Cannot read metadata from '" + mappingFile + "'", e );
-        }
-        catch ( IOException | XmlPullParserException e )
-        {
+        try (InputStream in = Files.newInputStream(mappingFile.toPath())) {
+            return new Metadata(new MetadataStaxReader().read(in, false));
+        } catch (FileNotFoundException e) {
+            throw new RepositoryMetadataReadException("Cannot read metadata from '" + mappingFile + "'", e);
+        } catch (IOException | XMLStreamException e) {
             throw new RepositoryMetadataReadException(
-                "Cannot read metadata from '" + mappingFile + "': " + e.getMessage(), e );
+                    "Cannot read metadata from '" + mappingFile + "': " + e.getMessage(), e);
         }
-        return result;
     }
 
     /**
      * Ensures the last updated timestamp of the specified metadata does not refer to the future and fixes the local
      * metadata if necessary to allow proper merging/updating of metadata during deployment.
      */
-    private void fixTimestamp( File metadataFile, Metadata metadata, Metadata reference )
-    {
+    private void fixTimestamp(File metadataFile, Metadata metadata, Metadata reference) {
         boolean changed = false;
 
-        if ( metadata != null && reference != null )
-        {
+        if (metadata != null && reference != null) {
             Versioning versioning = metadata.getVersioning();
             Versioning versioningRef = reference.getVersioning();
-            if ( versioning != null && versioningRef != null )
-            {
+            if (versioning != null && versioningRef != null) {
                 String lastUpdated = versioning.getLastUpdated();
                 String now = versioningRef.getLastUpdated();
-                if ( lastUpdated != null && now != null && now.compareTo( lastUpdated ) < 0 )
-                {
-                    getLogger().warn(
-                        "The last updated timestamp in " + metadataFile + " refers to the future (now = " + now
-                            + ", lastUpdated = " + lastUpdated + "). Please verify that the clocks of all"
-                            + " deploying machines are reasonably synchronized." );
-                    versioning.setLastUpdated( now );
+                if (lastUpdated != null && now != null && now.compareTo(lastUpdated) < 0) {
+                    getLogger()
+                            .warn("The last updated timestamp in " + metadataFile + " refers to the future (now = "
+                                    + now
+                                    + ", lastUpdated = " + lastUpdated + "). Please verify that the clocks of all"
+                                    + " deploying machines are reasonably synchronized.");
+                    versioning.setLastUpdated(now);
                     changed = true;
                 }
             }
         }
 
-        if ( changed )
-        {
-            getLogger().debug( "Repairing metadata in " + metadataFile );
+        if (changed) {
+            getLogger().debug("Repairing metadata in " + metadataFile);
 
-            try ( Writer writer = WriterFactory.newXmlWriter( metadataFile ) )
-            {
-                new MetadataXpp3Writer().write( writer, metadata );
-            }
-            catch ( IOException e )
-            {
+            try (OutputStream out = Files.newOutputStream(metadataFile.toPath())) {
+                new MetadataStaxWriter().write(out, metadata.getDelegate());
+            } catch (IOException | XMLStreamException e) {
                 String msg = "Could not write fixed metadata to " + metadataFile + ": " + e.getMessage();
-                if ( getLogger().isDebugEnabled() )
-                {
-                    getLogger().warn( msg, e );
-                }
-                else
-                {
-                    getLogger().warn( msg );
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().warn(msg, e);
+                } else {
+                    getLogger().warn(msg);
                 }
             }
         }
     }
 
-    public void resolveAlways( RepositoryMetadata metadata, ArtifactRepository localRepository,
-                               ArtifactRepository remoteRepository )
-        throws RepositoryMetadataResolutionException
-    {
+    public void resolveAlways(
+            RepositoryMetadata metadata, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws RepositoryMetadataResolutionException {
         File file;
-        try
-        {
-            file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, remoteRepository );
-        }
-        catch ( TransferFailedException e )
-        {
+        try {
+            file = getArtifactMetadataFromDeploymentRepository(metadata, localRepository, remoteRepository);
+        } catch (TransferFailedException e) {
             throw new RepositoryMetadataResolutionException(
-                metadata + " could not be retrieved from repository: " + remoteRepository.getId() + " due to an error: "
-                    + e.getMessage(), e );
+                    metadata + " could not be retrieved from repository: " + remoteRepository.getId()
+                            + " due to an error: " + e.getMessage(),
+                    e);
         }
 
-        try
-        {
-            if ( file.exists() )
-            {
-                Metadata prevMetadata = readMetadata( file );
-                metadata.setMetadata( prevMetadata );
+        try {
+            if (file.exists()) {
+                Metadata prevMetadata = readMetadata(file);
+                metadata.setMetadata(prevMetadata);
             }
-        }
-        catch ( RepositoryMetadataReadException e )
-        {
-            throw new RepositoryMetadataResolutionException( e.getMessage(), e );
+        } catch (RepositoryMetadataReadException e) {
+            throw new RepositoryMetadataResolutionException(e.getMessage(), e);
         }
     }
 
-    private File getArtifactMetadataFromDeploymentRepository( ArtifactMetadata metadata, ArtifactRepository localRepo,
-                                                              ArtifactRepository remoteRepository )
-        throws TransferFailedException
-    {
+    private File getArtifactMetadataFromDeploymentRepository(
+            ArtifactMetadata metadata, ArtifactRepository localRepo, ArtifactRepository remoteRepository)
+            throws TransferFailedException {
         File file =
-            new File( localRepo.getBasedir(), localRepo.pathOfLocalRepositoryMetadata( metadata, remoteRepository ) );
+                new File(localRepo.getBasedir(), localRepo.pathOfLocalRepositoryMetadata(metadata, remoteRepository));
 
-        try
-        {
-            wagonManager.getArtifactMetadataFromDeploymentRepository( metadata, remoteRepository, file,
-                                                                      ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
-        }
-        catch ( ResourceDoesNotExistException e )
-        {
-            getLogger().info(
-                metadata + " could not be found on repository: " + remoteRepository.getId() + ", so will be created" );
+        try {
+            wagonManager.getArtifactMetadataFromDeploymentRepository(
+                    metadata, remoteRepository, file, ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
+        } catch (ResourceDoesNotExistException e) {
+            getLogger()
+                    .info(metadata + " could not be found on repository: " + remoteRepository.getId()
+                            + ", so will be created");
 
             // delete the local copy so the old details aren't used.
-            if ( file.exists() )
-            {
-                if ( !file.delete() )
-                {
+            if (file.exists()) {
+                if (!file.delete()) {
                     // sleep for 10ms just in case this is windows holding a file lock
-                    try
-                    {
-                        Thread.sleep( 10 );
-                    }
-                    catch ( InterruptedException ie )
-                    {
+                    try {
+                        Thread.sleep(10);
+                    } catch (InterruptedException ie) {
                         // ignore
                     }
                     file.delete(); // if this fails, forget about it
                 }
             }
-        }
-        finally
-        {
-            if ( metadata instanceof RepositoryMetadata )
-            {
-                updateCheckManager.touch( (RepositoryMetadata) metadata, remoteRepository, file );
+        } finally {
+            if (metadata instanceof RepositoryMetadata) {
+                updateCheckManager.touch((RepositoryMetadata) metadata, remoteRepository, file);
             }
         }
         return file;
     }
 
-    public void deploy( ArtifactMetadata metadata, ArtifactRepository localRepository,
-                        ArtifactRepository deploymentRepository )
-        throws RepositoryMetadataDeploymentException
-    {
+    public void deploy(
+            ArtifactMetadata metadata, ArtifactRepository localRepository, ArtifactRepository deploymentRepository)
+            throws RepositoryMetadataDeploymentException {
         File file;
-        if ( metadata instanceof RepositoryMetadata )
-        {
-            getLogger().info( "Retrieving previous metadata from " + deploymentRepository.getId() );
-            try
-            {
-                file = getArtifactMetadataFromDeploymentRepository( metadata, localRepository, deploymentRepository );
-            }
-            catch ( TransferFailedException e )
-            {
+        if (metadata instanceof RepositoryMetadata) {
+            getLogger().info("Retrieving previous metadata from " + deploymentRepository.getId());
+            try {
+                file = getArtifactMetadataFromDeploymentRepository(metadata, localRepository, deploymentRepository);
+            } catch (TransferFailedException e) {
                 throw new RepositoryMetadataDeploymentException(
-                    metadata + " could not be retrieved from repository: " + deploymentRepository.getId()
-                        + " due to an error: " + e.getMessage(), e );
+                        metadata + " could not be retrieved from repository: " + deploymentRepository.getId()
+                                + " due to an error: " + e.getMessage(),
+                        e);
             }
 
-            if ( file.isFile() )
-            {
-                try
-                {
-                    fixTimestamp( file, readMetadata( file ), ( (RepositoryMetadata) metadata ).getMetadata() );
-                }
-                catch ( RepositoryMetadataReadException e )
-                {
+            if (file.isFile()) {
+                try {
+                    fixTimestamp(file, readMetadata(file), ((RepositoryMetadata) metadata).getMetadata());
+                } catch (RepositoryMetadataReadException e) {
                     // will be reported via storeInlocalRepository
                 }
             }
-        }
-        else
-        {
+        } else {
             // It's a POM - we don't need to retrieve it first
-            file = new File( localRepository.getBasedir(),
-                             localRepository.pathOfLocalRepositoryMetadata( metadata, deploymentRepository ) );
+            file = new File(
+                    localRepository.getBasedir(),
+                    localRepository.pathOfLocalRepositoryMetadata(metadata, deploymentRepository));
         }
 
-        try
-        {
-            metadata.storeInLocalRepository( localRepository, deploymentRepository );
-        }
-        catch ( RepositoryMetadataStoreException e )
-        {
-            throw new RepositoryMetadataDeploymentException( "Error installing metadata: " + e.getMessage(), e );
+        try {
+            metadata.storeInLocalRepository(localRepository, deploymentRepository);
+        } catch (RepositoryMetadataStoreException e) {
+            throw new RepositoryMetadataDeploymentException("Error installing metadata: " + e.getMessage(), e);
         }
 
-        try
-        {
-            wagonManager.putArtifactMetadata( file, metadata, deploymentRepository );
-        }
-        catch ( TransferFailedException e )
-        {
-            throw new RepositoryMetadataDeploymentException( "Error while deploying metadata: " + e.getMessage(), e );
+        try {
+            wagonManager.putArtifactMetadata(file, metadata, deploymentRepository);
+        } catch (TransferFailedException e) {
+            throw new RepositoryMetadataDeploymentException("Error while deploying metadata: " + e.getMessage(), e);
         }
     }
 
-    public void install( ArtifactMetadata metadata, ArtifactRepository localRepository )
-        throws RepositoryMetadataInstallationException
-    {
-        try
-        {
-            metadata.storeInLocalRepository( localRepository, localRepository );
-        }
-        catch ( RepositoryMetadataStoreException e )
-        {
-            throw new RepositoryMetadataInstallationException( "Error installing metadata: " + e.getMessage(), e );
+    public void install(ArtifactMetadata metadata, ArtifactRepository localRepository)
+            throws RepositoryMetadataInstallationException {
+        try {
+            metadata.storeInLocalRepository(localRepository, localRepository);
+        } catch (RepositoryMetadataStoreException e) {
+            throw new RepositoryMetadataInstallationException("Error installing metadata: " + e.getMessage(), e);
         }
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/GroupRepositoryMetadata.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/GroupRepositoryMetadata.java
index fd88ddc..a7c4515 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/GroupRepositoryMetadata.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/GroupRepositoryMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,102 +16,82 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.artifact.repository.ArtifactRepository;
+package org.apache.maven.artifact.repository.metadata;
 
 import java.util.Iterator;
 import java.util.List;
 
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
 /**
  * Metadata for the group directory of the repository.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class GroupRepositoryMetadata
-    extends AbstractRepositoryMetadata
-{
+@Deprecated
+public class GroupRepositoryMetadata extends AbstractRepositoryMetadata {
     private final String groupId;
 
-    public GroupRepositoryMetadata( String groupId )
-    {
-        super( new Metadata() );
+    public GroupRepositoryMetadata(String groupId) {
+        super(new Metadata());
         this.groupId = groupId;
     }
 
-    public boolean storedInGroupDirectory()
-    {
+    public boolean storedInGroupDirectory() {
         return true;
     }
 
-    public boolean storedInArtifactVersionDirectory()
-    {
+    public boolean storedInArtifactVersionDirectory() {
         return false;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return null;
     }
 
-    public String getBaseVersion()
-    {
+    public String getBaseVersion() {
         return null;
     }
 
-    public void addPluginMapping( String goalPrefix,
-                                  String artifactId )
-    {
-        addPluginMapping( goalPrefix, artifactId, artifactId );
+    public void addPluginMapping(String goalPrefix, String artifactId) {
+        addPluginMapping(goalPrefix, artifactId, artifactId);
     }
 
-    public void addPluginMapping( String goalPrefix,
-                                  String artifactId,
-                                  String name )
-    {
+    public void addPluginMapping(String goalPrefix, String artifactId, String name) {
         List<Plugin> plugins = getMetadata().getPlugins();
         boolean found = false;
-        for ( Iterator<Plugin> i = plugins.iterator(); i.hasNext() && !found; )
-        {
+        for (Iterator<Plugin> i = plugins.iterator(); i.hasNext() && !found; ) {
             Plugin plugin = i.next();
-            if ( plugin.getPrefix().equals( goalPrefix ) )
-            {
+            if (plugin.getPrefix().equals(goalPrefix)) {
                 found = true;
             }
         }
-        if ( !found )
-        {
+        if (!found) {
             Plugin plugin = new Plugin();
-            plugin.setPrefix( goalPrefix );
-            plugin.setArtifactId( artifactId );
-            plugin.setName( name );
+            plugin.setPrefix(goalPrefix);
+            plugin.setArtifactId(artifactId);
+            plugin.setName(name);
 
-
-            getMetadata().addPlugin( plugin );
+            getMetadata().addPlugin(plugin);
         }
     }
 
-    public Object getKey()
-    {
+    public Object getKey() {
         return groupId;
     }
 
-    public boolean isSnapshot()
-    {
+    public boolean isSnapshot() {
         return false;
     }
 
-    public ArtifactRepository getRepository()
-    {
+    public ArtifactRepository getRepository() {
         return null;
     }
 
-    public void setRepository( ArtifactRepository remoteRepository )
-    {
+    public void setRepository(ArtifactRepository remoteRepository) {
         // intentionally blank
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataBridge.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataBridge.java
index 0fd49dd..bc60117 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataBridge.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataBridge.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata;
 
 import java.io.File;
+import java.nio.file.Files;
 import java.util.Collections;
 import java.util.Map;
 
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.DefaultArtifactRepository;
-import org.codehaus.plexus.util.FileUtils;
 import org.eclipse.aether.RepositoryException;
 import org.eclipse.aether.metadata.AbstractMetadata;
 import org.eclipse.aether.metadata.MergeableMetadata;
@@ -36,87 +35,67 @@
  * <strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
  * of the public API. In particular, this class can be changed or deleted without prior notice.
  *
- * @author Benjamin Bentmann
  */
-public final class MetadataBridge
-    extends AbstractMetadata
-    implements MergeableMetadata
-{
+@Deprecated
+public final class MetadataBridge extends AbstractMetadata implements MergeableMetadata {
 
     private ArtifactMetadata metadata;
 
     private boolean merged;
 
-    public MetadataBridge( ArtifactMetadata metadata )
-    {
+    public MetadataBridge(ArtifactMetadata metadata) {
         this.metadata = metadata;
     }
 
-    public void merge( File current, File result )
-        throws RepositoryException
-    {
-        try
-        {
-            if ( current.exists() )
-            {
-                FileUtils.copyFile( current, result );
+    public void merge(File current, File result) throws RepositoryException {
+        try {
+            if (current.exists()) {
+                Files.createDirectories(result.toPath().getParent());
+                Files.copy(current.toPath(), result.toPath());
             }
-            ArtifactRepository localRepo = new MetadataRepository( result );
-            metadata.storeInLocalRepository( localRepo, localRepo );
+            ArtifactRepository localRepo = new MetadataRepository(result);
+            metadata.storeInLocalRepository(localRepo, localRepo);
             merged = true;
-        }
-        catch ( Exception e )
-        {
-            throw new RepositoryException( e.getMessage(), e );
+        } catch (Exception e) {
+            throw new RepositoryException(e.getMessage(), e);
         }
     }
 
-    public boolean isMerged()
-    {
+    public boolean isMerged() {
         return merged;
     }
 
-    public String getGroupId()
-    {
-        return emptify( metadata.getGroupId() );
+    public String getGroupId() {
+        return emptify(metadata.getGroupId());
     }
 
-    public String getArtifactId()
-    {
-        return metadata.storedInGroupDirectory() ? "" : emptify( metadata.getArtifactId() );
+    public String getArtifactId() {
+        return metadata.storedInGroupDirectory() ? "" : emptify(metadata.getArtifactId());
     }
 
-    public String getVersion()
-    {
-        return metadata.storedInArtifactVersionDirectory() ? emptify( metadata.getBaseVersion() ) : "";
+    public String getVersion() {
+        return metadata.storedInArtifactVersionDirectory() ? emptify(metadata.getBaseVersion()) : "";
     }
 
-    public String getType()
-    {
+    public String getType() {
         return metadata.getRemoteFilename();
     }
 
-    private String emptify( String string )
-    {
-        return ( string != null ) ? string : "";
+    private String emptify(String string) {
+        return (string != null) ? string : "";
     }
 
-    public File getFile()
-    {
+    public File getFile() {
         return null;
     }
 
-    public MetadataBridge setFile( File file )
-    {
+    public MetadataBridge setFile(File file) {
         return this;
     }
 
-    public Nature getNature()
-    {
-        if ( metadata instanceof RepositoryMetadata )
-        {
-            switch ( ( (RepositoryMetadata) metadata ).getNature() )
-            {
+    public Nature getNature() {
+        if (metadata instanceof RepositoryMetadata) {
+            switch (((RepositoryMetadata) metadata).getNature()) {
                 case RepositoryMetadata.RELEASE_OR_SNAPSHOT:
                     return Nature.RELEASE_OR_SNAPSHOT;
                 case RepositoryMetadata.SNAPSHOT:
@@ -124,49 +103,38 @@
                 default:
                     return Nature.RELEASE;
             }
-        }
-        else
-        {
+        } else {
             return Nature.RELEASE;
         }
     }
 
-    public Map<String, String> getProperties()
-    {
+    public Map<String, String> getProperties() {
         return Collections.emptyMap();
     }
 
     @Override
-    public Metadata setProperties( Map<String, String> properties )
-    {
+    public Metadata setProperties(Map<String, String> properties) {
         return this;
     }
 
-    @SuppressWarnings( "deprecation" )
-    static class MetadataRepository
-        extends DefaultArtifactRepository
-    {
+    @SuppressWarnings("deprecation")
+    static class MetadataRepository extends DefaultArtifactRepository {
 
         private File metadataFile;
 
-        MetadataRepository( File metadataFile )
-        {
-            super( "local", "", null );
+        MetadataRepository(File metadataFile) {
+            super("local", "", null);
             this.metadataFile = metadataFile;
         }
 
         @Override
-        public String getBasedir()
-        {
+        public String getBasedir() {
             return metadataFile.getParent();
         }
 
         @Override
-        public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-        {
+        public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
             return metadataFile.getName();
         }
-
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataUtils.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataUtils.java
index bdc4a79..1ef6090 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataUtils.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/MetadataUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,22 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata;
 
 /**
  * Assists in handling repository metadata.
  *
- * @author Benjamin Bentmann
  */
-class MetadataUtils
-{
+@Deprecated
+class MetadataUtils {
 
-    public static Metadata cloneMetadata( Metadata src )
-    {
-        if ( src == null )
-        {
+    public static Metadata cloneMetadata(Metadata src) {
+        if (src == null) {
             return null;
         }
         return src.clone();
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadata.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadata.java
new file mode 100644
index 0000000..078ce11
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadata.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+
+/**
+ * Describes repository directory metadata.
+ *
+ * TODO not happy about the store method - they use "this"
+ */
+@Deprecated
+public interface RepositoryMetadata extends org.apache.maven.artifact.metadata.ArtifactMetadata {
+
+    int RELEASE = 1;
+
+    int SNAPSHOT = 2;
+
+    int RELEASE_OR_SNAPSHOT = RELEASE | SNAPSHOT;
+
+    /**
+     * Get the repository the metadata was located in.
+     *
+     * @return the repository
+     */
+    ArtifactRepository getRepository();
+
+    /**
+     * Set the repository the metadata was located in.
+     *
+     * @param remoteRepository the repository
+     */
+    void setRepository(ArtifactRepository remoteRepository);
+
+    /**
+     * Get the repository metadata associated with this marker.
+     *
+     * @return the metadata, or <code>null</code> if none loaded
+     */
+    Metadata getMetadata();
+
+    /**
+     * Set the metadata contents.
+     *
+     * @param metadata the metadata
+     */
+    void setMetadata(Metadata metadata);
+
+    /**
+     * Whether this represents a snapshot.
+     *
+     * @return if it is a snapshot
+     */
+    boolean isSnapshot();
+
+    /**
+     * Gets the artifact quality this metadata refers to. One of {@link #RELEASE}, {@link #SNAPSHOT} or
+     * {@link #RELEASE_OR_SNAPSHOT}.
+     *
+     * @return The artifact quality this metadata refers to.
+     */
+    int getNature();
+
+    /**
+     * Gets the policy that applies to this metadata regarding the specified repository.
+     *
+     * @param repository The repository for which to determine the policy, must not be {@code null}.
+     * @return The policy, never {@code null}.
+     */
+    ArtifactRepositoryPolicy getPolicy(ArtifactRepository repository);
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException.java
new file mode 100644
index 0000000..8e374e9
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+/**
+ * Error while deploying repository metadata.
+ *
+ */
+@Deprecated
+public class RepositoryMetadataDeploymentException extends Throwable {
+    public RepositoryMetadataDeploymentException(String message) {
+        super(message);
+    }
+
+    public RepositoryMetadataDeploymentException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException.java
new file mode 100644
index 0000000..314b89b
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+/**
+ * Error while installing repository metadata.
+ *
+ */
+@Deprecated
+public class RepositoryMetadataInstallationException extends Throwable {
+    public RepositoryMetadataInstallationException(String message) {
+        super(message);
+    }
+
+    public RepositoryMetadataInstallationException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager.java
new file mode 100644
index 0000000..b92eddc
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+import java.util.List;
+
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.RepositoryRequest;
+
+/**
+ * RepositoryMetadataManager
+ */
+@Deprecated
+public interface RepositoryMetadataManager {
+
+    void resolve(RepositoryMetadata repositoryMetadata, RepositoryRequest repositoryRequest)
+            throws RepositoryMetadataResolutionException;
+
+    void resolve(
+            RepositoryMetadata repositoryMetadata,
+            List<ArtifactRepository> repositories,
+            ArtifactRepository localRepository)
+            throws RepositoryMetadataResolutionException;
+
+    void resolveAlways(
+            RepositoryMetadata metadata, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws RepositoryMetadataResolutionException;
+
+    /**
+     * Deploy metadata to the remote repository.
+     *
+     * @param metadata             the metadata to deploy
+     * @param localRepository      the local repository to install to first
+     * @param deploymentRepository the remote repository to deploy to
+     * @throws RepositoryMetadataDeploymentException in case of metadata deployment issue
+     */
+    void deploy(ArtifactMetadata metadata, ArtifactRepository localRepository, ArtifactRepository deploymentRepository)
+            throws RepositoryMetadataDeploymentException;
+
+    /**
+     * Install the metadata in the local repository.
+     *
+     * @param metadata        the metadata
+     * @param localRepository the local repository
+     * @throws RepositoryMetadataInstallationException in case of metadata installation issue
+     */
+    void install(ArtifactMetadata metadata, ArtifactRepository localRepository)
+            throws RepositoryMetadataInstallationException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataReadException.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataReadException.java
index 23e5984..8b588fb 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataReadException.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataReadException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata;
 
 /**
  * Problem storing the repository metadata in the local repository.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class RepositoryMetadataReadException
-    extends Exception
-{
-    public RepositoryMetadataReadException( String message )
-    {
-        super( message );
+@Deprecated
+public class RepositoryMetadataReadException extends Exception {
+    public RepositoryMetadataReadException(String message) {
+        super(message);
     }
 
-    public RepositoryMetadataReadException( String message,
-                                            Exception e )
-    {
-        super( message, e );
+    public RepositoryMetadataReadException(String message, Exception e) {
+        super(message, e);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException.java
new file mode 100644
index 0000000..50782b3
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+/**
+ * Error while retrieving repository metadata from the repository.
+ *
+ */
+@Deprecated
+public class RepositoryMetadataResolutionException extends Exception {
+    public RepositoryMetadataResolutionException(String message) {
+        super(message);
+    }
+
+    public RepositoryMetadataResolutionException(String message, Exception e) {
+        super(message, e);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/SnapshotArtifactRepositoryMetadata.java b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/SnapshotArtifactRepositoryMetadata.java
index 5120199..ca1c169 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/SnapshotArtifactRepositoryMetadata.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/repository/metadata/SnapshotArtifactRepositoryMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -25,74 +24,59 @@
 /**
  * Metadata for the artifact version directory of the repository.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  * TODO split instantiation (versioning, plugin mappings) from definition
  */
-public class SnapshotArtifactRepositoryMetadata
-    extends AbstractRepositoryMetadata
-{
+@Deprecated
+public class SnapshotArtifactRepositoryMetadata extends AbstractRepositoryMetadata {
     private Artifact artifact;
 
-    public SnapshotArtifactRepositoryMetadata( Artifact artifact )
-    {
-        super( createMetadata( artifact, null ) );
+    public SnapshotArtifactRepositoryMetadata(Artifact artifact) {
+        super(createMetadata(artifact, null));
         this.artifact = artifact;
     }
 
-    public SnapshotArtifactRepositoryMetadata( Artifact artifact,
-                                               Snapshot snapshot )
-    {
-        super( createMetadata( artifact, createVersioning( snapshot ) ) );
+    public SnapshotArtifactRepositoryMetadata(Artifact artifact, Snapshot snapshot) {
+        super(createMetadata(artifact, createVersioning(snapshot)));
         this.artifact = artifact;
     }
 
-    public boolean storedInGroupDirectory()
-    {
+    public boolean storedInGroupDirectory() {
         return false;
     }
 
-    public boolean storedInArtifactVersionDirectory()
-    {
+    public boolean storedInArtifactVersionDirectory() {
         return true;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return artifact.getGroupId();
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifact.getArtifactId();
     }
 
-    public String getBaseVersion()
-    {
+    public String getBaseVersion() {
         return artifact.getBaseVersion();
     }
 
-    public Object getKey()
-    {
+    public Object getKey() {
         return "snapshot " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getBaseVersion();
     }
 
-    public boolean isSnapshot()
-    {
+    public boolean isSnapshot() {
         return artifact.isSnapshot();
     }
 
-    public int getNature()
-    {
+    public int getNature() {
         return isSnapshot() ? SNAPSHOT : RELEASE;
     }
 
-    public ArtifactRepository getRepository()
-    {
+    public ArtifactRepository getRepository() {
         return artifact.getRepository();
     }
 
-    public void setRepository( ArtifactRepository remoteRepository )
-    {
-        artifact.setRepository( remoteRepository );
+    public void setRepository(ArtifactRepository remoteRepository) {
+        artifact.setRepository(remoteRepository);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactCollector.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactCollector.java
index 3526be4..7ce05c5 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactCollector.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.List;
 import java.util.Set;
@@ -32,15 +31,16 @@
  * along with their metadata. No artifacts are downloaded.
  */
 @Deprecated
-public interface ArtifactCollector
-    extends org.apache.maven.repository.legacy.resolver.LegacyArtifactCollector
-{
+public interface ArtifactCollector extends org.apache.maven.repository.legacy.resolver.LegacyArtifactCollector {
 
     @Deprecated
-    ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                      ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories,
-                                      ArtifactMetadataSource source, ArtifactFilter filter,
-                                      List<ResolutionListener> listeners )
-        throws ArtifactResolutionException;
-
+    ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners)
+            throws ArtifactResolutionException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionRequest.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionRequest.java
new file mode 100644
index 0000000..6bd018e
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionRequest.java
@@ -0,0 +1,296 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.resolver;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.RepositoryCache;
+import org.apache.maven.artifact.repository.RepositoryRequest;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+
+/**
+ * A resolution request allows you to either use an existing MavenProject, or a coordinate (gid:aid:version)
+ * to process a POMs dependencies.
+ *
+ */
+@Deprecated
+public class ArtifactResolutionRequest implements RepositoryRequest {
+    private static final String LS = System.lineSeparator();
+
+    private Artifact artifact;
+
+    // Needs to go away
+    // These are really overrides now, projects defining dependencies for a plugin that override what is
+    // specified in the plugin itself.
+    private Set<Artifact> artifactDependencies;
+
+    private ArtifactRepository localRepository;
+
+    private List<ArtifactRepository> remoteRepositories;
+
+    private ArtifactFilter collectionFilter;
+
+    private ArtifactFilter resolutionFilter;
+
+    // Needs to go away
+    private List<ResolutionListener> listeners = new ArrayList<>();
+
+    // This is like a filter but overrides all transitive versions
+    private Map<String, Artifact> managedVersionMap;
+
+    private boolean resolveRoot = true;
+
+    private boolean resolveTransitively = false;
+
+    private boolean offline;
+
+    private boolean forceUpdate;
+
+    private List<Server> servers;
+
+    private List<Mirror> mirrors;
+
+    private List<Proxy> proxies;
+
+    public ArtifactResolutionRequest() {
+        // nothing here
+    }
+
+    public ArtifactResolutionRequest(RepositoryRequest request) {
+        setLocalRepository(request.getLocalRepository());
+        setRemoteRepositories(request.getRemoteRepositories());
+        setOffline(request.isOffline());
+        setForceUpdate(request.isForceUpdate());
+    }
+
+    public Artifact getArtifact() {
+        return artifact;
+    }
+
+    public ArtifactResolutionRequest setArtifact(Artifact artifact) {
+        this.artifact = artifact;
+
+        return this;
+    }
+
+    public ArtifactResolutionRequest setArtifactDependencies(Set<Artifact> artifactDependencies) {
+        this.artifactDependencies = artifactDependencies;
+
+        return this;
+    }
+
+    public Set<Artifact> getArtifactDependencies() {
+        return artifactDependencies;
+    }
+
+    public ArtifactRepository getLocalRepository() {
+        return localRepository;
+    }
+
+    public ArtifactResolutionRequest setLocalRepository(ArtifactRepository localRepository) {
+        this.localRepository = localRepository;
+
+        return this;
+    }
+
+    public List<ArtifactRepository> getRemoteRepositories() {
+        return remoteRepositories;
+    }
+
+    public ArtifactResolutionRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories) {
+        this.remoteRepositories = remoteRepositories;
+
+        return this;
+    }
+
+    /**
+     * Gets the artifact filter that controls traversal of the dependency graph.
+     *
+     * @return The filter used to determine which of the artifacts in the dependency graph should be traversed or
+     *         {@code null} to collect all transitive dependencies.
+     */
+    public ArtifactFilter getCollectionFilter() {
+        return collectionFilter;
+    }
+
+    public ArtifactResolutionRequest setCollectionFilter(ArtifactFilter filter) {
+        this.collectionFilter = filter;
+
+        return this;
+    }
+
+    /**
+     * Gets the artifact filter that controls downloading of artifact files. This filter operates on those artifacts
+     * that have been included by the {@link #getCollectionFilter()}.
+     *
+     * @return The filter used to determine which of the artifacts should have their files resolved or {@code null} to
+     *         resolve the files for all collected artifacts.
+     */
+    public ArtifactFilter getResolutionFilter() {
+        return resolutionFilter;
+    }
+
+    public ArtifactResolutionRequest setResolutionFilter(ArtifactFilter filter) {
+        this.resolutionFilter = filter;
+
+        return this;
+    }
+
+    public List<ResolutionListener> getListeners() {
+        return listeners;
+    }
+
+    public ArtifactResolutionRequest setListeners(List<ResolutionListener> listeners) {
+        this.listeners = listeners;
+
+        return this;
+    }
+
+    public ArtifactResolutionRequest addListener(ResolutionListener listener) {
+        listeners.add(listener);
+
+        return this;
+    }
+
+    public Map<String, Artifact> getManagedVersionMap() {
+        return managedVersionMap;
+    }
+
+    public ArtifactResolutionRequest setManagedVersionMap(Map<String, Artifact> managedVersionMap) {
+        this.managedVersionMap = managedVersionMap;
+
+        return this;
+    }
+
+    public ArtifactResolutionRequest setResolveRoot(boolean resolveRoot) {
+        this.resolveRoot = resolveRoot;
+
+        return this;
+    }
+
+    public boolean isResolveRoot() {
+        return resolveRoot;
+    }
+
+    public ArtifactResolutionRequest setResolveTransitively(boolean resolveDependencies) {
+        this.resolveTransitively = resolveDependencies;
+
+        return this;
+    }
+
+    public boolean isResolveTransitively() {
+        return resolveTransitively;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder()
+                .append("REQUEST: ")
+                .append(LS)
+                .append("artifact: ")
+                .append(artifact)
+                .append(LS)
+                .append(artifactDependencies)
+                .append(LS)
+                .append("localRepository: ")
+                .append(localRepository)
+                .append(LS)
+                .append("remoteRepositories: ")
+                .append(remoteRepositories);
+
+        return sb.toString();
+    }
+
+    public boolean isOffline() {
+        return offline;
+    }
+
+    public ArtifactResolutionRequest setOffline(boolean offline) {
+        this.offline = offline;
+
+        return this;
+    }
+
+    public boolean isForceUpdate() {
+        return forceUpdate;
+    }
+
+    public ArtifactResolutionRequest setForceUpdate(boolean forceUpdate) {
+        this.forceUpdate = forceUpdate;
+
+        return this;
+    }
+
+    public ArtifactResolutionRequest setServers(List<Server> servers) {
+        this.servers = servers;
+
+        return this;
+    }
+
+    public List<Server> getServers() {
+        if (servers == null) {
+            servers = new ArrayList<>();
+        }
+
+        return servers;
+    }
+
+    public ArtifactResolutionRequest setMirrors(List<Mirror> mirrors) {
+        this.mirrors = mirrors;
+
+        return this;
+    }
+
+    public List<Mirror> getMirrors() {
+        if (mirrors == null) {
+            mirrors = new ArrayList<>();
+        }
+
+        return mirrors;
+    }
+
+    public ArtifactResolutionRequest setProxies(List<Proxy> proxies) {
+        this.proxies = proxies;
+
+        return this;
+    }
+
+    public List<Proxy> getProxies() {
+        if (proxies == null) {
+            proxies = new ArrayList<>();
+        }
+
+        return proxies;
+    }
+
+    //
+    // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
+    // this here, possibly indefinitely.
+    //
+    public ArtifactResolutionRequest setCache(RepositoryCache cache) {
+        return this;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java
new file mode 100644
index 0000000..c530287
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
+
+/**
+ * Specific problems during resolution that we want to account for:
+ * <ul>
+ *   <li>missing metadata</li>
+ *   <li>version range violations</li>
+ *   <li>version circular dependencies</li>
+ *   <li>missing artifacts</li>
+ *   <li>network/transfer errors</li>
+ *   <li>file system errors: permissions</li>
+ * </ul>
+ *
+ * TODO carlos: all these possible has*Exceptions and get*Exceptions methods make the clients too
+ *       complex requiring a long list of checks, need to create a parent/interface/encapsulation
+ *       for the types of exceptions
+ */
+@Deprecated
+public class ArtifactResolutionResult {
+    private static final String LS = System.lineSeparator();
+
+    private Artifact originatingArtifact;
+
+    private List<Artifact> missingArtifacts;
+
+    // Exceptions
+
+    private List<Exception> exceptions;
+
+    private List<Exception> versionRangeViolations;
+
+    private List<ArtifactResolutionException> metadataResolutionExceptions;
+
+    private List<CyclicDependencyException> circularDependencyExceptions;
+
+    private List<ArtifactResolutionException> errorArtifactExceptions;
+
+    // file system errors
+
+    private List<ArtifactRepository> repositories;
+
+    private Set<Artifact> artifacts;
+
+    private Set<ResolutionNode> resolutionNodes;
+
+    public Artifact getOriginatingArtifact() {
+        return originatingArtifact;
+    }
+
+    public ArtifactResolutionResult setOriginatingArtifact(final Artifact originatingArtifact) {
+        this.originatingArtifact = originatingArtifact;
+
+        return this;
+    }
+
+    public void addArtifact(Artifact artifact) {
+        if (artifacts == null) {
+            artifacts = new LinkedHashSet<>();
+        }
+
+        artifacts.add(artifact);
+    }
+
+    public Set<Artifact> getArtifacts() {
+        if (artifacts == null) {
+            artifacts = new LinkedHashSet<>();
+        }
+
+        return artifacts;
+    }
+
+    public void setArtifacts(Set<Artifact> artifacts) {
+        this.artifacts = artifacts;
+    }
+
+    public Set<ResolutionNode> getArtifactResolutionNodes() {
+        if (resolutionNodes == null) {
+            resolutionNodes = new LinkedHashSet<>();
+        }
+
+        return resolutionNodes;
+    }
+
+    public void setArtifactResolutionNodes(Set<ResolutionNode> resolutionNodes) {
+        this.resolutionNodes = resolutionNodes;
+    }
+
+    public boolean hasMissingArtifacts() {
+        return missingArtifacts != null && !missingArtifacts.isEmpty();
+    }
+
+    public List<Artifact> getMissingArtifacts() {
+        return missingArtifacts == null ? Collections.emptyList() : Collections.unmodifiableList(missingArtifacts);
+    }
+
+    public ArtifactResolutionResult addMissingArtifact(Artifact artifact) {
+        missingArtifacts = initList(missingArtifacts);
+
+        missingArtifacts.add(artifact);
+
+        return this;
+    }
+
+    public ArtifactResolutionResult setUnresolvedArtifacts(final List<Artifact> unresolvedArtifacts) {
+        this.missingArtifacts = unresolvedArtifacts;
+
+        return this;
+    }
+
+    public boolean isSuccess() {
+        return !(hasMissingArtifacts() || hasExceptions());
+    }
+
+    // ------------------------------------------------------------------------
+    // Exceptions
+    // ------------------------------------------------------------------------
+
+    public boolean hasExceptions() {
+        return exceptions != null && !exceptions.isEmpty();
+    }
+
+    public List<Exception> getExceptions() {
+        return exceptions == null ? Collections.emptyList() : Collections.unmodifiableList(exceptions);
+    }
+
+    // ------------------------------------------------------------------------
+    // Version Range Violations
+    // ------------------------------------------------------------------------
+
+    public boolean hasVersionRangeViolations() {
+        return versionRangeViolations != null;
+    }
+
+    /**
+     * TODO this needs to accept a {@link OverConstrainedVersionException} as returned by
+     *       {@link #getVersionRangeViolation(int)} but it's not used like that in
+     *       DefaultLegacyArtifactCollector
+     *
+     * @param e an exception
+     * @return {@code this}
+     */
+    public ArtifactResolutionResult addVersionRangeViolation(Exception e) {
+        versionRangeViolations = initList(versionRangeViolations);
+
+        versionRangeViolations.add(e);
+
+        exceptions = initList(exceptions);
+
+        exceptions.add(e);
+
+        return this;
+    }
+
+    public OverConstrainedVersionException getVersionRangeViolation(int i) {
+        return (OverConstrainedVersionException) versionRangeViolations.get(i);
+    }
+
+    public List<Exception> getVersionRangeViolations() {
+        return versionRangeViolations == null
+                ? Collections.emptyList()
+                : Collections.unmodifiableList(versionRangeViolations);
+    }
+
+    // ------------------------------------------------------------------------
+    // Metadata Resolution Exceptions: ArtifactResolutionExceptions
+    // ------------------------------------------------------------------------
+
+    public boolean hasMetadataResolutionExceptions() {
+        return metadataResolutionExceptions != null;
+    }
+
+    public ArtifactResolutionResult addMetadataResolutionException(ArtifactResolutionException e) {
+        metadataResolutionExceptions = initList(metadataResolutionExceptions);
+
+        metadataResolutionExceptions.add(e);
+
+        exceptions = initList(exceptions);
+
+        exceptions.add(e);
+
+        return this;
+    }
+
+    public ArtifactResolutionException getMetadataResolutionException(int i) {
+        return metadataResolutionExceptions.get(i);
+    }
+
+    public List<ArtifactResolutionException> getMetadataResolutionExceptions() {
+        return metadataResolutionExceptions == null
+                ? Collections.emptyList()
+                : Collections.unmodifiableList(metadataResolutionExceptions);
+    }
+
+    // ------------------------------------------------------------------------
+    // ErrorArtifactExceptions: ArtifactResolutionExceptions
+    // ------------------------------------------------------------------------
+
+    public boolean hasErrorArtifactExceptions() {
+        return errorArtifactExceptions != null;
+    }
+
+    public ArtifactResolutionResult addErrorArtifactException(ArtifactResolutionException e) {
+        errorArtifactExceptions = initList(errorArtifactExceptions);
+
+        errorArtifactExceptions.add(e);
+
+        exceptions = initList(exceptions);
+
+        exceptions.add(e);
+
+        return this;
+    }
+
+    public List<ArtifactResolutionException> getErrorArtifactExceptions() {
+        if (errorArtifactExceptions == null) {
+            return Collections.emptyList();
+        }
+
+        return Collections.unmodifiableList(errorArtifactExceptions);
+    }
+
+    // ------------------------------------------------------------------------
+    // Circular Dependency Exceptions
+    // ------------------------------------------------------------------------
+
+    public boolean hasCircularDependencyExceptions() {
+        return circularDependencyExceptions != null;
+    }
+
+    public ArtifactResolutionResult addCircularDependencyException(CyclicDependencyException e) {
+        circularDependencyExceptions = initList(circularDependencyExceptions);
+
+        circularDependencyExceptions.add(e);
+
+        exceptions = initList(exceptions);
+
+        exceptions.add(e);
+
+        return this;
+    }
+
+    public CyclicDependencyException getCircularDependencyException(int i) {
+        return circularDependencyExceptions.get(i);
+    }
+
+    public List<CyclicDependencyException> getCircularDependencyExceptions() {
+        if (circularDependencyExceptions == null) {
+            return Collections.emptyList();
+        }
+
+        return Collections.unmodifiableList(circularDependencyExceptions);
+    }
+
+    // ------------------------------------------------------------------------
+    // Repositories
+    // ------------------------------------------------------------------------
+
+    public List<ArtifactRepository> getRepositories() {
+        if (repositories == null) {
+            return Collections.emptyList();
+        }
+
+        return Collections.unmodifiableList(repositories);
+    }
+
+    public ArtifactResolutionResult setRepositories(final List<ArtifactRepository> repositories) {
+        this.repositories = repositories;
+
+        return this;
+    }
+
+    //
+    // Internal
+    //
+
+    private <T> List<T> initList(final List<T> l) {
+        if (l == null) {
+            return new ArrayList<>();
+        }
+        return l;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+
+        if (artifacts != null) {
+            int i = 1;
+            sb.append("---------").append(LS);
+            sb.append(artifacts.size()).append(LS);
+            for (Artifact a : artifacts) {
+                sb.append(i).append(' ').append(a).append(LS);
+                i++;
+            }
+            sb.append("---------");
+        }
+
+        return sb.toString();
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolver.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolver.java
index 45204f8..ccdd808 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.List;
 import java.util.Map;
@@ -30,13 +29,12 @@
 import org.apache.maven.wagon.events.TransferListener;
 
 /**
- * @author Jason van Zyl
  */
 // Just hide the one method we want behind the RepositorySystem interface.
-public interface ArtifactResolver
-{
+@Deprecated
+public interface ArtifactResolver {
 
-    ArtifactResolutionResult resolve( ArtifactResolutionRequest request );
+    ArtifactResolutionResult resolve(ArtifactResolutionRequest request);
 
     // The rest is deprecated
     // USED BY MAVEN ASSEMBLY PLUGIN 2.2-beta-2
@@ -46,71 +44,87 @@
     // USED BY SUREFIRE, DEPENDENCY PLUGIN
     @Deprecated
     ArtifactResolutionResult resolveTransitively(
-        Set<Artifact> artifacts, Artifact originatingArtifact,
-        ArtifactRepository localRepository,
-        List<ArtifactRepository> remoteRepositories,
-        ArtifactMetadataSource source, ArtifactFilter filter )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     // USED BY MAVEN ASSEMBLY PLUGIN
     @Deprecated
     ArtifactResolutionResult resolveTransitively(
-        Set<Artifact> artifacts, Artifact originatingArtifact,
-        Map<String, Artifact> managedVersions, ArtifactRepository localRepository,
-        List<ArtifactRepository> remoteRepositories,
-        ArtifactMetadataSource source )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     // USED BY MAVEN ASSEMBLY PLUGIN
     @Deprecated
     ArtifactResolutionResult resolveTransitively(
-        Set<Artifact> artifacts, Artifact originatingArtifact,
-        Map<String, Artifact> managedVersions, ArtifactRepository localRepository,
-        List<ArtifactRepository> remoteRepositories,
-        ArtifactMetadataSource source, ArtifactFilter filter )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     // USED BY INVOKER PLUGIN
     @Deprecated
     ArtifactResolutionResult resolveTransitively(
-        Set<Artifact> artifacts, Artifact originatingArtifact,
-        List<ArtifactRepository> remoteRepositories,
-        ArtifactRepository localRepository, ArtifactMetadataSource source )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            ArtifactMetadataSource source)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     @Deprecated
-    @SuppressWarnings( "checkstyle:parameternumber" )
+    @SuppressWarnings("checkstyle:parameternumber")
     ArtifactResolutionResult resolveTransitively(
-        Set<Artifact> artifacts, Artifact originatingArtifact,
-        Map<String, Artifact> managedVersions, ArtifactRepository localRepository,
-        List<ArtifactRepository> remoteRepositories,
-        ArtifactMetadataSource source, ArtifactFilter filter,
-        List<ResolutionListener> listeners )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     @Deprecated
     ArtifactResolutionResult resolveTransitively(
-        Set<Artifact> artifacts, Artifact originatingArtifact,
-        List<ArtifactRepository> remoteRepositories,
-        ArtifactRepository localRepository, ArtifactMetadataSource source,
-        List<ResolutionListener> listeners )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            ArtifactMetadataSource source,
+            List<ResolutionListener> listeners)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     // USED BY REMOTE RESOURCES PLUGIN, DEPENDENCY PLUGIN, SHADE PLUGIN
     @Deprecated
-    void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+    void resolve(Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     // USED BY REMOTE RESOURCES PLUGIN
     @Deprecated
-    void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository,
-                  TransferListener downloadMonitor )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+    void resolve(
+            Artifact artifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            TransferListener downloadMonitor)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     // USED BY DEPENDENCY PLUGIN, ARCHETYPE DOWNLOADER
     @Deprecated
-    void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                        ArtifactRepository localRepository )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
-
+    void resolveAlways(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DebugResolutionListener.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DebugResolutionListener.java
index 56c1805..70191b2 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DebugResolutionListener.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DebugResolutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.HashSet;
 import java.util.Objects;
@@ -30,87 +29,71 @@
 /**
  * Send resolution events to the debug log.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class DebugResolutionListener
-    implements ResolutionListener, ResolutionListenerForDepMgmt
-{
+@Deprecated
+public class DebugResolutionListener implements ResolutionListener, ResolutionListenerForDepMgmt {
     private Logger logger;
 
     private String indent = "";
 
     private static Set<Artifact> ignoredArtifacts = new HashSet<>();
 
-    public DebugResolutionListener( Logger logger )
-    {
+    public DebugResolutionListener(Logger logger) {
         this.logger = logger;
     }
 
-    public void testArtifact( Artifact node )
-    {
-    }
+    public void testArtifact(Artifact node) {}
 
-    public void startProcessChildren( Artifact artifact )
-    {
+    public void startProcessChildren(Artifact artifact) {
         indent += "  ";
     }
 
-    public void endProcessChildren( Artifact artifact )
-    {
-        indent = indent.substring( 2 );
+    public void endProcessChildren(Artifact artifact) {
+        indent = indent.substring(2);
     }
 
-    public void includeArtifact( Artifact artifact )
-    {
-        logger.debug( indent + artifact + " (selected for " + artifact.getScope() + ")" );
+    public void includeArtifact(Artifact artifact) {
+        logger.debug(indent + artifact + " (selected for " + artifact.getScope() + ")");
     }
 
-    public void omitForNearer( Artifact omitted, Artifact kept )
-    {
+    public void omitForNearer(Artifact omitted, Artifact kept) {
         String omittedVersion = omitted.getVersion();
         String keptVersion = kept.getVersion();
 
-        if ( !Objects.equals( omittedVersion, keptVersion ) )
-        {
-            logger.debug( indent + omitted + " (removed - nearer found: " + keptVersion + ")" );
+        if (!Objects.equals(omittedVersion, keptVersion)) {
+            logger.debug(indent + omitted + " (removed - nearer found: " + keptVersion + ")");
         }
     }
 
-    public void omitForCycle( Artifact omitted )
-    {
-        logger.debug( indent + omitted + " (removed - causes a cycle in the graph)" );
+    public void omitForCycle(Artifact omitted) {
+        logger.debug(indent + omitted + " (removed - causes a cycle in the graph)");
     }
 
-    public void updateScopeCurrentPom( Artifact artifact, String ignoredScope )
-    {
-        logger.debug( indent + artifact + " (not setting artifactScope to: " + ignoredScope + "; local artifactScope "
-            + artifact.getScope() + " wins)" );
+    public void updateScopeCurrentPom(Artifact artifact, String ignoredScope) {
+        logger.debug(indent + artifact + " (not setting artifactScope to: " + ignoredScope + "; local artifactScope "
+                + artifact.getScope() + " wins)");
 
         // TODO better way than static? this might hide messages in a reactor
-        if ( !ignoredArtifacts.contains( artifact ) )
-        {
-            logger.warn( "\n\tArtifact " + artifact + " retains local artifactScope '" + artifact.getScope()
-                + "' overriding broader artifactScope '" + ignoredScope + "'\n"
-                + "\tgiven by a dependency. If this is not intended, modify or remove the local artifactScope.\n" );
-            ignoredArtifacts.add( artifact );
+        if (!ignoredArtifacts.contains(artifact)) {
+            logger.warn("\n\tArtifact " + artifact + " retains local artifactScope '" + artifact.getScope()
+                    + "' overriding broader artifactScope '" + ignoredScope + "'\n"
+                    + "\tgiven by a dependency. If this is not intended, modify or remove the local artifactScope.\n");
+            ignoredArtifacts.add(artifact);
         }
     }
 
-    public void updateScope( Artifact artifact, String scope )
-    {
-        logger.debug( indent + artifact + " (setting artifactScope to: " + scope + ")" );
+    public void updateScope(Artifact artifact, String scope) {
+        logger.debug(indent + artifact + " (setting artifactScope to: " + scope + ")");
     }
 
-    public void selectVersionFromRange( Artifact artifact )
-    {
-        logger.debug( indent + artifact + " (setting version to: " + artifact.getVersion() + " from range: "
-            + artifact.getVersionRange() + ")" );
+    public void selectVersionFromRange(Artifact artifact) {
+        logger.debug(indent + artifact + " (setting version to: " + artifact.getVersion() + " from range: "
+                + artifact.getVersionRange() + ")");
     }
 
-    public void restrictRange( Artifact artifact, Artifact replacement, VersionRange newRange )
-    {
-        logger.debug( indent + artifact + " (range restricted from: " + artifact.getVersionRange() + " and: "
-            + replacement.getVersionRange() + " to: " + newRange + " )" );
+    public void restrictRange(Artifact artifact, Artifact replacement, VersionRange newRange) {
+        logger.debug(indent + artifact + " (range restricted from: " + artifact.getVersionRange() + " and: "
+                + replacement.getVersionRange() + " to: " + newRange + " )");
     }
 
     /**
@@ -119,50 +102,40 @@
      * (and more information) is needed to be able to determine when and if the version and/or artifactScope changes.
      * See the two added methods, manageArtifactVersion and manageArtifactScope.
      */
-    public void manageArtifact( Artifact artifact, Artifact replacement )
-    {
+    public void manageArtifact(Artifact artifact, Artifact replacement) {
         String msg = indent + artifact;
         msg += " (";
-        if ( replacement.getVersion() != null )
-        {
+        if (replacement.getVersion() != null) {
             msg += "applying version: " + replacement.getVersion() + ";";
         }
-        if ( replacement.getScope() != null )
-        {
+        if (replacement.getScope() != null) {
             msg += "applying artifactScope: " + replacement.getScope();
         }
         msg += ")";
-        logger.debug( msg );
+        logger.debug(msg);
     }
 
-    public void manageArtifactVersion( Artifact artifact, Artifact replacement )
-    {
+    public void manageArtifactVersion(Artifact artifact, Artifact replacement) {
         // only show msg if a change is actually taking place
-        if ( !replacement.getVersion().equals( artifact.getVersion() ) )
-        {
+        if (!replacement.getVersion().equals(artifact.getVersion())) {
             String msg = indent + artifact + " (applying version: " + replacement.getVersion() + ")";
-            logger.debug( msg );
+            logger.debug(msg);
         }
     }
 
-    public void manageArtifactScope( Artifact artifact, Artifact replacement )
-    {
+    public void manageArtifactScope(Artifact artifact, Artifact replacement) {
         // only show msg if a change is actually taking place
-        if ( !replacement.getScope().equals( artifact.getScope() ) )
-        {
+        if (!replacement.getScope().equals(artifact.getScope())) {
             String msg = indent + artifact + " (applying artifactScope: " + replacement.getScope() + ")";
-            logger.debug( msg );
+            logger.debug(msg);
         }
     }
 
-    public void manageArtifactSystemPath( Artifact artifact, Artifact replacement )
-    {
+    public void manageArtifactSystemPath(Artifact artifact, Artifact replacement) {
         // only show msg if a change is actually taking place
-        if ( !replacement.getScope().equals( artifact.getScope() ) )
-        {
+        if (!replacement.getScope().equals(artifact.getScope())) {
             String msg = indent + artifact + " (applying system path: " + replacement.getFile() + ")";
-            logger.debug( msg );
+            logger.debug(msg);
         }
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java
index 25e92c4..0c0a235 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
-import org.codehaus.plexus.component.annotations.Component;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 /**
  * Artifact collector - takes a set of original artifacts and resolves all of the best versions to use
  * along with their metadata. No artifacts are downloaded.
  */
 @Deprecated
-@Component( role = ArtifactCollector.class )
-public class DefaultArtifactCollector
-    extends org.apache.maven.repository.legacy.resolver.DefaultLegacyArtifactCollector
-    implements ArtifactCollector
-{
-}
+@Named
+@Singleton
+public class DefaultArtifactCollector extends org.apache.maven.repository.legacy.resolver.DefaultLegacyArtifactCollector
+        implements ArtifactCollector {}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java
index 6dffccd..c2b90b2 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultArtifactResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -56,8 +59,6 @@
 import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver;
 import org.apache.maven.wagon.events.TransferListener;
 import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
@@ -68,294 +69,294 @@
 import org.eclipse.aether.resolution.ArtifactResult;
 
 /**
- * @author Jason van Zyl
  */
-@Component( role = ArtifactResolver.class )
-public class DefaultArtifactResolver
-    implements ArtifactResolver, Disposable
-{
-    @Requirement
+@Named
+@Singleton
+@Deprecated
+public class DefaultArtifactResolver implements ArtifactResolver, Disposable {
+    @Inject
     private Logger logger;
 
-    @Requirement
+    @Inject
     protected ArtifactFactory artifactFactory;
 
-    @Requirement
+    @Inject
     private ArtifactCollector artifactCollector;
 
-    @Requirement
+    @Inject
     private ResolutionErrorHandler resolutionErrorHandler;
 
-    @Requirement
+    @Inject
     private ArtifactMetadataSource source;
 
-    @Requirement
+    @Inject
     private PlexusContainer container;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
-    @Requirement
-    private RepositorySystem repoSystem;
-
     private final Executor executor;
 
-    public DefaultArtifactResolver()
-    {
-        int threads = Integer.getInteger( "maven.artifact.threads", 5 );
-        if ( threads <= 1 )
-        {
+    public DefaultArtifactResolver() {
+        int threads = Integer.getInteger("maven.artifact.threads", 5);
+        if (threads <= 1) {
             executor = Runnable::run;
-        }
-        else
-        {
-            executor = new ThreadPoolExecutor( threads, threads, 3, TimeUnit.SECONDS,
-                    new LinkedBlockingQueue<>(), new DaemonThreadCreator() );
+        } else {
+            executor = new ThreadPoolExecutor(
+                    threads, threads, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new DaemonThreadCreator());
         }
     }
 
-    private RepositorySystemSession getSession( ArtifactRepository localRepository )
-    {
-        return LegacyLocalRepositoryManager.overlay( localRepository, legacySupport.getRepositorySession(),
-                                                     repoSystem );
+    private RepositorySystemSession getSession(ArtifactRepository localRepository) {
+        return LegacyLocalRepositoryManager.overlay(localRepository, legacySupport.getRepositorySession(), null);
     }
 
-    private void injectSession1( RepositoryRequest request, MavenSession session )
-    {
-        if ( session != null )
-        {
-            request.setOffline( session.isOffline() );
-            request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
+    private void injectSession1(RepositoryRequest request, MavenSession session) {
+        if (session != null) {
+            request.setOffline(session.isOffline());
+            request.setForceUpdate(session.getRequest().isUpdateSnapshots());
         }
     }
 
-    private void injectSession2( ArtifactResolutionRequest request, MavenSession session )
-    {
-        injectSession1( request, session );
+    private void injectSession2(ArtifactResolutionRequest request, MavenSession session) {
+        injectSession1(request, session);
 
-        if ( session != null )
-        {
-            request.setServers( session.getRequest().getServers() );
-            request.setMirrors( session.getRequest().getMirrors() );
-            request.setProxies( session.getRequest().getProxies() );
+        if (session != null) {
+            request.setServers(session.getRequest().getServers());
+            request.setMirrors(session.getRequest().getMirrors());
+            request.setProxies(session.getRequest().getProxies());
         }
     }
 
-    public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                         ArtifactRepository localRepository, TransferListener resolutionListener )
-                             throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        resolve( artifact, remoteRepositories, getSession( localRepository ) );
+    public void resolve(
+            Artifact artifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            TransferListener resolutionListener)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        resolve(artifact, remoteRepositories, getSession(localRepository));
     }
 
-    public void resolveAlways( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                               ArtifactRepository localRepository )
-                                   throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        resolve( artifact, remoteRepositories, getSession( localRepository ) );
+    public void resolveAlways(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        resolve(artifact, remoteRepositories, getSession(localRepository));
     }
 
-    private void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                          RepositorySystemSession session )
-                              throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        if ( artifact == null )
-        {
+    private void resolve(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, RepositorySystemSession session)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        if (artifact == null) {
             return;
         }
 
-        if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
-        {
+        if (Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
             File systemFile = artifact.getFile();
 
-            if ( systemFile == null )
-            {
-                throw new ArtifactNotFoundException( "System artifact: " + artifact + " has no file attached",
-                                                     artifact );
+            if (systemFile == null) {
+                throw new ArtifactNotFoundException("System artifact: " + artifact + " has no file attached", artifact);
             }
 
-            if ( !systemFile.exists() )
-            {
-                throw new ArtifactNotFoundException( "System artifact: " + artifact + " not found in path: "
-                    + systemFile, artifact );
+            if (!systemFile.exists()) {
+                throw new ArtifactNotFoundException(
+                        "System artifact: " + artifact + " not found in path: " + systemFile, artifact);
             }
 
-            if ( !systemFile.isFile() )
-            {
-                throw new ArtifactNotFoundException( "System artifact: " + artifact + " is not a file: " + systemFile,
-                                                     artifact );
+            if (!systemFile.isFile()) {
+                throw new ArtifactNotFoundException(
+                        "System artifact: " + artifact + " is not a file: " + systemFile, artifact);
             }
 
-            artifact.setResolved( true );
+            artifact.setResolved(true);
 
             return;
         }
 
-        if ( !artifact.isResolved() )
-        {
+        if (!artifact.isResolved()) {
             ArtifactResult result;
 
-            try
-            {
+            try {
                 ArtifactRequest artifactRequest = new ArtifactRequest();
-                artifactRequest.setArtifact( RepositoryUtils.toArtifact( artifact ) );
-                artifactRequest.setRepositories( RepositoryUtils.toRepos( remoteRepositories ) );
+                artifactRequest.setArtifact(RepositoryUtils.toArtifact(artifact));
+                artifactRequest.setRepositories(RepositoryUtils.toRepos(remoteRepositories));
 
                 // Maven 2.x quirk: an artifact always points at the local repo, regardless whether resolved or not
                 LocalRepositoryManager lrm = session.getLocalRepositoryManager();
-                String path = lrm.getPathForLocalArtifact( artifactRequest.getArtifact() );
-                artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) );
+                String path = lrm.getPathForLocalArtifact(artifactRequest.getArtifact());
+                artifact.setFile(new File(lrm.getRepository().getBasedir(), path));
 
-                result = repoSystem.resolveArtifact( session, artifactRequest );
-            }
-            catch ( org.eclipse.aether.resolution.ArtifactResolutionException e )
-            {
-                if ( e.getCause() instanceof org.eclipse.aether.transfer.ArtifactNotFoundException )
-                {
-                    throw new ArtifactNotFoundException( e.getMessage(), artifact, remoteRepositories, e );
-                }
-                else
-                {
-                    throw new ArtifactResolutionException( e.getMessage(), artifact, remoteRepositories, e );
+                RepositorySystem repoSystem = container.lookup(RepositorySystem.class);
+                result = repoSystem.resolveArtifact(session, artifactRequest);
+            } catch (ComponentLookupException e) {
+                throw new IllegalStateException("Unable to lookup " + RepositorySystem.class.getName());
+            } catch (org.eclipse.aether.resolution.ArtifactResolutionException e) {
+                if (e.getCause() instanceof org.eclipse.aether.transfer.ArtifactNotFoundException) {
+                    throw new ArtifactNotFoundException(e.getMessage(), artifact, remoteRepositories, e);
+                } else {
+                    throw new ArtifactResolutionException(e.getMessage(), artifact, remoteRepositories, e);
                 }
             }
 
-            artifact.selectVersion( result.getArtifact().getVersion() );
-            artifact.setFile( result.getArtifact().getFile() );
-            artifact.setResolved( true );
+            artifact.selectVersion(result.getArtifact().getVersion());
+            artifact.setFile(result.getArtifact().getFile());
+            artifact.setResolved(true);
 
-            if ( artifact.isSnapshot() )
-            {
-                Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher( artifact.getVersion() );
-                if ( matcher.matches() )
-                {
+            if (artifact.isSnapshot()) {
+                Matcher matcher = Artifact.VERSION_FILE_PATTERN.matcher(artifact.getVersion());
+                if (matcher.matches()) {
                     Snapshot snapshot = new Snapshot();
-                    snapshot.setTimestamp( matcher.group( 2 ) );
-                    try
-                    {
-                        snapshot.setBuildNumber( Integer.parseInt( matcher.group( 3 ) ) );
-                        artifact.addMetadata( new SnapshotArtifactRepositoryMetadata( artifact, snapshot ) );
-                    }
-                    catch ( NumberFormatException e )
-                    {
-                        logger.warn( "Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage() );
+                    snapshot.setTimestamp(matcher.group(2));
+                    try {
+                        snapshot.setBuildNumber(Integer.parseInt(matcher.group(3)));
+                        artifact.addMetadata(new SnapshotArtifactRepositoryMetadata(artifact, snapshot));
+                    } catch (NumberFormatException e) {
+                        logger.warn("Invalid artifact version " + artifact.getVersion() + ": " + e.getMessage());
                     }
                 }
             }
         }
     }
 
-    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                                         ArtifactRepository localRepository,
-                                                         List<ArtifactRepository> remoteRepositories,
-                                                         ArtifactMetadataSource source, ArtifactFilter filter )
-                                                             throws ArtifactResolutionException,
-                                                             ArtifactNotFoundException
-    {
+    public ArtifactResolutionResult resolveTransitively(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
         return resolveTransitively(
-                artifacts, originatingArtifact, Collections.emptyMap(), localRepository,
-                                    remoteRepositories, source, filter );
-
+                artifacts,
+                originatingArtifact,
+                Collections.emptyMap(),
+                localRepository,
+                remoteRepositories,
+                source,
+                filter);
     }
 
-    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                                         Map<String, Artifact> managedVersions,
-                                                         ArtifactRepository localRepository,
-                                                         List<ArtifactRepository> remoteRepositories,
-                                                         ArtifactMetadataSource source )
-                                                             throws ArtifactResolutionException,
-                                                             ArtifactNotFoundException
-    {
-        return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
-                                    remoteRepositories, source, null );
-    }
-
-    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                                         Map<String, Artifact> managedVersions,
-                                                         ArtifactRepository localRepository,
-                                                         List<ArtifactRepository> remoteRepositories,
-                                                         ArtifactMetadataSource source, ArtifactFilter filter )
-                                                             throws ArtifactResolutionException,
-                                                             ArtifactNotFoundException
-    {
-        return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
-                                    remoteRepositories, source, filter, null );
-    }
-
-    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                                         List<ArtifactRepository> remoteRepositories,
-                                                         ArtifactRepository localRepository,
-                                                         ArtifactMetadataSource source )
-                                                             throws ArtifactResolutionException,
-                                                             ArtifactNotFoundException
-    {
-        return resolveTransitively( artifacts, originatingArtifact, localRepository, remoteRepositories, source, null );
-    }
-
-    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                                         List<ArtifactRepository> remoteRepositories,
-                                                         ArtifactRepository localRepository,
-                                                         ArtifactMetadataSource source,
-                                                         List<ResolutionListener> listeners )
-                                                             throws ArtifactResolutionException,
-                                                             ArtifactNotFoundException
-    {
+    public ArtifactResolutionResult resolveTransitively(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
         return resolveTransitively(
-                artifacts, originatingArtifact, Collections.emptyMap(), localRepository,
-                                    remoteRepositories, source, null, listeners );
+                artifacts, originatingArtifact, managedVersions, localRepository, remoteRepositories, source, null);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                                         Map<String, Artifact> managedVersions,
-                                                         ArtifactRepository localRepository,
-                                                         List<ArtifactRepository> remoteRepositories,
-                                                         ArtifactMetadataSource source, ArtifactFilter filter,
-                                                         List<ResolutionListener> listeners )
-                                                             throws ArtifactResolutionException,
-                                                             ArtifactNotFoundException
-    {
-        return resolveTransitively( artifacts, originatingArtifact, managedVersions, localRepository,
-                                    remoteRepositories, source, filter, listeners, null );
+    public ArtifactResolutionResult resolveTransitively(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        return resolveTransitively(
+                artifacts,
+                originatingArtifact,
+                managedVersions,
+                localRepository,
+                remoteRepositories,
+                source,
+                filter,
+                null);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactResolutionResult resolveTransitively( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                                         Map<String, Artifact> managedVersions,
-                                                         ArtifactRepository localRepository,
-                                                         List<ArtifactRepository> remoteRepositories,
-                                                         ArtifactMetadataSource source, ArtifactFilter filter,
-                                                         List<ResolutionListener> listeners,
-                                                         List<ConflictResolver> conflictResolvers )
-                                                             throws ArtifactResolutionException,
-                                                             ArtifactNotFoundException
-    {
-        ArtifactResolutionRequest request = new ArtifactResolutionRequest().
-            setArtifact( originatingArtifact ).
-            setResolveRoot( false ).
-            // This is required by the surefire plugin
-            setArtifactDependencies( artifacts ).
-            setManagedVersionMap( managedVersions ).
-            setLocalRepository( localRepository ).
-            setRemoteRepositories( remoteRepositories ).
-            setCollectionFilter( filter ).
-            setListeners( listeners );
-
-        injectSession2( request, legacySupport.getSession() );
-
-        return resolveWithExceptions( request );
+    public ArtifactResolutionResult resolveTransitively(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            ArtifactMetadataSource source)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        return resolveTransitively(artifacts, originatingArtifact, localRepository, remoteRepositories, source, null);
     }
 
-    public ArtifactResolutionResult resolveWithExceptions( ArtifactResolutionRequest request )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        ArtifactResolutionResult result = resolve( request );
+    public ArtifactResolutionResult resolveTransitively(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            ArtifactMetadataSource source,
+            List<ResolutionListener> listeners)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        return resolveTransitively(
+                artifacts,
+                originatingArtifact,
+                Collections.emptyMap(),
+                localRepository,
+                remoteRepositories,
+                source,
+                null,
+                listeners);
+    }
+
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactResolutionResult resolveTransitively(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        return resolveTransitively(
+                artifacts,
+                originatingArtifact,
+                managedVersions,
+                localRepository,
+                remoteRepositories,
+                source,
+                filter,
+                listeners,
+                null);
+    }
+
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactResolutionResult resolveTransitively(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners,
+            List<ConflictResolver> conflictResolvers)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        ArtifactResolutionRequest request = new ArtifactResolutionRequest()
+                .setArtifact(originatingArtifact)
+                .setResolveRoot(false)
+                .
+                // This is required by the surefire plugin
+                setArtifactDependencies(artifacts)
+                .setManagedVersionMap(managedVersions)
+                .setLocalRepository(localRepository)
+                .setRemoteRepositories(remoteRepositories)
+                .setCollectionFilter(filter)
+                .setListeners(listeners);
+
+        injectSession2(request, legacySupport.getSession());
+
+        return resolveWithExceptions(request);
+    }
+
+    public ArtifactResolutionResult resolveWithExceptions(ArtifactResolutionRequest request)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        ArtifactResolutionResult result = resolve(request);
 
         // We have collected all the problems so let's mimic the way the old code worked and just blow up right here.
         // That's right lets just let it rip right here and send a big incomprehensible blob of text at unsuspecting
         // users. Bad dog!
 
-        resolutionErrorHandler.throwErrors( request, result );
+        resolutionErrorHandler.throwErrors(request, result);
 
         return result;
     }
@@ -364,41 +365,34 @@
     //
     // ------------------------------------------------------------------------
 
-    @SuppressWarnings( "checkstyle:methodlength" )
-    public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
-    {
+    @SuppressWarnings("checkstyle:methodlength")
+    public ArtifactResolutionResult resolve(ArtifactResolutionRequest request) {
         Artifact rootArtifact = request.getArtifact();
         Set<Artifact> artifacts = request.getArtifactDependencies();
         Map<String, Artifact> managedVersions = request.getManagedVersionMap();
         List<ResolutionListener> listeners = request.getListeners();
         ArtifactFilter collectionFilter = request.getCollectionFilter();
         ArtifactFilter resolutionFilter = request.getResolutionFilter();
-        RepositorySystemSession session = getSession( request.getLocalRepository() );
+        RepositorySystemSession session = getSession(request.getLocalRepository());
 
         // TODO: hack because metadata isn't generated in m2e correctly and i want to run the maven i have in the
         // workspace
-        if ( source == null )
-        {
-            try
-            {
-                source = container.lookup( ArtifactMetadataSource.class );
-            }
-            catch ( ComponentLookupException e )
-            {
+        if (source == null) {
+            try {
+                source = container.lookup(ArtifactMetadataSource.class);
+            } catch (ComponentLookupException e) {
                 // won't happen
             }
         }
 
-        if ( listeners == null )
-        {
+        if (listeners == null) {
             listeners = new ArrayList<>();
 
-            if ( logger.isDebugEnabled() )
-            {
-                listeners.add( new DebugResolutionListener( logger ) );
+            if (logger.isDebugEnabled()) {
+                listeners.add(new DebugResolutionListener(logger));
             }
 
-            listeners.add( new WarningResolutionListener( logger ) );
+            listeners.add(new WarningResolutionListener(logger));
         }
 
         ArtifactResolutionResult result = new ArtifactResolutionResult();
@@ -408,182 +402,152 @@
         // file reference. But this may be a Maven Plugin that we need to resolve from a remote repository
         // as well as its dependencies.
 
-        if ( request.isResolveRoot() /* && rootArtifact.getFile() == null */ )
-        {
-            try
-            {
-                resolve( rootArtifact, request.getRemoteRepositories(), session );
-            }
-            catch ( ArtifactResolutionException e )
-            {
-                result.addErrorArtifactException( e );
+        if (request.isResolveRoot() /* && rootArtifact.getFile() == null */) {
+            try {
+                resolve(rootArtifact, request.getRemoteRepositories(), session);
+            } catch (ArtifactResolutionException e) {
+                result.addErrorArtifactException(e);
                 return result;
-            }
-            catch ( ArtifactNotFoundException e )
-            {
-                result.addMissingArtifact( request.getArtifact() );
+            } catch (ArtifactNotFoundException e) {
+                result.addMissingArtifact(request.getArtifact());
                 return result;
             }
         }
 
         ArtifactResolutionRequest collectionRequest = request;
 
-        if ( request.isResolveTransitively() )
-        {
-            MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest( request );
+        if (request.isResolveTransitively()) {
+            MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest(request);
 
-            metadataRequest.setArtifact( rootArtifact );
-            metadataRequest.setResolveManagedVersions( managedVersions == null );
+            metadataRequest.setArtifact(rootArtifact);
+            metadataRequest.setResolveManagedVersions(managedVersions == null);
 
-            try
-            {
-                ResolutionGroup resolutionGroup = source.retrieve( metadataRequest );
+            try {
+                ResolutionGroup resolutionGroup = source.retrieve(metadataRequest);
 
-                if ( managedVersions == null )
-                {
+                if (managedVersions == null) {
                     managedVersions = resolutionGroup.getManagedVersions();
                 }
 
                 Set<Artifact> directArtifacts = resolutionGroup.getArtifacts();
 
-                if ( artifacts == null || artifacts.isEmpty() )
-                {
+                if (artifacts == null || artifacts.isEmpty()) {
                     artifacts = directArtifacts;
-                }
-                else
-                {
+                } else {
                     List<Artifact> allArtifacts = new ArrayList<>();
-                    allArtifacts.addAll( artifacts );
-                    allArtifacts.addAll( directArtifacts );
+                    allArtifacts.addAll(artifacts);
+                    allArtifacts.addAll(directArtifacts);
 
                     Map<String, Artifact> mergedArtifacts = new LinkedHashMap<>();
-                    for ( Artifact artifact : allArtifacts )
-                    {
+                    for (Artifact artifact : allArtifacts) {
                         String conflictId = artifact.getDependencyConflictId();
-                        if ( !mergedArtifacts.containsKey( conflictId ) )
-                        {
-                            mergedArtifacts.put( conflictId, artifact );
+                        if (!mergedArtifacts.containsKey(conflictId)) {
+                            mergedArtifacts.put(conflictId, artifact);
                         }
                     }
 
-                    artifacts = new LinkedHashSet<>( mergedArtifacts.values() );
+                    artifacts = new LinkedHashSet<>(mergedArtifacts.values());
                 }
 
-                collectionRequest = new ArtifactResolutionRequest( request );
-                collectionRequest.setServers( request.getServers() );
-                collectionRequest.setMirrors( request.getMirrors() );
-                collectionRequest.setProxies( request.getProxies() );
-                collectionRequest.setRemoteRepositories( resolutionGroup.getResolutionRepositories() );
-            }
-            catch ( ArtifactMetadataRetrievalException e )
-            {
-                ArtifactResolutionException are =
-                    new ArtifactResolutionException( "Unable to get dependency information for " + rootArtifact.getId()
-                        + ": " + e.getMessage(), rootArtifact, metadataRequest.getRemoteRepositories(), e );
-                result.addMetadataResolutionException( are );
+                collectionRequest = new ArtifactResolutionRequest(request);
+                collectionRequest.setServers(request.getServers());
+                collectionRequest.setMirrors(request.getMirrors());
+                collectionRequest.setProxies(request.getProxies());
+                collectionRequest.setRemoteRepositories(resolutionGroup.getResolutionRepositories());
+            } catch (ArtifactMetadataRetrievalException e) {
+                ArtifactResolutionException are = new ArtifactResolutionException(
+                        "Unable to get dependency information for " + rootArtifact.getId() + ": " + e.getMessage(),
+                        rootArtifact,
+                        metadataRequest.getRemoteRepositories(),
+                        e);
+                result.addMetadataResolutionException(are);
                 return result;
             }
         }
 
-        if ( artifacts == null || artifacts.isEmpty() )
-        {
-            if ( request.isResolveRoot() )
-            {
-                result.addArtifact( rootArtifact );
+        if (artifacts == null || artifacts.isEmpty()) {
+            if (request.isResolveRoot()) {
+                result.addArtifact(rootArtifact);
             }
             return result;
         }
 
         // After the collection we will have the artifact object in the result but they will not be resolved yet.
-        result = artifactCollector.collect( artifacts, rootArtifact, managedVersions, collectionRequest, source,
-                                            collectionFilter, listeners, null );
+        result = artifactCollector.collect(
+                artifacts, rootArtifact, managedVersions, collectionRequest, source, collectionFilter, listeners, null);
 
         // We have metadata retrieval problems, or there are cycles that have been detected
         // so we give this back to the calling code and let them deal with this information
         // appropriately.
 
-        if ( result.hasMetadataResolutionExceptions() || result.hasVersionRangeViolations()
-            || result.hasCircularDependencyExceptions() )
-        {
+        if (result.hasMetadataResolutionExceptions()
+                || result.hasVersionRangeViolations()
+                || result.hasCircularDependencyExceptions()) {
             return result;
         }
 
-        if ( result.getArtifactResolutionNodes() != null )
-        {
+        if (result.getArtifactResolutionNodes() != null) {
             ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 
-            CountDownLatch latch = new CountDownLatch( result.getArtifactResolutionNodes().size() );
+            CountDownLatch latch =
+                    new CountDownLatch(result.getArtifactResolutionNodes().size());
 
-            for ( ResolutionNode node : result.getArtifactResolutionNodes() )
-            {
+            for (ResolutionNode node : result.getArtifactResolutionNodes()) {
                 Artifact artifact = node.getArtifact();
 
-                if ( resolutionFilter == null || resolutionFilter.include( artifact ) )
-                {
-                    executor.execute( new ResolveTask( classLoader, latch, artifact, session,
-                                                       node.getRemoteRepositories(), result ) );
-                }
-                else
-                {
+                if (resolutionFilter == null || resolutionFilter.include(artifact)) {
+                    executor.execute(new ResolveTask(
+                            classLoader, latch, artifact, session, node.getRemoteRepositories(), result));
+                } else {
                     latch.countDown();
                 }
             }
-            try
-            {
+            try {
                 latch.await();
-            }
-            catch ( InterruptedException e )
-            {
-                result.addErrorArtifactException( new ArtifactResolutionException( "Resolution interrupted",
-                                                                                   rootArtifact, e ) );
+            } catch (InterruptedException e) {
+                result.addErrorArtifactException(
+                        new ArtifactResolutionException("Resolution interrupted", rootArtifact, e));
             }
         }
 
         // We want to send the root artifact back in the result but we need to do this after the other dependencies
         // have been resolved.
-        if ( request.isResolveRoot() )
-        {
+        if (request.isResolveRoot()) {
             // Add the root artifact (as the first artifact to retain logical order of class path!)
             Set<Artifact> allArtifacts = new LinkedHashSet<>();
-            allArtifacts.add( rootArtifact );
-            allArtifacts.addAll( result.getArtifacts() );
-            result.setArtifacts( allArtifacts );
+            allArtifacts.add(rootArtifact);
+            allArtifacts.addAll(result.getArtifacts());
+            result.setArtifacts(allArtifacts);
         }
 
         return result;
     }
 
-    public void resolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                         ArtifactRepository localRepository )
-                             throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        resolve( artifact, remoteRepositories, localRepository, null );
+    public void resolve(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        resolve(artifact, remoteRepositories, localRepository, null);
     }
 
     /**
      * ThreadCreator for creating daemon threads with fixed ThreadGroup-name.
      */
-    static final class DaemonThreadCreator
-        implements ThreadFactory
-    {
+    static final class DaemonThreadCreator implements ThreadFactory {
         static final String THREADGROUP_NAME = "org.apache.maven.artifact.resolver.DefaultArtifactResolver";
 
-        static final ThreadGroup GROUP = new ThreadGroup( THREADGROUP_NAME );
+        static final ThreadGroup GROUP = new ThreadGroup(THREADGROUP_NAME);
 
-        static final AtomicInteger THREAD_NUMBER = new AtomicInteger( 1 );
+        static final AtomicInteger THREAD_NUMBER = new AtomicInteger(1);
 
-        public Thread newThread( Runnable r )
-        {
-            Thread newThread = new Thread( GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement() );
-            newThread.setDaemon( true );
-            newThread.setContextClassLoader( null );
+        public Thread newThread(Runnable r) {
+            Thread newThread = new Thread(GROUP, r, "resolver-" + THREAD_NUMBER.getAndIncrement());
+            newThread.setDaemon(true);
+            newThread.setContextClassLoader(null);
             return newThread;
         }
     }
 
-    private class ResolveTask
-        implements Runnable
-    {
+    private class ResolveTask implements Runnable {
 
         private final ClassLoader classLoader;
 
@@ -597,10 +561,13 @@
 
         private final ArtifactResolutionResult result;
 
-        ResolveTask( ClassLoader classLoader, CountDownLatch latch, Artifact artifact,
-                            RepositorySystemSession session, List<ArtifactRepository> remoteRepositories,
-                            ArtifactResolutionResult result )
-        {
+        ResolveTask(
+                ClassLoader classLoader,
+                CountDownLatch latch,
+                Artifact artifact,
+                RepositorySystemSession session,
+                List<ArtifactRepository> remoteRepositories,
+                ArtifactResolutionResult result) {
             this.classLoader = classLoader;
             this.latch = latch;
             this.artifact = artifact;
@@ -609,51 +576,36 @@
             this.result = result;
         }
 
-        public void run()
-        {
+        public void run() {
             ClassLoader old = Thread.currentThread().getContextClassLoader();
-            try
-            {
-                Thread.currentThread().setContextClassLoader( classLoader );
-                resolve( artifact, remoteRepositories, session );
-            }
-            catch ( ArtifactNotFoundException anfe )
-            {
+            try {
+                Thread.currentThread().setContextClassLoader(classLoader);
+                resolve(artifact, remoteRepositories, session);
+            } catch (ArtifactNotFoundException anfe) {
                 // These are cases where the artifact just isn't present in any of the remote repositories
                 // because it wasn't deployed, or it was deployed in the wrong place.
 
-                synchronized ( result )
-                {
-                    result.addMissingArtifact( artifact );
+                synchronized (result) {
+                    result.addMissingArtifact(artifact);
                 }
-            }
-            catch ( ArtifactResolutionException e )
-            {
+            } catch (ArtifactResolutionException e) {
                 // This is really a wagon TransferFailedException so something went wrong after we successfully
                 // retrieved the metadata.
 
-                synchronized ( result )
-                {
-                    result.addErrorArtifactException( e );
+                synchronized (result) {
+                    result.addErrorArtifactException(e);
                 }
-            }
-            finally
-            {
+            } finally {
                 latch.countDown();
-                Thread.currentThread().setContextClassLoader( old );
-
+                Thread.currentThread().setContextClassLoader(old);
             }
         }
-
     }
 
     @Override
-    public void dispose()
-    {
-        if ( executor instanceof ExecutorService )
-        {
-            ( (ExecutorService) executor ).shutdownNow();
+    public void dispose() {
+        if (executor instanceof ExecutorService) {
+            ((ExecutorService) executor).shutdownNow();
         }
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler.java
new file mode 100644
index 0000000..d2311e7
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.resolver;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ */
+@Named
+@Singleton
+@Deprecated
+public class DefaultResolutionErrorHandler implements ResolutionErrorHandler {
+
+    public void throwErrors(ArtifactResolutionRequest request, ArtifactResolutionResult result)
+            throws ArtifactResolutionException {
+        // Metadata cannot be found
+
+        if (result.hasMetadataResolutionExceptions()) {
+            throw result.getMetadataResolutionException(0);
+        }
+
+        // Metadata cannot be retrieved
+
+        // Cyclic Dependency Error
+
+        if (result.hasCircularDependencyExceptions()) {
+            throw result.getCircularDependencyException(0);
+        }
+
+        // Version Range Violation
+
+        if (result.hasVersionRangeViolations()) {
+            throw result.getVersionRangeViolation(0);
+        }
+
+        // Transfer Error
+
+        if (result.hasErrorArtifactExceptions()) {
+            throw result.getErrorArtifactExceptions().get(0);
+        }
+
+        if (result.hasMissingArtifacts()) {
+            throw new MultipleArtifactsNotFoundException(
+                    request.getArtifact(),
+                    toList(result.getArtifacts()),
+                    result.getMissingArtifacts(),
+                    request.getRemoteRepositories());
+        }
+
+        // this should never happen since we checked all possible error sources before but better be sure
+        if (result.hasExceptions()) {
+            throw new ArtifactResolutionException(
+                    "Unknown error during artifact resolution, " + request + ", " + result.getExceptions(),
+                    request.getArtifact(),
+                    request.getRemoteRepositories());
+        }
+    }
+
+    private static <T> List<T> toList(Collection<T> items) {
+        return (items != null) ? new ArrayList<>(items) : null;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionErrorHandler.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionErrorHandler.java
new file mode 100644
index 0000000..ccd8688
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionErrorHandler.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.resolver;
+
+/**
+ */
+@Deprecated
+public interface ResolutionErrorHandler {
+
+    void throwErrors(ArtifactResolutionRequest request, ArtifactResolutionResult result)
+            throws ArtifactResolutionException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionListener.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionListener.java
new file mode 100644
index 0000000..5015ff2
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionListener.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.resolver;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.versioning.VersionRange;
+
+/**
+ * Listens to the resolution process and handles events.
+ *
+ */
+@Deprecated
+public interface ResolutionListener {
+    String ROLE = ResolutionListener.class.getName();
+
+    int TEST_ARTIFACT = 1;
+
+    int PROCESS_CHILDREN = 2;
+
+    int FINISH_PROCESSING_CHILDREN = 3;
+
+    int INCLUDE_ARTIFACT = 4;
+
+    int OMIT_FOR_NEARER = 5;
+
+    int UPDATE_SCOPE = 6;
+
+    @Deprecated
+    int MANAGE_ARTIFACT = 7;
+
+    int OMIT_FOR_CYCLE = 8;
+
+    /**
+     * this event means that the artifactScope has NOT been updated to a farther node artifactScope because current
+     * node is in the first level pom
+     */
+    int UPDATE_SCOPE_CURRENT_POM = 9;
+
+    int SELECT_VERSION_FROM_RANGE = 10;
+
+    int RESTRICT_RANGE = 11;
+
+    int MANAGE_ARTIFACT_VERSION = 12;
+
+    int MANAGE_ARTIFACT_SCOPE = 13;
+
+    int MANAGE_ARTIFACT_SYSTEM_PATH = 14;
+
+    void testArtifact(Artifact node);
+
+    void startProcessChildren(Artifact artifact);
+
+    void endProcessChildren(Artifact artifact);
+
+    void includeArtifact(Artifact artifact);
+
+    void omitForNearer(Artifact omitted, Artifact kept);
+
+    void updateScope(Artifact artifact, String scope);
+
+    @Deprecated
+    void manageArtifact(Artifact artifact, Artifact replacement);
+
+    // TODO Use the following two instead of manageArtifact
+    // TODO Remove ResolutionListenerDM interface
+
+    // void manageArtifactVersion( Artifact artifact, Artifact replacement );
+
+    // void manageArtifactScope( Artifact artifact, Artifact replacement );
+
+    void omitForCycle(Artifact artifact);
+
+    /**
+     * This event means that the artifactScope has NOT been updated to a farther node artifactScope because current
+     * node is in the first level pom
+     *
+     * @param artifact     current node artifact, the one in the first level pom
+     * @param ignoredScope artifactScope that was ignored because artifact was in first level pom
+     */
+    void updateScopeCurrentPom(Artifact artifact, String ignoredScope);
+
+    void selectVersionFromRange(Artifact artifact);
+
+    void restrictRange(Artifact artifact, Artifact replacement, VersionRange newRange);
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionListenerForDepMgmt.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionListenerForDepMgmt.java
index 6cf06b1..288af42 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionListenerForDepMgmt.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionListenerForDepMgmt.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import org.apache.maven.artifact.Artifact;
 
@@ -30,14 +29,10 @@
  * interface) has had a chance to propagate to all interested plugins.
  */
 @Deprecated
-public interface ResolutionListenerForDepMgmt
-{
-    void manageArtifactVersion( Artifact artifact,
-                                Artifact replacement );
+public interface ResolutionListenerForDepMgmt {
+    void manageArtifactVersion(Artifact artifact, Artifact replacement);
 
-    void manageArtifactScope( Artifact artifact,
-                              Artifact replacement );
+    void manageArtifactScope(Artifact artifact, Artifact replacement);
 
-    void manageArtifactSystemPath( Artifact artifact,
-                                   Artifact replacement );
+    void manageArtifactSystemPath(Artifact artifact, Artifact replacement);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java
new file mode 100644
index 0000000..16e6217
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.resolver;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
+
+/**
+ * ResolutionNode
+ */
+@Deprecated
+public class ResolutionNode {
+    private Artifact artifact;
+
+    private List<ResolutionNode> children;
+
+    private final List<Object> parents;
+
+    private final int depth;
+
+    private final ResolutionNode parent;
+
+    private final List<ArtifactRepository> remoteRepositories;
+
+    private boolean active = true;
+
+    private List<Artifact> trail;
+
+    public ResolutionNode(Artifact artifact, List<ArtifactRepository> remoteRepositories) {
+        this.artifact = artifact;
+        this.remoteRepositories = remoteRepositories;
+        depth = 0;
+        parents = Collections.emptyList();
+        parent = null;
+    }
+
+    public ResolutionNode(Artifact artifact, List<ArtifactRepository> remoteRepositories, ResolutionNode parent) {
+        this.artifact = artifact;
+        this.remoteRepositories = remoteRepositories;
+        depth = parent.depth + 1;
+        parents = new ArrayList<>();
+        parents.addAll(parent.parents);
+        parents.add(parent.getKey());
+        this.parent = parent;
+    }
+
+    public Artifact getArtifact() {
+        return artifact;
+    }
+
+    public Object getKey() {
+        return artifact.getDependencyConflictId();
+    }
+
+    public void addDependencies(
+            Set<Artifact> artifacts, List<ArtifactRepository> remoteRepositories, ArtifactFilter filter)
+            throws CyclicDependencyException, OverConstrainedVersionException {
+        if (artifacts != null && !artifacts.isEmpty()) {
+            children = new ArrayList<>(artifacts.size());
+
+            for (Artifact a : artifacts) {
+                if (parents.contains(a.getDependencyConflictId())) {
+                    a.setDependencyTrail(getDependencyTrail());
+
+                    throw new CyclicDependencyException("A dependency has introduced a cycle", a);
+                }
+
+                children.add(new ResolutionNode(a, remoteRepositories, this));
+            }
+            children = Collections.unmodifiableList(children);
+        } else {
+            children = Collections.emptyList();
+        }
+        trail = null;
+    }
+
+    /**
+     * @return {@link List} &lt; {@link String} &gt; with artifact ids
+     * @throws OverConstrainedVersionException if version specification is over constrained
+     */
+    public List<String> getDependencyTrail() throws OverConstrainedVersionException {
+        List<Artifact> trial = getTrail();
+
+        List<String> ret = new ArrayList<>(trial.size());
+
+        for (Artifact artifact : trial) {
+            ret.add(artifact.getId());
+        }
+
+        return ret;
+    }
+
+    private List<Artifact> getTrail() throws OverConstrainedVersionException {
+        if (trail == null) {
+            List<Artifact> ids = new LinkedList<>();
+            ResolutionNode node = this;
+            while (node != null) {
+                Artifact artifact = node.getArtifact();
+                if (artifact.getVersion() == null) {
+                    // set the recommended version
+                    ArtifactVersion selected = artifact.getSelectedVersion();
+                    // MNG-2123: null is a valid response to getSelectedVersion, don't
+                    // assume it won't ever be.
+                    if (selected != null) {
+                        artifact.selectVersion(selected.toString());
+                    } else {
+                        throw new OverConstrainedVersionException(
+                                "Unable to get a selected Version for " + artifact.getArtifactId(), artifact);
+                    }
+                }
+
+                ids.add(0, artifact);
+                node = node.parent;
+            }
+            trail = ids;
+        }
+        return trail;
+    }
+
+    public boolean isResolved() {
+        return children != null;
+    }
+
+    /**
+     * Test whether the node is direct or transitive dependency.
+     *
+     * @return whether the node is direct or transitive dependency
+     */
+    public boolean isChildOfRootNode() {
+        return parent != null && parent.parent == null;
+    }
+
+    public Iterator<ResolutionNode> getChildrenIterator() {
+        return children.iterator();
+    }
+
+    public int getDepth() {
+        return depth;
+    }
+
+    public List<ArtifactRepository> getRemoteRepositories() {
+        return remoteRepositories;
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void enable() {
+        active = true;
+
+        // TODO if it was null, we really need to go find them now... or is this taken care of by the ordering?
+        if (children != null) {
+            for (ResolutionNode node : children) {
+                node.enable();
+            }
+        }
+    }
+
+    public void disable() {
+        active = false;
+        if (children != null) {
+            for (ResolutionNode node : children) {
+                node.disable();
+            }
+        }
+    }
+
+    public boolean filterTrail(ArtifactFilter filter) throws OverConstrainedVersionException {
+        boolean success = true;
+        if (filter != null) {
+            for (Artifact artifact : getTrail()) {
+                if (!filter.include(artifact)) {
+                    success = false;
+                }
+            }
+        }
+        return success;
+    }
+
+    @Override
+    public String toString() {
+        return artifact.toString() + " (" + depth + "; " + (active ? "enabled" : "disabled") + ")";
+    }
+
+    public void setArtifact(Artifact artifact) {
+        this.artifact = artifact;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/UnresolvedArtifacts.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/UnresolvedArtifacts.java
index b9ccf70..4e6016c 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/UnresolvedArtifacts.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/UnresolvedArtifacts.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.List;
 
@@ -28,20 +27,17 @@
  * A simple recording of the Artifacts that could not be resolved for a given resolution request, along with
  * the remote repositories where attempts were made to resolve the artifacts.
  *
- * @author Jason van Zyl
  */
-public class UnresolvedArtifacts
-{
+@Deprecated
+public class UnresolvedArtifacts {
     private Artifact originatingArtifact;
 
     private List<Artifact> artifacts;
 
     private List<ArtifactRepository> remoteRepositories;
 
-    public UnresolvedArtifacts( Artifact originatingArtifact,
-                                List<Artifact> artifacts,
-                                List<ArtifactRepository> remoteRepositories )
-    {
+    public UnresolvedArtifacts(
+            Artifact originatingArtifact, List<Artifact> artifacts, List<ArtifactRepository> remoteRepositories) {
         this.originatingArtifact = originatingArtifact;
 
         this.artifacts = artifacts;
@@ -49,18 +45,15 @@
         this.remoteRepositories = remoteRepositories;
     }
 
-    public Artifact getOriginatingArtifact()
-    {
+    public Artifact getOriginatingArtifact() {
         return originatingArtifact;
     }
 
-    public List<Artifact> getArtifacts()
-    {
+    public List<Artifact> getArtifacts() {
         return artifacts;
     }
 
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
+    public List<ArtifactRepository> getRemoteRepositories() {
         return remoteRepositories;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/WarningResolutionListener.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/WarningResolutionListener.java
index 825d595..ddfd568 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/WarningResolutionListener.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/WarningResolutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.versioning.VersionRange;
@@ -26,65 +25,34 @@
 /**
  * Send resolution warning events to the warning log.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class WarningResolutionListener
-    implements ResolutionListener
-{
+@Deprecated
+public class WarningResolutionListener implements ResolutionListener {
     private Logger logger;
 
-    public WarningResolutionListener( Logger logger )
-    {
+    public WarningResolutionListener(Logger logger) {
         this.logger = logger;
     }
 
-    public void testArtifact( Artifact node )
-    {
-    }
+    public void testArtifact(Artifact node) {}
 
-    public void startProcessChildren( Artifact artifact )
-    {
-    }
+    public void startProcessChildren(Artifact artifact) {}
 
-    public void endProcessChildren( Artifact artifact )
-    {
-    }
+    public void endProcessChildren(Artifact artifact) {}
 
-    public void includeArtifact( Artifact artifact )
-    {
-    }
+    public void includeArtifact(Artifact artifact) {}
 
-    public void omitForNearer( Artifact omitted,
-                               Artifact kept )
-    {
-    }
+    public void omitForNearer(Artifact omitted, Artifact kept) {}
 
-    public void omitForCycle( Artifact omitted )
-    {
-    }
+    public void omitForCycle(Artifact omitted) {}
 
-    public void updateScopeCurrentPom( Artifact artifact,
-                                       String scope )
-    {
-    }
+    public void updateScopeCurrentPom(Artifact artifact, String scope) {}
 
-    public void updateScope( Artifact artifact,
-                             String scope )
-    {
-    }
+    public void updateScope(Artifact artifact, String scope) {}
 
-    public void manageArtifact( Artifact artifact,
-                                Artifact replacement )
-    {
-    }
+    public void manageArtifact(Artifact artifact, Artifact replacement) {}
 
-    public void selectVersionFromRange( Artifact artifact )
-    {
-    }
+    public void selectVersionFromRange(Artifact artifact) {}
 
-    public void restrictRange( Artifact artifact,
-                               Artifact replacement,
-                               VersionRange newRange )
-    {
-    }
+    public void restrictRange(Artifact artifact, Artifact replacement, VersionRange newRange) {}
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/InversionArtifactFilter.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/InversionArtifactFilter.java
index fa66574..30f4e16 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/InversionArtifactFilter.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/InversionArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,51 +16,44 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import org.apache.maven.artifact.Artifact;
 
 /**
  * InversionArtifactFilter
  */
-public class InversionArtifactFilter
-    implements ArtifactFilter
-{
+@Deprecated
+public class InversionArtifactFilter implements ArtifactFilter {
     private final ArtifactFilter toInvert;
 
-    public InversionArtifactFilter( ArtifactFilter toInvert )
-    {
+    public InversionArtifactFilter(ArtifactFilter toInvert) {
         this.toInvert = toInvert;
     }
 
-    public boolean include( Artifact artifact )
-    {
-        return !toInvert.include( artifact );
+    public boolean include(Artifact artifact) {
+        return !toInvert.include(artifact);
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
         hash = hash * 31 + toInvert.hashCode();
         return hash;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof InversionArtifactFilter ) )
-        {
+        if (!(obj instanceof InversionArtifactFilter)) {
             return false;
         }
 
         InversionArtifactFilter other = (InversionArtifactFilter) obj;
 
-        return toInvert.equals( other.toInvert );
+        return toInvert.equals(other.toInvert);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilter.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilter.java
index 24bfbf4..274add4 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilter.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Collection;
 import java.util.LinkedHashSet;
@@ -28,30 +27,23 @@
 /**
  * Apply multiple filters, accepting an artifact if at least one of the filters accepts it.
  *
- * @author Benjamin Bentmann
  */
-public class OrArtifactFilter
-    implements ArtifactFilter
-{
+@Deprecated
+public class OrArtifactFilter implements ArtifactFilter {
 
     private Set<ArtifactFilter> filters;
 
-    public OrArtifactFilter()
-    {
+    public OrArtifactFilter() {
         this.filters = new LinkedHashSet<>();
     }
 
-    public OrArtifactFilter( Collection<ArtifactFilter> filters )
-    {
-        this.filters = new LinkedHashSet<>( filters );
+    public OrArtifactFilter(Collection<ArtifactFilter> filters) {
+        this.filters = new LinkedHashSet<>(filters);
     }
 
-    public boolean include( Artifact artifact )
-    {
-        for ( ArtifactFilter filter : filters )
-        {
-            if ( filter.include( artifact ) )
-            {
+    public boolean include(Artifact artifact) {
+        for (ArtifactFilter filter : filters) {
+            if (filter.include(artifact)) {
                 return true;
             }
         }
@@ -59,35 +51,29 @@
         return false;
     }
 
-    public void add( ArtifactFilter artifactFilter )
-    {
-        filters.add( artifactFilter );
+    public void add(ArtifactFilter artifactFilter) {
+        filters.add(artifactFilter);
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
         hash = hash * 31 + filters.hashCode();
         return hash;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof OrArtifactFilter ) )
-        {
+        if (!(obj instanceof OrArtifactFilter)) {
             return false;
         }
 
         OrArtifactFilter other = (OrArtifactFilter) obj;
 
-        return filters.equals( other.filters );
+        return filters.equals(other.filters);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/TypeArtifactFilter.java b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/TypeArtifactFilter.java
index 76c39ec..16ee7be 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/TypeArtifactFilter.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/resolver/filter/TypeArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,49 +16,42 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import org.apache.maven.artifact.Artifact;
 
 /** Artifact Filter which filters on artifact type */
-public class TypeArtifactFilter
-    implements ArtifactFilter
-{
+@Deprecated
+public class TypeArtifactFilter implements ArtifactFilter {
     private String type = "jar";
 
-    public TypeArtifactFilter( String type )
-    {
+    public TypeArtifactFilter(String type) {
         this.type = type;
     }
 
-    public boolean include( Artifact artifact )
-    {
-        return type.equals( artifact.getType() );
+    public boolean include(Artifact artifact) {
+        return type.equals(artifact.getType());
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
         hash = hash * 31 + type.hashCode();
         return hash;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof TypeArtifactFilter ) )
-        {
+        if (!(obj instanceof TypeArtifactFilter)) {
             return false;
         }
 
         TypeArtifactFilter other = (TypeArtifactFilter) obj;
 
-        return type.equals( other.type );
+        return type.equals(other.type);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/artifact/versioning/ManagedVersionMap.java b/maven-compat/src/main/java/org/apache/maven/artifact/versioning/ManagedVersionMap.java
index c098d7f..9e6b78e 100644
--- a/maven-compat/src/main/java/org/apache/maven/artifact/versioning/ManagedVersionMap.java
+++ b/maven-compat/src/main/java/org/apache/maven/artifact/versioning/ManagedVersionMap.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.versioning;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.versioning;
 
 import java.util.HashMap;
 import java.util.Iterator;
@@ -29,29 +28,22 @@
  * ManagedVersionMap
  */
 @Deprecated
-public class ManagedVersionMap
-    extends HashMap<String, Artifact>
-{
-    public ManagedVersionMap( Map<String, Artifact> map )
-    {
+public class ManagedVersionMap extends HashMap<String, Artifact> {
+    public ManagedVersionMap(Map<String, Artifact> map) {
         super();
-        if ( map != null )
-        {
-            putAll( map );
+        if (map != null) {
+            putAll(map);
         }
     }
 
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder( "ManagedVersionMap (" + size() + " entries)\n" );
+    public String toString() {
+        StringBuilder buffer = new StringBuilder("ManagedVersionMap (" + size() + " entries)\n");
         Iterator<String> iter = keySet().iterator();
-        while ( iter.hasNext() )
-        {
+        while (iter.hasNext()) {
             String key = iter.next();
-            buffer.append( key ).append( '=' ).append( get( key ) );
-            if ( iter.hasNext() )
-            {
-                buffer.append( '\n' );
+            buffer.append(key).append('=').append(get(key));
+            if (iter.hasNext()) {
+                buffer.append('\n');
             }
         }
         return buffer.toString();
diff --git a/maven-compat/src/main/java/org/apache/maven/execution/DefaultRuntimeInformation.java b/maven-compat/src/main/java/org/apache/maven/execution/DefaultRuntimeInformation.java
index 7767aff..40e3942 100644
--- a/maven-compat/src/main/java/org/apache/maven/execution/DefaultRuntimeInformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/execution/DefaultRuntimeInformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,47 +16,42 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Describes runtime information about the application.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
 @Deprecated
-@Component( role = RuntimeInformation.class )
-public class DefaultRuntimeInformation
-    implements RuntimeInformation, Initializable
-{
+@Named
+@Singleton
+public class DefaultRuntimeInformation implements RuntimeInformation, Initializable {
 
-    @Requirement
+    @Inject
     private org.apache.maven.rtinfo.RuntimeInformation rtInfo;
 
     private ArtifactVersion applicationVersion;
 
-    public ArtifactVersion getApplicationVersion()
-    {
+    public ArtifactVersion getApplicationVersion() {
         return applicationVersion;
     }
 
-    public void initialize()
-        throws InitializationException
-    {
+    public void initialize() throws InitializationException {
         String mavenVersion = rtInfo.getMavenVersion();
 
-        if ( StringUtils.isEmpty( mavenVersion ) )
-        {
-            throw new InitializationException( "Unable to read Maven version from maven-core" );
+        if (mavenVersion == null || mavenVersion.isEmpty()) {
+            throw new InitializationException("Unable to read Maven version from maven-core");
         }
 
-        applicationVersion = new DefaultArtifactVersion( mavenVersion );
+        applicationVersion = new DefaultArtifactVersion(mavenVersion);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/execution/RuntimeInformation.java b/maven-compat/src/main/java/org/apache/maven/execution/RuntimeInformation.java
index 22e522d..e169465 100644
--- a/maven-compat/src/main/java/org/apache/maven/execution/RuntimeInformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/execution/RuntimeInformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 
@@ -25,10 +24,8 @@
  * Describes runtime information about the application.
  *
  * @deprecated Use {@link org.apache.maven.rtinfo.RuntimeInformation} instead.
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
 @Deprecated
-public interface RuntimeInformation
-{
+public interface RuntimeInformation {
     ArtifactVersion getApplicationVersion();
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/plugin/PluginManager.java b/maven-compat/src/main/java/org/apache/maven/plugin/PluginManager.java
new file mode 100644
index 0000000..2b7e44e
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/plugin/PluginManager.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin;
+
+import java.util.Map;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.version.PluginVersionNotFoundException;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.InvalidDependencyVersionException;
+import org.apache.maven.settings.Settings;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+/**
+ */
+@Deprecated
+public interface PluginManager {
+    String ROLE = PluginManager.class.getName();
+
+    void executeMojo(MavenProject project, MojoExecution execution, MavenSession session)
+            throws MojoExecutionException, ArtifactResolutionException, MojoFailureException, ArtifactNotFoundException,
+                    InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException;
+
+    PluginDescriptor getPluginDescriptorForPrefix(String prefix);
+
+    Plugin getPluginDefinitionForPrefix(String prefix, MavenSession session, MavenProject project);
+
+    PluginDescriptor verifyPlugin(
+            Plugin plugin, MavenProject project, Settings settings, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
+                    InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException,
+                    PluginNotFoundException, PluginVersionNotFoundException;
+
+    Object getPluginComponent(Plugin plugin, String role, String roleHint)
+            throws PluginManagerException, ComponentLookupException;
+
+    Map<String, Object> getPluginComponents(Plugin plugin, String role)
+            throws ComponentLookupException, PluginManagerException;
+
+    /**
+     * @since 2.2.1
+     */
+    PluginDescriptor loadPluginDescriptor(Plugin plugin, MavenProject project, MavenSession session)
+            throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
+                    InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException,
+                    PluginNotFoundException, PluginVersionNotFoundException;
+
+    /**
+     * @since 2.2.1
+     */
+    PluginDescriptor loadPluginFully(Plugin plugin, MavenProject project, MavenSession session)
+            throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
+                    InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException,
+                    PluginNotFoundException, PluginVersionNotFoundException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java b/maven-compat/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java
new file mode 100644
index 0000000..7a60717
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java
@@ -0,0 +1,223 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Map;
+
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.InvalidPluginDescriptorException;
+import org.apache.maven.plugin.InvalidPluginException;
+import org.apache.maven.plugin.LegacySupport;
+import org.apache.maven.plugin.MavenPluginManager;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.PluginConfigurationException;
+import org.apache.maven.plugin.PluginDescriptorParsingException;
+import org.apache.maven.plugin.PluginManager;
+import org.apache.maven.plugin.PluginManagerException;
+import org.apache.maven.plugin.PluginNotFoundException;
+import org.apache.maven.plugin.PluginResolutionException;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.prefix.DefaultPluginPrefixRequest;
+import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
+import org.apache.maven.plugin.prefix.PluginPrefixRequest;
+import org.apache.maven.plugin.prefix.PluginPrefixResolver;
+import org.apache.maven.plugin.prefix.PluginPrefixResult;
+import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionNotFoundException;
+import org.apache.maven.plugin.version.PluginVersionRequest;
+import org.apache.maven.plugin.version.PluginVersionResolutionException;
+import org.apache.maven.plugin.version.PluginVersionResolver;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.InvalidDependencyVersionException;
+import org.apache.maven.settings.Settings;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+/**
+ */
+@Named
+@Singleton
+@Deprecated
+public class DefaultPluginManager implements PluginManager {
+
+    private final PlexusContainer container;
+    private final MavenPluginManager pluginManager;
+    private final PluginVersionResolver pluginVersionResolver;
+    private final PluginPrefixResolver pluginPrefixResolver;
+    private final LegacySupport legacySupport;
+
+    @Inject
+    public DefaultPluginManager(
+            PlexusContainer container,
+            MavenPluginManager pluginManager,
+            PluginVersionResolver pluginVersionResolver,
+            PluginPrefixResolver pluginPrefixResolver,
+            LegacySupport legacySupport) {
+        this.container = container;
+        this.pluginManager = pluginManager;
+        this.pluginVersionResolver = pluginVersionResolver;
+        this.pluginPrefixResolver = pluginPrefixResolver;
+        this.legacySupport = legacySupport;
+    }
+
+    public void executeMojo(MavenProject project, MojoExecution execution, MavenSession session)
+            throws MojoExecutionException, ArtifactResolutionException, MojoFailureException, ArtifactNotFoundException,
+                    InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException {
+        throw new UnsupportedOperationException();
+    }
+
+    public Object getPluginComponent(Plugin plugin, String role, String roleHint)
+            throws PluginManagerException, ComponentLookupException {
+        MavenSession session = legacySupport.getSession();
+
+        PluginDescriptor pluginDescriptor;
+        try {
+            pluginDescriptor = pluginManager.getPluginDescriptor(
+                    plugin, session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+
+            pluginManager.setupPluginRealm(pluginDescriptor, session, null, null, null);
+        } catch (Exception e) {
+            throw new PluginManagerException(plugin, e.getMessage(), e);
+        }
+
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(pluginDescriptor.getClassRealm());
+
+            return container.lookup(role, roleHint);
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+        }
+    }
+
+    public Map<String, Object> getPluginComponents(Plugin plugin, String role)
+            throws ComponentLookupException, PluginManagerException {
+        MavenSession session = legacySupport.getSession();
+
+        PluginDescriptor pluginDescriptor;
+        try {
+            pluginDescriptor = pluginManager.getPluginDescriptor(
+                    plugin, session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+
+            pluginManager.setupPluginRealm(pluginDescriptor, session, null, null, null);
+        } catch (Exception e) {
+            throw new PluginManagerException(plugin, e.getMessage(), e);
+        }
+
+        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(pluginDescriptor.getClassRealm());
+
+            return container.lookupMap(role);
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+        }
+    }
+
+    public Plugin getPluginDefinitionForPrefix(String prefix, MavenSession session, MavenProject project) {
+        PluginPrefixRequest request = new DefaultPluginPrefixRequest(prefix, session);
+        request.setPom(project.getModel());
+
+        try {
+            PluginPrefixResult result = pluginPrefixResolver.resolve(request);
+
+            Plugin plugin = new Plugin();
+            plugin.setGroupId(result.getGroupId());
+            plugin.setArtifactId(result.getArtifactId());
+
+            return plugin;
+        } catch (NoPluginFoundForPrefixException e) {
+            return null;
+        }
+    }
+
+    public PluginDescriptor getPluginDescriptorForPrefix(String prefix) {
+        MavenSession session = legacySupport.getSession();
+
+        PluginPrefixRequest request = new DefaultPluginPrefixRequest(prefix, session);
+
+        try {
+            PluginPrefixResult result = pluginPrefixResolver.resolve(request);
+
+            Plugin plugin = new Plugin();
+            plugin.setGroupId(result.getGroupId());
+            plugin.setArtifactId(result.getArtifactId());
+
+            return loadPluginDescriptor(plugin, session.getCurrentProject(), session);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    public PluginDescriptor loadPluginDescriptor(Plugin plugin, MavenProject project, MavenSession session)
+            throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
+                    InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException,
+                    PluginNotFoundException, PluginVersionNotFoundException {
+        return verifyPlugin(plugin, project, session.getSettings(), session.getLocalRepository());
+    }
+
+    public PluginDescriptor loadPluginFully(Plugin plugin, MavenProject project, MavenSession session)
+            throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
+                    InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException,
+                    PluginNotFoundException, PluginVersionNotFoundException {
+        PluginDescriptor pluginDescriptor = loadPluginDescriptor(plugin, project, session);
+
+        try {
+            pluginManager.setupPluginRealm(pluginDescriptor, session, null, null, null);
+        } catch (PluginResolutionException e) {
+            throw new PluginManagerException(plugin, e.getMessage(), e);
+        }
+
+        return pluginDescriptor;
+    }
+
+    public PluginDescriptor verifyPlugin(
+            Plugin plugin, MavenProject project, Settings settings, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
+                    InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException,
+                    PluginNotFoundException, PluginVersionNotFoundException {
+        MavenSession session = legacySupport.getSession();
+
+        if (plugin.getVersion() == null) {
+            PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(
+                    plugin, session.getRepositorySession(), project.getRemotePluginRepositories());
+            plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
+        }
+
+        try {
+            return pluginManager.getPluginDescriptor(
+                    plugin, project.getRemotePluginRepositories(), session.getRepositorySession());
+        } catch (PluginResolutionException e) {
+            throw new PluginNotFoundException(plugin, project.getPluginArtifactRepositories());
+        } catch (PluginDescriptorParsingException | InvalidPluginDescriptorException e) {
+            throw new PluginManagerException(plugin, e.getMessage(), e);
+        }
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/DefaultMavenProfilesBuilder.java b/maven-compat/src/main/java/org/apache/maven/profiles/DefaultMavenProfilesBuilder.java
deleted file mode 100644
index 8ee9001..0000000
--- a/maven-compat/src/main/java/org/apache/maven/profiles/DefaultMavenProfilesBuilder.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package org.apache.maven.profiles;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.profiles.io.xpp3.ProfilesXpp3Reader;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
-import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
-import org.codehaus.plexus.logging.AbstractLogEnabled;
-import org.codehaus.plexus.util.IOUtil;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-
-/**
- * DefaultMavenProfilesBuilder
- */
-@Deprecated
-@Component( role = MavenProfilesBuilder.class )
-public class DefaultMavenProfilesBuilder
-    extends AbstractLogEnabled
-    implements MavenProfilesBuilder
-{
-    private static final String PROFILES_XML_FILE = "profiles.xml";
-
-    public ProfilesRoot buildProfiles( File basedir )
-        throws IOException, XmlPullParserException
-    {
-        File profilesXml = new File( basedir, PROFILES_XML_FILE );
-
-        ProfilesRoot profilesRoot = null;
-
-        if ( profilesXml.exists() )
-        {
-            ProfilesXpp3Reader reader = new ProfilesXpp3Reader();
-            try ( Reader profileReader = ReaderFactory.newXmlReader( profilesXml );
-                  StringWriter sWriter = new StringWriter() )
-            {
-                IOUtil.copy( profileReader, sWriter );
-
-                String rawInput = sWriter.toString();
-
-                try
-                {
-                    RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
-                    interpolator.addValueSource( new EnvarBasedValueSource() );
-
-                    rawInput = interpolator.interpolate( rawInput, "settings" );
-                }
-                catch ( Exception e )
-                {
-                    getLogger().warn(
-                        "Failed to initialize environment variable resolver. Skipping environment " + "substitution in "
-                            + PROFILES_XML_FILE + "." );
-                    getLogger().debug( "Failed to initialize envar resolver. Skipping resolution.", e );
-                }
-
-                StringReader sReader = new StringReader( rawInput );
-
-                profilesRoot = reader.read( sReader );
-            }
-
-        }
-
-        return profilesRoot;
-    }
-
-}
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/DefaultProfileManager.java b/maven-compat/src/main/java/org/apache/maven/profiles/DefaultProfileManager.java
index 11dc0a3..6727261 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/DefaultProfileManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/DefaultProfileManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles;
+
+import javax.inject.Inject;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
 
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.Profile;
@@ -27,28 +34,19 @@
 import org.apache.maven.profiles.activation.ProfileActivationException;
 import org.codehaus.plexus.MutablePlexusContainer;
 import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.logging.Logger;
 
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-
 /**
  * DefaultProfileManager
  */
 @Deprecated
-public class DefaultProfileManager
-    implements ProfileManager
-{
+public class DefaultProfileManager implements ProfileManager {
 
-    @Requirement
+    @Inject
     private Logger logger;
 
-    @Requirement
+    @Inject
     private ProfileSelector profileSelector;
 
     private List<String> activatedIds = new ArrayList<>();
@@ -65,9 +63,9 @@
      * @deprecated without passing in the system properties, the SystemPropertiesProfileActivator will not work
      *             correctly in embedded environments.
      */
-    public DefaultProfileManager( PlexusContainer container )
-    {
-        this( container, null );
+    @Deprecated
+    public DefaultProfileManager(PlexusContainer container) {
+        this(container, null);
     }
 
     /**
@@ -75,127 +73,105 @@
      * are passed to maven, possibly containing profile activator properties
      *
      */
-    public DefaultProfileManager( PlexusContainer container, Properties props )
-    {
-        try
-        {
-            this.profileSelector = container.lookup( ProfileSelector.class );
-            this.logger = ( (MutablePlexusContainer) container ).getLogger();
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new IllegalStateException( e );
+    public DefaultProfileManager(PlexusContainer container, Properties props) {
+        try {
+            this.profileSelector = container.lookup(ProfileSelector.class);
+            this.logger = ((MutablePlexusContainer) container).getLogger();
+        } catch (ComponentLookupException e) {
+            throw new IllegalStateException(e);
         }
         this.requestProperties = props;
     }
 
-    public Properties getRequestProperties()
-    {
+    public Properties getRequestProperties() {
         return requestProperties;
     }
 
-    public Map<String, Profile> getProfilesById()
-    {
+    public Map<String, Profile> getProfilesById() {
         return profilesById;
     }
 
     /* (non-Javadoc)
-    * @see org.apache.maven.profiles.ProfileManager#addProfile(org.apache.maven.model.Profile)
-    */
-    public void addProfile( Profile profile )
-    {
+     * @see org.apache.maven.profiles.ProfileManager#addProfile(org.apache.maven.model.Profile)
+     */
+    public void addProfile(Profile profile) {
         String profileId = profile.getId();
 
-        Profile existing = profilesById.get( profileId );
-        if ( existing != null )
-        {
-            logger.warn( "Overriding profile: '" + profileId + "' (source: " + existing.getSource()
-                + ") with new instance from source: " + profile.getSource() );
+        Profile existing = profilesById.get(profileId);
+        if (existing != null) {
+            logger.warn("Overriding profile: '" + profileId + "' (source: " + existing.getSource()
+                    + ") with new instance from source: " + profile.getSource());
         }
 
-        profilesById.put( profile.getId(), profile );
+        profilesById.put(profile.getId(), profile);
 
         Activation activation = profile.getActivation();
 
-        if ( activation != null && activation.isActiveByDefault() )
-        {
-            activateAsDefault( profileId );
+        if (activation != null && activation.isActiveByDefault()) {
+            activateAsDefault(profileId);
         }
     }
 
     /* (non-Javadoc)
-    * @see org.apache.maven.profiles.ProfileManager#explicitlyActivate(java.lang.String)
-    */
-    public void explicitlyActivate( String profileId )
-    {
-        if ( !activatedIds.contains( profileId ) )
-        {
-            logger.debug( "Profile with id: '" + profileId + "' has been explicitly activated." );
+     * @see org.apache.maven.profiles.ProfileManager#explicitlyActivate(java.lang.String)
+     */
+    public void explicitlyActivate(String profileId) {
+        if (!activatedIds.contains(profileId)) {
+            logger.debug("Profile with id: '" + profileId + "' has been explicitly activated.");
 
-            activatedIds.add( profileId );
+            activatedIds.add(profileId);
         }
     }
 
     /* (non-Javadoc)
-    * @see org.apache.maven.profiles.ProfileManager#explicitlyActivate(java.util.List)
-    */
-    public void explicitlyActivate( List<String> profileIds )
-    {
-        for ( String profileId1 : profileIds )
-        {
-            explicitlyActivate( profileId1 );
+     * @see org.apache.maven.profiles.ProfileManager#explicitlyActivate(java.util.List)
+     */
+    public void explicitlyActivate(List<String> profileIds) {
+        for (String profileId1 : profileIds) {
+            explicitlyActivate(profileId1);
         }
     }
 
     /* (non-Javadoc)
-    * @see org.apache.maven.profiles.ProfileManager#explicitlyDeactivate(java.lang.String)
-    */
-    public void explicitlyDeactivate( String profileId )
-    {
-        if ( !deactivatedIds.contains( profileId ) )
-        {
-            logger.debug( "Profile with id: '" + profileId + "' has been explicitly deactivated." );
+     * @see org.apache.maven.profiles.ProfileManager#explicitlyDeactivate(java.lang.String)
+     */
+    public void explicitlyDeactivate(String profileId) {
+        if (!deactivatedIds.contains(profileId)) {
+            logger.debug("Profile with id: '" + profileId + "' has been explicitly deactivated.");
 
-            deactivatedIds.add( profileId );
+            deactivatedIds.add(profileId);
         }
     }
 
     /* (non-Javadoc)
-    * @see org.apache.maven.profiles.ProfileManager#explicitlyDeactivate(java.util.List)
-    */
-    public void explicitlyDeactivate( List<String> profileIds )
-    {
-        for ( String profileId1 : profileIds )
-        {
-            explicitlyDeactivate( profileId1 );
+     * @see org.apache.maven.profiles.ProfileManager#explicitlyDeactivate(java.util.List)
+     */
+    public void explicitlyDeactivate(List<String> profileIds) {
+        for (String profileId1 : profileIds) {
+            explicitlyDeactivate(profileId1);
         }
     }
 
     /* (non-Javadoc)
-    * @see org.apache.maven.profiles.ProfileManager#getActiveProfiles()
-    */
-    public List getActiveProfiles()
-        throws ProfileActivationException
-    {
+     * @see org.apache.maven.profiles.ProfileManager#getActiveProfiles()
+     */
+    public List getActiveProfiles() throws ProfileActivationException {
         DefaultProfileActivationContext context = new DefaultProfileActivationContext();
-        context.setActiveProfileIds( activatedIds );
-        context.setInactiveProfileIds( deactivatedIds );
-        context.setSystemProperties( System.getProperties() );
-        context.setUserProperties( requestProperties );
+        context.setActiveProfileIds(activatedIds);
+        context.setInactiveProfileIds(deactivatedIds);
+        context.setSystemProperties(System.getProperties());
+        context.setUserProperties(requestProperties);
 
         final List<ProfileActivationException> errors = new ArrayList<>();
 
-        List<Profile> profiles = profileSelector.getActiveProfiles( profilesById.values(), context, req ->
-        {
-            if ( !ModelProblem.Severity.WARNING.equals( req.getSeverity() ) )
-            {
-                errors.add( new ProfileActivationException( req.getMessage(), req.getException() ) );
+        List<Profile> profiles = profileSelector.getActiveProfiles(profilesById.values(), context, req -> {
+            if (!ModelProblem.Severity.WARNING.equals(req.getSeverity())) {
+                errors.add(new ProfileActivationException(req.getMessage(), req.getException()));
             }
-        } );
+        });
 
-        if ( !errors.isEmpty() )
-        {
-            throw errors.get( 0 );
+        if (!errors.isEmpty()) {
+            throw errors.get(0);
         }
 
         return profiles;
@@ -204,35 +180,27 @@
     /* (non-Javadoc)
      * @see org.apache.maven.profiles.ProfileManager#addProfiles(java.util.List)
      */
-    public void addProfiles( List<Profile> profiles )
-    {
-        for ( Profile profile1 : profiles )
-        {
-            addProfile( profile1 );
+    public void addProfiles(List<Profile> profiles) {
+        for (Profile profile1 : profiles) {
+            addProfile(profile1);
         }
     }
 
-    public void activateAsDefault( String profileId )
-    {
-        if ( !defaultIds.contains( profileId ) )
-        {
-            defaultIds.add( profileId );
+    public void activateAsDefault(String profileId) {
+        if (!defaultIds.contains(profileId)) {
+            defaultIds.add(profileId);
         }
     }
 
-    public List<String> getExplicitlyActivatedIds()
-    {
+    public List<String> getExplicitlyActivatedIds() {
         return activatedIds;
     }
 
-    public List<String>  getExplicitlyDeactivatedIds()
-    {
+    public List<String> getExplicitlyDeactivatedIds() {
         return deactivatedIds;
     }
 
-    public List getIdsActivatedByDefault()
-    {
+    public List getIdsActivatedByDefault() {
         return defaultIds;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/MavenProfilesBuilder.java b/maven-compat/src/main/java/org/apache/maven/profiles/MavenProfilesBuilder.java
deleted file mode 100644
index 32fb6aa..0000000
--- a/maven-compat/src/main/java/org/apache/maven/profiles/MavenProfilesBuilder.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.apache.maven.profiles;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * @author jdcasey
- */
-@Deprecated
-public interface MavenProfilesBuilder
-{
-    String ROLE = MavenProfilesBuilder.class.getName();
-
-    ProfilesRoot buildProfiles( File basedir )
-        throws IOException, XmlPullParserException;
-}
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/ProfileManager.java b/maven-compat/src/main/java/org/apache/maven/profiles/ProfileManager.java
index 5fab100..3781be1 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/ProfileManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/ProfileManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,35 +16,34 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.model.Profile;
-import org.apache.maven.profiles.activation.ProfileActivationException;
+package org.apache.maven.profiles;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
+import org.apache.maven.model.Profile;
+import org.apache.maven.profiles.activation.ProfileActivationException;
+
 /**
  * ProfileManager
  */
 @Deprecated
-public interface ProfileManager
-{
+public interface ProfileManager {
 
-    void addProfile( Profile profile );
+    void addProfile(Profile profile);
 
-    void explicitlyActivate( String profileId );
+    void explicitlyActivate(String profileId);
 
-    void explicitlyActivate( List<String> profileIds );
+    void explicitlyActivate(List<String> profileIds);
 
-    void explicitlyDeactivate( String profileId );
+    void explicitlyDeactivate(String profileId);
 
-    void explicitlyDeactivate( List<String> profileIds );
+    void explicitlyDeactivate(List<String> profileIds);
 
-    List getActiveProfiles()
-        throws ProfileActivationException;
+    List getActiveProfiles() throws ProfileActivationException;
 
-    void addProfiles( List<Profile> profiles );
+    void addProfiles(List<Profile> profiles);
 
     Map getProfilesById();
 
@@ -57,5 +54,4 @@
     List getIdsActivatedByDefault();
 
     Properties getRequestProperties();
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/ProfilesConversionUtils.java b/maven-compat/src/main/java/org/apache/maven/profiles/ProfilesConversionUtils.java
index 154176e..e0e77d2 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/ProfilesConversionUtils.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/ProfilesConversionUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles;
+
+import java.util.List;
 
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.ActivationFile;
@@ -25,130 +26,110 @@
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.Repository;
 
-import java.util.List;
-
 /**
  * ProfilesConversionUtils
  */
 @Deprecated
-public class ProfilesConversionUtils
-{
-    private ProfilesConversionUtils()
-    {
-    }
+public class ProfilesConversionUtils {
+    private ProfilesConversionUtils() {}
 
-    public static Profile convertFromProfileXmlProfile( org.apache.maven.profiles.Profile profileXmlProfile )
-    {
+    public static Profile convertFromProfileXmlProfile(org.apache.maven.profiles.Profile profileXmlProfile) {
         Profile profile = new Profile();
 
-        profile.setId( profileXmlProfile.getId() );
+        profile.setId(profileXmlProfile.getId());
 
-        profile.setSource( "profiles.xml" );
+        profile.setSource("profiles.xml");
 
         org.apache.maven.profiles.Activation profileActivation = profileXmlProfile.getActivation();
 
-        if ( profileActivation != null )
-        {
+        if (profileActivation != null) {
             Activation activation = new Activation();
 
-            activation.setActiveByDefault( profileActivation.isActiveByDefault() );
+            activation.setActiveByDefault(profileActivation.isActiveByDefault());
 
-            activation.setJdk( profileActivation.getJdk() );
+            activation.setJdk(profileActivation.getJdk());
 
             org.apache.maven.profiles.ActivationProperty profileProp = profileActivation.getProperty();
 
-            if ( profileProp != null )
-            {
+            if (profileProp != null) {
                 ActivationProperty prop = new ActivationProperty();
 
-                prop.setName( profileProp.getName() );
-                prop.setValue( profileProp.getValue() );
+                prop.setName(profileProp.getName());
+                prop.setValue(profileProp.getValue());
 
-                activation.setProperty( prop );
+                activation.setProperty(prop);
             }
 
-
             ActivationOS profileOs = profileActivation.getOs();
 
-            if ( profileOs != null )
-            {
+            if (profileOs != null) {
                 org.apache.maven.model.ActivationOS os = new org.apache.maven.model.ActivationOS();
 
-                os.setArch( profileOs.getArch() );
-                os.setFamily( profileOs.getFamily() );
-                os.setName( profileOs.getName() );
-                os.setVersion( profileOs.getVersion() );
+                os.setArch(profileOs.getArch());
+                os.setFamily(profileOs.getFamily());
+                os.setName(profileOs.getName());
+                os.setVersion(profileOs.getVersion());
 
-                activation.setOs( os );
+                activation.setOs(os);
             }
 
             org.apache.maven.profiles.ActivationFile profileFile = profileActivation.getFile();
 
-            if ( profileFile != null )
-            {
+            if (profileFile != null) {
                 ActivationFile file = new ActivationFile();
 
-                file.setExists( profileFile.getExists() );
-                file.setMissing( profileFile.getMissing() );
+                file.setExists(profileFile.getExists());
+                file.setMissing(profileFile.getMissing());
 
-                activation.setFile( file );
+                activation.setFile(file);
             }
 
-            profile.setActivation( activation );
+            profile.setActivation(activation);
         }
 
-        profile.setProperties( profileXmlProfile.getProperties() );
+        profile.setProperties(profileXmlProfile.getProperties());
 
         List repos = profileXmlProfile.getRepositories();
-        if ( repos != null )
-        {
-            for ( Object repo : repos )
-            {
-                profile.addRepository( convertFromProfileXmlRepository( (org.apache.maven.profiles.Repository) repo ) );
+        if (repos != null) {
+            for (Object repo : repos) {
+                profile.addRepository(convertFromProfileXmlRepository((org.apache.maven.profiles.Repository) repo));
             }
         }
 
         List pluginRepos = profileXmlProfile.getPluginRepositories();
-        if ( pluginRepos != null )
-        {
-            for ( Object pluginRepo : pluginRepos )
-            {
+        if (pluginRepos != null) {
+            for (Object pluginRepo : pluginRepos) {
                 profile.addPluginRepository(
-                    convertFromProfileXmlRepository( (org.apache.maven.profiles.Repository) pluginRepo ) );
+                        convertFromProfileXmlRepository((org.apache.maven.profiles.Repository) pluginRepo));
             }
         }
 
         return profile;
     }
 
-    private static Repository convertFromProfileXmlRepository( org.apache.maven.profiles.Repository profileXmlRepo )
-    {
+    private static Repository convertFromProfileXmlRepository(org.apache.maven.profiles.Repository profileXmlRepo) {
         Repository repo = new Repository();
 
-        repo.setId( profileXmlRepo.getId() );
-        repo.setLayout( profileXmlRepo.getLayout() );
-        repo.setName( profileXmlRepo.getName() );
-        repo.setUrl( profileXmlRepo.getUrl() );
+        repo.setId(profileXmlRepo.getId());
+        repo.setLayout(profileXmlRepo.getLayout());
+        repo.setName(profileXmlRepo.getName());
+        repo.setUrl(profileXmlRepo.getUrl());
 
-        if ( profileXmlRepo.getSnapshots() != null )
-        {
-            repo.setSnapshots( convertRepositoryPolicy( profileXmlRepo.getSnapshots() ) );
+        if (profileXmlRepo.getSnapshots() != null) {
+            repo.setSnapshots(convertRepositoryPolicy(profileXmlRepo.getSnapshots()));
         }
-        if ( profileXmlRepo.getReleases() != null )
-        {
-            repo.setReleases( convertRepositoryPolicy( profileXmlRepo.getReleases() ) );
+        if (profileXmlRepo.getReleases() != null) {
+            repo.setReleases(convertRepositoryPolicy(profileXmlRepo.getReleases()));
         }
 
         return repo;
     }
 
-    private static org.apache.maven.model.RepositoryPolicy convertRepositoryPolicy( RepositoryPolicy profileXmlRepo )
-    {
+    private static org.apache.maven.model.RepositoryPolicy convertRepositoryPolicy(RepositoryPolicy profileXmlRepo) {
         org.apache.maven.model.RepositoryPolicy policy = new org.apache.maven.model.RepositoryPolicy();
-        policy.setEnabled( profileXmlRepo.isEnabled() );
-        policy.setUpdatePolicy( profileXmlRepo.getUpdatePolicy() );
-        policy.setChecksumPolicy( profileXmlRepo.getChecksumPolicy() );
+        policy.setEnabled(profileXmlRepo.isEnabled());
+        policy.setUpdatePolicy(profileXmlRepo.getUpdatePolicy());
+        policy.setChecksumPolicy(profileXmlRepo.getChecksumPolicy());
         return policy;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/DetectedProfileActivator.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/DetectedProfileActivator.java
index f034245..ee023ff 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/DetectedProfileActivator.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/DetectedProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.activation;
 
 import org.apache.maven.model.Profile;
 
@@ -25,14 +24,10 @@
  * DetectedProfileActivator
  */
 @Deprecated
-public abstract class DetectedProfileActivator
-    implements ProfileActivator
-{
-    public boolean canDetermineActivation( Profile profile )
-    {
-        return canDetectActivation( profile );
+public abstract class DetectedProfileActivator implements ProfileActivator {
+    public boolean canDetermineActivation(Profile profile) {
+        return canDetectActivation(profile);
     }
 
-    protected abstract boolean canDetectActivation( Profile profile );
-
+    protected abstract boolean canDetectActivation(Profile profile);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/FileProfileActivator.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/FileProfileActivator.java
index 586f57f..081ff5f 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/FileProfileActivator.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/FileProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,7 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.activation;
 
+import java.io.File;
 import java.io.IOException;
 
 import org.apache.maven.model.Activation;
@@ -30,74 +30,56 @@
 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
 import org.codehaus.plexus.logging.LogEnabled;
 import org.codehaus.plexus.logging.Logger;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * FileProfileActivator
  */
 @Deprecated
-public class FileProfileActivator
-    extends DetectedProfileActivator
-    implements LogEnabled
-{
+public class FileProfileActivator extends DetectedProfileActivator implements LogEnabled {
     private Logger logger;
 
-    protected boolean canDetectActivation( Profile profile )
-    {
+    protected boolean canDetectActivation(Profile profile) {
         return profile.getActivation() != null && profile.getActivation().getFile() != null;
     }
 
-    public boolean isActive( Profile profile )
-    {
+    public boolean isActive(Profile profile) {
         Activation activation = profile.getActivation();
 
         ActivationFile actFile = activation.getFile();
 
-        if ( actFile != null )
-        {
+        if (actFile != null) {
             // check if the file exists, if it does then the profile will be active
             String fileString = actFile.getExists();
 
             RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
-            try
-            {
-                interpolator.addValueSource( new EnvarBasedValueSource() );
-            }
-            catch ( IOException e )
-            {
+            try {
+                interpolator.addValueSource(new EnvarBasedValueSource());
+            } catch (IOException e) {
                 // ignored
             }
-            interpolator.addValueSource( new MapBasedValueSource( System.getProperties() ) );
+            interpolator.addValueSource(new MapBasedValueSource(System.getProperties()));
 
-            try
-            {
-                if ( StringUtils.isNotEmpty( fileString ) )
-                {
-                    fileString = StringUtils.replace( interpolator.interpolate( fileString, "" ), "\\", "/" );
-                    return FileUtils.fileExists( fileString );
+            try {
+                if (fileString != null && !fileString.isEmpty()) {
+                    fileString = interpolator.interpolate(fileString, "").replace("\\", "/");
+                    File file = new File(fileString);
+                    return file.exists();
                 }
 
                 // check if the file is missing, if it is then the profile will be active
                 fileString = actFile.getMissing();
 
-                if ( StringUtils.isNotEmpty( fileString ) )
-                {
-                    fileString = StringUtils.replace( interpolator.interpolate( fileString, "" ), "\\", "/" );
-                    return !FileUtils.fileExists( fileString );
+                if (fileString != null && !fileString.isEmpty()) {
+                    fileString = interpolator.interpolate(fileString, "").replace("\\", "/");
+                    File file = new File(fileString);
+                    return !file.exists();
                 }
-            }
-            catch ( InterpolationException e )
-            {
-                if ( logger.isDebugEnabled() )
-                {
-                    logger.debug( "Failed to interpolate missing file location for profile activator: " + fileString,
-                                  e );
-                }
-                else
-                {
-                    logger.warn( "Failed to interpolate missing file location for profile activator: " + fileString
-                        + ", enable verbose output (-X) for more details" );
+            } catch (InterpolationException e) {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("Failed to interpolate missing file location for profile activator: " + fileString, e);
+                } else {
+                    logger.warn("Failed to interpolate missing file location for profile activator: " + fileString
+                            + ", enable verbose output (-X) for more details");
                 }
             }
         }
@@ -105,8 +87,7 @@
         return false;
     }
 
-    public void enableLogging( Logger logger )
-    {
+    public void enableLogging(Logger logger) {
         this.logger = logger;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java
index 1c835f8..4e18159 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/JdkPrefixProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,83 +16,67 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.activation;
 
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 import org.apache.maven.artifact.versioning.VersionRange;
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.Profile;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * JdkPrefixProfileActivator
  */
 @Deprecated
-public class JdkPrefixProfileActivator
-    extends DetectedProfileActivator
-{
-    private static final String JDK_VERSION = System.getProperty( "java.version" );
+public class JdkPrefixProfileActivator extends DetectedProfileActivator {
+    private static final String JDK_VERSION = System.getProperty("java.version");
 
-    public boolean isActive( Profile profile )
-        throws ProfileActivationException
-    {
+    public boolean isActive(Profile profile) throws ProfileActivationException {
         Activation activation = profile.getActivation();
 
         String jdk = activation.getJdk();
 
         // null case is covered by canDetermineActivation(), so we can do a straight startsWith() here.
-        if ( jdk.startsWith( "[" ) || jdk.startsWith( "(" ) )
-        {
-            try
-            {
-                return matchJdkVersionRange( jdk );
-            }
-            catch ( InvalidVersionSpecificationException e )
-            {
-                throw new ProfileActivationException( "Invalid JDK version in profile '" + profile.getId() + "': "
-                    + e.getMessage() );
+        if (jdk.startsWith("[") || jdk.startsWith("(")) {
+            try {
+                return matchJdkVersionRange(jdk);
+            } catch (InvalidVersionSpecificationException e) {
+                throw new ProfileActivationException(
+                        "Invalid JDK version in profile '" + profile.getId() + "': " + e.getMessage());
             }
         }
 
         boolean reverse = false;
 
-        if ( jdk.startsWith( "!" ) )
-        {
+        if (jdk.startsWith("!")) {
             reverse = true;
-            jdk = jdk.substring( 1 );
+            jdk = jdk.substring(1);
         }
 
-        if ( getJdkVersion().startsWith( jdk ) )
-        {
+        if (getJdkVersion().startsWith(jdk)) {
             return !reverse;
-        }
-        else
-        {
+        } else {
             return reverse;
         }
     }
 
-    private boolean matchJdkVersionRange( String jdk )
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange jdkVersionRange = VersionRange.createFromVersionSpec( convertJdkToMavenVersion( jdk ) );
-        DefaultArtifactVersion jdkVersion = new DefaultArtifactVersion( convertJdkToMavenVersion( getJdkVersion() ) );
-        return jdkVersionRange.containsVersion( jdkVersion );
+    private boolean matchJdkVersionRange(String jdk) throws InvalidVersionSpecificationException {
+        VersionRange jdkVersionRange = VersionRange.createFromVersionSpec(convertJdkToMavenVersion(jdk));
+        DefaultArtifactVersion jdkVersion = new DefaultArtifactVersion(convertJdkToMavenVersion(getJdkVersion()));
+        return jdkVersionRange.containsVersion(jdkVersion);
     }
 
-    private String convertJdkToMavenVersion( String jdk )
-    {
-        return jdk.replaceAll( "_", "-" );
+    private String convertJdkToMavenVersion(String jdk) {
+        return jdk.replace("_", "-");
     }
 
-    protected String getJdkVersion()
-    {
+    protected String getJdkVersion() {
         return JDK_VERSION;
     }
 
-    protected boolean canDetectActivation( Profile profile )
-    {
-        return profile.getActivation() != null && StringUtils.isNotEmpty( profile.getActivation().getJdk() );
+    protected boolean canDetectActivation(Profile profile) {
+        return profile.getActivation() != null
+                && profile.getActivation().getJdk() != null
+                && !profile.getActivation().getJdk().isEmpty();
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/OperatingSystemProfileActivator.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/OperatingSystemProfileActivator.java
index 378c3c9..0a33cdc 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/OperatingSystemProfileActivator.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/OperatingSystemProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,147 +16,118 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.activation;
 
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.ActivationOS;
 import org.apache.maven.model.Profile;
-import org.codehaus.plexus.util.Os;
+import org.apache.maven.utils.Os;
 
 /**
  * OperatingSystemProfileActivator
  */
 @Deprecated
-public class OperatingSystemProfileActivator
-    implements ProfileActivator
-{
+public class OperatingSystemProfileActivator implements ProfileActivator {
 
-    public boolean canDetermineActivation( Profile profile )
-    {
+    public boolean canDetermineActivation(Profile profile) {
         Activation activation = profile.getActivation();
         return activation != null && activation.getOs() != null;
     }
 
-    public boolean isActive( Profile profile )
-    {
+    public boolean isActive(Profile profile) {
         Activation activation = profile.getActivation();
         ActivationOS os = activation.getOs();
 
-        boolean result = ensureAtLeastOneNonNull( os );
+        boolean result = ensureAtLeastOneNonNull(os);
 
-        if ( result && os.getFamily() != null )
-        {
-            result = determineFamilyMatch( os.getFamily() );
+        if (result && os.getFamily() != null) {
+            result = determineFamilyMatch(os.getFamily());
         }
-        if ( result && os.getName() != null )
-        {
-            result = determineNameMatch( os.getName() );
+        if (result && os.getName() != null) {
+            result = determineNameMatch(os.getName());
         }
-        if ( result && os.getArch() != null )
-        {
-            result = determineArchMatch( os.getArch() );
+        if (result && os.getArch() != null) {
+            result = determineArchMatch(os.getArch());
         }
-        if ( result && os.getVersion() != null )
-        {
-            result = determineVersionMatch( os.getVersion() );
+        if (result && os.getVersion() != null) {
+            result = determineVersionMatch(os.getVersion());
         }
         return result;
     }
 
-    private boolean ensureAtLeastOneNonNull( ActivationOS os )
-    {
+    private boolean ensureAtLeastOneNonNull(ActivationOS os) {
         return os.getArch() != null || os.getFamily() != null || os.getName() != null || os.getVersion() != null;
     }
 
-    private boolean determineVersionMatch( String version )
-    {
+    private boolean determineVersionMatch(String version) {
         String test = version;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isVersion( test );
+        boolean result = Os.OS_VERSION.equals(test);
 
-        if ( reverse )
-        {
+        if (reverse) {
             return !result;
-        }
-        else
-        {
+        } else {
             return result;
         }
     }
 
-    private boolean determineArchMatch( String arch )
-    {
+    private boolean determineArchMatch(String arch) {
         String test = arch;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isArch( test );
+        boolean result = Os.OS_ARCH.equals(test);
 
-        if ( reverse )
-        {
+        if (reverse) {
             return !result;
-        }
-        else
-        {
+        } else {
             return result;
         }
     }
 
-    private boolean determineNameMatch( String name )
-    {
+    private boolean determineNameMatch(String name) {
         String test = name;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isName( test );
+        boolean result = Os.OS_NAME.equals(test);
 
-        if ( reverse )
-        {
+        if (reverse) {
             return !result;
-        }
-        else
-        {
+        } else {
             return result;
         }
     }
 
-    private boolean determineFamilyMatch( String family )
-    {
+    private boolean determineFamilyMatch(String family) {
         String test = family;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isFamily( test );
+        boolean result = Os.isFamily(test);
 
-        if ( reverse )
-        {
+        if (reverse) {
             return !result;
-        }
-        else
-        {
+        } else {
             return result;
         }
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivationException.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivationException.java
index 59f70be..5215d9e 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivationException.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,25 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.activation;
 
 /**
  * ProfileActivationException
  */
 @Deprecated
-public class ProfileActivationException
-    extends Exception
-{
+public class ProfileActivationException extends Exception {
 
     private static final long serialVersionUID = -90820222109103638L;
 
-    public ProfileActivationException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public ProfileActivationException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public ProfileActivationException( String message )
-    {
-        super( message );
+    public ProfileActivationException(String message) {
+        super(message);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivator.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivator.java
index 6482018..fc8a6e7 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivator.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/ProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.activation;
 
 import org.apache.maven.model.Profile;
 
@@ -25,14 +24,11 @@
  * ProfileActivator
  */
 @Deprecated
-public interface ProfileActivator
-{
+public interface ProfileActivator {
 
     String ROLE = ProfileActivator.class.getName();
 
-    boolean canDetermineActivation( Profile profile );
+    boolean canDetermineActivation(Profile profile);
 
-    boolean isActive( Profile profile )
-        throws ProfileActivationException;
-
+    boolean isActive(Profile profile) throws ProfileActivationException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/profiles/activation/SystemPropertyProfileActivator.java b/maven-compat/src/main/java/org/apache/maven/profiles/activation/SystemPropertyProfileActivator.java
index d7e4003..59d65d3 100644
--- a/maven-compat/src/main/java/org/apache/maven/profiles/activation/SystemPropertyProfileActivator.java
+++ b/maven-compat/src/main/java/org/apache/maven/profiles/activation/SystemPropertyProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,94 +16,75 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.activation;
 
 import java.util.Properties;
+
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.ActivationProperty;
 import org.apache.maven.model.Profile;
 import org.codehaus.plexus.context.Context;
 import org.codehaus.plexus.context.ContextException;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * SystemPropertyProfileActivator
  */
 @Deprecated
-public class SystemPropertyProfileActivator
-    extends DetectedProfileActivator implements Contextualizable
-{
+public class SystemPropertyProfileActivator extends DetectedProfileActivator implements Contextualizable {
     private Properties properties;
 
-    public void contextualize( Context context )
-        throws ContextException
-    {
-        properties = (Properties) context.get( "SystemProperties" );
+    public void contextualize(Context context) throws ContextException {
+        properties = (Properties) context.get("SystemProperties");
     }
 
-    protected boolean canDetectActivation( Profile profile )
-    {
+    protected boolean canDetectActivation(Profile profile) {
         return profile.getActivation() != null && profile.getActivation().getProperty() != null;
     }
 
-    public boolean isActive( Profile profile )
-        throws ProfileActivationException
-    {
+    public boolean isActive(Profile profile) throws ProfileActivationException {
         Activation activation = profile.getActivation();
 
         ActivationProperty property = activation.getProperty();
 
-        if ( property != null )
-        {
+        if (property != null) {
             String name = property.getName();
             boolean reverseName = false;
 
-            if ( name == null )
-            {
-                throw new ProfileActivationException( "The property name is required to activate the profile '"
-                    + profile.getId() + "'" );
+            if (name == null) {
+                throw new ProfileActivationException(
+                        "The property name is required to activate the profile '" + profile.getId() + "'");
             }
 
-            if ( name.startsWith( "!" ) )
-            {
+            if (name.startsWith("!")) {
                 reverseName = true;
-                name = name.substring( 1 );
+                name = name.substring(1);
             }
 
-            String sysValue = properties.getProperty( name );
+            String sysValue = properties.getProperty(name);
 
             String propValue = property.getValue();
-            if ( StringUtils.isNotEmpty( propValue ) )
-            {
+            if (propValue != null && !propValue.isEmpty()) {
                 boolean reverseValue = false;
-                if ( propValue.startsWith( "!" ) )
-                {
+                if (propValue.startsWith("!")) {
                     reverseValue = true;
-                    propValue = propValue.substring( 1 );
+                    propValue = propValue.substring(1);
                 }
 
                 // we have a value, so it has to match the system value...
-                boolean result = propValue.equals( sysValue );
+                boolean result = propValue.equals(sysValue);
 
-                if ( reverseValue )
-                {
+                if (reverseValue) {
                     return !result;
-                }
-                else
-                {
+                } else {
                     return result;
                 }
-            }
-            else
-            {
-                boolean result = StringUtils.isNotEmpty( sysValue );
+            } else {
+                boolean result = sysValue != null && !sysValue.isEmpty();
 
-                if ( reverseName )
-                {
+                if (reverseName) {
                     return !result;
-                }
-                else
-                {
+                } else {
                     return result;
                 }
             }
@@ -113,5 +92,4 @@
 
         return false;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java b/maven-compat/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java
index 7bc5a5c..e2d6928 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/DefaultMavenProjectBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -42,50 +45,43 @@
 import org.apache.maven.properties.internal.EnvironmentUtils;
 import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.wagon.events.TransferListener;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 
 /**
  */
-@Component( role = MavenProjectBuilder.class )
 @Deprecated
-public class DefaultMavenProjectBuilder
-    implements MavenProjectBuilder
-{
+@Named
+@Singleton
+public class DefaultMavenProjectBuilder implements MavenProjectBuilder {
 
-    @Requirement
+    @Inject
     private ProjectBuilder projectBuilder;
 
-    @Requirement
+    @Inject
     private RepositorySystem repositorySystem;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
     // ----------------------------------------------------------------------
     // MavenProjectBuilder Implementation
     // ----------------------------------------------------------------------
 
-    private ProjectBuildingRequest toRequest( ProjectBuilderConfiguration configuration )
-    {
+    private ProjectBuildingRequest toRequest(ProjectBuilderConfiguration configuration) {
         DefaultProjectBuildingRequest request = new DefaultProjectBuildingRequest();
 
-        request.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 );
-        request.setResolveDependencies( false );
+        request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0);
+        request.setResolveDependencies(false);
 
-        request.setLocalRepository( configuration.getLocalRepository() );
-        request.setBuildStartTime( configuration.getBuildStartTime() );
-        request.setUserProperties( configuration.getUserProperties() );
-        request.setSystemProperties( configuration.getExecutionProperties() );
+        request.setLocalRepository(configuration.getLocalRepository());
+        request.setBuildStartTime(configuration.getBuildStartTime());
+        request.setUserProperties(configuration.getUserProperties());
+        request.setSystemProperties(configuration.getExecutionProperties());
 
         ProfileManager profileManager = configuration.getGlobalProfileManager();
-        if ( profileManager != null )
-        {
-            request.setActiveProfileIds( profileManager.getExplicitlyActivatedIds() );
-            request.setInactiveProfileIds( profileManager.getExplicitlyDeactivatedIds() );
-        }
-        else
-        {
+        if (profileManager != null) {
+            request.setActiveProfileIds(profileManager.getExplicitlyActivatedIds());
+            request.setInactiveProfileIds(profileManager.getExplicitlyDeactivatedIds());
+        } else {
             /*
              * MNG-4900: Hack to workaround deficiency of legacy API which makes it impossible for plugins to access the
              * global profile manager which is required to build a POM like a CLI invocation does. Failure to consider
@@ -94,13 +90,11 @@
              * based on the configured remote repos.
              */
             MavenSession session = legacySupport.getSession();
-            if ( session != null )
-            {
+            if (session != null) {
                 MavenExecutionRequest req = session.getRequest();
-                if ( req != null )
-                {
-                    request.setActiveProfileIds( req.getActiveProfiles() );
-                    request.setInactiveProfileIds( req.getInactiveProfiles() );
+                if (req != null) {
+                    request.setActiveProfileIds(req.getActiveProfiles());
+                    request.setInactiveProfileIds(req.getInactiveProfiles());
                 }
             }
         }
@@ -108,77 +102,60 @@
         return request;
     }
 
-    private ProjectBuildingRequest injectSession( ProjectBuildingRequest request )
-    {
+    private ProjectBuildingRequest injectSession(ProjectBuildingRequest request) {
         MavenSession session = legacySupport.getSession();
-        if ( session != null )
-        {
-            request.setRepositorySession( session.getRepositorySession() );
-            request.setSystemProperties( session.getSystemProperties() );
-            if ( request.getUserProperties().isEmpty() )
-            {
-                request.setUserProperties( session.getUserProperties() );
+        if (session != null) {
+            request.setRepositorySession(session.getRepositorySession());
+            request.setSystemProperties(session.getSystemProperties());
+            if (request.getUserProperties().isEmpty()) {
+                request.setUserProperties(session.getUserProperties());
             }
 
             MavenExecutionRequest req = session.getRequest();
-            if ( req != null )
-            {
-                request.setRemoteRepositories( req.getRemoteRepositories() );
+            if (req != null) {
+                request.setRemoteRepositories(req.getRemoteRepositories());
             }
-        }
-        else
-        {
+        } else {
             Properties props = new Properties();
-            EnvironmentUtils.addEnvVars( props );
-            props.putAll( System.getProperties() );
-            request.setSystemProperties( props );
+            EnvironmentUtils.addEnvVars(props);
+            props.putAll(System.getProperties());
+            request.setSystemProperties(props);
         }
 
         return request;
     }
 
-    @SuppressWarnings( "unchecked" )
-    private List<ArtifactRepository> normalizeToArtifactRepositories( List<?> repositories,
-                                                                      ProjectBuildingRequest request )
-        throws ProjectBuildingException
-    {
+    @SuppressWarnings("unchecked")
+    private List<ArtifactRepository> normalizeToArtifactRepositories(
+            List<?> repositories, ProjectBuildingRequest request) throws ProjectBuildingException {
         /*
          * This provides backward-compat with 2.x that allowed plugins like the maven-remote-resources-plugin:1.0 to
          * populate the builder configuration with model repositories instead of artifact repositories.
          */
 
-        if ( repositories != null )
-        {
+        if (repositories != null) {
             boolean normalized = false;
 
-            List<ArtifactRepository> repos = new ArrayList<>( repositories.size() );
+            List<ArtifactRepository> repos = new ArrayList<>(repositories.size());
 
-            for ( Object repository : repositories )
-            {
-                if ( repository instanceof Repository )
-                {
-                    try
-                    {
-                        ArtifactRepository repo = repositorySystem.buildArtifactRepository( (Repository) repository );
-                        repositorySystem.injectMirror( request.getRepositorySession(), Arrays.asList( repo ) );
-                        repositorySystem.injectProxy( request.getRepositorySession(), Arrays.asList( repo ) );
-                        repositorySystem.injectAuthentication( request.getRepositorySession(), Arrays.asList( repo ) );
-                        repos.add( repo );
-                    }
-                    catch ( InvalidRepositoryException e )
-                    {
-                        throw new ProjectBuildingException( "", "Invalid remote repository " + repository, e );
+            for (Object repository : repositories) {
+                if (repository instanceof Repository) {
+                    try {
+                        ArtifactRepository repo = repositorySystem.buildArtifactRepository((Repository) repository);
+                        repositorySystem.injectMirror(request.getRepositorySession(), Arrays.asList(repo));
+                        repositorySystem.injectProxy(request.getRepositorySession(), Arrays.asList(repo));
+                        repositorySystem.injectAuthentication(request.getRepositorySession(), Arrays.asList(repo));
+                        repos.add(repo);
+                    } catch (InvalidRepositoryException e) {
+                        throw new ProjectBuildingException("", "Invalid remote repository " + repository, e);
                     }
                     normalized = true;
-                }
-                else
-                {
-                    repos.add( (ArtifactRepository) repository );
+                } else {
+                    repos.add((ArtifactRepository) repository);
                 }
             }
 
-            if ( normalized )
-            {
+            if (normalized) {
                 return repos;
             }
         }
@@ -186,139 +163,125 @@
         return (List<ArtifactRepository>) repositories;
     }
 
-    private ProjectBuildingException transformError( ProjectBuildingException e )
-    {
-        if ( e.getCause() instanceof ModelBuildingException )
-        {
-            return new InvalidProjectModelException( e.getProjectId(), e.getMessage(), e.getPomFile() );
+    private ProjectBuildingException transformError(ProjectBuildingException e) {
+        if (e.getCause() instanceof ModelBuildingException) {
+            return new InvalidProjectModelException(e.getProjectId(), e.getMessage(), e.getPomFile());
         }
 
         return e;
     }
 
-    public MavenProject build( File pom, ProjectBuilderConfiguration configuration )
-        throws ProjectBuildingException
-    {
-        ProjectBuildingRequest request = injectSession( toRequest( configuration ) );
+    public MavenProject build(File pom, ProjectBuilderConfiguration configuration) throws ProjectBuildingException {
+        ProjectBuildingRequest request = injectSession(toRequest(configuration));
 
-        try
-        {
-            return projectBuilder.build( pom, request ).getProject();
-        }
-        catch ( ProjectBuildingException e )
-        {
-            throw transformError( e );
+        try {
+            return projectBuilder.build(pom, request).getProject();
+        } catch (ProjectBuildingException e) {
+            throw transformError(e);
         }
     }
 
     // This is used by the SITE plugin.
-    public MavenProject build( File pom, ArtifactRepository localRepository, ProfileManager profileManager )
-        throws ProjectBuildingException
-    {
+    public MavenProject build(File pom, ArtifactRepository localRepository, ProfileManager profileManager)
+            throws ProjectBuildingException {
         ProjectBuilderConfiguration configuration = new DefaultProjectBuilderConfiguration();
-        configuration.setLocalRepository( localRepository );
-        configuration.setGlobalProfileManager( profileManager );
+        configuration.setLocalRepository(localRepository);
+        configuration.setGlobalProfileManager(profileManager);
 
-        return build( pom, configuration );
+        return build(pom, configuration);
     }
 
-    public MavenProject buildFromRepository( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                             ProjectBuilderConfiguration configuration, boolean allowStubModel )
-        throws ProjectBuildingException
-    {
-        ProjectBuildingRequest request = injectSession( toRequest( configuration ) );
-        request.setRemoteRepositories( normalizeToArtifactRepositories( remoteRepositories, request ) );
-        request.setProcessPlugins( false );
-        request.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
+    public MavenProject buildFromRepository(
+            Artifact artifact,
+            List<ArtifactRepository> remoteRepositories,
+            ProjectBuilderConfiguration configuration,
+            boolean allowStubModel)
+            throws ProjectBuildingException {
+        ProjectBuildingRequest request = injectSession(toRequest(configuration));
+        request.setRemoteRepositories(normalizeToArtifactRepositories(remoteRepositories, request));
+        request.setProcessPlugins(false);
+        request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
 
-        try
-        {
-            return projectBuilder.build( artifact, allowStubModel, request ).getProject();
-        }
-        catch ( ProjectBuildingException e )
-        {
-            throw transformError( e );
+        try {
+            return projectBuilder.build(artifact, allowStubModel, request).getProject();
+        } catch (ProjectBuildingException e) {
+            throw transformError(e);
         }
     }
 
-    public MavenProject buildFromRepository( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                             ArtifactRepository localRepository, boolean allowStubModel )
-        throws ProjectBuildingException
-    {
+    public MavenProject buildFromRepository(
+            Artifact artifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            boolean allowStubModel)
+            throws ProjectBuildingException {
         ProjectBuilderConfiguration configuration = new DefaultProjectBuilderConfiguration();
-        configuration.setLocalRepository( localRepository );
+        configuration.setLocalRepository(localRepository);
 
-        return buildFromRepository( artifact, remoteRepositories, configuration, allowStubModel );
+        return buildFromRepository(artifact, remoteRepositories, configuration, allowStubModel);
     }
 
-    public MavenProject buildFromRepository( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                             ArtifactRepository localRepository )
-        throws ProjectBuildingException
-    {
-        return buildFromRepository( artifact, remoteRepositories, localRepository, true );
+    public MavenProject buildFromRepository(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ProjectBuildingException {
+        return buildFromRepository(artifact, remoteRepositories, localRepository, true);
     }
 
     /**
      * This is used for pom-less execution like running archetype:generate. I am taking out the profile handling and the
      * interpolation of the base directory until we spec this out properly.
      */
-    public MavenProject buildStandaloneSuperProject( ProjectBuilderConfiguration configuration )
-        throws ProjectBuildingException
-    {
-        ProjectBuildingRequest request = injectSession( toRequest( configuration ) );
-        request.setProcessPlugins( false );
-        request.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
+    public MavenProject buildStandaloneSuperProject(ProjectBuilderConfiguration configuration)
+            throws ProjectBuildingException {
+        ProjectBuildingRequest request = injectSession(toRequest(configuration));
+        request.setProcessPlugins(false);
+        request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
 
-        ModelSource modelSource = new UrlModelSource( getClass().getResource( "standalone.xml" ) );
+        ModelSource modelSource = new UrlModelSource(getClass().getResource("standalone.xml"));
 
-        MavenProject project = projectBuilder.build( modelSource, request ).getProject();
-        project.setExecutionRoot( true );
+        MavenProject project = projectBuilder.build(modelSource, request).getProject();
+        project.setExecutionRoot(true);
         return project;
     }
 
-    public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository )
-        throws ProjectBuildingException
-    {
-        return buildStandaloneSuperProject( localRepository, null );
+    public MavenProject buildStandaloneSuperProject(ArtifactRepository localRepository)
+            throws ProjectBuildingException {
+        return buildStandaloneSuperProject(localRepository, null);
     }
 
-    public MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository, ProfileManager profileManager )
-        throws ProjectBuildingException
-    {
+    public MavenProject buildStandaloneSuperProject(ArtifactRepository localRepository, ProfileManager profileManager)
+            throws ProjectBuildingException {
         ProjectBuilderConfiguration configuration = new DefaultProjectBuilderConfiguration();
-        configuration.setLocalRepository( localRepository );
-        configuration.setGlobalProfileManager( profileManager );
+        configuration.setLocalRepository(localRepository);
+        configuration.setGlobalProfileManager(profileManager);
 
-        return buildStandaloneSuperProject( configuration );
+        return buildStandaloneSuperProject(configuration);
     }
 
-    public MavenProject buildWithDependencies( File pom, ArtifactRepository localRepository,
-                                               ProfileManager profileManager, TransferListener transferListener )
-        throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
-    {
+    public MavenProject buildWithDependencies(
+            File pom,
+            ArtifactRepository localRepository,
+            ProfileManager profileManager,
+            TransferListener transferListener)
+            throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException {
         ProjectBuilderConfiguration configuration = new DefaultProjectBuilderConfiguration();
-        configuration.setLocalRepository( localRepository );
-        configuration.setGlobalProfileManager( profileManager );
+        configuration.setLocalRepository(localRepository);
+        configuration.setGlobalProfileManager(profileManager);
 
-        ProjectBuildingRequest request = injectSession( toRequest( configuration ) );
+        ProjectBuildingRequest request = injectSession(toRequest(configuration));
 
-        request.setResolveDependencies( true );
+        request.setResolveDependencies(true);
 
-        try
-        {
-            return projectBuilder.build( pom, request ).getProject();
-        }
-        catch ( ProjectBuildingException e )
-        {
-            throw transformError( e );
+        try {
+            return projectBuilder.build(pom, request).getProject();
+        } catch (ProjectBuildingException e) {
+            throw transformError(e);
         }
     }
 
-    public MavenProject buildWithDependencies( File pom, ArtifactRepository localRepository,
-                                               ProfileManager profileManager )
-        throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return buildWithDependencies( pom, localRepository, profileManager, null );
+    public MavenProject buildWithDependencies(
+            File pom, ArtifactRepository localRepository, ProfileManager profileManager)
+            throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException {
+        return buildWithDependencies(pom, localRepository, profileManager, null);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/DefaultProjectBuilderConfiguration.java b/maven-compat/src/main/java/org/apache/maven/project/DefaultProjectBuilderConfiguration.java
index aca6a03..e19fdec 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/DefaultProjectBuilderConfiguration.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/DefaultProjectBuilderConfiguration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.Date;
 import java.util.Properties;
@@ -29,9 +28,7 @@
  * DefaultProjectBuilderConfiguration
  */
 @Deprecated
-public class DefaultProjectBuilderConfiguration
-    implements ProjectBuilderConfiguration
-{
+public class DefaultProjectBuilderConfiguration implements ProjectBuilderConfiguration {
 
     private ProfileManager globalProfileManager;
 
@@ -43,68 +40,54 @@
 
     private Date buildStartTime;
 
-    public DefaultProjectBuilderConfiguration()
-    {
-    }
+    public DefaultProjectBuilderConfiguration() {}
 
-    public ProjectBuilderConfiguration setGlobalProfileManager( ProfileManager globalProfileManager )
-    {
+    public ProjectBuilderConfiguration setGlobalProfileManager(ProfileManager globalProfileManager) {
         this.globalProfileManager = globalProfileManager;
         return this;
     }
 
-    public ProfileManager getGlobalProfileManager()
-    {
+    public ProfileManager getGlobalProfileManager() {
         return globalProfileManager;
     }
 
-    public ProjectBuilderConfiguration setLocalRepository( ArtifactRepository localRepository )
-    {
+    public ProjectBuilderConfiguration setLocalRepository(ArtifactRepository localRepository) {
         this.localRepository = localRepository;
         return this;
     }
 
-    public ArtifactRepository getLocalRepository()
-    {
+    public ArtifactRepository getLocalRepository() {
         return localRepository;
     }
 
-    public ProjectBuilderConfiguration setUserProperties( Properties userProperties )
-    {
+    public ProjectBuilderConfiguration setUserProperties(Properties userProperties) {
         this.userProperties = userProperties;
         return this;
     }
 
-    public Properties getUserProperties()
-    {
-        if ( userProperties == null )
-        {
+    public Properties getUserProperties() {
+        if (userProperties == null) {
             userProperties = new Properties();
         }
 
         return userProperties;
     }
 
-    public Properties getExecutionProperties()
-    {
+    public Properties getExecutionProperties() {
         return executionProperties;
     }
 
-    public ProjectBuilderConfiguration setExecutionProperties( Properties executionProperties )
-    {
+    public ProjectBuilderConfiguration setExecutionProperties(Properties executionProperties) {
         this.executionProperties = executionProperties;
         return this;
     }
 
-    public Date getBuildStartTime()
-    {
+    public Date getBuildStartTime() {
         return buildStartTime;
     }
 
-    public ProjectBuilderConfiguration setBuildStartTime( Date buildStartTime )
-    {
+    public ProjectBuilderConfiguration setBuildStartTime(Date buildStartTime) {
         this.buildStartTime = buildStartTime;
         return this;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/InvalidProjectModelException.java b/maven-compat/src/main/java/org/apache/maven/project/InvalidProjectModelException.java
index d7241fd..1b9e98f 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/InvalidProjectModelException.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/InvalidProjectModelException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 
@@ -27,14 +26,11 @@
  * InvalidProjectModelException
  */
 @Deprecated
-public class InvalidProjectModelException
-    extends ProjectBuildingException
-{
+public class InvalidProjectModelException extends ProjectBuildingException {
     private ModelValidationResult validationResult;
 
-    public InvalidProjectModelException( String projectId, String message, File pomLocation )
-    {
-        super( projectId, message, pomLocation );
+    public InvalidProjectModelException(String projectId, String message, File pomLocation) {
+        super(projectId, message, pomLocation);
     }
 
     /**
@@ -44,16 +40,15 @@
      * @param validationResult
      * @deprecated use {@link File} constructor for pomLocation
      */
-    public InvalidProjectModelException( String projectId, String pomLocation, String message,
-                                         ModelValidationResult validationResult )
-    {
-        this( projectId, message, new File( pomLocation ), validationResult );
+    @Deprecated
+    public InvalidProjectModelException(
+            String projectId, String pomLocation, String message, ModelValidationResult validationResult) {
+        this(projectId, message, new File(pomLocation), validationResult);
     }
 
-    public InvalidProjectModelException( String projectId, String message, File pomFile,
-                                         ModelValidationResult validationResult )
-    {
-        super( projectId, message, pomFile );
+    public InvalidProjectModelException(
+            String projectId, String message, File pomFile, ModelValidationResult validationResult) {
+        super(projectId, message, pomFile);
 
         this.validationResult = validationResult;
     }
@@ -64,14 +59,12 @@
      * @param message
      * @deprecated use {@link File} constructor for pomLocation
      */
-    public InvalidProjectModelException( String projectId, String pomLocation, String message )
-    {
-        this( projectId, message, new File( pomLocation ) );
+    @Deprecated
+    public InvalidProjectModelException(String projectId, String pomLocation, String message) {
+        this(projectId, message, new File(pomLocation));
     }
 
-    public final ModelValidationResult getValidationResult()
-    {
+    public final ModelValidationResult getValidationResult() {
         return validationResult;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/MavenProjectBuilder.java b/maven-compat/src/main/java/org/apache/maven/project/MavenProjectBuilder.java
index df97948..c471a5c 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/MavenProjectBuilder.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/MavenProjectBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.util.List;
@@ -33,45 +32,46 @@
  * @deprecated use {@link ProjectBuilder} instead
  */
 @Deprecated
-public interface MavenProjectBuilder
-{
+public interface MavenProjectBuilder {
 
-    MavenProject build( File pom, ProjectBuilderConfiguration configuration )
-        throws ProjectBuildingException;
+    MavenProject build(File pom, ProjectBuilderConfiguration configuration) throws ProjectBuildingException;
 
-    //TODO maven-site-plugin -- not used by the plugin directly, but used by Doxia Integration Tool & MPIR
+    // TODO maven-site-plugin -- not used by the plugin directly, but used by Doxia Integration Tool & MPIR
     // see DOXIASITETOOLS-167 & MPIR-349
-    MavenProject build( File pom, ArtifactRepository localRepository, ProfileManager profileManager )
-        throws ProjectBuildingException;
+    MavenProject build(File pom, ArtifactRepository localRepository, ProfileManager profileManager)
+            throws ProjectBuildingException;
 
-    //TODO remote-resources-plugin
-    MavenProject buildFromRepository( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                      ArtifactRepository localRepository )
-        throws ProjectBuildingException;
+    // TODO remote-resources-plugin
+    MavenProject buildFromRepository(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ProjectBuildingException;
 
-    //TODO remote-resources-plugin
-    MavenProject buildFromRepository( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                      ArtifactRepository localRepository, boolean allowStubModel )
-        throws ProjectBuildingException;
+    // TODO remote-resources-plugin
+    MavenProject buildFromRepository(
+            Artifact artifact,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactRepository localRepository,
+            boolean allowStubModel)
+            throws ProjectBuildingException;
 
     // TODO this is only to provide a project for plugins that don't need a project to execute but need some
     // of the values from a MavenProject. Ideally this should be something internal and nothing outside Maven
     // would ever need this so it should not be exposed in a public API
-    MavenProject buildStandaloneSuperProject( ProjectBuilderConfiguration configuration )
-        throws ProjectBuildingException;
+    MavenProject buildStandaloneSuperProject(ProjectBuilderConfiguration configuration) throws ProjectBuildingException;
 
-    MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository )
-        throws ProjectBuildingException;
+    MavenProject buildStandaloneSuperProject(ArtifactRepository localRepository) throws ProjectBuildingException;
 
-    MavenProject buildStandaloneSuperProject( ArtifactRepository localRepository, ProfileManager profileManager )
-        throws ProjectBuildingException;
+    MavenProject buildStandaloneSuperProject(ArtifactRepository localRepository, ProfileManager profileManager)
+            throws ProjectBuildingException;
 
-    MavenProject buildWithDependencies( File pom, ArtifactRepository localRepository,
-                                        ProfileManager globalProfileManager, TransferListener transferListener )
-        throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException;
+    MavenProject buildWithDependencies(
+            File pom,
+            ArtifactRepository localRepository,
+            ProfileManager globalProfileManager,
+            TransferListener transferListener)
+            throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException;
 
-    MavenProject buildWithDependencies( File pom, ArtifactRepository localRepository,
-                                        ProfileManager globalProfileManager )
-        throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException;
-
+    MavenProject buildWithDependencies(
+            File pom, ArtifactRepository localRepository, ProfileManager globalProfileManager)
+            throws ProjectBuildingException, ArtifactResolutionException, ArtifactNotFoundException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/MissingRepositoryElementException.java b/maven-compat/src/main/java/org/apache/maven/project/MissingRepositoryElementException.java
index 75384e1..d3a1246 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/MissingRepositoryElementException.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/MissingRepositoryElementException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import org.apache.maven.artifact.InvalidRepositoryException;
+
 /**
  * Error constructing an artifact repository.
  */
-public class MissingRepositoryElementException
-    extends InvalidRepositoryException
-{
+@Deprecated
+public class MissingRepositoryElementException extends InvalidRepositoryException {
 
-    public MissingRepositoryElementException( String message, String repositoryId )
-    {
-        super( message, repositoryId );
+    public MissingRepositoryElementException(String message, String repositoryId) {
+        super(message, repositoryId);
     }
 
-    public MissingRepositoryElementException( String message )
-    {
-        super( message, "-unknown-" );
+    public MissingRepositoryElementException(String message) {
+        super(message, "-unknown-");
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java b/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java
index 6b378b7..baf054a 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/ModelUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,25 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
 
-import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.Repository;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /** @deprecated */
 @Deprecated
-public final class ModelUtils
-{
+public final class ModelUtils {
 
     /**
      * This should be the resulting ordering of plugins after merging:
@@ -51,312 +40,21 @@
      * X -&gt; Y -&gt; A -&gt; B -&gt; C -&gt; D -&gt; E -&gt; F
      * </pre>
      */
-    public static void mergePluginLists( PluginContainer childContainer, PluginContainer parentContainer,
-                                         boolean handleAsInheritance )
-    {
-        if ( ( childContainer == null ) || ( parentContainer == null ) )
-        {
-            // nothing to do.
-            return;
-        }
-
-        List<Plugin> parentPlugins = parentContainer.getPlugins();
-
-        if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
-        {
-            parentPlugins = new ArrayList<>( parentPlugins );
-
-            // If we're processing this merge as an inheritance, we have to build up a list of
-            // plugins that were considered for inheritance.
-            if ( handleAsInheritance )
-            {
-                for ( Iterator<Plugin> it = parentPlugins.iterator(); it.hasNext(); )
-                {
-                    Plugin plugin = it.next();
-
-                    String inherited = plugin.getInherited();
-
-                    if ( ( inherited != null ) && !Boolean.parseBoolean( inherited ) )
-                    {
-                        it.remove();
-                    }
-                }
-            }
-
-            List<Plugin> assembledPlugins = new ArrayList<>();
-
-            Map<String, Plugin> childPlugins = childContainer.getPluginsAsMap();
-
-            for ( Plugin parentPlugin : parentPlugins )
-            {
-                String parentInherited = parentPlugin.getInherited();
-
-                // only merge plugin definition from the parent if at least one
-                // of these is true:
-                // 1. we're not processing the plugins in an inheritance-based merge
-                // 2. the parent's <inherited/> flag is not set
-                // 3. the parent's <inherited/> flag is set to true
-                if ( !handleAsInheritance || ( parentInherited == null )
-                    || Boolean.parseBoolean( parentInherited ) )
-                {
-                    Plugin childPlugin = childPlugins.get( parentPlugin.getKey() );
-
-                    if ( ( childPlugin != null ) && !assembledPlugins.contains( childPlugin ) )
-                    {
-                        mergePluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
-
-                        // fix for MNG-2221 (assembly cache was not being populated for later reference):
-                        assembledPlugins.add( childPlugin );
-                    }
-
-                    // if we're processing this as an inheritance-based merge, and
-                    // the parent's <inherited/> flag is not set, then we need to
-                    // clear the inherited flag in the merge result.
-                    if ( handleAsInheritance && ( parentInherited == null ) )
-                    {
-                        parentPlugin.unsetInheritanceApplied();
-                    }
-                }
-
-                // very important to use the parentPlugins List, rather than parentContainer.getPlugins()
-                // since this list is a local one, and may have been modified during processing.
-                List<Plugin> results =
-                    ModelUtils.orderAfterMerge( assembledPlugins, parentPlugins, childContainer.getPlugins() );
-
-                childContainer.setPlugins( results );
-
-                childContainer.flushPluginMap();
-            }
-        }
+    public static void mergePluginLists(
+            PluginContainer childContainer, PluginContainer parentContainer, boolean handleAsInheritance) {
+        throw new UnsupportedOperationException();
     }
 
-    public static List<Plugin> orderAfterMerge( List<Plugin> merged, List<Plugin> highPrioritySource,
-                                                List<Plugin> lowPrioritySource )
-    {
-        List<Plugin> results = new ArrayList<>();
-
-        if ( !merged.isEmpty() )
-        {
-            results.addAll( merged );
-        }
-
-        List<Plugin> missingFromResults = new ArrayList<>();
-
-        List<List<Plugin>> sources = new ArrayList<>();
-
-        sources.add( highPrioritySource );
-        sources.add( lowPrioritySource );
-
-        for ( List<Plugin> source : sources )
-        {
-            for ( Plugin item : source )
-            {
-                if ( results.contains( item ) )
-                {
-                    if ( !missingFromResults.isEmpty() )
-                    {
-                        int idx = results.indexOf( item );
-
-                        if ( idx < 0 )
-                        {
-                            idx = 0;
-                        }
-
-                        results.addAll( idx, missingFromResults );
-
-                        missingFromResults.clear();
-                    }
-                }
-                else
-                {
-                    missingFromResults.add( item );
-                }
-            }
-
-            if ( !missingFromResults.isEmpty() )
-            {
-                results.addAll( missingFromResults );
-
-                missingFromResults.clear();
-            }
-        }
-
-        return results;
+    public static List<Plugin> orderAfterMerge(
+            List<Plugin> merged, List<Plugin> highPrioritySource, List<Plugin> lowPrioritySource) {
+        throw new UnsupportedOperationException();
     }
 
-
-    public static void mergePluginDefinitions( Plugin child, Plugin parent, boolean handleAsInheritance )
-    {
-        if ( ( child == null ) || ( parent == null ) )
-        {
-            // nothing to do.
-            return;
-        }
-
-        if ( parent.isExtensions() )
-        {
-            child.setExtensions( true );
-        }
-
-        if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
-        {
-            child.setVersion( parent.getVersion() );
-        }
-
-        Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
-        Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
-
-        childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
-
-        child.setConfiguration( childConfiguration );
-
-        child.setDependencies( mergeDependencyList( child.getDependencies(), parent.getDependencies() ) );
-
-        // from here to the end of the method is dealing with merging of the <executions/> section.
-        String parentInherited = parent.getInherited();
-
-        boolean parentIsInherited = ( parentInherited == null ) || Boolean.parseBoolean( parentInherited );
-
-        List<PluginExecution> parentExecutions = parent.getExecutions();
-
-        if ( ( parentExecutions != null ) && !parentExecutions.isEmpty() )
-        {
-            List<PluginExecution> mergedExecutions = new ArrayList<>();
-
-            Map<String, PluginExecution> assembledExecutions = new TreeMap<>();
-
-            Map<String, PluginExecution> childExecutions = child.getExecutionsAsMap();
-
-            for ( PluginExecution parentExecution : parentExecutions )
-            {
-                String inherited = parentExecution.getInherited();
-
-                boolean parentExecInherited =
-                    parentIsInherited && ( ( inherited == null ) || Boolean.parseBoolean( inherited ) );
-
-                if ( !handleAsInheritance || parentExecInherited )
-                {
-                    PluginExecution assembled = parentExecution;
-
-                    PluginExecution childExecution = childExecutions.get( parentExecution.getId() );
-
-                    if ( childExecution != null )
-                    {
-                        mergePluginExecutionDefinitions( childExecution, parentExecution );
-
-                        assembled = childExecution;
-                    }
-                    else if ( handleAsInheritance && ( parentInherited == null ) )
-                    {
-                        parentExecution.unsetInheritanceApplied();
-                    }
-
-                    assembledExecutions.put( assembled.getId(), assembled );
-                    mergedExecutions.add( assembled );
-                }
-            }
-
-            for ( PluginExecution childExecution : child.getExecutions() )
-            {
-                if ( !assembledExecutions.containsKey( childExecution.getId() ) )
-                {
-                    mergedExecutions.add( childExecution );
-                }
-            }
-
-            child.setExecutions( mergedExecutions );
-
-            child.flushExecutionMap();
-        }
-
+    public static void mergePluginDefinitions(Plugin child, Plugin parent, boolean handleAsInheritance) {
+        throw new UnsupportedOperationException();
     }
 
-    private static void mergePluginExecutionDefinitions( PluginExecution child, PluginExecution parent )
-    {
-        if ( child.getPhase() == null )
-        {
-            child.setPhase( parent.getPhase() );
-        }
-
-        List<String> parentGoals = parent.getGoals();
-        List<String> childGoals = child.getGoals();
-
-        List<String> goals = new ArrayList<>();
-
-        if ( ( childGoals != null ) && !childGoals.isEmpty() )
-        {
-            goals.addAll( childGoals );
-        }
-
-        if ( parentGoals != null )
-        {
-            for (  String goal : parentGoals )
-            {
-                if ( !goals.contains( goal ) )
-                {
-                    goals.add( goal );
-                }
-            }
-        }
-
-        child.setGoals( goals );
-
-        Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
-        Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
-
-        childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
-
-        child.setConfiguration( childConfiguration );
+    public static void mergeFilterLists(List<String> childFilters, List<String> parentFilters) {
+        throw new UnsupportedOperationException();
     }
-
-    public static List<Repository> mergeRepositoryLists( List<Repository> dominant, List<Repository> recessive )
-    {
-
-        List<Repository> repositories = new ArrayList<>( dominant );
-
-        for ( Repository repository : recessive )
-        {
-            if ( !repositories.contains( repository ) )
-            {
-                repositories.add( repository );
-            }
-        }
-
-        return repositories;
-    }
-
-    public static void mergeFilterLists( List<String> childFilters, List<String> parentFilters )
-    {
-        for ( String f : parentFilters )
-        {
-            if ( !childFilters.contains( f ) )
-            {
-                childFilters.add( f );
-            }
-        }
-    }
-
-    private static List<Dependency> mergeDependencyList( List<Dependency> child, List<Dependency> parent )
-    {
-        Map<String, Dependency> depsMap = new LinkedHashMap<>();
-
-        if ( parent != null )
-        {
-            for ( Dependency dependency : parent )
-            {
-                depsMap.put( dependency.getManagementKey(), dependency );
-            }
-        }
-
-        if ( child != null )
-        {
-            for ( Dependency dependency : child )
-            {
-                depsMap.put( dependency.getManagementKey(), dependency );
-            }
-        }
-
-        return new ArrayList<>( depsMap.values() );
-    }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/ProjectBuilderConfiguration.java b/maven-compat/src/main/java/org/apache/maven/project/ProjectBuilderConfiguration.java
index ddfad3c..e4b98e1 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/ProjectBuilderConfiguration.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/ProjectBuilderConfiguration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.Date;
 import java.util.Properties;
@@ -29,8 +28,7 @@
  * @deprecated use {@link ProjectBuildingRequest} instead
  */
 @Deprecated
-public interface ProjectBuilderConfiguration
-{
+public interface ProjectBuilderConfiguration {
 
     ArtifactRepository getLocalRepository();
 
@@ -40,16 +38,15 @@
 
     Properties getExecutionProperties();
 
-    ProjectBuilderConfiguration setGlobalProfileManager( ProfileManager globalProfileManager );
+    ProjectBuilderConfiguration setGlobalProfileManager(ProfileManager globalProfileManager);
 
-    ProjectBuilderConfiguration setLocalRepository( ArtifactRepository localRepository );
+    ProjectBuilderConfiguration setLocalRepository(ArtifactRepository localRepository);
 
-    ProjectBuilderConfiguration setUserProperties( Properties userProperties );
+    ProjectBuilderConfiguration setUserProperties(Properties userProperties);
 
-    ProjectBuilderConfiguration setExecutionProperties( Properties executionProperties );
+    ProjectBuilderConfiguration setExecutionProperties(Properties executionProperties);
 
     Date getBuildStartTime();
 
-    ProjectBuilderConfiguration setBuildStartTime( Date buildStartTime );
-
+    ProjectBuilderConfiguration setBuildStartTime(Date buildStartTime);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/ProjectUtils.java b/maven-compat/src/main/java/org/apache/maven/project/ProjectUtils.java
index 8d42344..15c2158 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/ProjectUtils.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/ProjectUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -41,78 +40,61 @@
  * ProjectUtils
  */
 @Deprecated
-public final class ProjectUtils
-{
+public final class ProjectUtils {
 
-    private ProjectUtils()
-    {
-    }
+    private ProjectUtils() {}
 
     public static List<ArtifactRepository> buildArtifactRepositories(
-        List<Repository> repositories, ArtifactRepositoryFactory artifactRepositoryFactory, PlexusContainer c )
-        throws InvalidRepositoryException
-    {
+            List<Repository> repositories, ArtifactRepositoryFactory artifactRepositoryFactory, PlexusContainer c)
+            throws InvalidRepositoryException {
 
         List<ArtifactRepository> remoteRepositories = new ArrayList<>();
 
-        for ( Repository r : repositories )
-        {
-            remoteRepositories.add( buildArtifactRepository( r, artifactRepositoryFactory, c ) );
+        for (Repository r : repositories) {
+            remoteRepositories.add(buildArtifactRepository(r, artifactRepositoryFactory, c));
         }
 
         return remoteRepositories;
     }
 
     public static ArtifactRepository buildDeploymentArtifactRepository(
-        DeploymentRepository repo, ArtifactRepositoryFactory artifactRepositoryFactory, PlexusContainer c )
-        throws InvalidRepositoryException
-    {
-        return buildArtifactRepository( repo, artifactRepositoryFactory, c );
+            DeploymentRepository repo, ArtifactRepositoryFactory artifactRepositoryFactory, PlexusContainer c)
+            throws InvalidRepositoryException {
+        return buildArtifactRepository(repo, artifactRepositoryFactory, c);
     }
 
     public static ArtifactRepository buildArtifactRepository(
-        Repository repo, ArtifactRepositoryFactory artifactRepositoryFactory, PlexusContainer c )
-        throws InvalidRepositoryException
-    {
-        RepositorySystem repositorySystem = rs( c );
-        RepositorySystemSession session = rss( c );
+            Repository repo, ArtifactRepositoryFactory artifactRepositoryFactory, PlexusContainer c)
+            throws InvalidRepositoryException {
+        RepositorySystem repositorySystem = rs(c);
+        RepositorySystemSession session = rss(c);
 
-        ArtifactRepository repository = repositorySystem.buildArtifactRepository( repo );
+        ArtifactRepository repository = repositorySystem.buildArtifactRepository(repo);
 
-        if ( session != null )
-        {
-            repositorySystem.injectMirror( session, Arrays.asList( repository ) );
-            repositorySystem.injectProxy( session, Arrays.asList( repository ) );
-            repositorySystem.injectAuthentication( session, Arrays.asList( repository ) );
+        if (session != null) {
+            repositorySystem.injectMirror(session, Arrays.asList(repository));
+            repositorySystem.injectProxy(session, Arrays.asList(repository));
+            repositorySystem.injectAuthentication(session, Arrays.asList(repository));
         }
 
         return repository;
     }
 
-    private static RepositorySystem rs( PlexusContainer c )
-    {
-        try
-        {
-            return c.lookup( RepositorySystem.class );
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new IllegalStateException( e );
+    private static RepositorySystem rs(PlexusContainer c) {
+        try {
+            return c.lookup(RepositorySystem.class);
+        } catch (ComponentLookupException e) {
+            throw new IllegalStateException(e);
         }
     }
 
-    private static RepositorySystemSession rss( PlexusContainer c )
-    {
-        try
-        {
-            LegacySupport legacySupport = c.lookup( LegacySupport.class );
+    private static RepositorySystemSession rss(PlexusContainer c) {
+        try {
+            LegacySupport legacySupport = c.lookup(LegacySupport.class);
 
             return legacySupport.getRepositorySession();
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new IllegalStateException( e );
+        } catch (ComponentLookupException e) {
+            throw new IllegalStateException(e);
         }
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/artifact/ActiveProjectArtifact.java b/maven-compat/src/main/java/org/apache/maven/project/artifact/ActiveProjectArtifact.java
new file mode 100644
index 0000000..8e7bfd1
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/project/artifact/ActiveProjectArtifact.java
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * Wraps an active project instance to be able to receive updates from its artifact without affecting the original
+ * attributes of this artifact.
+ *
+ * TODO I think this exposes a design flaw in that the immutable and mutable parts of an artifact are in one class and
+ * should be split. ie scope, file, etc depend on the context of use, whereas everything else is immutable.
+ */
+@Deprecated
+public class ActiveProjectArtifact implements Artifact {
+    private final Artifact artifact;
+
+    private final MavenProject project;
+
+    public ActiveProjectArtifact(MavenProject project, Artifact artifact) {
+        this.artifact = artifact;
+        this.project = project;
+
+        artifact.setFile(project.getArtifact().getFile());
+        artifact.setResolved(true);
+    }
+
+    /** {@inheritDoc} */
+    public File getFile() {
+        // we need to get the latest file for the project, not the artifact that was created at one point in time
+        return project.getArtifact().getFile();
+    }
+
+    /** {@inheritDoc} */
+    public String getGroupId() {
+        return artifact.getGroupId();
+    }
+
+    /** {@inheritDoc} */
+    public String getArtifactId() {
+        return artifact.getArtifactId();
+    }
+
+    /** {@inheritDoc} */
+    public String getVersion() {
+        return artifact.getVersion();
+    }
+
+    /** {@inheritDoc} */
+    public void setVersion(String version) {
+        artifact.setVersion(version);
+    }
+
+    /** {@inheritDoc} */
+    public String getScope() {
+        return artifact.getScope();
+    }
+
+    /** {@inheritDoc} */
+    public String getType() {
+        return artifact.getType();
+    }
+
+    /** {@inheritDoc} */
+    public String getClassifier() {
+        return artifact.getClassifier();
+    }
+
+    /** {@inheritDoc} */
+    public boolean hasClassifier() {
+        return artifact.hasClassifier();
+    }
+
+    /** {@inheritDoc} */
+    public void setFile(File destination) {
+        artifact.setFile(destination);
+        project.getArtifact().setFile(destination);
+    }
+
+    /** {@inheritDoc} */
+    public String getBaseVersion() {
+        return artifact.getBaseVersion();
+    }
+
+    /** {@inheritDoc} */
+    public void setBaseVersion(String baseVersion) {
+        artifact.setBaseVersion(baseVersion);
+    }
+
+    /** {@inheritDoc} */
+    public String getId() {
+        return artifact.getId();
+    }
+
+    /** {@inheritDoc} */
+    public String getDependencyConflictId() {
+        return artifact.getDependencyConflictId();
+    }
+
+    /** {@inheritDoc} */
+    public void addMetadata(ArtifactMetadata metadata) {
+        artifact.addMetadata(metadata);
+    }
+
+    /** {@inheritDoc} */
+    public Collection<ArtifactMetadata> getMetadataList() {
+        return artifact.getMetadataList();
+    }
+
+    /** {@inheritDoc} */
+    public void setRepository(ArtifactRepository remoteRepository) {
+        artifact.setRepository(remoteRepository);
+    }
+
+    /** {@inheritDoc} */
+    public ArtifactRepository getRepository() {
+        return artifact.getRepository();
+    }
+
+    /** {@inheritDoc} */
+    public void updateVersion(String version, ArtifactRepository localRepository) {
+        artifact.updateVersion(version, localRepository);
+    }
+
+    /** {@inheritDoc} */
+    public String getDownloadUrl() {
+        return artifact.getDownloadUrl();
+    }
+
+    /** {@inheritDoc} */
+    public void setDownloadUrl(String downloadUrl) {
+        artifact.setDownloadUrl(downloadUrl);
+    }
+
+    /** {@inheritDoc} */
+    public ArtifactFilter getDependencyFilter() {
+        return artifact.getDependencyFilter();
+    }
+
+    /** {@inheritDoc} */
+    public void setDependencyFilter(ArtifactFilter artifactFilter) {
+        artifact.setDependencyFilter(artifactFilter);
+    }
+
+    /** {@inheritDoc} */
+    public ArtifactHandler getArtifactHandler() {
+        return artifact.getArtifactHandler();
+    }
+
+    /** {@inheritDoc} */
+    public List<String> getDependencyTrail() {
+        return artifact.getDependencyTrail();
+    }
+
+    /** {@inheritDoc} */
+    public void setDependencyTrail(List<String> dependencyTrail) {
+        artifact.setDependencyTrail(dependencyTrail);
+    }
+
+    /** {@inheritDoc} */
+    public void setScope(String scope) {
+        artifact.setScope(scope);
+    }
+
+    /** {@inheritDoc} */
+    public VersionRange getVersionRange() {
+        return artifact.getVersionRange();
+    }
+
+    /** {@inheritDoc} */
+    public void setVersionRange(VersionRange newRange) {
+        artifact.setVersionRange(newRange);
+    }
+
+    /** {@inheritDoc} */
+    public void selectVersion(String version) {
+        artifact.selectVersion(version);
+    }
+
+    /** {@inheritDoc} */
+    public void setGroupId(String groupId) {
+        artifact.setGroupId(groupId);
+    }
+
+    /** {@inheritDoc} */
+    public void setArtifactId(String artifactId) {
+        artifact.setArtifactId(artifactId);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSnapshot() {
+        return artifact.isSnapshot();
+    }
+
+    /** {@inheritDoc} */
+    public int compareTo(Artifact a) {
+        return artifact.compareTo(a);
+    }
+
+    /** {@inheritDoc} */
+    public void setResolved(boolean resolved) {
+        artifact.setResolved(resolved);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isResolved() {
+        return artifact.isResolved();
+    }
+
+    /** {@inheritDoc} */
+    public void setResolvedVersion(String version) {
+        artifact.setResolvedVersion(version);
+    }
+
+    /** {@inheritDoc} */
+    public void setArtifactHandler(ArtifactHandler handler) {
+        artifact.setArtifactHandler(handler);
+    }
+
+    /** {@inheritDoc} */
+    public String toString() {
+        return "active project artifact[artifact: " + artifact + ", project: " + project + "]";
+    }
+
+    /** {@inheritDoc} */
+    public boolean isRelease() {
+        return artifact.isRelease();
+    }
+
+    /** {@inheritDoc} */
+    public void setRelease(boolean release) {
+        artifact.setRelease(release);
+    }
+
+    /** {@inheritDoc} */
+    public List<ArtifactVersion> getAvailableVersions() {
+        return artifact.getAvailableVersions();
+    }
+
+    /** {@inheritDoc} */
+    public void setAvailableVersions(List<ArtifactVersion> versions) {
+        artifact.setAvailableVersions(versions);
+    }
+
+    /** {@inheritDoc} */
+    public boolean isOptional() {
+        return artifact.isOptional();
+    }
+
+    /** {@inheritDoc} */
+    public ArtifactVersion getSelectedVersion() throws OverConstrainedVersionException {
+        return artifact.getSelectedVersion();
+    }
+
+    /** {@inheritDoc} */
+    public boolean isSelectedVersionKnown() throws OverConstrainedVersionException {
+        return artifact.isSelectedVersionKnown();
+    }
+
+    /** {@inheritDoc} */
+    public void setOptional(boolean optional) {
+        artifact.setOptional(optional);
+    }
+
+    /** {@inheritDoc} */
+    public int hashCode() {
+        int result = 17;
+
+        result = 37 * result + getGroupId().hashCode();
+        result = 37 * result + getArtifactId().hashCode();
+        result = 37 * result + getType().hashCode();
+        if (getVersion() != null) {
+            result = 37 * result + getVersion().hashCode();
+        }
+        result = 37 * result + (getClassifier() != null ? getClassifier().hashCode() : 0);
+
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+
+        if (!(o instanceof Artifact)) {
+            return false;
+        }
+
+        Artifact a = (Artifact) o;
+
+        if (!a.getGroupId().equals(getGroupId())) {
+            return false;
+        } else if (!a.getArtifactId().equals(getArtifactId())) {
+            return false;
+        } else if (!a.getVersion().equals(getVersion())) {
+            return false;
+        } else if (!a.getType().equals(getType())) {
+            return false;
+        } else {
+            return a.getClassifier() == null
+                    ? getClassifier() == null
+                    : a.getClassifier().equals(getClassifier());
+        }
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/artifact/DefaultMavenMetadataCache.java b/maven-compat/src/main/java/org/apache/maven/project/artifact/DefaultMavenMetadataCache.java
new file mode 100644
index 0000000..48c889c
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/project/artifact/DefaultMavenMetadataCache.java
@@ -0,0 +1,324 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.artifact.metadata.ResolutionGroup;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+
+/**
+ * DefaultMavenMetadataCache
+ */
+@Named
+@Singleton
+@Deprecated
+public class DefaultMavenMetadataCache implements MavenMetadataCache {
+
+    protected final Map<CacheKey, CacheRecord> cache = new ConcurrentHashMap<>();
+
+    /**
+     * CacheKey
+     */
+    public static class CacheKey {
+        private final Artifact artifact;
+        private final long pomHash;
+        private final boolean resolveManagedVersions;
+        private final List<ArtifactRepository> repositories = new ArrayList<>();
+        private final int hashCode;
+
+        public CacheKey(
+                Artifact artifact,
+                boolean resolveManagedVersions,
+                ArtifactRepository localRepository,
+                List<ArtifactRepository> remoteRepositories) {
+            File file = artifact.getFile();
+            this.artifact = ArtifactUtils.copyArtifact(artifact);
+            if ("pom".equals(artifact.getType()) && file != null) {
+                pomHash = file.getPath().hashCode() + file.lastModified();
+            } else {
+                pomHash = 0;
+            }
+            this.resolveManagedVersions = resolveManagedVersions;
+            this.repositories.add(localRepository);
+            this.repositories.addAll(remoteRepositories);
+
+            int hash = 17;
+            hash = hash * 31 + artifactHashCode(artifact);
+            hash = hash * 31 + (resolveManagedVersions ? 1 : 2);
+            hash = hash * 31 + repositoriesHashCode(repositories);
+            this.hashCode = hash;
+        }
+
+        @Override
+        public int hashCode() {
+            return hashCode;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == this) {
+                return true;
+            }
+
+            if (!(o instanceof CacheKey)) {
+                return false;
+            }
+
+            CacheKey other = (CacheKey) o;
+
+            return pomHash == other.pomHash
+                    && artifactEquals(artifact, other.artifact)
+                    && resolveManagedVersions == other.resolveManagedVersions
+                    && repositoriesEquals(repositories, other.repositories);
+        }
+    }
+
+    private static int artifactHashCode(Artifact a) {
+        int result = 17;
+        result = 31 * result + a.getGroupId().hashCode();
+        result = 31 * result + a.getArtifactId().hashCode();
+        result = 31 * result + a.getType().hashCode();
+        if (a.getVersion() != null) {
+            result = 31 * result + a.getVersion().hashCode();
+        }
+        result = 31 * result + (a.getClassifier() != null ? a.getClassifier().hashCode() : 0);
+        result = 31 * result + (a.getScope() != null ? a.getScope().hashCode() : 0);
+        result = 31 * result
+                + (a.getDependencyFilter() != null ? a.getDependencyFilter().hashCode() : 0);
+        result = 31 * result + (a.isOptional() ? 1 : 0);
+        return result;
+    }
+
+    private static boolean artifactEquals(Artifact a1, Artifact a2) {
+        if (a1 == a2) {
+            return true;
+        }
+
+        return Objects.equals(a1.getGroupId(), a2.getGroupId())
+                && Objects.equals(a1.getArtifactId(), a2.getArtifactId())
+                && Objects.equals(a1.getType(), a2.getType())
+                && Objects.equals(a1.getVersion(), a2.getVersion())
+                && Objects.equals(a1.getClassifier(), a2.getClassifier())
+                && Objects.equals(a1.getScope(), a2.getScope())
+                && Objects.equals(a1.getDependencyFilter(), a2.getDependencyFilter())
+                && a1.isOptional() == a2.isOptional();
+    }
+
+    private static int repositoryHashCode(ArtifactRepository repository) {
+        int result = 17;
+        result = 31 * result + (repository.getId() != null ? repository.getId().hashCode() : 0);
+        return result;
+    }
+
+    private static int repositoriesHashCode(List<ArtifactRepository> repositories) {
+        int result = 17;
+        for (ArtifactRepository repository : repositories) {
+            result = 31 * result + repositoryHashCode(repository);
+        }
+        return result;
+    }
+
+    private static boolean repositoryEquals(ArtifactRepository r1, ArtifactRepository r2) {
+        if (r1 == r2) {
+            return true;
+        }
+
+        return Objects.equals(r1.getId(), r2.getId())
+                && Objects.equals(r1.getUrl(), r2.getUrl())
+                && repositoryPolicyEquals(r1.getReleases(), r2.getReleases())
+                && repositoryPolicyEquals(r1.getSnapshots(), r2.getSnapshots());
+    }
+
+    private static boolean repositoryPolicyEquals(ArtifactRepositoryPolicy p1, ArtifactRepositoryPolicy p2) {
+        if (p1 == p2) {
+            return true;
+        }
+
+        return p1.isEnabled() == p2.isEnabled() && Objects.equals(p1.getUpdatePolicy(), p2.getUpdatePolicy());
+    }
+
+    private static boolean repositoriesEquals(List<ArtifactRepository> r1, List<ArtifactRepository> r2) {
+        if (r1.size() != r2.size()) {
+            return false;
+        }
+
+        for (Iterator<ArtifactRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); ) {
+            if (!repositoryEquals(it1.next(), it2.next())) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * CacheRecord
+     */
+    public class CacheRecord {
+        private Artifact pomArtifact;
+        private Artifact relocatedArtifact;
+        private List<Artifact> artifacts;
+        private Map<String, Artifact> managedVersions;
+        private List<ArtifactRepository> remoteRepositories;
+
+        private long length;
+        private long timestamp;
+
+        CacheRecord(
+                Artifact pomArtifact,
+                Artifact relocatedArtifact,
+                Set<Artifact> artifacts,
+                Map<String, Artifact> managedVersions,
+                List<ArtifactRepository> remoteRepositories) {
+            this.pomArtifact = ArtifactUtils.copyArtifact(pomArtifact);
+            this.relocatedArtifact = ArtifactUtils.copyArtifactSafe(relocatedArtifact);
+            this.artifacts = ArtifactUtils.copyArtifacts(artifacts, new ArrayList<>());
+            this.remoteRepositories = new ArrayList<>(remoteRepositories);
+
+            this.managedVersions = managedVersions;
+            if (managedVersions != null) {
+                this.managedVersions = ArtifactUtils.copyArtifacts(managedVersions, new LinkedHashMap<>());
+            }
+
+            File pomFile = pomArtifact.getFile();
+            if (pomFile != null && pomFile.canRead()) {
+                this.length = pomFile.length();
+                this.timestamp = pomFile.lastModified();
+            } else {
+                this.length = -1;
+                this.timestamp = -1;
+            }
+        }
+
+        public Artifact getArtifact() {
+            return pomArtifact;
+        }
+
+        public Artifact getRelocatedArtifact() {
+            return relocatedArtifact;
+        }
+
+        public List<Artifact> getArtifacts() {
+            return artifacts;
+        }
+
+        public Map<String, Artifact> getManagedVersions() {
+            return managedVersions;
+        }
+
+        public List<ArtifactRepository> getRemoteRepositories() {
+            return remoteRepositories;
+        }
+
+        public boolean isStale() {
+            File pomFile = pomArtifact.getFile();
+            if (pomFile != null) {
+                if (pomFile.canRead()) {
+                    return length != pomFile.length() || timestamp != pomFile.lastModified();
+                } else {
+                    // if the POM didn't exist, retry if any repo is configured to always update
+                    boolean snapshot = pomArtifact.isSnapshot();
+                    for (ArtifactRepository repository : remoteRepositories) {
+                        ArtifactRepositoryPolicy policy =
+                                snapshot ? repository.getSnapshots() : repository.getReleases();
+                        if (ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS.equals(policy.getUpdatePolicy())) {
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            return length != -1 || timestamp != -1;
+        }
+    }
+
+    public ResolutionGroup get(
+            Artifact artifact,
+            boolean resolveManagedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories) {
+        CacheKey cacheKey = newCacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories);
+
+        CacheRecord cacheRecord = cache.get(cacheKey);
+
+        if (cacheRecord != null && !cacheRecord.isStale()) {
+            Artifact pomArtifact = ArtifactUtils.copyArtifact(cacheRecord.getArtifact());
+            Artifact relocatedArtifact = ArtifactUtils.copyArtifactSafe(cacheRecord.getRelocatedArtifact());
+            Set<Artifact> artifacts = ArtifactUtils.copyArtifacts(cacheRecord.getArtifacts(), new LinkedHashSet<>());
+            Map<String, Artifact> managedVersions = cacheRecord.getManagedVersions();
+            if (managedVersions != null) {
+                managedVersions = ArtifactUtils.copyArtifacts(managedVersions, new LinkedHashMap<>());
+            }
+            return new ResolutionGroup(
+                    pomArtifact, relocatedArtifact, artifacts, managedVersions, cacheRecord.getRemoteRepositories());
+        }
+
+        cache.remove(cacheKey);
+
+        return null;
+    }
+
+    public void put(
+            Artifact artifact,
+            boolean resolveManagedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ResolutionGroup result) {
+        put(newCacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories), result);
+    }
+
+    protected CacheKey newCacheKey(
+            Artifact artifact,
+            boolean resolveManagedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories) {
+        return new CacheKey(artifact, resolveManagedVersions, localRepository, remoteRepositories);
+    }
+
+    protected void put(CacheKey cacheKey, ResolutionGroup result) {
+        CacheRecord cacheRecord = new CacheRecord(
+                result.getPomArtifact(),
+                result.getRelocatedArtifact(),
+                result.getArtifacts(),
+                result.getManagedVersions(),
+                result.getResolutionRepositories());
+
+        cache.put(cacheKey, cacheRecord);
+    }
+
+    public void flush() {
+        cache.clear();
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/artifact/DefaultMetadataSource.java b/maven-compat/src/main/java/org/apache/maven/project/artifact/DefaultMetadataSource.java
new file mode 100644
index 0000000..723352f
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/project/artifact/DefaultMetadataSource.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.plugin.LegacySupport;
+import org.apache.maven.project.ProjectBuilder;
+
+/**
+ * This realizes the metadata source via the default hint to provide backward-compat with Maven 2.x whose Plexus version
+ * registered component descriptors twice: once keyed by role+roleHint and once keyed by role only. This effectively
+ * made the metadata source available with its original role hint ("maven") as well as the default hint.
+ *
+ */
+@Named
+@Singleton
+@Deprecated
+public class DefaultMetadataSource extends MavenMetadataSource {
+    @Inject
+    public DefaultMetadataSource(
+            RepositoryMetadataManager repositoryMetadataManager,
+            ArtifactFactory artifactFactory,
+            ProjectBuilder projectBuilder,
+            MavenMetadataCache cache,
+            LegacySupport legacySupport,
+            MavenRepositorySystem mavenRepositorySystem) {
+        super(repositoryMetadataManager, artifactFactory, projectBuilder, cache, legacySupport, mavenRepositorySystem);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/artifact/MavenMetadataCache.java b/maven-compat/src/main/java/org/apache/maven/project/artifact/MavenMetadataCache.java
new file mode 100644
index 0000000..bafc22c
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/project/artifact/MavenMetadataCache.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ResolutionGroup;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
+/**
+ * MavenMetadataCache
+ */
+@Deprecated
+public interface MavenMetadataCache {
+
+    ResolutionGroup get(
+            Artifact artifact,
+            boolean resolveManagedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories);
+
+    void put(
+            Artifact artifact,
+            boolean resolveManagedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ResolutionGroup result);
+
+    void flush();
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java b/maven-compat/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java
new file mode 100644
index 0000000..4240cec
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java
@@ -0,0 +1,712 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.InvalidRepositoryException;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.metadata.ResolutionGroup;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
+import org.apache.maven.artifact.repository.metadata.Metadata;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
+import org.apache.maven.artifact.resolver.ArtifactResolutionException;
+import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
+import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ExclusionArtifactFilter;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.DependencyManagement;
+import org.apache.maven.model.DistributionManagement;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Relocation;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.ModelProblem;
+import org.apache.maven.model.resolution.UnresolvableModelException;
+import org.apache.maven.plugin.LegacySupport;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.properties.internal.EnvironmentUtils;
+import org.apache.maven.properties.internal.SystemProperties;
+import org.apache.maven.repository.internal.MavenWorkspaceReader;
+import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
+import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.RepositoryPolicy;
+import org.eclipse.aether.repository.WorkspaceReader;
+import org.eclipse.aether.transfer.ArtifactNotFoundException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ */
+@Named("maven")
+@Singleton
+@Deprecated
+public class MavenMetadataSource implements ArtifactMetadataSource {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+    private final RepositoryMetadataManager repositoryMetadataManager;
+    private final ArtifactFactory artifactFactory;
+    private final ProjectBuilder projectBuilder;
+    private final MavenMetadataCache cache;
+    private final LegacySupport legacySupport;
+
+    private MavenRepositorySystem mavenRepositorySystem;
+
+    @Inject
+    public MavenMetadataSource(
+            RepositoryMetadataManager repositoryMetadataManager,
+            ArtifactFactory artifactFactory,
+            ProjectBuilder projectBuilder,
+            MavenMetadataCache cache,
+            LegacySupport legacySupport,
+            MavenRepositorySystem mavenRepositorySystem) {
+        this.repositoryMetadataManager = repositoryMetadataManager;
+        this.artifactFactory = artifactFactory;
+        this.projectBuilder = projectBuilder;
+        this.cache = cache;
+        this.legacySupport = legacySupport;
+        this.mavenRepositorySystem = mavenRepositorySystem;
+    }
+
+    private void injectSession(MetadataResolutionRequest request) {
+        RepositorySystemSession session = legacySupport.getRepositorySession();
+
+        if (session != null) {
+            request.setOffline(session.isOffline());
+            request.setForceUpdate(RepositoryPolicy.UPDATE_POLICY_ALWAYS.equals(session.getUpdatePolicy()));
+        }
+    }
+
+    @Override
+    public ResolutionGroup retrieve(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
+        return retrieve(artifact, localRepository, remoteRepositories, false);
+    }
+
+    public ResolutionGroup retrieve(
+            Artifact artifact,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            boolean resolveManagedVersions)
+            throws ArtifactMetadataRetrievalException {
+        MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
+        injectSession(request);
+        request.setArtifact(artifact);
+        request.setLocalRepository(localRepository);
+        request.setRemoteRepositories(remoteRepositories);
+        request.setResolveManagedVersions(resolveManagedVersions);
+        return retrieve(request);
+    }
+
+    @Override
+    public ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException {
+        Artifact artifact = request.getArtifact();
+
+        //
+        // If we have a system scoped artifact then we do not want any searching in local or remote repositories
+        // and we want artifact resolution to only return the system scoped artifact itself.
+        //
+        if (artifact.getScope() != null && artifact.getScope().equals(Artifact.SCOPE_SYSTEM)) {
+            return new ResolutionGroup(null, null, null);
+        }
+
+        ResolutionGroup cached = cache.get(
+                artifact,
+                request.isResolveManagedVersions(),
+                request.getLocalRepository(),
+                request.getRemoteRepositories());
+
+        if (cached != null
+                // if the POM has no file, we cached a missing artifact, only return the cached data if no update forced
+                && (!request.isForceUpdate() || hasFile(cached.getPomArtifact()))) {
+            return cached;
+        }
+
+        List<Dependency> dependencies;
+
+        List<Dependency> managedDependencies = null;
+
+        List<ArtifactRepository> pomRepositories = null;
+
+        Artifact pomArtifact;
+
+        Artifact relocatedArtifact = null;
+
+        // TODO hack: don't rebuild model if it was already loaded during reactor resolution
+        RepositorySystemSession repositorySession = legacySupport.getRepositorySession();
+        final WorkspaceReader workspace = repositorySession.getWorkspaceReader();
+        Model model;
+        if (workspace instanceof MavenWorkspaceReader) {
+            model = ((MavenWorkspaceReader) workspace).findModel(RepositoryUtils.toArtifact(artifact));
+        } else {
+            model = null;
+        }
+
+        if (model != null) {
+            pomArtifact = artifact;
+            dependencies = model.getDependencies();
+            DependencyManagement dependencyManagement = model.getDependencyManagement();
+            managedDependencies = dependencyManagement == null ? null : dependencyManagement.getDependencies();
+            MavenSession session = legacySupport.getSession();
+            if (session != null) {
+                pomRepositories = session.getProjects().stream()
+                        .filter(p -> artifact.equals(p.getArtifact()))
+                        .map(MavenProject::getRemoteArtifactRepositories)
+                        .findFirst()
+                        .orElseGet(() -> getRepositoriesFromModel(repositorySession, model));
+            } else {
+                pomRepositories = new ArrayList<>();
+            }
+        } else if (artifact instanceof ArtifactWithDependencies) {
+            pomArtifact = artifact;
+
+            dependencies = ((ArtifactWithDependencies) artifact).getDependencies();
+
+            managedDependencies = ((ArtifactWithDependencies) artifact).getManagedDependencies();
+        } else {
+            ProjectRelocation rel = retrieveRelocatedProject(artifact, request);
+
+            if (rel == null) {
+                return null;
+            }
+
+            pomArtifact = rel.pomArtifact;
+
+            relocatedArtifact = rel.relocatedArtifact;
+
+            if (rel.project == null) {
+                // When this happens we have a Maven 1.x POM, or some invalid POM.
+                // It should have never found its way into Maven 2.x repository but it did.
+                dependencies = Collections.emptyList();
+            } else {
+                dependencies = rel.project.getModel().getDependencies();
+
+                DependencyManagement depMgmt = rel.project.getModel().getDependencyManagement();
+                managedDependencies = (depMgmt != null) ? depMgmt.getDependencies() : null;
+
+                pomRepositories = rel.project.getRemoteArtifactRepositories();
+            }
+        }
+
+        Set<Artifact> artifacts = Collections.emptySet();
+
+        if (!artifact.getArtifactHandler().isIncludesDependencies()) {
+            artifacts = new LinkedHashSet<>();
+
+            for (Dependency dependency : dependencies) {
+                Artifact dependencyArtifact = createDependencyArtifact(dependency, artifact, pomArtifact);
+
+                if (dependencyArtifact != null) {
+                    artifacts.add(dependencyArtifact);
+                }
+            }
+        }
+
+        Map<String, Artifact> managedVersions = null;
+
+        if (managedDependencies != null && request.isResolveManagedVersions()) {
+            managedVersions = new HashMap<>();
+
+            for (Dependency managedDependency : managedDependencies) {
+                Artifact managedArtifact = createDependencyArtifact(managedDependency, null, pomArtifact);
+
+                managedVersions.put(managedDependency.getManagementKey(), managedArtifact);
+            }
+        }
+
+        List<ArtifactRepository> aggregatedRepositories =
+                aggregateRepositories(request.getRemoteRepositories(), pomRepositories);
+
+        ResolutionGroup result =
+                new ResolutionGroup(pomArtifact, relocatedArtifact, artifacts, managedVersions, aggregatedRepositories);
+
+        cache.put(
+                artifact,
+                request.isResolveManagedVersions(),
+                request.getLocalRepository(),
+                request.getRemoteRepositories(),
+                result);
+
+        return result;
+    }
+
+    private List<ArtifactRepository> getRepositoriesFromModel(RepositorySystemSession repositorySession, Model model) {
+        List<ArtifactRepository> pomRepositories = new ArrayList<>();
+        for (Repository modelRepository : model.getRepositories()) {
+            try {
+                pomRepositories.add(MavenRepositorySystem.buildArtifactRepository(modelRepository));
+            } catch (InvalidRepositoryException e) {
+                // can not use this then
+            }
+        }
+        mavenRepositorySystem.injectMirror(repositorySession, pomRepositories);
+        mavenRepositorySystem.injectProxy(repositorySession, pomRepositories);
+        mavenRepositorySystem.injectAuthentication(repositorySession, pomRepositories);
+        return pomRepositories;
+    }
+
+    private boolean hasFile(Artifact artifact) {
+        return artifact != null
+                && artifact.getFile() != null
+                && artifact.getFile().exists();
+    }
+
+    private List<ArtifactRepository> aggregateRepositories(
+            List<ArtifactRepository> requestRepositories, List<ArtifactRepository> pomRepositories) {
+        List<ArtifactRepository> repositories = requestRepositories;
+
+        if (pomRepositories != null && !pomRepositories.isEmpty()) {
+            Map<String, ArtifactRepository> repos = new LinkedHashMap<>();
+
+            for (ArtifactRepository repo : requestRepositories) {
+                if (!repos.containsKey(repo.getId())) {
+                    repos.put(repo.getId(), repo);
+                }
+            }
+
+            for (ArtifactRepository repo : pomRepositories) {
+                if (!repos.containsKey(repo.getId())) {
+                    repos.put(repo.getId(), repo);
+                }
+            }
+
+            repositories = new ArrayList<>(repos.values());
+        }
+
+        return repositories;
+    }
+
+    private Artifact createDependencyArtifact(Dependency dependency, Artifact owner, Artifact pom)
+            throws ArtifactMetadataRetrievalException {
+        try {
+            String inheritedScope = (owner != null) ? owner.getScope() : null;
+
+            ArtifactFilter inheritedFilter = (owner != null) ? owner.getDependencyFilter() : null;
+
+            return createDependencyArtifact(artifactFactory, dependency, inheritedScope, inheritedFilter);
+        } catch (InvalidVersionSpecificationException e) {
+            throw new ArtifactMetadataRetrievalException(
+                    "Invalid version for dependency " + dependency.getManagementKey() + ": " + e.getMessage(), e, pom);
+        }
+    }
+
+    private static Artifact createDependencyArtifact(
+            ArtifactFactory factory, Dependency dependency, String inheritedScope, ArtifactFilter inheritedFilter)
+            throws InvalidVersionSpecificationException {
+        String effectiveScope = getEffectiveScope(dependency.getScope(), inheritedScope);
+
+        if (effectiveScope == null) {
+            return null;
+        }
+
+        VersionRange versionRange = VersionRange.createFromVersionSpec(dependency.getVersion());
+
+        Artifact dependencyArtifact = factory.createDependencyArtifact(
+                dependency.getGroupId(),
+                dependency.getArtifactId(),
+                versionRange,
+                dependency.getType(),
+                dependency.getClassifier(),
+                effectiveScope,
+                dependency.isOptional());
+
+        if (inheritedFilter != null && !inheritedFilter.include(dependencyArtifact)) {
+            return null;
+        }
+
+        if (Artifact.SCOPE_SYSTEM.equals(effectiveScope)) {
+            dependencyArtifact.setFile(new File(dependency.getSystemPath()));
+        }
+
+        dependencyArtifact.setDependencyFilter(createDependencyFilter(dependency, inheritedFilter));
+
+        return dependencyArtifact;
+    }
+
+    private static String getEffectiveScope(String originalScope, String inheritedScope) {
+        String effectiveScope = Artifact.SCOPE_RUNTIME;
+
+        if (originalScope == null) {
+            originalScope = Artifact.SCOPE_COMPILE;
+        }
+
+        if (inheritedScope == null) {
+            // direct dependency retains its scope
+            effectiveScope = originalScope;
+        } else if (Artifact.SCOPE_TEST.equals(originalScope) || Artifact.SCOPE_PROVIDED.equals(originalScope)) {
+            // test and provided are not transitive, so exclude them
+            effectiveScope = null;
+        } else if (Artifact.SCOPE_SYSTEM.equals(originalScope)) {
+            // system scope come through unchanged...
+            effectiveScope = Artifact.SCOPE_SYSTEM;
+        } else if (Artifact.SCOPE_COMPILE.equals(originalScope) && Artifact.SCOPE_COMPILE.equals(inheritedScope)) {
+            // added to retain compile scope. Remove if you want compile inherited as runtime
+            effectiveScope = Artifact.SCOPE_COMPILE;
+        } else if (Artifact.SCOPE_TEST.equals(inheritedScope)) {
+            effectiveScope = Artifact.SCOPE_TEST;
+        } else if (Artifact.SCOPE_PROVIDED.equals(inheritedScope)) {
+            effectiveScope = Artifact.SCOPE_PROVIDED;
+        }
+
+        return effectiveScope;
+    }
+
+    private static ArtifactFilter createDependencyFilter(Dependency dependency, ArtifactFilter inheritedFilter) {
+        ArtifactFilter effectiveFilter = inheritedFilter;
+
+        if (!dependency.getExclusions().isEmpty()) {
+            effectiveFilter = new ExclusionArtifactFilter(dependency.getExclusions());
+
+            if (inheritedFilter != null) {
+                effectiveFilter = new AndArtifactFilter(Arrays.asList(inheritedFilter, effectiveFilter));
+            }
+        }
+
+        return effectiveFilter;
+    }
+
+    @Override
+    public List<ArtifactVersion> retrieveAvailableVersions(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
+        MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
+        injectSession(request);
+        request.setArtifact(artifact);
+        request.setLocalRepository(localRepository);
+        request.setRemoteRepositories(remoteRepositories);
+        return retrieveAvailableVersions(request);
+    }
+
+    @Override
+    public List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request)
+            throws ArtifactMetadataRetrievalException {
+        RepositoryMetadata metadata = new ArtifactRepositoryMetadata(request.getArtifact());
+
+        try {
+            repositoryMetadataManager.resolve(metadata, request);
+        } catch (RepositoryMetadataResolutionException e) {
+            throw new ArtifactMetadataRetrievalException(e.getMessage(), e, request.getArtifact());
+        }
+
+        List<String> availableVersions = request.getLocalRepository().findVersions(request.getArtifact());
+
+        return retrieveAvailableVersionsFromMetadata(metadata.getMetadata(), availableVersions);
+    }
+
+    @Override
+    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository deploymentRepository)
+            throws ArtifactMetadataRetrievalException {
+        RepositoryMetadata metadata = new ArtifactRepositoryMetadata(artifact);
+
+        try {
+            repositoryMetadataManager.resolveAlways(metadata, localRepository, deploymentRepository);
+        } catch (RepositoryMetadataResolutionException e) {
+            throw new ArtifactMetadataRetrievalException(e.getMessage(), e, artifact);
+        }
+
+        List<String> availableVersions = localRepository.findVersions(artifact);
+
+        return retrieveAvailableVersionsFromMetadata(metadata.getMetadata(), availableVersions);
+    }
+
+    private List<ArtifactVersion> retrieveAvailableVersionsFromMetadata(
+            Metadata repoMetadata, List<String> availableVersions) {
+        Collection<String> versions = new LinkedHashSet<>();
+
+        if ((repoMetadata != null) && (repoMetadata.getVersioning() != null)) {
+            versions.addAll(repoMetadata.getVersioning().getVersions());
+        }
+
+        versions.addAll(availableVersions);
+
+        List<ArtifactVersion> artifactVersions = new ArrayList<>(versions.size());
+
+        for (String version : versions) {
+            artifactVersions.add(new DefaultArtifactVersion(version));
+        }
+
+        return artifactVersions;
+    }
+
+    // USED BY MAVEN ASSEMBLY PLUGIN
+    @Deprecated
+    public static Set<Artifact> createArtifacts(
+            ArtifactFactory artifactFactory,
+            List<Dependency> dependencies,
+            String inheritedScope,
+            ArtifactFilter dependencyFilter,
+            MavenProject project)
+            throws InvalidDependencyVersionException {
+        Set<Artifact> artifacts = new LinkedHashSet<>();
+
+        for (Dependency d : dependencies) {
+            Artifact dependencyArtifact;
+            try {
+                dependencyArtifact = createDependencyArtifact(artifactFactory, d, inheritedScope, dependencyFilter);
+            } catch (InvalidVersionSpecificationException e) {
+                throw new InvalidDependencyVersionException(project.getId(), d, project.getFile(), e);
+            }
+
+            if (dependencyArtifact != null) {
+                artifacts.add(dependencyArtifact);
+            }
+        }
+
+        return artifacts;
+    }
+
+    @SuppressWarnings("checkstyle:methodlength")
+    private ProjectRelocation retrieveRelocatedProject(Artifact artifact, MetadataResolutionRequest repositoryRequest)
+            throws ArtifactMetadataRetrievalException {
+        MavenProject project;
+
+        Artifact pomArtifact;
+        Artifact relocatedArtifact = null;
+        boolean done = false;
+        do {
+            project = null;
+
+            pomArtifact = artifactFactory.createProjectArtifact(
+                    artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion(), artifact.getScope());
+
+            if ("pom".equals(artifact.getType())) {
+                pomArtifact.setFile(artifact.getFile());
+            }
+
+            if (Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
+                done = true;
+            } else {
+                try {
+                    ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
+                    configuration.setLocalRepository(repositoryRequest.getLocalRepository());
+                    configuration.setRemoteRepositories(repositoryRequest.getRemoteRepositories());
+                    configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+                    configuration.setProcessPlugins(false);
+                    configuration.setRepositoryMerging(ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT);
+                    MavenSession session = legacySupport.getSession();
+                    if (session != null) {
+                        configuration.setSystemProperties(session.getSystemProperties());
+                        configuration.setUserProperties(session.getUserProperties());
+                    } else {
+                        configuration.setSystemProperties(getSystemProperties());
+                        configuration.setUserProperties(new Properties());
+                    }
+                    configuration.setRepositorySession(legacySupport.getRepositorySession());
+
+                    project = projectBuilder.build(pomArtifact, configuration).getProject();
+                } catch (ProjectBuildingException e) {
+                    ModelProblem missingParentPom = hasMissingParentPom(e);
+                    if (missingParentPom != null) {
+                        throw new ArtifactMetadataRetrievalException(
+                                "Failed to process POM for " + artifact.getId() + ": " + missingParentPom.getMessage(),
+                                missingParentPom.getException(),
+                                artifact);
+                    }
+
+                    String message;
+
+                    if (isMissingPom(e)) {
+                        message = "Missing POM for " + artifact.getId();
+                    } else if (isNonTransferablePom(e)) {
+                        throw new ArtifactMetadataRetrievalException(
+                                "Failed to retrieve POM for " + artifact.getId() + ": "
+                                        + e.getCause().getMessage(),
+                                e.getCause(),
+                                artifact);
+                    } else {
+                        message = "Invalid POM for " + artifact.getId()
+                                + ", transitive dependencies (if any) will not be available"
+                                + ", enable verbose output (-X) for more details";
+                    }
+
+                    if (logger.isDebugEnabled()) {
+                        message += ": " + e.getMessage();
+                    }
+
+                    logger.warn(message);
+                }
+
+                if (project != null) {
+                    Relocation relocation = null;
+
+                    DistributionManagement distMgmt = project.getModel().getDistributionManagement();
+                    if (distMgmt != null) {
+                        relocation = distMgmt.getRelocation();
+
+                        artifact.setDownloadUrl(distMgmt.getDownloadUrl());
+                        pomArtifact.setDownloadUrl(distMgmt.getDownloadUrl());
+                    }
+
+                    if (relocation != null) {
+                        if (relocation.getGroupId() != null) {
+                            artifact.setGroupId(relocation.getGroupId());
+                            relocatedArtifact = artifact;
+                            project.setGroupId(relocation.getGroupId());
+                        }
+                        if (relocation.getArtifactId() != null) {
+                            artifact.setArtifactId(relocation.getArtifactId());
+                            relocatedArtifact = artifact;
+                            project.setArtifactId(relocation.getArtifactId());
+                        }
+                        if (relocation.getVersion() != null) {
+                            // note: see MNG-3454. This causes a problem, but fixing it may break more.
+                            artifact.setVersionRange(VersionRange.createFromVersion(relocation.getVersion()));
+                            relocatedArtifact = artifact;
+                            project.setVersion(relocation.getVersion());
+                        }
+
+                        if (artifact.getDependencyFilter() != null
+                                && !artifact.getDependencyFilter().include(artifact)) {
+                            return null;
+                        }
+
+                        // MNG-2861: the artifact data has changed. If the available versions where previously
+                        // retrieved, we need to update it.
+                        // TODO shouldn't the versions be merged across relocations?
+                        List<ArtifactVersion> available = artifact.getAvailableVersions();
+                        if (available != null && !available.isEmpty()) {
+                            MetadataResolutionRequest metadataRequest =
+                                    new DefaultMetadataResolutionRequest(repositoryRequest);
+                            metadataRequest.setArtifact(artifact);
+                            available = retrieveAvailableVersions(metadataRequest);
+                            artifact.setAvailableVersions(available);
+                        }
+
+                        String message = "  this artifact has been relocated to " + artifact.getGroupId() + ":"
+                                + artifact.getArtifactId() + ":" + artifact.getVersion() + ".";
+
+                        if (relocation.getMessage() != null) {
+                            message += "  " + relocation.getMessage();
+                        }
+
+                        if (artifact.getDependencyTrail() != null
+                                && artifact.getDependencyTrail().size() == 1) {
+                            logger.warn(
+                                    "While downloading {}:{}:{}{}",
+                                    pomArtifact.getGroupId(),
+                                    pomArtifact.getArtifactId(),
+                                    pomArtifact.getVersion(),
+                                    message);
+                        } else {
+                            logger.debug(
+                                    "While downloading {}:{}:{}{}",
+                                    pomArtifact.getGroupId(),
+                                    pomArtifact.getArtifactId(),
+                                    pomArtifact.getVersion(),
+                                    message);
+                        }
+                    } else {
+                        done = true;
+                    }
+                } else {
+                    done = true;
+                }
+            }
+        } while (!done);
+
+        ProjectRelocation rel = new ProjectRelocation();
+        rel.project = project;
+        rel.pomArtifact = pomArtifact;
+        rel.relocatedArtifact = relocatedArtifact;
+
+        return rel;
+    }
+
+    private ModelProblem hasMissingParentPom(ProjectBuildingException e) {
+        if (e.getCause() instanceof ModelBuildingException) {
+            ModelBuildingException mbe = (ModelBuildingException) e.getCause();
+            for (ModelProblem problem : mbe.getProblems()) {
+                if (problem.getException() instanceof UnresolvableModelException) {
+                    return problem;
+                }
+            }
+        }
+        return null;
+    }
+
+    private boolean isMissingPom(Exception e) {
+        if (e.getCause() instanceof MultipleArtifactsNotFoundException) {
+            return true;
+        }
+        return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
+                && e.getCause().getCause() instanceof ArtifactNotFoundException;
+    }
+
+    private boolean isNonTransferablePom(Exception e) {
+        if (e.getCause() instanceof ArtifactResolutionException) {
+            return true;
+        }
+        return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
+                && !(e.getCause().getCause() instanceof ArtifactNotFoundException);
+    }
+
+    private Properties getSystemProperties() {
+        Properties props = new Properties();
+
+        EnvironmentUtils.addEnvVars(props);
+
+        SystemProperties.addSystemProperties(props);
+
+        return props;
+    }
+
+    private static final class ProjectRelocation {
+        private MavenProject project;
+
+        private Artifact pomArtifact;
+
+        private Artifact relocatedArtifact;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/artifact/ProjectArtifactMetadata.java b/maven-compat/src/main/java/org/apache/maven/project/artifact/ProjectArtifactMetadata.java
new file mode 100644
index 0000000..3cdd8a2
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/project/artifact/ProjectArtifactMetadata.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.AbstractArtifactMetadata;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadataStoreException;
+
+/**
+ * Attach a POM to an artifact.
+ *
+ */
+@Deprecated
+public class ProjectArtifactMetadata extends AbstractArtifactMetadata {
+    private final File file;
+
+    public ProjectArtifactMetadata(Artifact artifact) {
+        this(artifact, null);
+    }
+
+    public ProjectArtifactMetadata(Artifact artifact, File file) {
+        super(artifact);
+        this.file = file;
+    }
+
+    public File getFile() {
+        return file;
+    }
+
+    public String getRemoteFilename() {
+        return getFilename();
+    }
+
+    public String getLocalFilename(ArtifactRepository repository) {
+        return getFilename();
+    }
+
+    private String getFilename() {
+        return getArtifactId() + "-" + artifact.getVersion() + ".pom";
+    }
+
+    public void storeInLocalRepository(ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws RepositoryMetadataStoreException {
+        File destination = new File(
+                localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata(this, remoteRepository));
+
+        // ----------------------------------------------------------------------------
+        // I'm fully aware that the file could just be moved using File.rename but
+        // there are bugs in various JVM that have problems doing this across
+        // different filesystem. So we'll incur the small hit to actually copy
+        // here and be safe. jvz.
+        // ----------------------------------------------------------------------------
+
+        try {
+            Files.createDirectories(destination.toPath().getParent());
+            Files.copy(file.toPath(), destination.toPath());
+        } catch (IOException e) {
+            throw new RepositoryMetadataStoreException("Error copying POM to the local repository.", e);
+        }
+    }
+
+    public String toString() {
+        return "project information for " + artifact.getArtifactId() + " " + artifact.getVersion();
+    }
+
+    public boolean storedInArtifactVersionDirectory() {
+        return true;
+    }
+
+    public String getBaseVersion() {
+        return artifact.getBaseVersion();
+    }
+
+    public Object getKey() {
+        return "project " + artifact.getGroupId() + ":" + artifact.getArtifactId();
+    }
+
+    public void merge(ArtifactMetadata metadata) {
+        ProjectArtifactMetadata m = (ProjectArtifactMetadata) metadata;
+        if (!m.file.equals(file)) {
+            throw new IllegalStateException("Cannot add two different pieces of metadata for: " + getKey());
+        }
+    }
+
+    public void merge(org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata) {
+        this.merge((ArtifactMetadata) metadata);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java b/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java
index 0113562..c265dc0 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/inheritance/DefaultModelInheritanceAssembler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,730 +16,38 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance;
 
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.StringTokenizer;
-import java.util.TreeMap;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.model.Build;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.DeploymentRepository;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Extension;
 import org.apache.maven.model.Model;
-import org.apache.maven.model.PluginManagement;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Reporting;
-import org.apache.maven.model.Resource;
-import org.apache.maven.model.Scm;
-import org.apache.maven.model.Site;
-import org.apache.maven.project.ModelUtils;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * DefaultModelInheritanceAssembler
  */
-@Component( role = ModelInheritanceAssembler.class )
-public class DefaultModelInheritanceAssembler
-    implements ModelInheritanceAssembler
-{
-    public void assembleBuildInheritance( Build childBuild, Build parentBuild, boolean handleAsInheritance )
-    {
-        // The build has been set but we want to step in here and fill in
-        // values that have not been set by the child.
-
-        if ( childBuild.getSourceDirectory() == null )
-        {
-            childBuild.setSourceDirectory( parentBuild.getSourceDirectory() );
-        }
-
-        if ( childBuild.getScriptSourceDirectory() == null )
-        {
-            childBuild.setScriptSourceDirectory( parentBuild.getScriptSourceDirectory() );
-        }
-
-        if ( childBuild.getTestSourceDirectory() == null )
-        {
-            childBuild.setTestSourceDirectory( parentBuild.getTestSourceDirectory() );
-        }
-
-        if ( childBuild.getOutputDirectory() == null )
-        {
-            childBuild.setOutputDirectory( parentBuild.getOutputDirectory() );
-        }
-
-        if ( childBuild.getTestOutputDirectory() == null )
-        {
-            childBuild.setTestOutputDirectory( parentBuild.getTestOutputDirectory() );
-        }
-
-        // Extensions are accumulated
-        mergeExtensionLists( childBuild, parentBuild );
-
-        if ( childBuild.getDirectory() == null )
-        {
-            childBuild.setDirectory( parentBuild.getDirectory() );
-        }
-
-        if ( childBuild.getDefaultGoal() == null )
-        {
-            childBuild.setDefaultGoal( parentBuild.getDefaultGoal() );
-        }
-
-        if ( childBuild.getFinalName() == null )
-        {
-            childBuild.setFinalName( parentBuild.getFinalName() );
-        }
-
-        ModelUtils.mergeFilterLists( childBuild.getFilters(), parentBuild.getFilters() );
-
-        List<Resource> resources = childBuild.getResources();
-        if ( ( resources == null ) || resources.isEmpty() )
-        {
-            childBuild.setResources( parentBuild.getResources() );
-        }
-
-        resources = childBuild.getTestResources();
-        if ( ( resources == null ) || resources.isEmpty() )
-        {
-            childBuild.setTestResources( parentBuild.getTestResources() );
-        }
-
-        // Plugins are aggregated if Plugin.inherit != false
-        ModelUtils.mergePluginLists( childBuild, parentBuild, handleAsInheritance );
-
-        // Plugin management :: aggregate
-        PluginManagement dominantPM = childBuild.getPluginManagement();
-        PluginManagement recessivePM = parentBuild.getPluginManagement();
-
-        if ( ( dominantPM == null ) && ( recessivePM != null ) )
-        {
-            // FIXME: Filter out the inherited == false stuff!
-            childBuild.setPluginManagement( recessivePM );
-        }
-        else
-        {
-            ModelUtils.mergePluginLists( childBuild.getPluginManagement(), parentBuild.getPluginManagement(), false );
-        }
+@Named
+@Singleton
+@Deprecated
+public class DefaultModelInheritanceAssembler implements ModelInheritanceAssembler {
+    @Override
+    public void assembleModelInheritance(Model child, Model parent, String childPathAdjustment) {
+        throw new UnsupportedOperationException();
     }
 
-    private void assembleScmInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
-    {
-        if ( parent.getScm() != null )
-        {
-            Scm parentScm = parent.getScm();
-
-            Scm childScm = child.getScm();
-
-            if ( childScm == null )
-            {
-                childScm = new Scm();
-
-                child.setScm( childScm );
-            }
-
-            if ( StringUtils.isEmpty( childScm.getConnection() ) && !StringUtils.isEmpty( parentScm.getConnection() ) )
-            {
-                childScm.setConnection(
-                    appendPath( parentScm.getConnection(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
-            }
-
-            if ( StringUtils.isEmpty( childScm.getDeveloperConnection() )
-                && !StringUtils.isEmpty( parentScm.getDeveloperConnection() ) )
-            {
-                childScm
-                    .setDeveloperConnection( appendPath( parentScm.getDeveloperConnection(), child.getArtifactId(),
-                                                         childPathAdjustment, appendPaths ) );
-            }
-
-            if ( StringUtils.isEmpty( childScm.getUrl() ) && !StringUtils.isEmpty( parentScm.getUrl() ) )
-            {
-                childScm.setUrl(
-                    appendPath( parentScm.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
-            }
-        }
+    @Override
+    public void assembleModelInheritance(Model child, Model parent) {
+        throw new UnsupportedOperationException();
     }
 
-    public void copyModel( Model dest, Model source )
-    {
-        assembleModelInheritance( dest, source, null, false );
+    @Override
+    public void assembleBuildInheritance(Build childBuild, Build parentBuild, boolean handleAsInheritance) {
+        throw new UnsupportedOperationException();
     }
 
-    public void assembleModelInheritance( Model child, Model parent, String childPathAdjustment )
-    {
-        assembleModelInheritance( child, parent, childPathAdjustment, true );
-    }
-
-    public void assembleModelInheritance( Model child, Model parent )
-    {
-        assembleModelInheritance( child, parent, null, true );
-    }
-
-    private void assembleModelInheritance( Model child, Model parent, String childPathAdjustment, boolean appendPaths )
-    {
-        // cannot inherit from null parent.
-        if ( parent == null )
-        {
-            return;
-        }
-
-        // Group id
-        if ( child.getGroupId() == null )
-        {
-            child.setGroupId( parent.getGroupId() );
-        }
-
-        // version
-        if ( child.getVersion() == null )
-        {
-            // The parent version may have resolved to something different, so we take what we asked for...
-            // instead of - child.setVersion( parent.getVersion() );
-
-            if ( child.getParent() != null )
-            {
-                child.setVersion( child.getParent().getVersion() );
-            }
-        }
-
-        // inceptionYear
-        if ( child.getInceptionYear() == null )
-        {
-            child.setInceptionYear( parent.getInceptionYear() );
-        }
-
-        // url
-        if ( child.getUrl() == null )
-        {
-            if ( parent.getUrl() != null )
-            {
-                child.setUrl( appendPath( parent.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
-            }
-            else
-            {
-                child.setUrl( parent.getUrl() );
-            }
-        }
-
-        assembleDistributionInheritance( child, parent, childPathAdjustment, appendPaths );
-
-        // issueManagement
-        if ( child.getIssueManagement() == null )
-        {
-            child.setIssueManagement( parent.getIssueManagement() );
-        }
-
-        // description
-        if ( child.getDescription() == null )
-        {
-            child.setDescription( parent.getDescription() );
-        }
-
-        // Organization
-        if ( child.getOrganization() == null )
-        {
-            child.setOrganization( parent.getOrganization() );
-        }
-
-        // Scm
-        assembleScmInheritance( child, parent, childPathAdjustment, appendPaths );
-
-        // ciManagement
-        if ( child.getCiManagement() == null )
-        {
-            child.setCiManagement( parent.getCiManagement() );
-        }
-
-        // developers
-        if ( child.getDevelopers().size() == 0 )
-        {
-            child.setDevelopers( parent.getDevelopers() );
-        }
-
-        // licenses
-        if ( child.getLicenses().size() == 0 )
-        {
-            child.setLicenses( parent.getLicenses() );
-        }
-
-        // developers
-        if ( child.getContributors().size() == 0 )
-        {
-            child.setContributors( parent.getContributors() );
-        }
-
-        // mailingLists
-        if ( child.getMailingLists().size() == 0 )
-        {
-            child.setMailingLists( parent.getMailingLists() );
-        }
-
-        // Build
-        assembleBuildInheritance( child, parent );
-
-        assembleDependencyInheritance( child, parent );
-
-        child.setRepositories( ModelUtils.mergeRepositoryLists( child.getRepositories(), parent.getRepositories() ) );
-//        child.setPluginRepositories(
-//            ModelUtils.mergeRepositoryLists( child.getPluginRepositories(), parent.getPluginRepositories() ) );
-
-        assembleReportingInheritance( child, parent );
-
-        assembleDependencyManagementInheritance( child, parent );
-
-        Properties props = new Properties();
-        props.putAll( parent.getProperties() );
-        props.putAll( child.getProperties() );
-
-        child.setProperties( props );
-    }
-
-    private void assembleDependencyManagementInheritance( Model child, Model parent )
-    {
-        DependencyManagement parentDepMgmt = parent.getDependencyManagement();
-
-        DependencyManagement childDepMgmt = child.getDependencyManagement();
-
-        if ( parentDepMgmt != null )
-        {
-            if ( childDepMgmt == null )
-            {
-                child.setDependencyManagement( parentDepMgmt );
-            }
-            else
-            {
-                List<Dependency> childDeps = childDepMgmt.getDependencies();
-
-                Map<String, Dependency> mappedChildDeps = new TreeMap<>();
-                for ( Dependency dep : childDeps )
-                {
-                    mappedChildDeps.put( dep.getManagementKey(), dep );
-                }
-
-                for ( Dependency dep : parentDepMgmt.getDependencies() )
-                {
-                    if ( !mappedChildDeps.containsKey( dep.getManagementKey() ) )
-                    {
-                        childDepMgmt.addDependency( dep );
-                    }
-                }
-            }
-        }
-    }
-
-    private void assembleReportingInheritance( Model child, Model parent )
-    {
-        // Reports :: aggregate
-        Reporting childReporting = child.getReporting();
-        Reporting parentReporting = parent.getReporting();
-
-        if ( parentReporting != null )
-        {
-            if ( childReporting == null )
-            {
-                childReporting = new Reporting();
-                child.setReporting( childReporting );
-            }
-
-            childReporting.setExcludeDefaults( parentReporting.isExcludeDefaults() );
-
-            if ( StringUtils.isEmpty( childReporting.getOutputDirectory() ) )
-            {
-                childReporting.setOutputDirectory( parentReporting.getOutputDirectory() );
-            }
-
-            mergeReportPluginLists( childReporting, parentReporting, true );
-        }
-    }
-
-    private static void mergeReportPluginLists( Reporting child, Reporting parent, boolean handleAsInheritance )
-    {
-        if ( ( child == null ) || ( parent == null ) )
-        {
-            // nothing to do.
-            return;
-        }
-
-        List<ReportPlugin> parentPlugins = parent.getPlugins();
-
-        if ( ( parentPlugins != null ) && !parentPlugins.isEmpty() )
-        {
-            Map<String, ReportPlugin> assembledPlugins = new TreeMap<>();
-
-            Map<String, ReportPlugin> childPlugins = child.getReportPluginsAsMap();
-
-            for ( ReportPlugin parentPlugin : parentPlugins )
-            {
-                String parentInherited = parentPlugin.getInherited();
-
-                if ( !handleAsInheritance || ( parentInherited == null ) || Boolean.parseBoolean( parentInherited ) )
-                {
-
-                    ReportPlugin assembledPlugin = parentPlugin;
-
-                    ReportPlugin childPlugin = childPlugins.get( parentPlugin.getKey() );
-
-                    if ( childPlugin != null )
-                    {
-                        assembledPlugin = childPlugin;
-
-                        mergeReportPluginDefinitions( childPlugin, parentPlugin, handleAsInheritance );
-                    }
-
-                    if ( handleAsInheritance && ( parentInherited == null ) )
-                    {
-                        assembledPlugin.unsetInheritanceApplied();
-                    }
-
-                    assembledPlugins.put( assembledPlugin.getKey(), assembledPlugin );
-                }
-            }
-
-            for ( ReportPlugin childPlugin : childPlugins.values() )
-            {
-                if ( !assembledPlugins.containsKey( childPlugin.getKey() ) )
-                {
-                    assembledPlugins.put( childPlugin.getKey(), childPlugin );
-                }
-            }
-
-            child.setPlugins( new ArrayList<>( assembledPlugins.values() ) );
-
-            child.flushReportPluginMap();
-        }
-    }
-
-    private static void mergeReportSetDefinitions( ReportSet child, ReportSet parent )
-    {
-        List<String> parentReports = parent.getReports();
-        List<String> childReports = child.getReports();
-
-        List<String> reports = new ArrayList<>();
-
-        if ( ( childReports != null ) && !childReports.isEmpty() )
-        {
-            reports.addAll( childReports );
-        }
-
-        if ( parentReports != null )
-        {
-            for ( String report : parentReports )
-            {
-                if ( !reports.contains( report ) )
-                {
-                    reports.add( report );
-                }
-            }
-        }
-
-        child.setReports( reports );
-
-        Xpp3Dom childConfiguration = (Xpp3Dom) child.getConfiguration();
-        Xpp3Dom parentConfiguration = (Xpp3Dom) parent.getConfiguration();
-
-        childConfiguration = Xpp3Dom.mergeXpp3Dom( childConfiguration, parentConfiguration );
-
-        child.setConfiguration( childConfiguration );
-    }
-
-
-    public static void mergeReportPluginDefinitions( ReportPlugin child, ReportPlugin parent,
-                                                     boolean handleAsInheritance )
-    {
-        if ( ( child == null ) || ( parent == null ) )
-        {
-            // nothing to do.
-            return;
-        }
-
-        if ( ( child.getVersion() == null ) && ( parent.getVersion() != null ) )
-        {
-            child.setVersion( parent.getVersion() );
-        }
-
-        // from here to the end of the method is dealing with merging of the <executions/> section.
-        String parentInherited = parent.getInherited();
-
-        boolean parentIsInherited = ( parentInherited == null ) || Boolean.parseBoolean( parentInherited );
-
-        List<ReportSet> parentReportSets = parent.getReportSets();
-
-        if ( ( parentReportSets != null ) && !parentReportSets.isEmpty() )
-        {
-            Map<String, ReportSet> assembledReportSets = new TreeMap<>();
-
-            Map<String, ReportSet> childReportSets = child.getReportSetsAsMap();
-
-            for ( Object parentReportSet1 : parentReportSets )
-            {
-                ReportSet parentReportSet = (ReportSet) parentReportSet1;
-
-                if ( !handleAsInheritance || parentIsInherited )
-                {
-                    ReportSet assembledReportSet = parentReportSet;
-
-                    ReportSet childReportSet = childReportSets.get( parentReportSet.getId() );
-
-                    if ( childReportSet != null )
-                    {
-                        mergeReportSetDefinitions( childReportSet, parentReportSet );
-
-                        assembledReportSet = childReportSet;
-                    }
-                    else if ( handleAsInheritance && ( parentInherited == null ) )
-                    {
-                        parentReportSet.unsetInheritanceApplied();
-                    }
-
-                    assembledReportSets.put( assembledReportSet.getId(), assembledReportSet );
-                }
-            }
-
-            for ( Map.Entry<String, ReportSet> entry : childReportSets.entrySet() )
-            {
-                String id = entry.getKey();
-
-                if ( !assembledReportSets.containsKey( id ) )
-                {
-                    assembledReportSets.put( id, entry.getValue() );
-                }
-            }
-
-            child.setReportSets( new ArrayList<>( assembledReportSets.values() ) );
-
-            child.flushReportSetMap();
-        }
-
-    }
-
-    private void assembleDependencyInheritance( Model child, Model parent )
-    {
-        Map<String, Dependency> depsMap = new LinkedHashMap<>();
-
-        List<Dependency> deps = parent.getDependencies();
-
-        if ( deps != null )
-        {
-            for ( Dependency dependency : deps )
-            {
-                depsMap.put( dependency.getManagementKey(), dependency );
-            }
-        }
-
-        deps = child.getDependencies();
-
-        if ( deps != null )
-        {
-            for ( Dependency dependency : deps )
-            {
-                depsMap.put( dependency.getManagementKey(), dependency );
-            }
-        }
-
-        child.setDependencies( new ArrayList<>( depsMap.values() ) );
-    }
-
-    private void assembleBuildInheritance( Model child, Model parent )
-    {
-        Build childBuild = child.getBuild();
-        Build parentBuild = parent.getBuild();
-
-        if ( parentBuild != null )
-        {
-            if ( childBuild == null )
-            {
-                childBuild = new Build();
-                child.setBuild( childBuild );
-            }
-
-            assembleBuildInheritance( childBuild, parentBuild, true );
-        }
-    }
-
-    private void assembleDistributionInheritance( Model child, Model parent, String childPathAdjustment,
-                                                  boolean appendPaths )
-    {
-        if ( parent.getDistributionManagement() != null )
-        {
-            DistributionManagement parentDistMgmt = parent.getDistributionManagement();
-
-            DistributionManagement childDistMgmt = child.getDistributionManagement();
-
-            if ( childDistMgmt == null )
-            {
-                childDistMgmt = new DistributionManagement();
-
-                child.setDistributionManagement( childDistMgmt );
-            }
-
-            if ( childDistMgmt.getSite() == null )
-            {
-                if ( parentDistMgmt.getSite() != null )
-                {
-                    Site site = new Site();
-
-                    childDistMgmt.setSite( site );
-
-                    site.setId( parentDistMgmt.getSite().getId() );
-
-                    site.setName( parentDistMgmt.getSite().getName() );
-
-                    site.setUrl( parentDistMgmt.getSite().getUrl() );
-
-                    if ( site.getUrl() != null )
-                    {
-                        site.setUrl(
-                            appendPath( site.getUrl(), child.getArtifactId(), childPathAdjustment, appendPaths ) );
-                    }
-                }
-            }
-
-            if ( childDistMgmt.getRepository() == null )
-            {
-                if ( parentDistMgmt.getRepository() != null )
-                {
-                    DeploymentRepository repository = copyDistributionRepository( parentDistMgmt.getRepository() );
-                    childDistMgmt.setRepository( repository );
-                }
-            }
-
-            if ( childDistMgmt.getSnapshotRepository() == null )
-            {
-                if ( parentDistMgmt.getSnapshotRepository() != null )
-                {
-                    DeploymentRepository repository =
-                        copyDistributionRepository( parentDistMgmt.getSnapshotRepository() );
-                    childDistMgmt.setSnapshotRepository( repository );
-                }
-            }
-
-            if ( StringUtils.isEmpty( childDistMgmt.getDownloadUrl() ) )
-            {
-                childDistMgmt.setDownloadUrl( parentDistMgmt.getDownloadUrl() );
-            }
-
-            // NOTE: We SHOULD NOT be inheriting status, since this is an assessment of the POM quality.
-            // NOTE: We SHOULD NOT be inheriting relocation, since this relates to a single POM
-        }
-    }
-
-    private static DeploymentRepository copyDistributionRepository( DeploymentRepository parentRepository )
-    {
-        DeploymentRepository repository = new DeploymentRepository();
-
-        repository.setId( parentRepository.getId() );
-
-        repository.setName( parentRepository.getName() );
-
-        repository.setUrl( parentRepository.getUrl() );
-
-        repository.setLayout( parentRepository.getLayout() );
-
-        repository.setUniqueVersion( parentRepository.isUniqueVersion() );
-
-        return repository;
-    }
-
-    // TODO This should eventually be migrated to DefaultPathTranslator.
-    protected String appendPath( String parentPath, String childPath, String pathAdjustment, boolean appendPaths )
-    {
-        String uncleanPath = parentPath;
-
-        if ( appendPaths )
-        {
-            if ( pathAdjustment != null )
-            {
-                uncleanPath += "/" + pathAdjustment;
-            }
-
-            if ( childPath != null )
-            {
-                uncleanPath += "/" + childPath;
-            }
-        }
-
-        String cleanedPath = "";
-
-        int protocolIdx = uncleanPath.indexOf( "://" );
-
-        if ( protocolIdx > -1 )
-        {
-            cleanedPath = uncleanPath.substring( 0, protocolIdx + 3 );
-            uncleanPath = uncleanPath.substring( protocolIdx + 3 );
-        }
-
-        if ( uncleanPath.startsWith( "/" ) )
-        {
-            cleanedPath += "/";
-        }
-
-        return cleanedPath + resolvePath( uncleanPath );
-    }
-
-    // TODO Move this to plexus-utils' PathTool.
-    private static String resolvePath( String uncleanPath )
-    {
-        LinkedList<String> pathElements = new LinkedList<>();
-
-        StringTokenizer tokenizer = new StringTokenizer( uncleanPath, "/" );
-
-        while ( tokenizer.hasMoreTokens() )
-        {
-            String token = tokenizer.nextToken();
-
-            switch ( token )
-            {
-                case "":
-                    // Empty path entry ("...//.."), remove.
-                    break;
-                case "..":
-                    if ( pathElements.isEmpty() )
-                    {
-                        // FIXME: somehow report to the user
-                        // that there are too many '..' elements.
-                        // For now, ignore the extra '..'.
-                    }
-                    else
-                    {
-                        pathElements.removeLast();
-                    }
-                    break;
-                default:
-                    pathElements.addLast( token );
-                    break;
-            }
-        }
-
-        StringBuilder cleanedPath = new StringBuilder();
-
-        while ( !pathElements.isEmpty() )
-        {
-            cleanedPath.append( pathElements.removeFirst() );
-            if ( !pathElements.isEmpty() )
-            {
-                cleanedPath.append( '/' );
-            }
-        }
-
-        return cleanedPath.toString();
-    }
-
-    private static void mergeExtensionLists( Build childBuild, Build parentBuild )
-    {
-        for ( Extension e : parentBuild.getExtensions() )
-        {
-            if ( !childBuild.getExtensions().contains( e ) )
-            {
-                childBuild.addExtension( e );
-            }
-        }
+    @Override
+    public void copyModel(Model dest, Model source) {
+        throw new UnsupportedOperationException();
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/inheritance/ModelInheritanceAssembler.java b/maven-compat/src/main/java/org/apache/maven/project/inheritance/ModelInheritanceAssembler.java
index bf8a63b..df0fc5a 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/inheritance/ModelInheritanceAssembler.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/inheritance/ModelInheritanceAssembler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,24 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance;
 
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Model;
 
 /**
- * @author Jason van Zyl
- * @deprecated
  */
 @Deprecated
-public interface ModelInheritanceAssembler
-{
+public interface ModelInheritanceAssembler {
     String ROLE = ModelInheritanceAssembler.class.getName();
 
-    void assembleModelInheritance( Model child, Model parent, String childPathAdjustment );
+    void assembleModelInheritance(Model child, Model parent, String childPathAdjustment);
 
-    void assembleModelInheritance( Model child, Model parent );
+    void assembleModelInheritance(Model child, Model parent);
 
-    void assembleBuildInheritance( Build childBuild, Build parentBuild, boolean handleAsInheritance );
+    void assembleBuildInheritance(Build childBuild, Build parentBuild, boolean handleAsInheritance);
 
-    void copyModel( Model dest, Model source );
+    void copyModel(Model dest, Model source);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/interpolation/AbstractStringBasedModelInterpolator.java b/maven-compat/src/main/java/org/apache/maven/project/interpolation/AbstractStringBasedModelInterpolator.java
index 996baef..0570d20 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/interpolation/AbstractStringBasedModelInterpolator.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/interpolation/AbstractStringBasedModelInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.interpolation;
+
+import javax.inject.Inject;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
 
 import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.apache.maven.model.v4.MavenStaxReader;
+import org.apache.maven.model.v4.MavenStaxWriter;
 import org.apache.maven.project.DefaultProjectBuilderConfiguration;
 import org.apache.maven.project.ProjectBuilderConfiguration;
 import org.apache.maven.project.path.PathTranslator;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.interpolation.AbstractValueSource;
 import org.codehaus.plexus.interpolation.InterpolationException;
 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
@@ -41,37 +53,21 @@
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
 
 /**
  * Use a regular expression search to find and resolve expressions within the POM.
  *
- * @author jdcasey Created on Feb 3, 2005
  * TODO Consolidate this logic with the PluginParameterExpressionEvaluator, minus deprecations/bans.
  */
 @Deprecated
-public abstract class AbstractStringBasedModelInterpolator
-    extends AbstractLogEnabled
-    implements ModelInterpolator, Initializable
-{
+public abstract class AbstractStringBasedModelInterpolator extends AbstractLogEnabled
+        implements ModelInterpolator, Initializable {
 
-    private static final List<String> PROJECT_PREFIXES = Arrays.asList( "pom.", "project." );
+    private static final List<String> PROJECT_PREFIXES = Arrays.asList("pom.", "project.");
 
     private static final List<String> TRANSLATED_PATH_EXPRESSIONS;
 
-    static
-    {
+    static {
         List<String> translatedPrefixes = new ArrayList<>();
 
         // MNG-1927, MNG-2124, MNG-3355:
@@ -79,18 +75,18 @@
         // sure interpolation of the directories below uses translated paths.
         // Afterward, we'll double back and translate any paths that weren't covered during interpolation via the
         // code below...
-        translatedPrefixes.add( "build.directory" );
-        translatedPrefixes.add( "build.outputDirectory" );
-        translatedPrefixes.add( "build.testOutputDirectory" );
-        translatedPrefixes.add( "build.sourceDirectory" );
-        translatedPrefixes.add( "build.testSourceDirectory" );
-        translatedPrefixes.add( "build.scriptSourceDirectory" );
-        translatedPrefixes.add( "reporting.outputDirectory" );
+        translatedPrefixes.add("build.directory");
+        translatedPrefixes.add("build.outputDirectory");
+        translatedPrefixes.add("build.testOutputDirectory");
+        translatedPrefixes.add("build.sourceDirectory");
+        translatedPrefixes.add("build.testSourceDirectory");
+        translatedPrefixes.add("build.scriptSourceDirectory");
+        translatedPrefixes.add("reporting.outputDirectory");
 
         TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
     }
 
-    @Requirement
+    @Inject
     private PathTranslator pathTranslator;
 
     private Interpolator interpolator;
@@ -98,19 +94,14 @@
     private RecursionInterceptor recursionInterceptor;
 
     // for testing.
-    protected AbstractStringBasedModelInterpolator( PathTranslator pathTranslator )
-    {
+    protected AbstractStringBasedModelInterpolator(PathTranslator pathTranslator) {
         this.pathTranslator = pathTranslator;
     }
 
-    protected AbstractStringBasedModelInterpolator()
-    {
-    }
+    protected AbstractStringBasedModelInterpolator() {}
 
-    public Model interpolate( Model model, Map<String, ?> context )
-        throws ModelInterpolationException
-    {
-        return interpolate( model, context, true );
+    public Model interpolate(Model model, Map<String, ?> context) throws ModelInterpolationException {
+        return interpolate(model, context, true);
     }
 
     /**
@@ -126,50 +117,36 @@
      *
      * @deprecated Use {@link ModelInterpolator#interpolate(Model, File, ProjectBuilderConfiguration, boolean)} instead.
      */
-    public Model interpolate( Model model, Map<String, ?> context, boolean strict )
-        throws ModelInterpolationException
-    {
+    @Deprecated
+    public Model interpolate(Model model, Map<String, ?> context, boolean strict) throws ModelInterpolationException {
         Properties props = new Properties();
-        props.putAll( context );
+        props.putAll(context);
 
-        return interpolate( model,
-                            null,
-                            new DefaultProjectBuilderConfiguration().setExecutionProperties( props ),
-                            true );
+        return interpolate(model, null, new DefaultProjectBuilderConfiguration().setExecutionProperties(props), true);
     }
 
-    public Model interpolate( Model model,
-                              File projectDir,
-                              ProjectBuilderConfiguration config,
-                              boolean debugEnabled )
-        throws ModelInterpolationException
-    {
-        StringWriter sWriter = new StringWriter( 1024 );
+    public Model interpolate(Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled)
+            throws ModelInterpolationException {
+        StringWriter sWriter = new StringWriter(1024);
 
-        MavenXpp3Writer writer = new MavenXpp3Writer();
-        try
-        {
-            writer.write( sWriter, model );
-        }
-        catch ( IOException e )
-        {
-            throw new ModelInterpolationException( "Cannot serialize project model for interpolation.", e );
+        MavenStaxWriter writer = new MavenStaxWriter();
+        try {
+            writer.write(sWriter, model.getDelegate());
+        } catch (IOException | XMLStreamException e) {
+            throw new ModelInterpolationException("Cannot serialize project model for interpolation.", e);
         }
 
         String serializedModel = sWriter.toString();
-        serializedModel = interpolate( serializedModel, model, projectDir, config, debugEnabled );
+        serializedModel = interpolate(serializedModel, model, projectDir, config, debugEnabled);
 
-        StringReader sReader = new StringReader( serializedModel );
+        StringReader sReader = new StringReader(serializedModel);
 
-        MavenXpp3Reader modelReader = new MavenXpp3Reader();
-        try
-        {
-            model = modelReader.read( sReader );
-        }
-        catch ( IOException | XmlPullParserException e )
-        {
+        MavenStaxReader modelReader = new MavenStaxReader();
+        try {
+            model = new Model(modelReader.read(sReader));
+        } catch (XMLStreamException e) {
             throw new ModelInterpolationException(
-                "Cannot read project model from interpolating filter of serialized version.", e );
+                    "Cannot read project model from interpolating filter of serialized version.", e);
         }
 
         return model;
@@ -187,191 +164,146 @@
      *   <li>If the value is null, get it from the model properties.</li>
      * </ul>
      */
-    public String interpolate( String src,
-                               Model model,
-                               final File projectDir,
-                               ProjectBuilderConfiguration config,
-                               boolean debug )
-        throws ModelInterpolationException
-    {
-        try
-        {
-            List<ValueSource> valueSources = createValueSources( model, projectDir, config );
-            List<InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
+    public String interpolate(
+            String src, Model model, final File projectDir, ProjectBuilderConfiguration config, boolean debug)
+            throws ModelInterpolationException {
+        try {
+            List<ValueSource> valueSources = createValueSources(model, projectDir, config);
+            List<InterpolationPostProcessor> postProcessors = createPostProcessors(model, projectDir, config);
 
-            return interpolateInternal( src, valueSources, postProcessors, debug );
-        }
-        finally
-        {
+            return interpolateInternal(src, valueSources, postProcessors, debug);
+        } finally {
             interpolator.clearAnswers();
         }
     }
 
-    protected List<ValueSource> createValueSources( final Model model, final File projectDir,
-                                                    final ProjectBuilderConfiguration config )
-    {
+    protected List<ValueSource> createValueSources(
+            final Model model, final File projectDir, final ProjectBuilderConfiguration config) {
         String timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
 
         Properties modelProperties = model.getProperties();
-        if ( modelProperties != null )
-        {
-            timestampFormat = modelProperties.getProperty( BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat );
+        if (modelProperties != null) {
+            timestampFormat = modelProperties.getProperty(BUILD_TIMESTAMP_FORMAT_PROPERTY, timestampFormat);
         }
 
-        ValueSource modelValueSource1 = new PrefixedObjectValueSource( PROJECT_PREFIXES, model, false );
-        ValueSource modelValueSource2 = new ObjectBasedValueSource( model );
+        ValueSource modelValueSource1 = new PrefixedObjectValueSource(PROJECT_PREFIXES, model, false);
+        ValueSource modelValueSource2 = new ObjectBasedValueSource(model);
 
-        ValueSource basedirValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
-        {
+        ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
+                new AbstractValueSource(false) {
 
-            public Object getValue( String expression )
-            {
-                if ( projectDir != null && "basedir".equals( expression ) )
-                {
-                    return projectDir.getAbsolutePath();
-                }
-                return null;
-            }
+                    public Object getValue(String expression) {
+                        if (projectDir != null && "basedir".equals(expression)) {
+                            return projectDir.getAbsolutePath();
+                        }
+                        return null;
+                    }
+                },
+                PROJECT_PREFIXES,
+                true);
+        ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
+                new AbstractValueSource(false) {
 
-        }, PROJECT_PREFIXES, true );
-        ValueSource baseUriValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
-        {
+                    public Object getValue(String expression) {
+                        if (projectDir != null && "baseUri".equals(expression)) {
+                            return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
+                        }
+                        return null;
+                    }
+                },
+                PROJECT_PREFIXES,
+                false);
 
-            public Object getValue( String expression )
-            {
-                if ( projectDir != null && "baseUri".equals( expression ) )
-                {
-                    return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
-                }
-                return null;
-            }
-
-        }, PROJECT_PREFIXES, false );
-
-        List<ValueSource> valueSources = new ArrayList<>( 9 );
+        List<ValueSource> valueSources = new ArrayList<>(9);
 
         // NOTE: Order counts here!
-        valueSources.add( basedirValueSource );
-        valueSources.add( baseUriValueSource );
-        valueSources.add( new BuildTimestampValueSource( config.getBuildStartTime(), timestampFormat ) );
-        valueSources.add( modelValueSource1 );
-        valueSources.add( new MapBasedValueSource( config.getUserProperties() ) );
-        valueSources.add( new MapBasedValueSource( modelProperties ) );
-        valueSources.add( new MapBasedValueSource( config.getExecutionProperties() ) );
-        valueSources.add( new AbstractValueSource( false )
-        {
+        valueSources.add(basedirValueSource);
+        valueSources.add(baseUriValueSource);
+        valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), timestampFormat));
+        valueSources.add(modelValueSource1);
+        valueSources.add(new MapBasedValueSource(config.getUserProperties()));
+        valueSources.add(new MapBasedValueSource(modelProperties));
+        valueSources.add(new MapBasedValueSource(config.getExecutionProperties()));
+        valueSources.add(new AbstractValueSource(false) {
 
-            public Object getValue( String expression )
-            {
-                return config.getExecutionProperties().getProperty( "env." + expression );
+            public Object getValue(String expression) {
+                return config.getExecutionProperties().getProperty("env." + expression);
             }
-
-        } );
-        valueSources.add( modelValueSource2 );
+        });
+        valueSources.add(modelValueSource2);
 
         return valueSources;
     }
 
-    protected List<InterpolationPostProcessor> createPostProcessors( final Model model, final File projectDir,
-                                                                     final ProjectBuilderConfiguration config )
-    {
-        return Collections.singletonList(
-            (InterpolationPostProcessor) new PathTranslatingPostProcessor(
-                PROJECT_PREFIXES,
-                TRANSLATED_PATH_EXPRESSIONS,
-                projectDir,
-                pathTranslator ) );
-
+    protected List<InterpolationPostProcessor> createPostProcessors(
+            final Model model, final File projectDir, final ProjectBuilderConfiguration config) {
+        return Collections.singletonList((InterpolationPostProcessor) new PathTranslatingPostProcessor(
+                PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS, projectDir, pathTranslator));
     }
 
-    @SuppressWarnings( "unchecked" )
-    protected String interpolateInternal( String src, List<ValueSource> valueSources,
-                                          List<InterpolationPostProcessor> postProcessors, boolean debug )
-        throws ModelInterpolationException
-    {
-        if ( !src.contains( "${" ) )
-        {
+    @SuppressWarnings("unchecked")
+    protected String interpolateInternal(
+            String src, List<ValueSource> valueSources, List<InterpolationPostProcessor> postProcessors, boolean debug)
+            throws ModelInterpolationException {
+        if (!src.contains("${")) {
             return src;
         }
 
         Logger logger = getLogger();
 
         String result = src;
-        synchronized ( this )
-        {
-
-            for ( ValueSource vs : valueSources )
-            {
-                interpolator.addValueSource( vs );
+        synchronized (this) {
+            for (ValueSource vs : valueSources) {
+                interpolator.addValueSource(vs);
             }
 
-            for ( InterpolationPostProcessor postProcessor : postProcessors )
-            {
-                interpolator.addPostProcessor( postProcessor );
+            for (InterpolationPostProcessor postProcessor : postProcessors) {
+                interpolator.addPostProcessor(postProcessor);
             }
 
-            try
-            {
-                try
-                {
-                    result = interpolator.interpolate( result, recursionInterceptor );
-                }
-                catch ( InterpolationException e )
-                {
-                    throw new ModelInterpolationException( e.getMessage(), e );
+            try {
+                try {
+                    result = interpolator.interpolate(result, recursionInterceptor);
+                } catch (InterpolationException e) {
+                    throw new ModelInterpolationException(e.getMessage(), e);
                 }
 
-                if ( debug )
-                {
+                if (debug) {
                     List<Object> feedback = interpolator.getFeedback();
-                    if ( feedback != null && !feedback.isEmpty() )
-                    {
-                        logger.debug( "Maven encountered the following problems during initial POM interpolation:" );
+                    if (feedback != null && !feedback.isEmpty()) {
+                        logger.debug("Maven encountered the following problems during initial POM interpolation:");
 
                         Object last = null;
-                        for ( Object next : feedback )
-                        {
-                            if ( next instanceof Throwable )
-                            {
-                                if ( last == null )
-                                {
-                                    logger.debug( "", ( (Throwable) next ) );
+                        for (Object next : feedback) {
+                            if (next instanceof Throwable) {
+                                if (last == null) {
+                                    logger.debug("", ((Throwable) next));
+                                } else {
+                                    logger.debug(String.valueOf(last), ((Throwable) next));
                                 }
-                                else
-                                {
-                                    logger.debug( String.valueOf( last ), ( (Throwable) next ) );
-                                }
-                            }
-                            else
-                            {
-                                if ( last != null )
-                                {
-                                    logger.debug( String.valueOf( last ) );
+                            } else {
+                                if (last != null) {
+                                    logger.debug(String.valueOf(last));
                                 }
 
                                 last = next;
                             }
                         }
 
-                        if ( last != null )
-                        {
-                            logger.debug( String.valueOf( last ) );
+                        if (last != null) {
+                            logger.debug(String.valueOf(last));
                         }
                     }
                 }
 
                 interpolator.clearFeedback();
-            }
-            finally
-            {
-                for ( ValueSource vs : valueSources )
-                {
-                    interpolator.removeValuesSource( vs );
+            } finally {
+                for (ValueSource vs : valueSources) {
+                    interpolator.removeValuesSource(vs);
                 }
 
-                for ( InterpolationPostProcessor postProcessor : postProcessors )
-                {
-                    interpolator.removePostProcessor( postProcessor );
+                for (InterpolationPostProcessor postProcessor : postProcessors) {
+                    interpolator.removePostProcessor(postProcessor);
                 }
             }
         }
@@ -379,28 +311,22 @@
         return result;
     }
 
-    protected RecursionInterceptor getRecursionInterceptor()
-    {
+    protected RecursionInterceptor getRecursionInterceptor() {
         return recursionInterceptor;
     }
 
-    protected void setRecursionInterceptor( RecursionInterceptor recursionInterceptor )
-    {
+    protected void setRecursionInterceptor(RecursionInterceptor recursionInterceptor) {
         this.recursionInterceptor = recursionInterceptor;
     }
 
     protected abstract Interpolator createInterpolator();
 
-    public void initialize()
-        throws InitializationException
-    {
+    public void initialize() throws InitializationException {
         interpolator = createInterpolator();
-        recursionInterceptor = new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
+        recursionInterceptor = new PrefixAwareRecursionInterceptor(PROJECT_PREFIXES);
     }
 
-    protected final Interpolator getInterpolator()
-    {
+    protected final Interpolator getInterpolator() {
         return interpolator;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/interpolation/BuildTimestampValueSource.java b/maven-compat/src/main/java/org/apache/maven/project/interpolation/BuildTimestampValueSource.java
index f6319fa..f2af803 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/interpolation/BuildTimestampValueSource.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/interpolation/BuildTimestampValueSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.interpolation;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -28,9 +27,7 @@
  *
  */
 @Deprecated
-public class BuildTimestampValueSource
-    extends AbstractValueSource
-{
+public class BuildTimestampValueSource extends AbstractValueSource {
 
     private final Date startTime;
 
@@ -38,20 +35,16 @@
 
     private String formattedDate;
 
-    public BuildTimestampValueSource( Date startTime, String format )
-    {
-        super( false );
+    public BuildTimestampValueSource(Date startTime, String format) {
+        super(false);
         this.startTime = startTime;
         this.format = format;
     }
 
-    public Object getValue( String expression )
-    {
-        if ( "build.timestamp".equals( expression ) || "maven.build.timestamp".equals( expression ) )
-        {
-            if ( formattedDate == null && startTime != null )
-            {
-                formattedDate = new SimpleDateFormat( format ).format( startTime );
+    public Object getValue(String expression) {
+        if ("build.timestamp".equals(expression) || "maven.build.timestamp".equals(expression)) {
+            if (formattedDate == null && startTime != null) {
+                formattedDate = new SimpleDateFormat(format).format(startTime);
             }
 
             return formattedDate;
@@ -59,5 +52,4 @@
 
         return null;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolationException.java b/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolationException.java
index ea60f16..9200a09 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolationException.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,53 +16,44 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.interpolation;
 
 /**
- * @author jdcasey
  */
-@SuppressWarnings( "serial" )
+@SuppressWarnings("serial")
 @Deprecated
-public class ModelInterpolationException
-    extends Exception
-{
+public class ModelInterpolationException extends Exception {
     private String expression;
 
     private String originalMessage;
 
-    public ModelInterpolationException( String message )
-    {
-        super( message );
+    public ModelInterpolationException(String message) {
+        super(message);
     }
 
-    public ModelInterpolationException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public ModelInterpolationException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public ModelInterpolationException( String expression, String message, Throwable cause )
-    {
-        super( "The POM expression: " + expression + " could not be evaluated. Reason: " + message, cause );
+    public ModelInterpolationException(String expression, String message, Throwable cause) {
+        super("The POM expression: " + expression + " could not be evaluated. Reason: " + message, cause);
 
         this.expression = expression;
         this.originalMessage = message;
     }
 
-    public ModelInterpolationException( String expression, String message )
-    {
-        super( "The POM expression: " + expression + " could not be evaluated. Reason: " + message );
+    public ModelInterpolationException(String expression, String message) {
+        super("The POM expression: " + expression + " could not be evaluated. Reason: " + message);
 
         this.expression = expression;
         this.originalMessage = message;
     }
 
-    public String getExpression()
-    {
+    public String getExpression() {
         return expression;
     }
 
-    public String getOriginalMessage()
-    {
+    public String getOriginalMessage() {
         return originalMessage;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolator.java b/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolator.java
index 036e7f0..42d4f12 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolator.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/interpolation/ModelInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.model.Model;
-import org.apache.maven.project.ProjectBuilderConfiguration;
+package org.apache.maven.project.interpolation;
 
 import java.io.File;
 import java.util.Map;
 
+import org.apache.maven.model.Model;
+import org.apache.maven.project.ProjectBuilderConfiguration;
+
 /**
- * @author jdcasey
  */
 @Deprecated
-public interface ModelInterpolator
-{
+public interface ModelInterpolator {
     String DEFAULT_BUILD_TIMESTAMP_FORMAT = "yyyyMMdd-HHmm";
 
     String BUILD_TIMESTAMP_FORMAT_PROPERTY = "maven.build.timestamp.format";
@@ -40,25 +37,19 @@
     /**
      * @deprecated Use {@link ModelInterpolator#interpolate(Model, File, ProjectBuilderConfiguration, boolean)} instead.
      */
-    Model interpolate( Model project, Map<String, ?> context )
-        throws ModelInterpolationException;
+    @Deprecated
+    Model interpolate(Model project, Map<String, ?> context) throws ModelInterpolationException;
 
     /**
      * @deprecated Use {@link ModelInterpolator#interpolate(Model, File, ProjectBuilderConfiguration, boolean)} instead.
      */
-    Model interpolate( Model model, Map<String, ?> context, boolean strict )
-        throws ModelInterpolationException;
+    @Deprecated
+    Model interpolate(Model model, Map<String, ?> context, boolean strict) throws ModelInterpolationException;
 
-    Model interpolate( Model model,
-                       File projectDir,
-                       ProjectBuilderConfiguration config,
-                       boolean debugEnabled )
-        throws ModelInterpolationException;
+    Model interpolate(Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled)
+            throws ModelInterpolationException;
 
-    String interpolate( String src,
-                        Model model,
-                        File projectDir,
-                        ProjectBuilderConfiguration config,
-                        boolean debugEnabled )
-        throws ModelInterpolationException;
+    String interpolate(
+            String src, Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled)
+            throws ModelInterpolationException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/interpolation/PathTranslatingPostProcessor.java b/maven-compat/src/main/java/org/apache/maven/project/interpolation/PathTranslatingPostProcessor.java
index da2ba05..c6651fb 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/interpolation/PathTranslatingPostProcessor.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/interpolation/PathTranslatingPostProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,47 +16,44 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.interpolation;
+
+import java.io.File;
+import java.util.List;
 
 import org.apache.maven.project.path.PathTranslator;
 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
 import org.codehaus.plexus.interpolation.util.ValueSourceUtils;
 
-import java.io.File;
-import java.util.List;
-
 /**
  *
  */
 @Deprecated
-public class PathTranslatingPostProcessor
-    implements InterpolationPostProcessor
-{
+public class PathTranslatingPostProcessor implements InterpolationPostProcessor {
 
     private final List<String> unprefixedPathKeys;
     private final File projectDir;
     private final PathTranslator pathTranslator;
     private final List<String> expressionPrefixes;
 
-    public PathTranslatingPostProcessor( List<String> expressionPrefixes, List<String> unprefixedPathKeys,
-                                         File projectDir, PathTranslator pathTranslator )
-    {
+    public PathTranslatingPostProcessor(
+            List<String> expressionPrefixes,
+            List<String> unprefixedPathKeys,
+            File projectDir,
+            PathTranslator pathTranslator) {
         this.expressionPrefixes = expressionPrefixes;
         this.unprefixedPathKeys = unprefixedPathKeys;
         this.projectDir = projectDir;
         this.pathTranslator = pathTranslator;
     }
 
-    public Object execute( String expression,
-                                      Object value )
-    {
-        expression = ValueSourceUtils.trimPrefix( expression, expressionPrefixes, true );
+    public Object execute(String expression, Object value) {
+        expression = ValueSourceUtils.trimPrefix(expression, expressionPrefixes, true);
 
-        if ( projectDir != null && value != null && unprefixedPathKeys.contains( expression ) )
-        {
-            return pathTranslator.alignToBaseDirectory( String.valueOf( value ), projectDir );
+        if (projectDir != null && value != null && unprefixedPathKeys.contains(expression)) {
+            return pathTranslator.alignToBaseDirectory(String.valueOf(value), projectDir);
         }
 
         return value;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java b/maven-compat/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java
index 78990ea..f1dfe3f 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/interpolation/RegexBasedModelInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.interpolation;
 
 import java.io.IOException;
 import java.util.Properties;
@@ -29,30 +28,20 @@
 /**
  * Use a regular expression search to find and resolve expressions within the POM.
  *
- * @author jdcasey Created on Feb 3, 2005
  * TODO Consolidate this logic with the PluginParameterExpressionEvaluator, minus deprecations/bans.
  */
 @Deprecated
-public class RegexBasedModelInterpolator
-    extends AbstractStringBasedModelInterpolator
-{
+public class RegexBasedModelInterpolator extends AbstractStringBasedModelInterpolator {
 
-    public RegexBasedModelInterpolator()
-        throws IOException
-    {
+    public RegexBasedModelInterpolator() throws IOException {}
+
+    public RegexBasedModelInterpolator(PathTranslator pathTranslator) {
+        super(pathTranslator);
     }
 
-    public RegexBasedModelInterpolator( PathTranslator pathTranslator )
-    {
-        super( pathTranslator );
-    }
+    public RegexBasedModelInterpolator(Properties envars) {}
 
-    public RegexBasedModelInterpolator( Properties envars )
-    {
-    }
-
-    protected Interpolator createInterpolator()
-    {
-        return new RegexBasedInterpolator( true );
+    protected Interpolator createInterpolator() {
+        return new RegexBasedInterpolator(true);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java b/maven-compat/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java
index 8dc8784..d63cbec 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/interpolation/StringSearchModelInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.interpolation;
 
-import org.apache.maven.model.Model;
-import org.apache.maven.project.ProjectBuilderConfiguration;
-import org.apache.maven.project.path.PathTranslator;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
-import org.codehaus.plexus.interpolation.Interpolator;
-import org.codehaus.plexus.interpolation.StringSearchInterpolator;
-import org.codehaus.plexus.interpolation.ValueSource;
-import org.codehaus.plexus.logging.Logger;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.lang.reflect.Array;
@@ -41,71 +33,67 @@
 import java.util.Map;
 import java.util.WeakHashMap;
 
+import org.apache.maven.model.Model;
+import org.apache.maven.project.ProjectBuilderConfiguration;
+import org.apache.maven.project.path.PathTranslator;
+import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
+import org.codehaus.plexus.interpolation.Interpolator;
+import org.codehaus.plexus.interpolation.StringSearchInterpolator;
+import org.codehaus.plexus.interpolation.ValueSource;
+import org.codehaus.plexus.logging.Logger;
+
 /**
  * StringSearchModelInterpolator
  */
 @Deprecated
-@Component( role = ModelInterpolator.class )
-public class StringSearchModelInterpolator
-    extends AbstractStringBasedModelInterpolator
-{
+@Named
+@Singleton
+public class StringSearchModelInterpolator extends AbstractStringBasedModelInterpolator {
 
     private static final Map<Class<?>, Field[]> FIELDS_BY_CLASS = new WeakHashMap<>();
     private static final Map<Class<?>, Boolean> PRIMITIVE_BY_CLASS = new WeakHashMap<>();
 
-    public StringSearchModelInterpolator()
-    {
+    public StringSearchModelInterpolator() {}
+
+    public StringSearchModelInterpolator(PathTranslator pathTranslator) {
+        super(pathTranslator);
     }
 
-    public StringSearchModelInterpolator( PathTranslator pathTranslator )
-    {
-        super( pathTranslator );
-    }
-
-    public Model interpolate( Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled )
-        throws ModelInterpolationException
-    {
-        interpolateObject( model, model, projectDir, config, debugEnabled );
+    public Model interpolate(Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled)
+            throws ModelInterpolationException {
+        interpolateObject(model, model, projectDir, config, debugEnabled);
 
         return model;
     }
 
-    protected void interpolateObject( Object obj, Model model, File projectDir, ProjectBuilderConfiguration config,
-                                      boolean debugEnabled )
-        throws ModelInterpolationException
-    {
-        try
-        {
-            List<ValueSource> valueSources = createValueSources( model, projectDir, config );
-            List<InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
+    protected void interpolateObject(
+            Object obj, Model model, File projectDir, ProjectBuilderConfiguration config, boolean debugEnabled)
+            throws ModelInterpolationException {
+        try {
+            List<ValueSource> valueSources = createValueSources(model, projectDir, config);
+            List<InterpolationPostProcessor> postProcessors = createPostProcessors(model, projectDir, config);
 
             InterpolateObjectAction action =
-                new InterpolateObjectAction( obj, valueSources, postProcessors, debugEnabled,
-                                             this, getLogger() );
+                    new InterpolateObjectAction(obj, valueSources, postProcessors, debugEnabled, this, getLogger());
 
-            ModelInterpolationException error = AccessController.doPrivileged( action );
+            ModelInterpolationException error = AccessController.doPrivileged(action);
 
-            if ( error != null )
-            {
+            if (error != null) {
                 throw error;
             }
-        }
-        finally
-        {
+        } finally {
             getInterpolator().clearAnswers();
         }
     }
 
-    protected Interpolator createInterpolator()
-    {
+    protected Interpolator createInterpolator() {
         StringSearchInterpolator interpolator = new StringSearchInterpolator();
-        interpolator.setCacheAnswers( true );
+        interpolator.setCacheAnswers(true);
 
         return interpolator;
     }
 
-    private static final class InterpolateObjectAction implements PrivilegedAction<ModelInterpolationException>
-    {
+    private static final class InterpolateObjectAction implements PrivilegedAction<ModelInterpolationException> {
 
         private final boolean debugEnabled;
         private final LinkedList<Object> interpolationTargets;
@@ -114,33 +102,31 @@
         private final List<ValueSource> valueSources;
         private final List<InterpolationPostProcessor> postProcessors;
 
-        InterpolateObjectAction( Object target, List<ValueSource> valueSources,
-                                        List<InterpolationPostProcessor> postProcessors, boolean debugEnabled,
-                                        StringSearchModelInterpolator modelInterpolator, Logger logger )
-        {
+        InterpolateObjectAction(
+                Object target,
+                List<ValueSource> valueSources,
+                List<InterpolationPostProcessor> postProcessors,
+                boolean debugEnabled,
+                StringSearchModelInterpolator modelInterpolator,
+                Logger logger) {
             this.valueSources = valueSources;
             this.postProcessors = postProcessors;
             this.debugEnabled = debugEnabled;
 
             this.interpolationTargets = new LinkedList<>();
-            interpolationTargets.add( target );
+            interpolationTargets.add(target);
 
             this.modelInterpolator = modelInterpolator;
             this.logger = logger;
         }
 
-        public ModelInterpolationException run()
-        {
-            while ( !interpolationTargets.isEmpty() )
-            {
+        public ModelInterpolationException run() {
+            while (!interpolationTargets.isEmpty()) {
                 Object obj = interpolationTargets.removeFirst();
 
-                try
-                {
-                    traverseObjectWithParents( obj.getClass(), obj );
-                }
-                catch ( ModelInterpolationException e )
-                {
+                try {
+                    traverseObjectWithParents(obj.getClass(), obj);
+                } catch (ModelInterpolationException e) {
                     return e;
                 }
             }
@@ -148,251 +134,170 @@
             return null;
         }
 
-        @SuppressWarnings( { "unchecked", "checkstyle:methodlength" } )
-        private void traverseObjectWithParents( Class<?> cls, Object target )
-            throws ModelInterpolationException
-        {
-            if ( cls == null )
-            {
+        @SuppressWarnings({"unchecked", "checkstyle:methodlength"})
+        private void traverseObjectWithParents(Class<?> cls, Object target) throws ModelInterpolationException {
+            if (cls == null) {
                 return;
             }
 
+            if (cls.isArray()) {
+                evaluateArray(target);
+            } else if (isQualifiedForInterpolation(cls)) {
+                Field[] fields = FIELDS_BY_CLASS.computeIfAbsent(cls, k -> cls.getDeclaredFields());
 
-            if ( cls.isArray() )
-            {
-                evaluateArray( target );
-            }
-            else if ( isQualifiedForInterpolation( cls ) )
-            {
-                Field[] fields = FIELDS_BY_CLASS.computeIfAbsent( cls, k -> cls.getDeclaredFields() );
-
-                for ( Field field : fields )
-                {
+                for (Field field : fields) {
                     Class<?> type = field.getType();
-                    if ( isQualifiedForInterpolation( field, type ) )
-                    {
+                    if (isQualifiedForInterpolation(field, type)) {
                         boolean isAccessible = field.isAccessible();
-                        field.setAccessible( true );
-                        try
-                        {
-                            try
-                            {
-                                if ( String.class == type )
-                                {
-                                    String value = (String) field.get( target );
-                                    if ( value != null )
-                                    {
-                                        String interpolated =
-                                            modelInterpolator.interpolateInternal( value, valueSources, postProcessors,
-                                                                                   debugEnabled );
+                        field.setAccessible(true);
+                        try {
+                            try {
+                                if (String.class == type) {
+                                    String value = (String) field.get(target);
+                                    if (value != null) {
+                                        String interpolated = modelInterpolator.interpolateInternal(
+                                                value, valueSources, postProcessors, debugEnabled);
 
-                                        if ( !interpolated.equals( value ) )
-                                        {
-                                            field.set( target, interpolated );
+                                        if (!interpolated.equals(value)) {
+                                            field.set(target, interpolated);
                                         }
                                     }
-                                }
-                                else if ( Collection.class.isAssignableFrom( type ) )
-                                {
-                                    Collection<Object> c = (Collection<Object>) field.get( target );
-                                    if ( c != null && !c.isEmpty() )
-                                    {
-                                        List<Object> originalValues = new ArrayList<>( c );
-                                        try
-                                        {
+                                } else if (Collection.class.isAssignableFrom(type)) {
+                                    Collection<Object> c = (Collection<Object>) field.get(target);
+                                    if (c != null && !c.isEmpty()) {
+                                        List<Object> originalValues = new ArrayList<>(c);
+                                        try {
                                             c.clear();
-                                        }
-                                        catch ( UnsupportedOperationException e )
-                                        {
-                                            if ( debugEnabled && logger != null )
-                                            {
-                                                logger.debug( "Skipping interpolation of field: " + field + " in: "
-                                                                  + cls.getName()
-                                                                  + "; it is an unmodifiable collection." );
+                                        } catch (UnsupportedOperationException e) {
+                                            if (debugEnabled && logger != null) {
+                                                logger.debug("Skipping interpolation of field: " + field + " in: "
+                                                        + cls.getName()
+                                                        + "; it is an unmodifiable collection.");
                                             }
                                             continue;
                                         }
 
-                                        for ( Object value : originalValues )
-                                        {
-                                            if ( value != null )
-                                            {
-                                                if ( String.class == value.getClass() )
-                                                {
-                                                    String interpolated =
-                                                        modelInterpolator.interpolateInternal( (String) value,
-                                                                                               valueSources,
-                                                                                               postProcessors,
-                                                                                               debugEnabled );
+                                        for (Object value : originalValues) {
+                                            if (value != null) {
+                                                if (String.class == value.getClass()) {
+                                                    String interpolated = modelInterpolator.interpolateInternal(
+                                                            (String) value, valueSources, postProcessors, debugEnabled);
 
-                                                    if ( !interpolated.equals( value ) )
-                                                    {
-                                                        c.add( interpolated );
+                                                    if (!interpolated.equals(value)) {
+                                                        c.add(interpolated);
+                                                    } else {
+                                                        c.add(value);
                                                     }
-                                                    else
-                                                    {
-                                                        c.add( value );
+                                                } else {
+                                                    c.add(value);
+                                                    if (value.getClass().isArray()) {
+                                                        evaluateArray(value);
+                                                    } else {
+                                                        interpolationTargets.add(value);
                                                     }
                                                 }
-                                                else
-                                                {
-                                                    c.add( value );
-                                                    if ( value.getClass().isArray() )
-                                                    {
-                                                        evaluateArray( value );
-                                                    }
-                                                    else
-                                                    {
-                                                        interpolationTargets.add( value );
-                                                    }
-                                                }
-                                            }
-                                            else
-                                            {
+                                            } else {
                                                 // add the null back in...not sure what else to do...
-                                                c.add( value );
+                                                c.add(value);
                                             }
                                         }
                                     }
-                                }
-                                else if ( Map.class.isAssignableFrom( type ) )
-                                {
-                                    Map<Object, Object> m = (Map<Object, Object>) field.get( target );
-                                    if ( m != null && !m.isEmpty() )
-                                    {
-                                        for ( Map.Entry<Object, Object> entry : m.entrySet() )
-                                        {
+                                } else if (Map.class.isAssignableFrom(type)) {
+                                    Map<Object, Object> m = (Map<Object, Object>) field.get(target);
+                                    if (m != null && !m.isEmpty()) {
+                                        for (Map.Entry<Object, Object> entry : m.entrySet()) {
                                             Object value = entry.getValue();
 
-                                            if ( value != null )
-                                            {
-                                                if ( String.class == value.getClass() )
-                                                {
-                                                    String interpolated =
-                                                        modelInterpolator.interpolateInternal( (String) value,
-                                                                                               valueSources,
-                                                                                               postProcessors,
-                                                                                               debugEnabled );
+                                            if (value != null) {
+                                                if (String.class == value.getClass()) {
+                                                    String interpolated = modelInterpolator.interpolateInternal(
+                                                            (String) value, valueSources, postProcessors, debugEnabled);
 
-                                                    if ( !interpolated.equals( value ) )
-                                                    {
-                                                        try
-                                                        {
-                                                            entry.setValue( interpolated );
-                                                        }
-                                                        catch ( UnsupportedOperationException e )
-                                                        {
-                                                            if ( debugEnabled && logger != null )
-                                                            {
-                                                                logger.debug(
-                                                                    "Skipping interpolation of field: " + field
+                                                    if (!interpolated.equals(value)) {
+                                                        try {
+                                                            entry.setValue(interpolated);
+                                                        } catch (UnsupportedOperationException e) {
+                                                            if (debugEnabled && logger != null) {
+                                                                logger.debug("Skipping interpolation of field: " + field
                                                                         + " (key: " + entry.getKey() + ") in: "
                                                                         + cls.getName()
-                                                                        + "; it is an unmodifiable collection." );
+                                                                        + "; it is an unmodifiable collection.");
                                                             }
                                                         }
                                                     }
-                                                }
-                                                else
-                                                {
-                                                    if ( value.getClass().isArray() )
-                                                    {
-                                                        evaluateArray( value );
-                                                    }
-                                                    else
-                                                    {
-                                                        interpolationTargets.add( value );
+                                                } else {
+                                                    if (value.getClass().isArray()) {
+                                                        evaluateArray(value);
+                                                    } else {
+                                                        interpolationTargets.add(value);
                                                     }
                                                 }
                                             }
                                         }
                                     }
-                                }
-                                else
-                                {
-                                    Object value = field.get( target );
-                                    if ( value != null )
-                                    {
-                                        if ( field.getType().isArray() )
-                                        {
-                                            evaluateArray( value );
-                                        }
-                                        else
-                                        {
-                                            interpolationTargets.add( value );
+                                } else {
+                                    Object value = field.get(target);
+                                    if (value != null) {
+                                        if (field.getType().isArray()) {
+                                            evaluateArray(value);
+                                        } else {
+                                            interpolationTargets.add(value);
                                         }
                                     }
                                 }
-                            }
-                            catch ( IllegalArgumentException | IllegalAccessException e )
-                            {
+                            } catch (IllegalArgumentException | IllegalAccessException e) {
                                 throw new ModelInterpolationException(
-                                    "Failed to interpolate field: " + field + " on class: " + cls.getName(), e );
+                                        "Failed to interpolate field: " + field + " on class: " + cls.getName(), e);
                             }
-                        }
-                        finally
-                        {
-                            field.setAccessible( isAccessible );
+                        } finally {
+                            field.setAccessible(isAccessible);
                         }
                     }
                 }
 
-                traverseObjectWithParents( cls.getSuperclass(), target );
+                traverseObjectWithParents(cls.getSuperclass(), target);
             }
         }
 
-        private boolean isQualifiedForInterpolation( Class<?> cls )
-        {
-            return !cls.getPackage().getName().startsWith( "java" );
+        private boolean isQualifiedForInterpolation(Class<?> cls) {
+            return !cls.getPackage().getName().startsWith("java")
+                    && !cls.getPackage().getName().startsWith("sun.nio.fs");
         }
 
-        private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType )
-        {
-            if ( !PRIMITIVE_BY_CLASS.containsKey( fieldType ) )
-            {
-                PRIMITIVE_BY_CLASS.put( fieldType, fieldType.isPrimitive() );
+        private boolean isQualifiedForInterpolation(Field field, Class<?> fieldType) {
+            if (!PRIMITIVE_BY_CLASS.containsKey(fieldType)) {
+                PRIMITIVE_BY_CLASS.put(fieldType, fieldType.isPrimitive());
             }
 
-            if ( PRIMITIVE_BY_CLASS.get( fieldType ) )
-            {
+            if (PRIMITIVE_BY_CLASS.get(fieldType)) {
                 return false;
             }
 
-//            if ( fieldType.isPrimitive() )
-//            {
-//                return false;
-//            }
+            //            if ( fieldType.isPrimitive() )
+            //            {
+            //                return false;
+            //            }
 
-            return !"parent".equals( field.getName() );
+            return !"parent".equals(field.getName());
         }
 
-        private void evaluateArray( Object target )
-            throws ModelInterpolationException
-        {
-            int len = Array.getLength( target );
-            for ( int i = 0; i < len; i++ )
-            {
-                Object value = Array.get( target, i );
-                if ( value != null )
-                {
-                    if ( String.class == value.getClass() )
-                    {
-                        String interpolated =
-                            modelInterpolator.interpolateInternal( (String) value, valueSources, postProcessors,
-                                                                   debugEnabled );
+        private void evaluateArray(Object target) throws ModelInterpolationException {
+            int len = Array.getLength(target);
+            for (int i = 0; i < len; i++) {
+                Object value = Array.get(target, i);
+                if (value != null) {
+                    if (String.class == value.getClass()) {
+                        String interpolated = modelInterpolator.interpolateInternal(
+                                (String) value, valueSources, postProcessors, debugEnabled);
 
-                        if ( !interpolated.equals( value ) )
-                        {
-                            Array.set( target, i, interpolated );
+                        if (!interpolated.equals(value)) {
+                            Array.set(target, i, interpolated);
                         }
-                    }
-                    else
-                    {
-                        interpolationTargets.add( value );
+                    } else {
+                        interpolationTargets.add(value);
                     }
                 }
             }
         }
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/path/DefaultPathTranslator.java b/maven-compat/src/main/java/org/apache/maven/project/path/DefaultPathTranslator.java
index 79e1f41..9a6bc49 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/path/DefaultPathTranslator.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/path/DefaultPathTranslator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.path;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -27,125 +29,99 @@
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Reporting;
 import org.apache.maven.model.Resource;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * DefaultPathTranslator
  */
 @Deprecated
-@Component( role = PathTranslator.class )
-public class DefaultPathTranslator
-    implements PathTranslator
-{
+@Named
+@Singleton
+public class DefaultPathTranslator implements PathTranslator {
     private static final String[] BASEDIR_EXPRESSIONS = {"${basedir}", "${pom.basedir}", "${project.basedir}"};
 
-    public void alignToBaseDirectory( Model model, File basedir )
-    {
-        if ( basedir == null )
-        {
+    public void alignToBaseDirectory(Model model, File basedir) {
+        if (basedir == null) {
             return;
         }
 
         Build build = model.getBuild();
 
-        if ( build != null )
-        {
-            build.setDirectory( alignToBaseDirectory( build.getDirectory(), basedir ) );
+        if (build != null) {
+            build.setDirectory(alignToBaseDirectory(build.getDirectory(), basedir));
 
-            build.setSourceDirectory( alignToBaseDirectory( build.getSourceDirectory(), basedir ) );
+            build.setSourceDirectory(alignToBaseDirectory(build.getSourceDirectory(), basedir));
 
-            build.setTestSourceDirectory( alignToBaseDirectory( build.getTestSourceDirectory(), basedir ) );
+            build.setTestSourceDirectory(alignToBaseDirectory(build.getTestSourceDirectory(), basedir));
 
-            for ( Resource resource : build.getResources() )
-            {
-                resource.setDirectory( alignToBaseDirectory( resource.getDirectory(), basedir ) );
+            for (Resource resource : build.getResources()) {
+                resource.setDirectory(alignToBaseDirectory(resource.getDirectory(), basedir));
             }
 
-            for ( Resource resource : build.getTestResources() )
-            {
-                resource.setDirectory( alignToBaseDirectory( resource.getDirectory(), basedir ) );
+            for (Resource resource : build.getTestResources()) {
+                resource.setDirectory(alignToBaseDirectory(resource.getDirectory(), basedir));
             }
 
-            if ( build.getFilters() != null )
-            {
+            if (build.getFilters() != null) {
                 List<String> filters = new ArrayList<>();
-                for ( String filter : build.getFilters() )
-                {
-                    filters.add( alignToBaseDirectory( filter, basedir ) );
+                for (String filter : build.getFilters()) {
+                    filters.add(alignToBaseDirectory(filter, basedir));
                 }
-                build.setFilters( filters );
+                build.setFilters(filters);
             }
 
-            build.setOutputDirectory( alignToBaseDirectory( build.getOutputDirectory(), basedir ) );
+            build.setOutputDirectory(alignToBaseDirectory(build.getOutputDirectory(), basedir));
 
-            build.setTestOutputDirectory( alignToBaseDirectory( build.getTestOutputDirectory(), basedir ) );
+            build.setTestOutputDirectory(alignToBaseDirectory(build.getTestOutputDirectory(), basedir));
         }
 
         Reporting reporting = model.getReporting();
 
-        if ( reporting != null )
-        {
-            reporting.setOutputDirectory( alignToBaseDirectory( reporting.getOutputDirectory(), basedir ) );
+        if (reporting != null) {
+            reporting.setOutputDirectory(alignToBaseDirectory(reporting.getOutputDirectory(), basedir));
         }
     }
 
-    public String alignToBaseDirectory( String path, File basedir )
-    {
-        if ( basedir == null )
-        {
+    public String alignToBaseDirectory(String path, File basedir) {
+        if (basedir == null) {
             return path;
         }
 
-        if ( path == null )
-        {
+        if (path == null) {
             return null;
         }
 
-        String s = stripBasedirToken( path );
+        String s = stripBasedirToken(path);
 
-        File file = new File( s );
-        if ( file.isAbsolute() )
-        {
+        File file = new File(s);
+        if (file.isAbsolute()) {
             // path was already absolute, just normalize file separator and we're done
             s = file.getPath();
-        }
-        else if ( file.getPath().startsWith( File.separator ) )
-        {
+        } else if (file.getPath().startsWith(File.separator)) {
             // drive-relative Windows path, don't align with project directory but with drive root
             s = file.getAbsolutePath();
-        }
-        else
-        {
+        } else {
             // an ordinary relative path, align with project directory
-            s = new File( new File( basedir, s ).toURI().normalize() ).getAbsolutePath();
+            s = new File(new File(basedir, s).toURI().normalize()).getAbsolutePath();
         }
 
         return s;
     }
 
-    private String stripBasedirToken( String s )
-    {
-        if ( s != null )
-        {
+    private String stripBasedirToken(String s) {
+        if (s != null) {
             String basedirExpr = null;
-            for ( String expression : BASEDIR_EXPRESSIONS )
-            {
-                if ( s.startsWith( expression ) )
-                {
+            for (String expression : BASEDIR_EXPRESSIONS) {
+                if (s.startsWith(expression)) {
                     basedirExpr = expression;
                     break;
                 }
             }
 
-            if ( basedirExpr != null )
-            {
-                if ( s.length() > basedirExpr.length() )
-                {
+            if (basedirExpr != null) {
+                if (s.length() > basedirExpr.length()) {
                     // Take out basedir expression and the leading slash
-                    s = chopLeadingFileSeparator( s.substring( basedirExpr.length() ) );
-                }
-                else
-                {
+                    s = chopLeadingFileSeparator(s.substring(basedirExpr.length()));
+                } else {
                     s = ".";
                 }
             }
@@ -161,100 +137,81 @@
      * @param path The filesystem path, may be <code>null</code>.
      * @return The altered filesystem path or <code>null</code> if the input path was <code>null</code>.
      */
-    private String chopLeadingFileSeparator( String path )
-    {
-        if ( path != null )
-        {
-            if ( path.startsWith( "/" ) || path.startsWith( "\\" ) )
-            {
-                path = path.substring( 1 );
+    private String chopLeadingFileSeparator(String path) {
+        if (path != null) {
+            if (path.startsWith("/") || path.startsWith("\\")) {
+                path = path.substring(1);
             }
         }
         return path;
     }
 
-    public void unalignFromBaseDirectory( Model model, File basedir )
-    {
-        if ( basedir == null )
-        {
+    public void unalignFromBaseDirectory(Model model, File basedir) {
+        if (basedir == null) {
             return;
         }
 
         Build build = model.getBuild();
 
-        if ( build != null )
-        {
-            build.setDirectory( unalignFromBaseDirectory( build.getDirectory(), basedir ) );
+        if (build != null) {
+            build.setDirectory(unalignFromBaseDirectory(build.getDirectory(), basedir));
 
-            build.setSourceDirectory( unalignFromBaseDirectory( build.getSourceDirectory(), basedir ) );
+            build.setSourceDirectory(unalignFromBaseDirectory(build.getSourceDirectory(), basedir));
 
-            build.setTestSourceDirectory( unalignFromBaseDirectory( build.getTestSourceDirectory(), basedir ) );
+            build.setTestSourceDirectory(unalignFromBaseDirectory(build.getTestSourceDirectory(), basedir));
 
-            for ( Resource resource : build.getResources() )
-            {
-                resource.setDirectory( unalignFromBaseDirectory( resource.getDirectory(), basedir ) );
+            for (Resource resource : build.getResources()) {
+                resource.setDirectory(unalignFromBaseDirectory(resource.getDirectory(), basedir));
             }
 
-            for ( Resource resource : build.getTestResources() )
-            {
-                resource.setDirectory( unalignFromBaseDirectory( resource.getDirectory(), basedir ) );
+            for (Resource resource : build.getTestResources()) {
+                resource.setDirectory(unalignFromBaseDirectory(resource.getDirectory(), basedir));
             }
 
-            if ( build.getFilters() != null )
-            {
+            if (build.getFilters() != null) {
                 List<String> filters = new ArrayList<>();
-                for ( String filter : build.getFilters() )
-                {
-                    filters.add( unalignFromBaseDirectory( filter, basedir ) );
+                for (String filter : build.getFilters()) {
+                    filters.add(unalignFromBaseDirectory(filter, basedir));
                 }
-                build.setFilters( filters );
+                build.setFilters(filters);
             }
 
-            build.setOutputDirectory( unalignFromBaseDirectory( build.getOutputDirectory(), basedir ) );
+            build.setOutputDirectory(unalignFromBaseDirectory(build.getOutputDirectory(), basedir));
 
-            build.setTestOutputDirectory( unalignFromBaseDirectory( build.getTestOutputDirectory(), basedir ) );
+            build.setTestOutputDirectory(unalignFromBaseDirectory(build.getTestOutputDirectory(), basedir));
         }
 
         Reporting reporting = model.getReporting();
 
-        if ( reporting != null )
-        {
-            reporting.setOutputDirectory( unalignFromBaseDirectory( reporting.getOutputDirectory(), basedir ) );
+        if (reporting != null) {
+            reporting.setOutputDirectory(unalignFromBaseDirectory(reporting.getOutputDirectory(), basedir));
         }
     }
 
-    public String unalignFromBaseDirectory( String path, File basedir )
-    {
-        if ( basedir == null )
-        {
+    public String unalignFromBaseDirectory(String path, File basedir) {
+        if (basedir == null) {
             return path;
         }
 
-        if ( path == null )
-        {
+        if (path == null) {
             return null;
         }
 
         path = path.trim();
 
         String base = basedir.getAbsolutePath();
-        if ( path.startsWith( base ) )
-        {
-            path = chopLeadingFileSeparator( path.substring( base.length() ) );
+        if (path.startsWith(base)) {
+            path = chopLeadingFileSeparator(path.substring(base.length()));
         }
 
-        if ( path.length() <= 0 )
-        {
+        if (path.length() <= 0) {
             path = ".";
         }
 
-        if ( !new File( path ).isAbsolute() )
-        {
-            path = path.replace( '\\', '/' );
+        if (!new File(path).isAbsolute()) {
+            path = path.replace('\\', '/');
         }
 
         return path;
     }
-
 }
-
diff --git a/maven-compat/src/main/java/org/apache/maven/project/path/PathTranslator.java b/maven-compat/src/main/java/org/apache/maven/project/path/PathTranslator.java
new file mode 100644
index 0000000..c345412
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/project/path/PathTranslator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.path;
+
+import java.io.File;
+
+import org.apache.maven.model.Model;
+
+/**
+ */
+@Deprecated
+public interface PathTranslator {
+    String ROLE = PathTranslator.class.getName();
+
+    void alignToBaseDirectory(Model model, File basedir);
+
+    String alignToBaseDirectory(String path, File basedir);
+
+    void unalignFromBaseDirectory(Model model, File basedir);
+
+    String unalignFromBaseDirectory(String directory, File basedir);
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/project/validation/DefaultModelValidator.java b/maven-compat/src/main/java/org/apache/maven/project/validation/DefaultModelValidator.java
index 6406b58..180a49e 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/validation/DefaultModelValidator.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/validation/DefaultModelValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.validation;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.DefaultModelBuildingRequest;
@@ -25,51 +28,41 @@
 import org.apache.maven.model.building.ModelProblem;
 import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblemCollectorRequest;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 
 /**
- * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
  */
-@Component( role = ModelValidator.class )
 @Deprecated
-public class DefaultModelValidator
-    implements ModelValidator
-{
+@Named
+@Singleton
+public class DefaultModelValidator implements ModelValidator {
 
-    @Requirement
+    @Inject
     private org.apache.maven.model.validation.ModelValidator modelValidator;
 
-    public ModelValidationResult validate( Model model )
-    {
+    public ModelValidationResult validate(Model model) {
         ModelValidationResult result = new ModelValidationResult();
 
         ModelBuildingRequest request =
-            new DefaultModelBuildingRequest().setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 );
+                new DefaultModelBuildingRequest().setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0);
 
-        SimpleModelProblemCollector problems = new SimpleModelProblemCollector( result );
+        SimpleModelProblemCollector problems = new SimpleModelProblemCollector(result);
 
-        modelValidator.validateEffectiveModel( model, request, problems );
+        modelValidator.validateEffectiveModel(model, request, problems);
 
         return result;
     }
 
-    private static class SimpleModelProblemCollector
-        implements ModelProblemCollector
-    {
+    private static class SimpleModelProblemCollector implements ModelProblemCollector {
 
         ModelValidationResult result;
 
-        SimpleModelProblemCollector( ModelValidationResult result )
-        {
+        SimpleModelProblemCollector(ModelValidationResult result) {
             this.result = result;
         }
 
-        public void add( ModelProblemCollectorRequest req )
-        {
-            if ( !ModelProblem.Severity.WARNING.equals( req.getSeverity() ) )
-            {
-                result.addMessage( req.getMessage() );
+        public void add(ModelProblemCollectorRequest req) {
+            if (!ModelProblem.Severity.WARNING.equals(req.getSeverity())) {
+                result.addMessage(req.getMessage());
             }
         }
     }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java b/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java
index 9e2966e..bc305cb 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidationResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.validation;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
 /**
- * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
  */
-public class ModelValidationResult
-{
+@Deprecated
+public class ModelValidationResult {
 
     /** */
     private static final String LS = System.lineSeparator();
@@ -35,61 +33,55 @@
     /** */
     private List<String> messages;
 
-    public ModelValidationResult()
-    {
+    public ModelValidationResult() {
         messages = new ArrayList<>();
     }
 
-    public int getMessageCount()
-    {
+    public int getMessageCount() {
         return messages.size();
     }
 
-    public String getMessage( int i )
-    {
-        return messages.get( i );
+    public String getMessage(int i) {
+        return messages.get(i);
     }
 
-    public List<String> getMessages()
-    {
-        return Collections.unmodifiableList( messages );
+    public List<String> getMessages() {
+        return Collections.unmodifiableList(messages);
     }
 
-    public void addMessage( String message )
-    {
-        messages.add( message );
+    public void addMessage(String message) {
+        messages.add(message);
     }
 
-    public String toString()
-    {
-        return render( "" );
+    public String toString() {
+        return render("");
     }
 
-    public String render( String indentation )
-    {
-        if ( messages.size() == 0 )
-        {
+    public String render(String indentation) {
+        if (messages.size() == 0) {
             return indentation + "There were no validation errors.";
         }
 
         StringBuilder message = new StringBuilder();
 
-//        if ( messages.size() == 1 )
-//        {
-//            message.append( "There was 1 validation error: " );
-//        }
-//        else
-//        {
-//            message.append( "There was " + messages.size() + " validation errors: " + LS );
-//        }
-//
-        for ( int i = 0; i < messages.size(); i++ )
-        {
-            message.append( indentation ).append( '[' ).append( i ).append( "]  " ).append( messages.get( i ) ).append(
-                LS );
+        //        if ( messages.size() == 1 )
+        //        {
+        //            message.append( "There was 1 validation error: " );
+        //        }
+        //        else
+        //        {
+        //            message.append( "There was " + messages.size() + " validation errors: " + LS );
+        //        }
+        //
+        for (int i = 0; i < messages.size(); i++) {
+            message.append(indentation)
+                    .append('[')
+                    .append(i)
+                    .append("]  ")
+                    .append(messages.get(i))
+                    .append(LS);
         }
 
         return message.toString();
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidator.java b/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidator.java
index 54fd04c..a9bd44b 100644
--- a/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidator.java
+++ b/maven-compat/src/main/java/org/apache/maven/project/validation/ModelValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,20 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.validation;
 
 import org.apache.maven.model.Model;
 
 /**
  * Checks the model for missing or invalid values.
  *
- * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
  */
 @Deprecated
-public interface ModelValidator
-{
+public interface ModelValidator {
 
     String ROLE = ModelValidator.class.getName();
 
-    ModelValidationResult validate( Model model );
-
+    ModelValidationResult validate(Model model);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/reporting/MavenReportException.java b/maven-compat/src/main/java/org/apache/maven/reporting/MavenReportException.java
index af27a84..f6e1fbb 100644
--- a/maven-compat/src/main/java/org/apache/maven/reporting/MavenReportException.java
+++ b/maven-compat/src/main/java/org/apache/maven/reporting/MavenReportException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.reporting;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.reporting;
 
 /**
  * An exception occurring during the execution of a Maven report.
  *
- * @author Brett Porter
- * @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
  */
-public class MavenReportException extends Exception
-{
-    public MavenReportException( String msg )
-    {
-        super( msg );
+@Deprecated
+public class MavenReportException extends Exception {
+    public MavenReportException(String msg) {
+        super(msg);
     }
 
-    public MavenReportException( String msg, Exception e )
-    {
-        super( msg, e );
+    public MavenReportException(String msg, Exception e) {
+        super(msg, e);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/ArtifactDoesNotExistException.java b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactDoesNotExistException.java
new file mode 100644
index 0000000..5624e1d
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactDoesNotExistException.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+/**
+ * ArtifactDoesNotExistException
+ */
+@Deprecated
+public class ArtifactDoesNotExistException extends Exception {
+    public ArtifactDoesNotExistException(final String message) {
+        super(message);
+    }
+
+    public ArtifactDoesNotExistException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferEvent.java b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferEvent.java
new file mode 100644
index 0000000..f6b70ff
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferEvent.java
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import java.io.File;
+import java.util.EventObject;
+
+/**
+ * TransferEvent is used to notify TransferListeners about progress
+ * in transfer of resources form/to the repository
+ *
+ */
+@Deprecated
+public class ArtifactTransferEvent extends EventObject {
+    /**
+     * A transfer was attempted, but has not yet commenced.
+     */
+    public static final int TRANSFER_INITIATED = 0;
+
+    /**
+     * A transfer was started.
+     */
+    public static final int TRANSFER_STARTED = 1;
+
+    /**
+     * A transfer is completed.
+     */
+    public static final int TRANSFER_COMPLETED = 2;
+
+    /**
+     * A transfer is in progress.
+     */
+    public static final int TRANSFER_PROGRESS = 3;
+
+    /**
+     * An error occurred during transfer
+     */
+    public static final int TRANSFER_ERROR = 4;
+
+    /**
+     * Indicates GET transfer  (from the repository)
+     */
+    public static final int REQUEST_GET = 5;
+
+    /**
+     * Indicates PUT transfer (to the repository)
+     */
+    public static final int REQUEST_PUT = 6;
+
+    private int eventType;
+
+    private int requestType;
+
+    private Exception exception;
+
+    private File localFile;
+
+    private ArtifactTransferResource artifact;
+
+    private long transferredBytes;
+
+    private byte[] dataBuffer;
+
+    private int dataOffset;
+
+    private int dataLength;
+
+    public ArtifactTransferEvent(
+            String wagon, final int eventType, final int requestType, ArtifactTransferResource artifact) {
+        super(wagon);
+
+        setEventType(eventType);
+
+        setRequestType(requestType);
+
+        this.artifact = artifact;
+    }
+
+    public ArtifactTransferEvent(
+            String wagon, final Exception exception, final int requestType, ArtifactTransferResource artifact) {
+        this(wagon, TRANSFER_ERROR, requestType, artifact);
+
+        this.exception = exception;
+    }
+
+    public ArtifactTransferResource getResource() {
+        return artifact;
+    }
+
+    /**
+     * @return Returns the exception.
+     */
+    public Exception getException() {
+        return exception;
+    }
+
+    /**
+     * Returns the request type.
+     *
+     * @return Returns the request type. The Request type is one of
+     *         <code>TransferEvent.REQUEST_GET</code> or <code>TransferEvent.REQUEST_PUT</code>
+     */
+    public int getRequestType() {
+        return requestType;
+    }
+
+    /**
+     * Sets the request type
+     *
+     * @param requestType The requestType to set.
+     *                    The Request type value should be either
+     *                    <code>TransferEvent.REQUEST_GET</code> or <code>TransferEvent.REQUEST_PUT</code>.
+     * @throws IllegalArgumentException when
+     */
+    public void setRequestType(final int requestType) {
+        switch (requestType) {
+            case REQUEST_PUT:
+                break;
+            case REQUEST_GET:
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal request type: " + requestType);
+        }
+
+        this.requestType = requestType;
+    }
+
+    /**
+     * @return Returns the eventType.
+     */
+    public int getEventType() {
+        return eventType;
+    }
+
+    /**
+     * @param eventType The eventType to set.
+     */
+    public void setEventType(final int eventType) {
+        switch (eventType) {
+            case TRANSFER_INITIATED:
+                break;
+            case TRANSFER_STARTED:
+                break;
+            case TRANSFER_COMPLETED:
+                break;
+            case TRANSFER_PROGRESS:
+                break;
+            case TRANSFER_ERROR:
+                break;
+            default:
+                throw new IllegalArgumentException("Illegal event type: " + eventType);
+        }
+
+        this.eventType = eventType;
+    }
+
+    /**
+     * @return Returns the local file.
+     */
+    public File getLocalFile() {
+        return localFile;
+    }
+
+    /**
+     * @param localFile The local file to set.
+     */
+    public void setLocalFile(File localFile) {
+        this.localFile = localFile;
+    }
+
+    public long getTransferredBytes() {
+        return transferredBytes;
+    }
+
+    public void setTransferredBytes(long transferredBytes) {
+        this.transferredBytes = transferredBytes;
+    }
+
+    public byte[] getDataBuffer() {
+        return dataBuffer;
+    }
+
+    public void setDataBuffer(byte[] dataBuffer) {
+        this.dataBuffer = dataBuffer;
+    }
+
+    public int getDataOffset() {
+        return dataOffset;
+    }
+
+    public void setDataOffset(int dataOffset) {
+        this.dataOffset = dataOffset;
+    }
+
+    public int getDataLength() {
+        return dataLength;
+    }
+
+    public void setDataLength(int dataLength) {
+        this.dataLength = dataLength;
+    }
+
+    public String toString() {
+        StringBuilder sb = new StringBuilder(64);
+
+        sb.append("TransferEvent[");
+
+        switch (this.getRequestType()) {
+            case REQUEST_GET:
+                sb.append("GET");
+                break;
+            case REQUEST_PUT:
+                sb.append("PUT");
+                break;
+            default:
+                sb.append(this.getRequestType());
+                break;
+        }
+
+        sb.append('|');
+        switch (this.getEventType()) {
+            case TRANSFER_COMPLETED:
+                sb.append("COMPLETED");
+                break;
+            case TRANSFER_ERROR:
+                sb.append("ERROR");
+                break;
+            case TRANSFER_INITIATED:
+                sb.append("INITIATED");
+                break;
+            case TRANSFER_PROGRESS:
+                sb.append("PROGRESS");
+                break;
+            case TRANSFER_STARTED:
+                sb.append("STARTED");
+                break;
+            default:
+                sb.append(this.getEventType());
+                break;
+        }
+
+        sb.append('|');
+        sb.append(this.getLocalFile()).append('|');
+        sb.append(']');
+
+        return sb.toString();
+    }
+
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + eventType;
+        result = prime * result + ((exception == null) ? 0 : exception.hashCode());
+        result = prime * result + ((localFile == null) ? 0 : localFile.hashCode());
+        result = prime * result + requestType;
+        return result;
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if ((obj == null) || (getClass() != obj.getClass())) {
+            return false;
+        }
+        final ArtifactTransferEvent other = (ArtifactTransferEvent) obj;
+        if (eventType != other.eventType) {
+            return false;
+        }
+        if (exception == null) {
+            if (other.exception != null) {
+                return false;
+            }
+        } else if (!exception.getClass().equals(other.exception.getClass())) {
+            return false;
+        }
+        if (requestType != other.requestType) {
+            return false;
+        } else {
+            return source.equals(other.source);
+        }
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferFailedException.java b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferFailedException.java
new file mode 100644
index 0000000..530ec34
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferFailedException.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+/**
+ * ArtifactTransferFailedException
+ */
+@Deprecated
+public class ArtifactTransferFailedException extends Exception {
+    public ArtifactTransferFailedException(final String message) {
+        super(message);
+    }
+
+    public ArtifactTransferFailedException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferListener.java b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferListener.java
new file mode 100644
index 0000000..c286881
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferListener.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+/**
+ * ArtifactTransferListener
+ */
+@Deprecated
+public interface ArtifactTransferListener {
+    boolean isShowChecksumEvents();
+
+    void setShowChecksumEvents(boolean showChecksumEvents);
+
+    void transferInitiated(ArtifactTransferEvent transferEvent);
+
+    void transferStarted(ArtifactTransferEvent transferEvent);
+
+    void transferProgress(ArtifactTransferEvent transferEvent);
+
+    void transferCompleted(ArtifactTransferEvent transferEvent);
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferResource.java b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferResource.java
new file mode 100644
index 0000000..22aeba5
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/ArtifactTransferResource.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+/**
+ * Describes a resource being uploaded or downloaded by the repository system.
+ *
+ */
+@Deprecated
+public interface ArtifactTransferResource {
+
+    /**
+     * The base URL of the repository, e.g. "http://repo1.maven.org/maven2/". Unless the URL is unknown, it will be
+     * terminated by a trailing slash.
+     *
+     * @return The base URL of the repository or an empty string if unknown, never {@code null}.
+     */
+    String getRepositoryUrl();
+
+    /**
+     * The path of the artifact relative to the repository's base URL.
+     *
+     * @return The path of the artifact, never {@code null}.
+     */
+    String getName();
+
+    /**
+     * Gets the full URL of the artifact.
+     *
+     * @return The full URL of the artifact, never {@code null}.
+     */
+    String getUrl();
+
+    /**
+     * The size of the artifact in bytes.
+     *
+     * @return The of the artifact in bytes or a negative value if unknown.
+     */
+    long getContentLength();
+
+    /**
+     * Gets the timestamp when the transfer of this artifact was started.
+     *
+     * @return The timestamp when the transfer of this artifact was started.
+     */
+    long getTransferStartTime();
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java b/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java
index 5c176e6..fc8361c 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/DefaultMirrorSelector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -26,16 +28,13 @@
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.settings.Mirror;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * DefaultMirrorSelector
  */
-@Component( role = MirrorSelector.class )
-public class DefaultMirrorSelector
-    implements MirrorSelector
-{
+@Named
+@Singleton
+public class DefaultMirrorSelector implements MirrorSelector {
 
     private static final String WILDCARD = "*";
 
@@ -43,24 +42,18 @@
 
     private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*";
 
-    public Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
-    {
+    public Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors) {
         String repoId = repository.getId();
 
-        if ( repoId != null && mirrors != null )
-        {
-            for ( Mirror mirror : mirrors )
-            {
-                if ( repoId.equals( mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
-                {
+        if (repoId != null && mirrors != null) {
+            for (Mirror mirror : mirrors) {
+                if (repoId.equals(mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
                     return mirror;
                 }
             }
 
-            for ( Mirror mirror : mirrors )
-            {
-                if ( matchPattern( repository, mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
-                {
+            for (Mirror mirror : mirrors) {
+                if (matchPattern(repository, mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
                     return mirror;
                 }
             }
@@ -83,53 +76,41 @@
      * @param pattern used for match.
      * @return true if the repository is a match to this pattern.
      */
-    static boolean matchPattern( ArtifactRepository originalRepository, String pattern )
-    {
+    static boolean matchPattern(ArtifactRepository originalRepository, String pattern) {
         boolean result = false;
         String originalId = originalRepository.getId();
 
         // simple checks first to short circuit processing below.
-        if ( WILDCARD.equals( pattern ) || pattern.equals( originalId ) )
-        {
+        if (WILDCARD.equals(pattern) || pattern.equals(originalId)) {
             result = true;
-        }
-        else
-        {
+        } else {
             // process the list
-            String[] repos = pattern.split( "," );
-            for ( String repo : repos )
-            {
+            String[] repos = pattern.split(",");
+            for (String repo : repos) {
                 repo = repo.trim();
                 // see if this is a negative match
-                if ( repo.length() > 1 && repo.startsWith( "!" ) )
-                {
-                    if ( repo.substring( 1 ).equals( originalId ) )
-                    {
+                if (repo.length() > 1 && repo.startsWith("!")) {
+                    if (repo.substring(1).equals(originalId)) {
                         // explicitly exclude. Set result and stop processing.
                         result = false;
                         break;
                     }
                 }
                 // check for exact match
-                else if ( repo.equals( originalId ) )
-                {
+                else if (repo.equals(originalId)) {
                     result = true;
                     break;
                 }
                 // check for external:*
-                else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository ) )
-                {
+                else if (EXTERNAL_WILDCARD.equals(repo) && isExternalRepo(originalRepository)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
                 }
                 // check for external:http:*
-                else if ( EXTERNAL_HTTP_WILDCARD.equals( repo ) && isExternalHttpRepo( originalRepository ) )
-                {
+                else if (EXTERNAL_HTTP_WILDCARD.equals(repo) && isExternalHttpRepo(originalRepository)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
-                }
-                else if ( WILDCARD.equals( repo ) )
-                {
+                } else if (WILDCARD.equals(repo)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
                 }
@@ -144,23 +125,18 @@
      * @param originalRepository
      * @return true if external.
      */
-    static boolean isExternalRepo( ArtifactRepository originalRepository )
-    {
-        try
-        {
-            URL url = new URL( originalRepository.getUrl() );
-            return !( isLocal( url.getHost() ) || url.getProtocol().equals( "file" ) );
-        }
-        catch ( MalformedURLException e )
-        {
+    static boolean isExternalRepo(ArtifactRepository originalRepository) {
+        try {
+            URL url = new URL(originalRepository.getUrl());
+            return !(isLocal(url.getHost()) || url.getProtocol().equals("file"));
+        } catch (MalformedURLException e) {
             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
             return false;
         }
     }
 
-    private static boolean isLocal( String host )
-    {
-        return "localhost".equals( host ) || "127.0.0.1".equals( host );
+    private static boolean isLocal(String host) {
+        return "localhost".equals(host) || "127.0.0.1".equals(host);
     }
 
     /**
@@ -169,25 +145,22 @@
      * @param originalRepository
      * @return true if external.
      */
-    static boolean isExternalHttpRepo( ArtifactRepository originalRepository )
-    {
-        try
-        {
-            URL url = new URL( originalRepository.getUrl() );
-            return ( "http".equalsIgnoreCase( url.getProtocol() ) || "dav".equalsIgnoreCase( url.getProtocol() )
-                || "dav:http".equalsIgnoreCase( url.getProtocol() )
-                || "dav+http".equalsIgnoreCase( url.getProtocol() ) ) && !isLocal( url.getHost() );
-        }
-        catch ( MalformedURLException e )
-        {
+    static boolean isExternalHttpRepo(ArtifactRepository originalRepository) {
+        try {
+            URL url = new URL(originalRepository.getUrl());
+            return ("http".equalsIgnoreCase(url.getProtocol())
+                            || "dav".equalsIgnoreCase(url.getProtocol())
+                            || "dav:http".equalsIgnoreCase(url.getProtocol())
+                            || "dav+http".equalsIgnoreCase(url.getProtocol()))
+                    && !isLocal(url.getHost());
+        } catch (MalformedURLException e) {
             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
             return false;
         }
     }
 
-   static boolean matchesLayout( ArtifactRepository repository, Mirror mirror )
-    {
-        return matchesLayout( RepositoryUtils.getLayout( repository ), mirror.getMirrorOfLayouts() );
+    static boolean matchesLayout(ArtifactRepository repository, Mirror mirror) {
+        return matchesLayout(RepositoryUtils.getLayout(repository), mirror.getMirrorOfLayouts());
     }
 
     /**
@@ -198,43 +171,31 @@
      * @return {@code true} if the layouts associated with the mirror match the layout of the original repository,
      *         {@code false} otherwise.
      */
-    static boolean matchesLayout( String repoLayout, String mirrorLayout )
-    {
+    static boolean matchesLayout(String repoLayout, String mirrorLayout) {
         boolean result = false;
 
         // simple checks first to short circuit processing below.
-        if ( StringUtils.isEmpty( mirrorLayout ) || WILDCARD.equals( mirrorLayout ) )
-        {
+        if ((mirrorLayout == null || mirrorLayout.isEmpty()) || WILDCARD.equals(mirrorLayout)) {
             result = true;
-        }
-        else if ( mirrorLayout.equals( repoLayout ) )
-        {
+        } else if (mirrorLayout.equals(repoLayout)) {
             result = true;
-        }
-        else
-        {
+        } else {
             // process the list
-            String[] layouts = mirrorLayout.split( "," );
-            for ( String layout : layouts )
-            {
+            String[] layouts = mirrorLayout.split(",");
+            for (String layout : layouts) {
                 // see if this is a negative match
-                if ( layout.length() > 1 && layout.startsWith( "!" ) )
-                {
-                    if ( layout.substring( 1 ).equals( repoLayout ) )
-                    {
+                if (layout.length() > 1 && layout.startsWith("!")) {
+                    if (layout.substring(1).equals(repoLayout)) {
                         // explicitly exclude. Set result and stop processing.
                         result = false;
                         break;
                     }
                 }
                 // check for exact match
-                else if ( layout.equals( repoLayout ) )
-                {
+                else if (layout.equals(repoLayout)) {
                     result = true;
                     break;
-                }
-                else if ( WILDCARD.equals( layout ) )
-                {
+                } else if (WILDCARD.equals(layout)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
                 }
@@ -243,5 +204,4 @@
 
         return result;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/DelegatingLocalArtifactRepository.java b/maven-compat/src/main/java/org/apache/maven/repository/DelegatingLocalArtifactRepository.java
new file mode 100644
index 0000000..306d612
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/DelegatingLocalArtifactRepository.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.ArtifactMetadata;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+
+/**
+ * Delegating local artifact repository chains the reactor, IDE workspace
+ * and user local repository.
+ */
+@Deprecated
+public class DelegatingLocalArtifactRepository extends MavenArtifactRepository {
+    private LocalArtifactRepository buildReactor;
+
+    private LocalArtifactRepository ideWorkspace;
+
+    private ArtifactRepository userLocalArtifactRepository;
+
+    public DelegatingLocalArtifactRepository(ArtifactRepository artifactRepository) {
+        this.userLocalArtifactRepository = artifactRepository;
+    }
+
+    public void setBuildReactor(LocalArtifactRepository localRepository) {
+        this.buildReactor = localRepository;
+    }
+
+    public void setIdeWorkspace(LocalArtifactRepository localRepository) {
+        this.ideWorkspace = localRepository;
+    }
+
+    /**
+     * @deprecated instead use {@link #getIdeWorkspace()}
+     */
+    @Deprecated
+    public LocalArtifactRepository getIdeWorspace() {
+        return ideWorkspace;
+    }
+
+    public LocalArtifactRepository getIdeWorkspace() {
+        return getIdeWorspace();
+    }
+
+    @Override
+    public Artifact find(Artifact artifact) {
+        if (!artifact.isRelease() && buildReactor != null) {
+            artifact = buildReactor.find(artifact);
+        }
+
+        if (!artifact.isResolved() && ideWorkspace != null) {
+            artifact = ideWorkspace.find(artifact);
+        }
+
+        if (!artifact.isResolved()) {
+            artifact = userLocalArtifactRepository.find(artifact);
+        }
+
+        return artifact;
+    }
+
+    @Override
+    public List<String> findVersions(Artifact artifact) {
+        Collection<String> versions = new LinkedHashSet<>();
+
+        if (buildReactor != null) {
+            versions.addAll(buildReactor.findVersions(artifact));
+        }
+
+        if (ideWorkspace != null) {
+            versions.addAll(ideWorkspace.findVersions(artifact));
+        }
+
+        versions.addAll(userLocalArtifactRepository.findVersions(artifact));
+
+        return Collections.unmodifiableList(new ArrayList<>(versions));
+    }
+
+    public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+        return userLocalArtifactRepository.pathOfLocalRepositoryMetadata(metadata, repository);
+    }
+
+    public String getId() {
+        return userLocalArtifactRepository.getId();
+    }
+
+    @Override
+    public String pathOf(Artifact artifact) {
+        return userLocalArtifactRepository.pathOf(artifact);
+    }
+
+    @Override
+    public String getBasedir() {
+        return (userLocalArtifactRepository != null) ? userLocalArtifactRepository.getBasedir() : null;
+    }
+
+    @Override
+    public ArtifactRepositoryLayout getLayout() {
+        return userLocalArtifactRepository.getLayout();
+    }
+
+    @Override
+    public ArtifactRepositoryPolicy getReleases() {
+        return userLocalArtifactRepository.getReleases();
+    }
+
+    @Override
+    public ArtifactRepositoryPolicy getSnapshots() {
+        return userLocalArtifactRepository.getSnapshots();
+    }
+
+    @Override
+    public String getKey() {
+        return userLocalArtifactRepository.getKey();
+    }
+
+    @Override
+    public String getUrl() {
+        return userLocalArtifactRepository.getUrl();
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 17;
+        hash = hash * 31 + (buildReactor == null ? 0 : buildReactor.hashCode());
+        hash = hash * 31 + (ideWorkspace == null ? 0 : ideWorkspace.hashCode());
+        hash = hash * 31 + (userLocalArtifactRepository == null ? 0 : userLocalArtifactRepository.hashCode());
+
+        return hash;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+
+        DelegatingLocalArtifactRepository other = (DelegatingLocalArtifactRepository) obj;
+
+        return eq(buildReactor, other.buildReactor)
+                && eq(ideWorkspace, other.ideWorkspace)
+                && eq(userLocalArtifactRepository, other.userLocalArtifactRepository);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/LocalArtifactRepository.java b/maven-compat/src/main/java/org/apache/maven/repository/LocalArtifactRepository.java
new file mode 100644
index 0000000..3577c31
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/LocalArtifactRepository.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+
+/**
+ * LocalArtifactRepository
+ */
+@Deprecated
+public abstract class LocalArtifactRepository extends MavenArtifactRepository {
+    public static final String IDE_WORKSPACE = "ide-workspace";
+
+    public abstract Artifact find(Artifact artifact);
+
+    public abstract boolean hasLocalMetadata();
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/LocalRepositoryNotAccessibleException.java b/maven-compat/src/main/java/org/apache/maven/repository/LocalRepositoryNotAccessibleException.java
new file mode 100644
index 0000000..921c07d
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/LocalRepositoryNotAccessibleException.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import java.io.IOException;
+
+/**
+ * Signals a failure to store files within the local repository.
+ *
+ */
+@Deprecated
+public class LocalRepositoryNotAccessibleException extends IOException {
+
+    public LocalRepositoryNotAccessibleException(String message, Throwable cause) {
+        super(message);
+        initCause(cause);
+    }
+
+    public LocalRepositoryNotAccessibleException(String message) {
+        super(message);
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/MavenArtifactMetadata.java b/maven-compat/src/main/java/org/apache/maven/repository/MavenArtifactMetadata.java
index c507bf7..d84e67a 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/MavenArtifactMetadata.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/MavenArtifactMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 /**
  *
  *
- * @author Oleg Gusakov
  *
  */
-public class MavenArtifactMetadata
-{
+@Deprecated
+public class MavenArtifactMetadata {
     public static final String DEFAULT_TYPE = "jar";
 
     String groupId;
@@ -38,82 +36,66 @@
 
     transient Object datum;
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public void setGroupId( String groupId )
-    {
+    public void setGroupId(String groupId) {
         this.groupId = groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public void setArtifactId( String artifactId )
-    {
+    public void setArtifactId(String artifactId) {
         this.artifactId = artifactId;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
-    public void setVersion( String version )
-    {
+    public void setVersion(String version) {
         this.version = version;
     }
 
-    public String getClassifier()
-    {
+    public String getClassifier() {
         return classifier;
     }
 
-    public void setClassifier( String classifier )
-    {
+    public void setClassifier(String classifier) {
         this.classifier = classifier;
     }
 
-    public String getType()
-    {
+    public String getType() {
         return type;
     }
 
-    public void setType( String type )
-    {
+    public void setType(String type) {
         this.type = type;
     }
 
-    public Object getDatum()
-    {
+    public Object getDatum() {
         return datum;
     }
 
-    public void setDatum( Object datum )
-    {
+    public void setDatum(Object datum) {
         this.datum = datum;
     }
 
-    public String getScope()
-    {
+    public String getScope() {
         return scope;
     }
 
-    public void setScope( String scope )
-    {
+    public void setScope(String scope) {
         this.scope = scope;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getGroupId() + ":" + getArtifactId() + ":" + getVersion() + ":"
-            + ( getClassifier() == null ? "" : getClassifier() ) + ":"
-            + ( getType() == null ? DEFAULT_TYPE : getType() );
+                + (getClassifier() == null ? "" : getClassifier()) + ":"
+                + (getType() == null ? DEFAULT_TYPE : getType());
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraph.java b/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraph.java
index 3568ff0..d6b7c92 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraph.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraph.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -25,32 +24,28 @@
 /**
  * This is the main graph data structure used by the RepositorySystem to present tree and graph objects.
  *
- * @author Oleg Gusakov
  *
  */
-public class MetadataGraph
-{
+@Deprecated
+public class MetadataGraph {
     /** all graph nodes */
     Collection<MetadataGraphNode> nodes;
 
     /** entry point for tree-like structures */
     MetadataGraphNode entry;
 
-    public MetadataGraph( MetadataGraphNode entry )
-    {
+    public MetadataGraph(MetadataGraphNode entry) {
         this();
 
         this.entry = entry;
     }
 
-    public MetadataGraph()
-    {
-        nodes = new ArrayList<>( 64 );
+    public MetadataGraph() {
+        nodes = new ArrayList<>(64);
     }
 
-    public void addNode( MetadataGraphNode node )
-    {
-        nodes.add( node );
+    public void addNode(MetadataGraphNode node) {
+        nodes.add(node);
     }
 
     /**
@@ -58,34 +53,29 @@
      *
      * @param md
      */
-    public MetadataGraphNode findNode( MavenArtifactMetadata md )
-    {
-        for ( MetadataGraphNode mgn : nodes )
-        {
-            if ( mgn.metadata.equals( md ) )
-            {
+    public MetadataGraphNode findNode(MavenArtifactMetadata md) {
+        for (MetadataGraphNode mgn : nodes) {
+            if (mgn.metadata.equals(md)) {
                 return mgn;
             }
         }
 
-        MetadataGraphNode node = new MetadataGraphNode( md );
-        addNode( node );
+        MetadataGraphNode node = new MetadataGraphNode(md);
+        addNode(node);
         return node;
     }
 
     /**
      * getter
      */
-    public MetadataGraphNode getEntry()
-    {
+    public MetadataGraphNode getEntry() {
         return entry;
     }
 
     /**
      * getter
      */
-    public Collection<MetadataGraphNode> getNodes()
-    {
+    public Collection<MetadataGraphNode> getNodes() {
         return nodes;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraphNode.java b/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraphNode.java
index c258f05..c67a555 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraphNode.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/MetadataGraphNode.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -25,11 +24,10 @@
 /**
  * MetadataGraph node - as it's a directed graph - holds adjacency lists for incident and exident nodes
  *
- * @author Oleg Gusakov
  *
  */
-public class MetadataGraphNode
-{
+@Deprecated
+public class MetadataGraphNode {
     /** node payload */
     MavenArtifactMetadata metadata;
 
@@ -39,60 +37,48 @@
     /** nodes, exident to this (I depend on) */
     List<MetadataGraphNode> exNodes;
 
-    public MetadataGraphNode()
-    {
-        inNodes = new ArrayList<>( 4 );
-        exNodes = new ArrayList<>( 8 );
+    public MetadataGraphNode() {
+        inNodes = new ArrayList<>(4);
+        exNodes = new ArrayList<>(8);
     }
 
-    public MetadataGraphNode( MavenArtifactMetadata metadata )
-    {
+    public MetadataGraphNode(MavenArtifactMetadata metadata) {
         this();
         this.metadata = metadata;
     }
 
-    public MetadataGraphNode addIncident( MetadataGraphNode node )
-    {
-        inNodes.add( node );
+    public MetadataGraphNode addIncident(MetadataGraphNode node) {
+        inNodes.add(node);
         return this;
     }
 
-    public MetadataGraphNode addExident( MetadataGraphNode node )
-    {
-        exNodes.add( node );
+    public MetadataGraphNode addExident(MetadataGraphNode node) {
+        exNodes.add(node);
         return this;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( obj == null )
-        {
+    public boolean equals(Object obj) {
+        if (obj == null) {
             return false;
         }
 
-        if ( MetadataGraphNode.class.isAssignableFrom( obj.getClass() ) )
-        {
+        if (MetadataGraphNode.class.isAssignableFrom(obj.getClass())) {
             MetadataGraphNode node2 = (MetadataGraphNode) obj;
 
-            if ( node2.metadata == null )
-            {
+            if (node2.metadata == null) {
                 return metadata == null;
             }
 
-            return metadata != null && metadata.toString().equals( node2.metadata.toString() );
-        }
-        else
-        {
-            return super.equals( obj );
+            return metadata != null && metadata.toString().equals(node2.metadata.toString());
+        } else {
+            return super.equals(obj);
         }
     }
 
     @Override
-    public int hashCode()
-    {
-        if ( metadata == null )
-        {
+    public int hashCode() {
+        if (metadata == null) {
             return super.hashCode();
         }
 
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionRequest.java b/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionRequest.java
index ea0cd73..4c438ca 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionRequest.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.util.List;
 import java.util.Map;
@@ -29,11 +28,10 @@
 /**
  *
  *
- * @author Oleg Gusakov
  *
  */
-public class MetadataResolutionRequest
-{
+@Deprecated
+public class MetadataResolutionRequest {
     private MavenArtifactMetadata mad;
 
     private String scope;
@@ -60,49 +58,40 @@
     /** result type - graph */
     private boolean asGraph = false;
 
-    public MetadataResolutionRequest()
-    {
-    }
+    public MetadataResolutionRequest() {}
 
-    public MetadataResolutionRequest( MavenArtifactMetadata md, ArtifactRepository localRepository,
-                                      List<ArtifactRepository> remoteRepositories )
-    {
+    public MetadataResolutionRequest(
+            MavenArtifactMetadata md, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories) {
         this.mad = md;
         this.localRepository = localRepository;
         this.remoteRepositories = remoteRepositories;
     }
 
-    public MavenArtifactMetadata getArtifactMetadata()
-    {
+    public MavenArtifactMetadata getArtifactMetadata() {
         return mad;
     }
 
-    public MetadataResolutionRequest setArtifactMetadata( MavenArtifactMetadata md )
-    {
+    public MetadataResolutionRequest setArtifactMetadata(MavenArtifactMetadata md) {
         this.mad = md;
 
         return this;
     }
 
-    public MetadataResolutionRequest setArtifactDependencies( Set<Artifact> artifactDependencies )
-    {
+    public MetadataResolutionRequest setArtifactDependencies(Set<Artifact> artifactDependencies) {
         this.artifactDependencies = artifactDependencies;
 
         return this;
     }
 
-    public Set<Artifact> getArtifactDependencies()
-    {
+    public Set<Artifact> getArtifactDependencies() {
         return artifactDependencies;
     }
 
-    public ArtifactRepository getLocalRepository()
-    {
+    public ArtifactRepository getLocalRepository() {
         return localRepository;
     }
 
-    public MetadataResolutionRequest setLocalRepository( ArtifactRepository localRepository )
-    {
+    public MetadataResolutionRequest setLocalRepository(ArtifactRepository localRepository) {
         this.localRepository = localRepository;
 
         return this;
@@ -112,13 +101,11 @@
      * @deprecated instead use {@link #getRemoteRepositories()}
      */
     @Deprecated
-    public List<ArtifactRepository> getRemoteRepostories()
-    {
+    public List<ArtifactRepository> getRemoteRepostories() {
         return remoteRepositories;
     }
 
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
+    public List<ArtifactRepository> getRemoteRepositories() {
         return getRemoteRepostories();
     }
 
@@ -126,95 +113,87 @@
      * @deprecated instead use {@link #setRemoteRepositories(List)}
      */
     @Deprecated
-    public MetadataResolutionRequest setRemoteRepostories( List<ArtifactRepository> remoteRepositories )
-    {
+    public MetadataResolutionRequest setRemoteRepostories(List<ArtifactRepository> remoteRepositories) {
         this.remoteRepositories = remoteRepositories;
 
         return this;
     }
 
-    public MetadataResolutionRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
-    {
-        return setRemoteRepostories( remoteRepositories );
+    public MetadataResolutionRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories) {
+        return setRemoteRepostories(remoteRepositories);
     }
 
-    public Map getManagedVersionMap()
-    {
+    public Map getManagedVersionMap() {
         return managedVersionMap;
     }
 
-    public MetadataResolutionRequest setManagedVersionMap( Map managedVersionMap )
-    {
+    public MetadataResolutionRequest setManagedVersionMap(Map managedVersionMap) {
         this.managedVersionMap = managedVersionMap;
 
         return this;
     }
 
-    public String toString()
-    {
+    public String toString() {
         StringBuilder sb = new StringBuilder()
-                .append( "REQUEST: " ).append(  "\n" )
-                .append( "artifact: " ).append( mad ).append(  "\n" )
-                .append( artifactDependencies ).append(  "\n" )
-                .append( "localRepository: " ).append(  localRepository ).append(  "\n" )
-                .append( "remoteRepositories: " ).append(  remoteRepositories ).append(  "\n" )
-                ;
+                .append("REQUEST: ")
+                .append("\n")
+                .append("artifact: ")
+                .append(mad)
+                .append("\n")
+                .append(artifactDependencies)
+                .append("\n")
+                .append("localRepository: ")
+                .append(localRepository)
+                .append("\n")
+                .append("remoteRepositories: ")
+                .append(remoteRepositories)
+                .append("\n");
 
         return sb.toString();
     }
 
-    public boolean isAsList()
-    {
+    public boolean isAsList() {
         return asList;
     }
 
-    public MetadataResolutionRequest setAsList( boolean asList )
-    {
+    public MetadataResolutionRequest setAsList(boolean asList) {
         this.asList = asList;
         return this;
     }
 
-    public boolean isAsDirtyTree()
-    {
+    public boolean isAsDirtyTree() {
         return asDirtyTree;
     }
 
-    public MetadataResolutionRequest setAsDirtyTree( boolean asDirtyTree )
-    {
+    public MetadataResolutionRequest setAsDirtyTree(boolean asDirtyTree) {
         this.asDirtyTree = asDirtyTree;
         return this;
     }
 
-    public boolean isAsResolvedTree()
-    {
+    public boolean isAsResolvedTree() {
         return asResolvedTree;
     }
 
-    public MetadataResolutionRequest setAsResolvedTree( boolean asResolvedTree )
-    {
+    public MetadataResolutionRequest setAsResolvedTree(boolean asResolvedTree) {
         this.asResolvedTree = asResolvedTree;
         return this;
     }
 
-    public boolean isAsGraph()
-    {
+    public boolean isAsGraph() {
         return asGraph;
     }
 
-    public MetadataResolutionRequest setAsGraph( boolean asGraph )
-    {
+    public MetadataResolutionRequest setAsGraph(boolean asGraph) {
         this.asGraph = asGraph;
         return this;
     }
 
-    public MetadataResolutionRequest setScope( String scope )
-    {
+    public MetadataResolutionRequest setScope(String scope) {
         this.scope = scope;
         return this;
     }
 
-    public String getScope()
-    {
+    public String getScope() {
         return scope;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java b/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java
index 2d1c5db..6f9ff29 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/MetadataResolutionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -34,11 +33,10 @@
 /**
  *
  *
- * @author Oleg Gusakov
  *
  */
-public class MetadataResolutionResult
-{
+@Deprecated
+public class MetadataResolutionResult {
     private Artifact originatingArtifact;
 
     private List<Artifact> missingArtifacts;
@@ -69,72 +67,57 @@
 
     private MetadataGraph resolvedGraph;
 
-    public Artifact getOriginatingArtifact()
-    {
+    public Artifact getOriginatingArtifact() {
         return originatingArtifact;
     }
 
-    public MetadataResolutionResult listOriginatingArtifact( final Artifact originatingArtifact )
-    {
+    public MetadataResolutionResult listOriginatingArtifact(final Artifact originatingArtifact) {
         this.originatingArtifact = originatingArtifact;
 
         return this;
     }
 
-    public void addArtifact( Artifact artifact )
-    {
-        if ( artifacts == null )
-        {
+    public void addArtifact(Artifact artifact) {
+        if (artifacts == null) {
             artifacts = new LinkedHashSet<>();
         }
 
-        artifacts.add( artifact );
+        artifacts.add(artifact);
     }
 
-    public Set<Artifact> getArtifacts()
-    {
+    public Set<Artifact> getArtifacts() {
         return artifacts;
     }
 
-    public void addRequestedArtifact( Artifact artifact )
-    {
-        if ( requestedArtifacts == null )
-        {
+    public void addRequestedArtifact(Artifact artifact) {
+        if (requestedArtifacts == null) {
             requestedArtifacts = new LinkedHashSet<>();
         }
 
-        requestedArtifacts.add( artifact );
+        requestedArtifacts.add(artifact);
     }
 
-    public Set<Artifact> getRequestedArtifacts()
-    {
+    public Set<Artifact> getRequestedArtifacts() {
         return requestedArtifacts;
     }
 
-    public boolean hasMissingArtifacts()
-    {
+    public boolean hasMissingArtifacts() {
         return missingArtifacts != null && !missingArtifacts.isEmpty();
     }
 
-    public List<Artifact> getMissingArtifacts()
-    {
-        return missingArtifacts == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( missingArtifacts );
-
+    public List<Artifact> getMissingArtifacts() {
+        return missingArtifacts == null ? Collections.emptyList() : Collections.unmodifiableList(missingArtifacts);
     }
 
-    public MetadataResolutionResult addMissingArtifact( Artifact artifact )
-    {
-        missingArtifacts = initList( missingArtifacts );
+    public MetadataResolutionResult addMissingArtifact(Artifact artifact) {
+        missingArtifacts = initList(missingArtifacts);
 
-        missingArtifacts.add( artifact );
+        missingArtifacts.add(artifact);
 
         return this;
     }
 
-    public MetadataResolutionResult setUnresolvedArtifacts( final List<Artifact> unresolvedArtifacts )
-    {
+    public MetadataResolutionResult setUnresolvedArtifacts(final List<Artifact> unresolvedArtifacts) {
         this.missingArtifacts = unresolvedArtifacts;
 
         return this;
@@ -144,25 +127,19 @@
     // Exceptions
     // ------------------------------------------------------------------------
 
-    public boolean hasExceptions()
-    {
+    public boolean hasExceptions() {
         return exceptions != null && !exceptions.isEmpty();
     }
 
-    public List<Exception> getExceptions()
-    {
-        return exceptions == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( exceptions );
-
+    public List<Exception> getExceptions() {
+        return exceptions == null ? Collections.emptyList() : Collections.unmodifiableList(exceptions);
     }
 
     // ------------------------------------------------------------------------
     // Version Range Violations
     // ------------------------------------------------------------------------
 
-    public boolean hasVersionRangeViolations()
-    {
+    public boolean hasVersionRangeViolations() {
         return versionRangeViolations != null;
     }
 
@@ -171,148 +148,127 @@
      *       {@link #getVersionRangeViolation(int)} but it's not used like that in
      *       {@link org.apache.maven.repository.legacy.resolver.DefaultLegacyArtifactCollector}
      */
-    public MetadataResolutionResult addVersionRangeViolation( Exception e )
-    {
-        versionRangeViolations = initList( versionRangeViolations );
+    public MetadataResolutionResult addVersionRangeViolation(Exception e) {
+        versionRangeViolations = initList(versionRangeViolations);
 
-        versionRangeViolations.add( e );
+        versionRangeViolations.add(e);
 
-        exceptions = initList( exceptions );
+        exceptions = initList(exceptions);
 
-        exceptions.add( e );
+        exceptions.add(e);
 
         return this;
     }
 
-    public OverConstrainedVersionException getVersionRangeViolation( int i )
-    {
-        return (OverConstrainedVersionException) versionRangeViolations.get( i );
+    public OverConstrainedVersionException getVersionRangeViolation(int i) {
+        return (OverConstrainedVersionException) versionRangeViolations.get(i);
     }
 
-    public List<Exception> getVersionRangeViolations()
-    {
+    public List<Exception> getVersionRangeViolations() {
         return versionRangeViolations == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( versionRangeViolations );
-
+                ? Collections.emptyList()
+                : Collections.unmodifiableList(versionRangeViolations);
     }
 
     // ------------------------------------------------------------------------
     // Metadata Resolution Exceptions: ArtifactResolutionExceptions
     // ------------------------------------------------------------------------
 
-    public boolean hasMetadataResolutionExceptions()
-    {
+    public boolean hasMetadataResolutionExceptions() {
         return metadataResolutionExceptions != null;
     }
 
-    public MetadataResolutionResult addMetadataResolutionException( ArtifactResolutionException e )
-    {
-        metadataResolutionExceptions = initList( metadataResolutionExceptions );
+    public MetadataResolutionResult addMetadataResolutionException(ArtifactResolutionException e) {
+        metadataResolutionExceptions = initList(metadataResolutionExceptions);
 
-        metadataResolutionExceptions.add( e );
+        metadataResolutionExceptions.add(e);
 
-        exceptions = initList( exceptions );
+        exceptions = initList(exceptions);
 
-        exceptions.add( e );
+        exceptions.add(e);
 
         return this;
     }
 
-    public ArtifactResolutionException getMetadataResolutionException( int i )
-    {
-        return metadataResolutionExceptions.get( i );
+    public ArtifactResolutionException getMetadataResolutionException(int i) {
+        return metadataResolutionExceptions.get(i);
     }
 
-    public List<ArtifactResolutionException> getMetadataResolutionExceptions()
-    {
+    public List<ArtifactResolutionException> getMetadataResolutionExceptions() {
         return metadataResolutionExceptions == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( metadataResolutionExceptions );
-
+                ? Collections.emptyList()
+                : Collections.unmodifiableList(metadataResolutionExceptions);
     }
 
     // ------------------------------------------------------------------------
     // ErrorArtifactExceptions: ArtifactResolutionExceptions
     // ------------------------------------------------------------------------
 
-    public boolean hasErrorArtifactExceptions()
-    {
+    public boolean hasErrorArtifactExceptions() {
         return errorArtifactExceptions != null;
     }
 
-    public MetadataResolutionResult addError( Exception e )
-    {
-        exceptions = initList( exceptions );
+    public MetadataResolutionResult addError(Exception e) {
+        exceptions = initList(exceptions);
 
-        exceptions.add( e );
+        exceptions.add(e);
 
         return this;
     }
 
-    public List<ArtifactResolutionException> getErrorArtifactExceptions()
-    {
-        if ( errorArtifactExceptions == null )
-        {
+    public List<ArtifactResolutionException> getErrorArtifactExceptions() {
+        if (errorArtifactExceptions == null) {
             return Collections.emptyList();
         }
 
-        return Collections.unmodifiableList( errorArtifactExceptions );
+        return Collections.unmodifiableList(errorArtifactExceptions);
     }
 
     // ------------------------------------------------------------------------
     // Circular Dependency Exceptions
     // ------------------------------------------------------------------------
 
-    public boolean hasCircularDependencyExceptions()
-    {
+    public boolean hasCircularDependencyExceptions() {
         return circularDependencyExceptions != null;
     }
 
-    public MetadataResolutionResult addCircularDependencyException( CyclicDependencyException e )
-    {
-        circularDependencyExceptions = initList( circularDependencyExceptions );
+    public MetadataResolutionResult addCircularDependencyException(CyclicDependencyException e) {
+        circularDependencyExceptions = initList(circularDependencyExceptions);
 
-        circularDependencyExceptions.add( e );
+        circularDependencyExceptions.add(e);
 
-        exceptions = initList( exceptions );
+        exceptions = initList(exceptions);
 
-        exceptions.add( e );
+        exceptions.add(e);
 
         return this;
     }
 
-    public CyclicDependencyException getCircularDependencyException( int i )
-    {
-        return circularDependencyExceptions.get( i );
+    public CyclicDependencyException getCircularDependencyException(int i) {
+        return circularDependencyExceptions.get(i);
     }
 
-    public List<CyclicDependencyException> getCircularDependencyExceptions()
-    {
-        if ( circularDependencyExceptions == null )
-        {
+    public List<CyclicDependencyException> getCircularDependencyExceptions() {
+        if (circularDependencyExceptions == null) {
             return Collections.emptyList();
         }
 
-        return Collections.unmodifiableList( circularDependencyExceptions );
+        return Collections.unmodifiableList(circularDependencyExceptions);
     }
 
     // ------------------------------------------------------------------------
     // Repositories
     // ------------------------------------------------------------------------
 
-    public List<ArtifactRepository> getRepositories()
-    {
-        if ( repositories == null )
-        {
+    public List<ArtifactRepository> getRepositories() {
+        if (repositories == null) {
             return Collections.emptyList();
         }
 
-        return Collections.unmodifiableList( repositories );
+        return Collections.unmodifiableList(repositories);
     }
 
-    public MetadataResolutionResult setRepositories( final List<ArtifactRepository> repositories )
-    {
+    public MetadataResolutionResult setRepositories(final List<ArtifactRepository> repositories) {
         this.repositories = repositories;
 
         return this;
@@ -322,42 +278,34 @@
     // Internal
     //
 
-    private <T> List<T> initList( final List<T> l )
-    {
-        if ( l == null )
-        {
+    private <T> List<T> initList(final List<T> l) {
+        if (l == null) {
             return new ArrayList<>();
         }
         return l;
     }
 
-    public String toString()
-    {
-        if ( artifacts == null )
-        {
+    public String toString() {
+        if (artifacts == null) {
             return "";
         }
-        StringBuilder sb = new StringBuilder( 256 );
+        StringBuilder sb = new StringBuilder(256);
         int i = 1;
-        sb.append( "---------\n" );
-        sb.append( artifacts.size() ).append( '\n' );
-        for ( Artifact a : artifacts )
-        {
-            sb.append( i ).append( ' ' ).append( a ).append( '\n' );
+        sb.append("---------\n");
+        sb.append(artifacts.size()).append('\n');
+        for (Artifact a : artifacts) {
+            sb.append(i).append(' ').append(a).append('\n');
             i++;
         }
-        sb.append( "---------\n" );
+        sb.append("---------\n");
         return sb.toString();
     }
 
-    public MetadataGraph getResolvedTree()
-    {
+    public MetadataGraph getResolvedTree() {
         return resolvedTree;
     }
 
-    public void setResolvedTree( MetadataGraph resolvedTree )
-    {
+    public void setResolvedTree(MetadataGraph resolvedTree) {
         this.resolvedTree = resolvedTree;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/MirrorSelector.java b/maven-compat/src/main/java/org/apache/maven/repository/MirrorSelector.java
index c15899e..eb958ae 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/MirrorSelector.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/MirrorSelector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.util.List;
 
@@ -27,10 +26,9 @@
 /**
  * Handles the selection of mirrors for repositories.
  *
- * @author Benjamin Bentmann
  */
-public interface MirrorSelector
-{
+@Deprecated
+public interface MirrorSelector {
 
     /**
      * Determines the mirror for the specified repository.
@@ -39,6 +37,5 @@
      * @param mirrors The available mirrors, may be {@code null}.
      * @return The mirror specification for the repository or {@code null} if no mirror matched.
      */
-    Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors );
-
+    Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/RepositorySystem.java b/maven-compat/src/main/java/org/apache/maven/repository/RepositorySystem.java
new file mode 100644
index 0000000..789c2cf
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/RepositorySystem.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import java.io.File;
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.InvalidRepositoryException;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.Repository;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Server;
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * @since 3.0-alpha
+ * @deprecated Use {@link MavenRepositorySystem} if needed, or maven-resolver directly, until maven 4.x api is out
+ */
+@Deprecated
+public interface RepositorySystem {
+    String DEFAULT_LOCAL_REPO_ID = MavenRepositorySystem.DEFAULT_LOCAL_REPO_ID;
+
+    @SuppressWarnings("checkstyle:constantname")
+    String userHome = System.getProperty("user.home");
+
+    @SuppressWarnings("checkstyle:constantname")
+    File userMavenConfigurationHome = new File(userHome, ".m2");
+
+    @SuppressWarnings("checkstyle:constantname")
+    File defaultUserLocalRepository = new File(userMavenConfigurationHome, "repository");
+
+    String DEFAULT_REMOTE_REPO_ID = MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID;
+
+    String DEFAULT_REMOTE_REPO_URL = MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID;
+
+    Artifact createArtifact(String groupId, String artifactId, String version, String packaging);
+
+    Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type);
+
+    Artifact createProjectArtifact(String groupId, String artifactId, String version);
+
+    Artifact createArtifactWithClassifier(
+            String groupId, String artifactId, String version, String type, String classifier);
+
+    Artifact createPluginArtifact(Plugin plugin);
+
+    Artifact createDependencyArtifact(Dependency dependency);
+
+    ArtifactRepository buildArtifactRepository(Repository repository) throws InvalidRepositoryException;
+
+    ArtifactRepository createDefaultRemoteRepository() throws InvalidRepositoryException;
+
+    ArtifactRepository createDefaultLocalRepository() throws InvalidRepositoryException;
+
+    ArtifactRepository createLocalRepository(File localRepository) throws InvalidRepositoryException;
+
+    ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases);
+
+    /**
+     * Calculates the effective repositories for the given input repositories which are assumed to be already mirrored
+     * (if applicable). This process will essentially remove duplicate repositories by merging them into one equivalent
+     * repository. It is worth to point out that merging does not simply choose one of the input repositories and
+     * discards the others but actually combines their possibly different policies.
+     *
+     * @param repositories The original repositories, may be {@code null}.
+     * @return The effective repositories or {@code null} if the input was {@code null}.
+     */
+    List<ArtifactRepository> getEffectiveRepositories(List<ArtifactRepository> repositories);
+
+    /**
+     * Determines the mirror for the specified repository.
+     *
+     * @param repository The repository to determine the mirror for, must not be {@code null}.
+     * @param mirrors The available mirrors, may be {@code null}.
+     * @return The mirror specification for the repository or {@code null} if no mirror matched.
+     */
+    Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors);
+
+    /**
+     * Injects the mirroring information into the specified repositories. For each repository that is matched by a
+     * mirror, its URL and ID will be updated to match the values from the mirror specification. Repositories without a
+     * matching mirror will pass through unchanged. <em>Note:</em> This method must be called before
+     * {@link #injectAuthentication(List, List)} or the repositories will end up with the wrong credentials.
+     *
+     * @param repositories The repositories into which to inject the mirror information, may be {@code null}.
+     * @param mirrors The available mirrors, may be {@code null}.
+     */
+    void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors);
+
+    /**
+     * Injects the proxy information into the specified repositories. For each repository that is matched by a proxy,
+     * its proxy data will be set accordingly. Repositories without a matching proxy will have their proxy cleared.
+     * <em>Note:</em> This method must be called after {@link #injectMirror(List, List)} or the repositories will end up
+     * with the wrong proxies.
+     *
+     * @param repositories The repositories into which to inject the proxy information, may be {@code null}.
+     * @param proxies The available proxies, may be {@code null}.
+     */
+    void injectProxy(List<ArtifactRepository> repositories, List<org.apache.maven.settings.Proxy> proxies);
+
+    /**
+     * Injects the authentication information into the specified repositories. For each repository that is matched by a
+     * server, its credentials will be updated to match the values from the server specification. Repositories without a
+     * matching server will have their credentials cleared. <em>Note:</em> This method must be called after
+     * {@link #injectMirror(List, List)} or the repositories will end up with the wrong credentials.
+     *
+     * @param repositories The repositories into which to inject the authentication information, may be {@code null}.
+     * @param servers The available servers, may be {@code null}.
+     */
+    void injectAuthentication(List<ArtifactRepository> repositories, List<Server> servers);
+
+    void injectMirror(RepositorySystemSession session, List<ArtifactRepository> repositories);
+
+    void injectProxy(RepositorySystemSession session, List<ArtifactRepository> repositories);
+
+    void injectAuthentication(RepositorySystemSession session, List<ArtifactRepository> repositories);
+
+    ArtifactResolutionResult resolve(ArtifactResolutionRequest request);
+
+    // Install
+
+    // Deploy
+
+    // Map types of artifacts
+
+    //
+    // Raw file transfers
+    //
+    void publish(
+            ArtifactRepository repository, File source, String remotePath, ArtifactTransferListener transferListener)
+            throws ArtifactTransferFailedException;
+
+    void retrieve(
+            ArtifactRepository repository,
+            File destination,
+            String remotePath,
+            ArtifactTransferListener transferListener)
+            throws ArtifactTransferFailedException, ArtifactDoesNotExistException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/UserLocalArtifactRepository.java b/maven-compat/src/main/java/org/apache/maven/repository/UserLocalArtifactRepository.java
index a88b009..2cc8e36 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/UserLocalArtifactRepository.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/UserLocalArtifactRepository.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.io.File;
 
@@ -28,50 +27,43 @@
 /**
  * UserLocalArtifactRepository
  */
-public class UserLocalArtifactRepository
-    extends LocalArtifactRepository
-{
+@Deprecated
+public class UserLocalArtifactRepository extends LocalArtifactRepository {
     private ArtifactRepository localRepository;
 
-    public UserLocalArtifactRepository( ArtifactRepository localRepository )
-    {
+    public UserLocalArtifactRepository(ArtifactRepository localRepository) {
         this.localRepository = localRepository;
-        setLayout( localRepository.getLayout() );
+        setLayout(localRepository.getLayout());
     }
 
     @Override
-    public Artifact find( Artifact artifact )
-    {
-        File artifactFile = new File( localRepository.getBasedir(), pathOf( artifact ) );
+    public Artifact find(Artifact artifact) {
+        File artifactFile = new File(localRepository.getBasedir(), pathOf(artifact));
 
         // We need to set the file here or the resolver will fail with an NPE, not fully equipped to deal
         // with multiple local repository implementations yet.
-        artifact.setFile( artifactFile );
+        artifact.setFile(artifactFile);
 
         return artifact;
     }
 
     @Override
-    public String getId()
-    {
+    public String getId() {
         return localRepository.getId();
     }
 
     @Override
-    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-    {
-        return localRepository.pathOfLocalRepositoryMetadata( metadata, repository );
+    public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+        return localRepository.pathOfLocalRepositoryMetadata(metadata, repository);
     }
 
     @Override
-    public String pathOf( Artifact artifact )
-    {
-        return localRepository.pathOf( artifact );
+    public String pathOf(Artifact artifact) {
+        return localRepository.pathOf(artifact);
     }
 
     @Override
-    public boolean hasLocalMetadata()
-    {
+    public boolean hasLocalMetadata() {
         return true;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/VersionNotFoundException.java b/maven-compat/src/main/java/org/apache/maven/repository/VersionNotFoundException.java
index 77b1af1..4adb4eb 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/VersionNotFoundException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/VersionNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.io.File;
 
@@ -28,22 +27,21 @@
 /**
  * Thrown if a dependency has an invalid version.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class VersionNotFoundException
-    extends Exception
-{
+@Deprecated
+public class VersionNotFoundException extends Exception {
     private Dependency dependency;
 
     private String projectId;
     private File pomFile;
     private InvalidVersionSpecificationException cause;
 
-    public VersionNotFoundException( String projectId, Dependency dependency, File pomFile,
-                                     InvalidVersionSpecificationException cause )
-    {
-        super( projectId + ", " + formatLocationInPom( dependency ) + " " + dependency.getVersion() + ", pom file "
-            + pomFile, cause );
+    public VersionNotFoundException(
+            String projectId, Dependency dependency, File pomFile, InvalidVersionSpecificationException cause) {
+        super(
+                projectId + ", " + formatLocationInPom(dependency) + " " + dependency.getVersion() + ", pom file "
+                        + pomFile,
+                cause);
 
         this.projectId = projectId;
 
@@ -54,30 +52,23 @@
         this.dependency = dependency;
     }
 
-    private static String formatLocationInPom( Dependency dependency )
-    {
-        return "Dependency: " + ArtifactUtils.versionlessKey( dependency.getGroupId(), dependency.getArtifactId() );
+    private static String formatLocationInPom(Dependency dependency) {
+        return "Dependency: " + ArtifactUtils.versionlessKey(dependency.getGroupId(), dependency.getArtifactId());
     }
 
-    public Dependency getDependency()
-    {
+    public Dependency getDependency() {
         return dependency;
     }
 
-    public String getProjectId()
-    {
+    public String getProjectId() {
         return projectId;
     }
 
-    public File getPomFile()
-    {
+    public File getPomFile() {
         return pomFile;
     }
 
-    public InvalidVersionSpecificationException getCauseException()
-    {
+    public InvalidVersionSpecificationException getCauseException() {
         return cause;
     }
-
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/ChecksumFailedException.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/ChecksumFailedException.java
index 4e0c4a6..ea375a3 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/ChecksumFailedException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/ChecksumFailedException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,25 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import org.apache.maven.wagon.TransferFailedException;
 
 /**
  * Occurs when a download checksum fails.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class ChecksumFailedException
-    extends TransferFailedException
-{
-    public ChecksumFailedException( String s )
-    {
-        super( s );
+@Deprecated
+public class ChecksumFailedException extends TransferFailedException {
+    public ChecksumFailedException(String s) {
+        super(s);
     }
 
-    public ChecksumFailedException( String message,
-                                    Throwable cause )
-    {
-        super( message, cause );
+    public ChecksumFailedException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManager.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManager.java
index 993ac5e..4c4156a 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-import org.apache.maven.artifact.repository.Authentication;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
-import org.apache.maven.repository.Proxy;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.logging.AbstractLogEnabled;
-import org.codehaus.plexus.logging.Logger;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.io.FileInputStream;
@@ -39,358 +31,301 @@
 import java.util.Date;
 import java.util.Properties;
 
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.Authentication;
+import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
+import org.apache.maven.repository.Proxy;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.logging.Logger;
+
 /**
  * DefaultUpdateCheckManager
  */
-@Component( role = UpdateCheckManager.class )
-public class DefaultUpdateCheckManager
-    extends AbstractLogEnabled
-    implements UpdateCheckManager
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultUpdateCheckManager extends AbstractLogEnabled implements UpdateCheckManager {
 
     private static final String ERROR_KEY_SUFFIX = ".error";
 
-    public DefaultUpdateCheckManager()
-    {
+    public DefaultUpdateCheckManager() {}
 
-    }
-
-    public DefaultUpdateCheckManager( Logger logger )
-    {
-        enableLogging( logger );
+    public DefaultUpdateCheckManager(Logger logger) {
+        enableLogging(logger);
     }
 
     public static final String LAST_UPDATE_TAG = ".lastUpdated";
 
     private static final String TOUCHFILE_NAME = "resolver-status.properties";
 
-    public boolean isUpdateRequired( Artifact artifact, ArtifactRepository repository )
-    {
+    public boolean isUpdateRequired(Artifact artifact, ArtifactRepository repository) {
         File file = artifact.getFile();
 
         ArtifactRepositoryPolicy policy = artifact.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
 
-        if ( !policy.isEnabled() )
-        {
-            if ( getLogger().isDebugEnabled() )
-            {
-                getLogger().debug(
-                    "Skipping update check for " + artifact + " (" + file + ") from " + repository.getId() + " ("
-                        + repository.getUrl() + ")" );
+        if (!policy.isEnabled()) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger()
+                        .debug("Skipping update check for " + artifact + " (" + file + ") from " + repository.getId()
+                                + " (" + repository.getUrl() + ")");
             }
 
             return false;
         }
 
-        if ( getLogger().isDebugEnabled() )
-        {
-            getLogger().debug(
-                "Determining update check for " + artifact + " (" + file + ") from " + repository.getId() + " ("
-                    + repository.getUrl() + ")" );
+        if (getLogger().isDebugEnabled()) {
+            getLogger()
+                    .debug("Determining update check for " + artifact + " (" + file + ") from " + repository.getId()
+                            + " (" + repository.getUrl() + ")");
         }
 
-        if ( file == null )
-        {
+        if (file == null) {
             // TODO throw something instead?
             return true;
         }
 
         Date lastCheckDate;
 
-        if ( file.exists() )
-        {
-            lastCheckDate = new Date( file.lastModified() );
-        }
-        else
-        {
-            File touchfile = getTouchfile( artifact );
-            lastCheckDate = readLastUpdated( touchfile, getRepositoryKey( repository ) );
+        if (file.exists()) {
+            lastCheckDate = new Date(file.lastModified());
+        } else {
+            File touchfile = getTouchfile(artifact);
+            lastCheckDate = readLastUpdated(touchfile, getRepositoryKey(repository));
         }
 
-        return ( lastCheckDate == null ) || policy.checkOutOfDate( lastCheckDate );
+        return (lastCheckDate == null) || policy.checkOutOfDate(lastCheckDate);
     }
 
-    public boolean isUpdateRequired( RepositoryMetadata metadata, ArtifactRepository repository, File file )
-    {
+    public boolean isUpdateRequired(RepositoryMetadata metadata, ArtifactRepository repository, File file) {
         // Here, we need to determine which policy to use. Release updateInterval will be used when
         // the metadata refers to a release artifact or meta-version, and snapshot updateInterval will be used when
         // it refers to a snapshot artifact or meta-version.
         // NOTE: Release metadata includes version information about artifacts that have been released, to allow
         // meta-versions like RELEASE and LATEST to resolve, and also to allow retrieval of the range of valid, released
         // artifacts available.
-        ArtifactRepositoryPolicy policy = metadata.getPolicy( repository );
+        ArtifactRepositoryPolicy policy = metadata.getPolicy(repository);
 
-        if ( !policy.isEnabled() )
-        {
-            if ( getLogger().isDebugEnabled() )
-            {
-                getLogger().debug(
-                    "Skipping update check for " + metadata.getKey() + " (" + file + ") from " + repository.getId()
-                        + " (" + repository.getUrl() + ")" );
+        if (!policy.isEnabled()) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger()
+                        .debug("Skipping update check for " + metadata.getKey() + " (" + file + ") from "
+                                + repository.getId() + " (" + repository.getUrl() + ")");
             }
 
             return false;
         }
 
-        if ( getLogger().isDebugEnabled() )
-        {
-            getLogger().debug(
-                "Determining update check for " + metadata.getKey() + " (" + file + ") from " + repository.getId()
-                    + " (" + repository.getUrl() + ")" );
+        if (getLogger().isDebugEnabled()) {
+            getLogger()
+                    .debug("Determining update check for " + metadata.getKey() + " (" + file + ") from "
+                            + repository.getId() + " (" + repository.getUrl() + ")");
         }
 
-        if ( file == null )
-        {
+        if (file == null) {
             // TODO throw something instead?
             return true;
         }
 
-        Date lastCheckDate = readLastUpdated( metadata, repository, file );
+        Date lastCheckDate = readLastUpdated(metadata, repository, file);
 
-        return ( lastCheckDate == null ) || policy.checkOutOfDate( lastCheckDate );
+        return (lastCheckDate == null) || policy.checkOutOfDate(lastCheckDate);
     }
 
-    private Date readLastUpdated( RepositoryMetadata metadata, ArtifactRepository repository, File file )
-    {
-        File touchfile = getTouchfile( metadata, file );
+    private Date readLastUpdated(RepositoryMetadata metadata, ArtifactRepository repository, File file) {
+        File touchfile = getTouchfile(metadata, file);
 
-        String key = getMetadataKey( repository, file );
+        String key = getMetadataKey(repository, file);
 
-        return readLastUpdated( touchfile, key );
+        return readLastUpdated(touchfile, key);
     }
 
-    public String getError( Artifact artifact, ArtifactRepository repository )
-    {
-        File touchFile = getTouchfile( artifact );
-        return getError( touchFile, getRepositoryKey( repository ) );
+    public String getError(Artifact artifact, ArtifactRepository repository) {
+        File touchFile = getTouchfile(artifact);
+        return getError(touchFile, getRepositoryKey(repository));
     }
 
-    public void touch( Artifact artifact, ArtifactRepository repository, String error )
-    {
+    public void touch(Artifact artifact, ArtifactRepository repository, String error) {
         File file = artifact.getFile();
 
-        File touchfile = getTouchfile( artifact );
+        File touchfile = getTouchfile(artifact);
 
-        if ( file.exists() )
-        {
+        if (file.exists()) {
             touchfile.delete();
-        }
-        else
-        {
-            writeLastUpdated( touchfile, getRepositoryKey( repository ), error );
+        } else {
+            writeLastUpdated(touchfile, getRepositoryKey(repository), error);
         }
     }
 
-    public void touch( RepositoryMetadata metadata, ArtifactRepository repository, File file )
-    {
-        File touchfile = getTouchfile( metadata, file );
+    public void touch(RepositoryMetadata metadata, ArtifactRepository repository, File file) {
+        File touchfile = getTouchfile(metadata, file);
 
-        String key = getMetadataKey( repository, file );
+        String key = getMetadataKey(repository, file);
 
-        writeLastUpdated( touchfile, key, null );
+        writeLastUpdated(touchfile, key, null);
     }
 
-    String getMetadataKey( ArtifactRepository repository, File file )
-    {
+    String getMetadataKey(ArtifactRepository repository, File file) {
         return repository.getId() + '.' + file.getName() + LAST_UPDATE_TAG;
     }
 
-    String getRepositoryKey( ArtifactRepository repository )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
+    String getRepositoryKey(ArtifactRepository repository) {
+        StringBuilder buffer = new StringBuilder(256);
 
         Proxy proxy = repository.getProxy();
-        if ( proxy != null )
-        {
-            if ( proxy.getUserName() != null )
-            {
-                int hash = ( proxy.getUserName() + proxy.getPassword() ).hashCode();
-                buffer.append( hash ).append( '@' );
+        if (proxy != null) {
+            if (proxy.getUserName() != null) {
+                int hash = (proxy.getUserName() + proxy.getPassword()).hashCode();
+                buffer.append(hash).append('@');
             }
-            buffer.append( proxy.getHost() ).append( ':' ).append( proxy.getPort() ).append( '>' );
+            buffer.append(proxy.getHost()).append(':').append(proxy.getPort()).append('>');
         }
 
         // consider the username&password because a repo manager might block artifacts depending on authorization
         Authentication auth = repository.getAuthentication();
-        if ( auth != null )
-        {
-            int hash = ( auth.getUsername() + auth.getPassword() ).hashCode();
-            buffer.append( hash ).append( '@' );
+        if (auth != null) {
+            int hash = (auth.getUsername() + auth.getPassword()).hashCode();
+            buffer.append(hash).append('@');
         }
 
         // consider the URL (instead of the id) as this most closely relates to the contents in the repo
-        buffer.append( repository.getUrl() );
+        buffer.append(repository.getUrl());
 
         return buffer.toString();
     }
 
-    private void writeLastUpdated( File touchfile, String key, String error )
-    {
-        synchronized ( touchfile.getAbsolutePath().intern() )
-        {
-            if ( !touchfile.getParentFile().exists() && !touchfile.getParentFile().mkdirs() )
-            {
-                getLogger().debug( "Failed to create directory: " + touchfile.getParent()
-                                       + " for tracking artifact metadata resolution." );
+    private void writeLastUpdated(File touchfile, String key, String error) {
+        synchronized (touchfile.getAbsolutePath().intern()) {
+            if (!touchfile.getParentFile().exists()
+                    && !touchfile.getParentFile().mkdirs()) {
+                getLogger()
+                        .debug("Failed to create directory: " + touchfile.getParent()
+                                + " for tracking artifact metadata resolution.");
                 return;
             }
 
             FileChannel channel = null;
             FileLock lock = null;
-            try
-            {
+            try {
                 Properties props = new Properties();
 
-                channel = new RandomAccessFile( touchfile, "rw" ).getChannel();
+                channel = new RandomAccessFile(touchfile, "rw").getChannel();
                 lock = channel.lock();
 
-                if ( touchfile.canRead() )
-                {
-                    getLogger().debug( "Reading resolution-state from: " + touchfile );
-                    props.load( Channels.newInputStream( channel ) );
+                if (touchfile.canRead()) {
+                    getLogger().debug("Reading resolution-state from: " + touchfile);
+                    props.load(Channels.newInputStream(channel));
                 }
 
-                props.setProperty( key, Long.toString( System.currentTimeMillis() ) );
+                props.setProperty(key, Long.toString(System.currentTimeMillis()));
 
-                if ( error != null )
-                {
-                    props.setProperty( key + ERROR_KEY_SUFFIX, error );
-                }
-                else
-                {
-                    props.remove( key + ERROR_KEY_SUFFIX );
+                if (error != null) {
+                    props.setProperty(key + ERROR_KEY_SUFFIX, error);
+                } else {
+                    props.remove(key + ERROR_KEY_SUFFIX);
                 }
 
-                getLogger().debug( "Writing resolution-state to: " + touchfile );
-                channel.truncate( 0 );
-                props.store( Channels.newOutputStream( channel ), "Last modified on: " + new Date() );
+                getLogger().debug("Writing resolution-state to: " + touchfile);
+                channel.truncate(0);
+                props.store(Channels.newOutputStream(channel), "Last modified on: " + new Date());
 
                 lock.release();
                 lock = null;
 
                 channel.close();
                 channel = null;
-            }
-            catch ( IOException e )
-            {
-                getLogger().debug(
-                    "Failed to record lastUpdated information for resolution.\nFile: " + touchfile.toString()
-                        + "; key: " + key, e );
-            }
-            finally
-            {
-                if ( lock != null )
-                {
-                    try
-                    {
+            } catch (IOException e) {
+                getLogger()
+                        .debug(
+                                "Failed to record lastUpdated information for resolution.\nFile: "
+                                        + touchfile.toString() + "; key: " + key,
+                                e);
+            } finally {
+                if (lock != null) {
+                    try {
                         lock.release();
-                    }
-                    catch ( IOException e )
-                    {
-                        getLogger().debug( "Error releasing exclusive lock for resolution tracking file: " + touchfile,
-                                           e );
+                    } catch (IOException e) {
+                        getLogger()
+                                .debug("Error releasing exclusive lock for resolution tracking file: " + touchfile, e);
                     }
                 }
 
-                if ( channel != null )
-                {
-                    try
-                    {
+                if (channel != null) {
+                    try {
                         channel.close();
-                    }
-                    catch ( IOException e )
-                    {
-                        getLogger().debug( "Error closing FileChannel for resolution tracking file: " + touchfile, e );
+                    } catch (IOException e) {
+                        getLogger().debug("Error closing FileChannel for resolution tracking file: " + touchfile, e);
                     }
                 }
             }
         }
     }
 
-    Date readLastUpdated( File touchfile, String key )
-    {
-        getLogger().debug( "Searching for " + key + " in resolution tracking file." );
+    Date readLastUpdated(File touchfile, String key) {
+        getLogger().debug("Searching for " + key + " in resolution tracking file.");
 
-        Properties props = read( touchfile );
-        if ( props != null )
-        {
-            String rawVal = props.getProperty( key );
-            if ( rawVal != null )
-            {
-                try
-                {
-                    return new Date( Long.parseLong( rawVal ) );
-                }
-                catch ( NumberFormatException e )
-                {
-                    getLogger().debug( "Cannot parse lastUpdated date: '" + rawVal + "'. Ignoring.", e );
+        Properties props = read(touchfile);
+        if (props != null) {
+            String rawVal = props.getProperty(key);
+            if (rawVal != null) {
+                try {
+                    return new Date(Long.parseLong(rawVal));
+                } catch (NumberFormatException e) {
+                    getLogger().debug("Cannot parse lastUpdated date: '" + rawVal + "'. Ignoring.", e);
                 }
             }
         }
         return null;
     }
 
-    private String getError( File touchFile, String key )
-    {
-        Properties props = read( touchFile );
-        if ( props != null )
-        {
-            return props.getProperty( key + ERROR_KEY_SUFFIX );
+    private String getError(File touchFile, String key) {
+        Properties props = read(touchFile);
+        if (props != null) {
+            return props.getProperty(key + ERROR_KEY_SUFFIX);
         }
         return null;
     }
 
-    private Properties read( File touchfile )
-    {
-        if ( !touchfile.canRead() )
-        {
-            getLogger().debug( "Skipped unreadable resolution tracking file: " + touchfile );
+    private Properties read(File touchfile) {
+        if (!touchfile.canRead()) {
+            getLogger().debug("Skipped unreadable resolution tracking file: " + touchfile);
             return null;
         }
 
-        synchronized ( touchfile.getAbsolutePath().intern() )
-        {
-            try
-            {
+        synchronized (touchfile.getAbsolutePath().intern()) {
+            try {
                 Properties props = new Properties();
 
-                try ( FileInputStream in = new FileInputStream( touchfile ) )
-                {
-                    try ( FileLock lock = in.getChannel().lock( 0, Long.MAX_VALUE, true ) )
-                    {
-                        getLogger().debug( "Reading resolution-state from: " + touchfile );
-                        props.load( in );
+                try (FileInputStream in = new FileInputStream(touchfile)) {
+                    try (FileLock lock = in.getChannel().lock(0, Long.MAX_VALUE, true)) {
+                        getLogger().debug("Reading resolution-state from: " + touchfile);
+                        props.load(in);
 
                         return props;
                     }
                 }
 
-            }
-            catch ( IOException e )
-            {
-                getLogger().debug( "Failed to read resolution tracking file: " + touchfile, e );
+            } catch (IOException e) {
+                getLogger().debug("Failed to read resolution tracking file: " + touchfile, e);
 
                 return null;
             }
         }
     }
 
-    File getTouchfile( Artifact artifact )
-    {
-        StringBuilder sb = new StringBuilder( 128 );
-        sb.append( artifact.getArtifactId() );
-        sb.append( '-' ).append( artifact.getBaseVersion() );
-        if ( artifact.getClassifier() != null )
-        {
-            sb.append( '-' ).append( artifact.getClassifier() );
+    File getTouchfile(Artifact artifact) {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append(artifact.getArtifactId());
+        sb.append('-').append(artifact.getBaseVersion());
+        if (artifact.getClassifier() != null) {
+            sb.append('-').append(artifact.getClassifier());
         }
-        sb.append( '.' ).append( artifact.getType() ).append( LAST_UPDATE_TAG );
-        return new File( artifact.getFile().getParentFile(), sb.toString() );
+        sb.append('.').append(artifact.getType()).append(LAST_UPDATE_TAG);
+        return new File(artifact.getFile().getParentFile(), sb.toString());
     }
 
-    File getTouchfile( RepositoryMetadata metadata, File file )
-    {
-        return new File( file.getParent(), TOUCHFILE_NAME );
+    File getTouchfile(RepositoryMetadata metadata, File file) {
+        return new File(file.getParent(), TOUCHFILE_NAME);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultWagonManager.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultWagonManager.java
index 3272dde..4fa05c9 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultWagonManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/DefaultWagonManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,10 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.nio.file.StandardOpenOption;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -47,204 +55,173 @@
 import org.apache.maven.wagon.proxy.ProxyInfo;
 import org.apache.maven.wagon.repository.Repository;
 import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.logging.Logger;
-import org.codehaus.plexus.util.FileUtils;
 import org.eclipse.aether.ConfigurationProperties;
 import org.eclipse.aether.util.ConfigUtils;
 
-//TODO remove the update check manager
-//TODO separate into retriever and publisher
-//TODO remove hardcoding of checksum logic
+// TODO remove the update check manager
+// TODO separate into retriever and publisher
+// TODO remove hardcoding of checksum logic
 
 /**
  * Manages <a href="https://maven.apache.org/wagon">Wagon</a> related operations in Maven.
  */
-@Component( role = WagonManager.class )
-public class DefaultWagonManager
-    implements WagonManager
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultWagonManager implements WagonManager {
 
-    private static final String[] CHECKSUM_IDS =
-    {
-        "md5", "sha1"
-    };
+    private static final String[] CHECKSUM_IDS = {"md5", "sha1"};
 
     /**
      * have to match the CHECKSUM_IDS
      */
-    private static final String[] CHECKSUM_ALGORITHMS =
-    {
-        "MD5", "SHA-1"
-    };
+    private static final String[] CHECKSUM_ALGORITHMS = {"MD5", "SHA-1"};
 
-    @Requirement
+    @Inject
     private Logger logger;
 
-    @Requirement
+    @Inject
     private PlexusContainer container;
 
-    @Requirement
+    @Inject
     private UpdateCheckManager updateCheckManager;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
     //
     // Retriever
     //
     @Override
-    public void getArtifact( Artifact artifact, ArtifactRepository repository, TransferListener downloadMonitor,
-                             boolean force )
-        throws TransferFailedException, ResourceDoesNotExistException
-    {
-        String remotePath = repository.pathOf( artifact );
+    public void getArtifact(
+            Artifact artifact, ArtifactRepository repository, TransferListener downloadMonitor, boolean force)
+            throws TransferFailedException, ResourceDoesNotExistException {
+        String remotePath = repository.pathOf(artifact);
 
         ArtifactRepositoryPolicy policy = artifact.isSnapshot() ? repository.getSnapshots() : repository.getReleases();
 
-        if ( !policy.isEnabled() )
-        {
-            logger.debug( "Skipping disabled repository " + repository.getId() + " for resolution of "
-                              + artifact.getId() );
+        if (!policy.isEnabled()) {
+            logger.debug(
+                    "Skipping disabled repository " + repository.getId() + " for resolution of " + artifact.getId());
 
-        }
-        else if ( artifact.isSnapshot() || !artifact.getFile().exists() )
-        {
-            if ( force || updateCheckManager.isUpdateRequired( artifact, repository ) )
-            {
-                logger.debug( "Trying repository " + repository.getId() + " for resolution of " + artifact.getId()
-                                  + " from " + remotePath );
+        } else if (artifact.isSnapshot() || !artifact.getFile().exists()) {
+            if (force || updateCheckManager.isUpdateRequired(artifact, repository)) {
+                logger.debug("Trying repository " + repository.getId() + " for resolution of " + artifact.getId()
+                        + " from " + remotePath);
 
-                try
-                {
-                    getRemoteFile( repository, artifact.getFile(), remotePath, downloadMonitor,
-                                   policy.getChecksumPolicy(), false );
+                try {
+                    getRemoteFile(
+                            repository,
+                            artifact.getFile(),
+                            remotePath,
+                            downloadMonitor,
+                            policy.getChecksumPolicy(),
+                            false);
 
-                    updateCheckManager.touch( artifact, repository, null );
-                }
-                catch ( ResourceDoesNotExistException e )
-                {
-                    updateCheckManager.touch( artifact, repository, null );
+                    updateCheckManager.touch(artifact, repository, null);
+                } catch (ResourceDoesNotExistException e) {
+                    updateCheckManager.touch(artifact, repository, null);
                     throw e;
-                }
-                catch ( TransferFailedException e )
-                {
-                    String error = ( e.getMessage() != null ) ? e.getMessage() : e.getClass().getSimpleName();
-                    updateCheckManager.touch( artifact, repository, error );
+                } catch (TransferFailedException e) {
+                    String error = (e.getMessage() != null)
+                            ? e.getMessage()
+                            : e.getClass().getSimpleName();
+                    updateCheckManager.touch(artifact, repository, error);
                     throw e;
                 }
 
-                logger.debug( "  Artifact " + artifact.getId() + " resolved to " + artifact.getFile() );
+                logger.debug("  Artifact " + artifact.getId() + " resolved to " + artifact.getFile());
 
-                artifact.setResolved( true );
-            }
-            else if ( !artifact.getFile().exists() )
-            {
-                String error = updateCheckManager.getError( artifact, repository );
-                if ( error != null )
-                {
-                    throw new TransferFailedException(
-                        "Failure to resolve " + remotePath + " from " + repository.getUrl()
+                artifact.setResolved(true);
+            } else if (!artifact.getFile().exists()) {
+                String error = updateCheckManager.getError(artifact, repository);
+                if (error != null) {
+                    throw new TransferFailedException("Failure to resolve " + remotePath + " from "
+                            + repository.getUrl()
                             + " was cached in the local repository. "
                             + "Resolution will not be reattempted until the update interval of "
-                            + repository.getId() + " has elapsed or updates are forced. Original error: " + error );
+                            + repository.getId() + " has elapsed or updates are forced. Original error: " + error);
 
-                }
-                else
-                {
+                } else {
                     throw new ResourceDoesNotExistException(
-                        "Failure to resolve " + remotePath + " from " + repository.getUrl()
-                            + " was cached in the local repository. "
-                            + "Resolution will not be reattempted until the update interval of "
-                            + repository.getId() + " has elapsed or updates are forced." );
-
+                            "Failure to resolve " + remotePath + " from " + repository.getUrl()
+                                    + " was cached in the local repository. "
+                                    + "Resolution will not be reattempted until the update interval of "
+                                    + repository.getId() + " has elapsed or updates are forced.");
                 }
             }
         }
     }
 
     @Override
-    public void getArtifact( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                             TransferListener downloadMonitor, boolean force )
-        throws TransferFailedException, ResourceDoesNotExistException
-    {
+    public void getArtifact(
+            Artifact artifact,
+            List<ArtifactRepository> remoteRepositories,
+            TransferListener downloadMonitor,
+            boolean force)
+            throws TransferFailedException, ResourceDoesNotExistException {
         TransferFailedException tfe = null;
 
-        for ( ArtifactRepository repository : remoteRepositories )
-        {
-            try
-            {
-                getArtifact( artifact, repository, downloadMonitor, force );
+        for (ArtifactRepository repository : remoteRepositories) {
+            try {
+                getArtifact(artifact, repository, downloadMonitor, force);
 
-                if ( artifact.isResolved() )
-                {
-                    artifact.setRepository( repository );
+                if (artifact.isResolved()) {
+                    artifact.setRepository(repository);
                     break;
                 }
-            }
-            catch ( ResourceDoesNotExistException e )
-            {
+            } catch (ResourceDoesNotExistException e) {
                 // This one we will eat when looking through remote repositories
                 // because we want to cycle through them all before squawking.
 
-                logger.debug( "Unable to find artifact " + artifact.getId() + " in repository " + repository.getId()
-                                  + " (" + repository.getUrl() + ")", e );
+                logger.debug(
+                        "Unable to find artifact " + artifact.getId() + " in repository " + repository.getId() + " ("
+                                + repository.getUrl() + ")",
+                        e);
 
-            }
-            catch ( TransferFailedException e )
-            {
+            } catch (TransferFailedException e) {
                 tfe = e;
 
-                String msg =
-                    "Unable to get artifact " + artifact.getId() + " from repository " + repository.getId() + " ("
-                        + repository.getUrl() + "): " + e.getMessage();
+                String msg = "Unable to get artifact " + artifact.getId() + " from repository " + repository.getId()
+                        + " (" + repository.getUrl() + "): " + e.getMessage();
 
-                if ( logger.isDebugEnabled() )
-                {
-                    logger.warn( msg, e );
-                }
-                else
-                {
-                    logger.warn( msg );
+                if (logger.isDebugEnabled()) {
+                    logger.warn(msg, e);
+                } else {
+                    logger.warn(msg);
                 }
             }
         }
 
         // if it already exists locally we were just trying to force it - ignore the update
-        if ( !artifact.getFile().exists() )
-        {
-            if ( tfe != null )
-            {
+        if (!artifact.getFile().exists()) {
+            if (tfe != null) {
                 throw tfe;
-            }
-            else
-            {
-                throw new ResourceDoesNotExistException( "Unable to download the artifact from any repository" );
+            } else {
+                throw new ResourceDoesNotExistException("Unable to download the artifact from any repository");
             }
         }
     }
 
     @Override
-    public void getArtifactMetadata( ArtifactMetadata metadata, ArtifactRepository repository, File destination,
-                                     String checksumPolicy )
-        throws TransferFailedException, ResourceDoesNotExistException
-    {
-        String remotePath = repository.pathOfRemoteRepositoryMetadata( metadata );
+    public void getArtifactMetadata(
+            ArtifactMetadata metadata, ArtifactRepository repository, File destination, String checksumPolicy)
+            throws TransferFailedException, ResourceDoesNotExistException {
+        String remotePath = repository.pathOfRemoteRepositoryMetadata(metadata);
 
-        getRemoteFile( repository, destination, remotePath, null, checksumPolicy, true );
+        getRemoteFile(repository, destination, remotePath, null, checksumPolicy, true);
     }
 
     @Override
-    public void getArtifactMetadataFromDeploymentRepository( ArtifactMetadata metadata, ArtifactRepository repository,
-                                                             File destination, String checksumPolicy )
-        throws TransferFailedException, ResourceDoesNotExistException
-    {
-        String remotePath = repository.pathOfRemoteRepositoryMetadata( metadata );
+    public void getArtifactMetadataFromDeploymentRepository(
+            ArtifactMetadata metadata, ArtifactRepository repository, File destination, String checksumPolicy)
+            throws TransferFailedException, ResourceDoesNotExistException {
+        String remotePath = repository.pathOfRemoteRepositoryMetadata(metadata);
 
-        getRemoteFile( repository, destination, remotePath, null, checksumPolicy, true );
+        getRemoteFile(repository, destination, remotePath, null, checksumPolicy, true);
     }
 
     /**
@@ -256,120 +233,104 @@
      * @throws ConnectionException
      * @throws AuthenticationException
      */
-    private void connectWagon( Wagon wagon, ArtifactRepository repository )
-        throws ConnectionException, AuthenticationException
-    {
+    private void connectWagon(Wagon wagon, ArtifactRepository repository)
+            throws ConnectionException, AuthenticationException {
         // MNG-5509
         // See org.eclipse.aether.connector.wagon.WagonRepositoryConnector.connectWagon(Wagon)
-        if ( legacySupport.getRepositorySession() != null )
-        {
-            String userAgent = ConfigUtils.getString( legacySupport.getRepositorySession(), null,
-                                                      ConfigurationProperties.USER_AGENT );
+        if (legacySupport.getRepositorySession() != null) {
+            String userAgent = ConfigUtils.getString(
+                    legacySupport.getRepositorySession(), null, ConfigurationProperties.USER_AGENT);
 
-            if ( userAgent == null )
-            {
+            if (userAgent == null) {
                 Properties headers = new Properties();
 
-                headers.put( "User-Agent", ConfigUtils.getString( legacySupport.getRepositorySession(), "Maven",
-                                                                  ConfigurationProperties.USER_AGENT ) );
-                try
-                {
-                    Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class );
-                    setHttpHeaders.invoke( wagon, headers );
-                }
-                catch ( NoSuchMethodException e )
-                {
+                headers.put(
+                        "User-Agent",
+                        ConfigUtils.getString(
+                                legacySupport.getRepositorySession(), "Maven", ConfigurationProperties.USER_AGENT));
+                try {
+                    Method setHttpHeaders = wagon.getClass().getMethod("setHttpHeaders", Properties.class);
+                    setHttpHeaders.invoke(wagon, headers);
+                } catch (NoSuchMethodException e) {
                     // normal for non-http wagons
-                }
-                catch ( Exception e )
-                {
-                    logger.debug( "Could not set user agent for wagon " + wagon.getClass().getName() + ": " + e );
+                } catch (Exception e) {
+                    logger.debug("Could not set user agent for wagon "
+                            + wagon.getClass().getName() + ": " + e);
                 }
             }
         }
 
-        if ( repository.getProxy() != null && logger.isDebugEnabled() )
-        {
-            logger.debug( "Using proxy " + repository.getProxy().getHost() + ":" + repository.getProxy().getPort()
-                              + " for " + repository.getUrl() );
-
+        if (repository.getProxy() != null && logger.isDebugEnabled()) {
+            logger.debug("Using proxy " + repository.getProxy().getHost() + ":"
+                    + repository.getProxy().getPort() + " for " + repository.getUrl());
         }
 
-        if ( repository.getAuthentication() != null && repository.getProxy() != null )
-        {
-            wagon.connect( new Repository( repository.getId(), repository.getUrl() ), authenticationInfo( repository ),
-                           proxyInfo( repository ) );
+        if (repository.getAuthentication() != null && repository.getProxy() != null) {
+            wagon.connect(
+                    new Repository(repository.getId(), repository.getUrl()),
+                    authenticationInfo(repository),
+                    proxyInfo(repository));
 
-        }
-        else if ( repository.getAuthentication() != null )
-        {
-            wagon.connect( new Repository( repository.getId(), repository.getUrl() ),
-                           authenticationInfo( repository ) );
+        } else if (repository.getAuthentication() != null) {
+            wagon.connect(new Repository(repository.getId(), repository.getUrl()), authenticationInfo(repository));
 
-        }
-        else if ( repository.getProxy() != null )
-        {
-            wagon.connect( new Repository( repository.getId(), repository.getUrl() ), proxyInfo( repository ) );
-        }
-        else
-        {
-            wagon.connect( new Repository( repository.getId(), repository.getUrl() ) );
+        } else if (repository.getProxy() != null) {
+            wagon.connect(new Repository(repository.getId(), repository.getUrl()), proxyInfo(repository));
+        } else {
+            wagon.connect(new Repository(repository.getId(), repository.getUrl()));
         }
     }
 
-    private AuthenticationInfo authenticationInfo( ArtifactRepository repository )
-    {
+    private AuthenticationInfo authenticationInfo(ArtifactRepository repository) {
         AuthenticationInfo ai = new AuthenticationInfo();
-        ai.setUserName( repository.getAuthentication().getUsername() );
-        ai.setPassword( repository.getAuthentication().getPassword() );
+        ai.setUserName(repository.getAuthentication().getUsername());
+        ai.setPassword(repository.getAuthentication().getPassword());
         return ai;
     }
 
-    private ProxyInfo proxyInfo( ArtifactRepository repository )
-    {
+    private ProxyInfo proxyInfo(ArtifactRepository repository) {
         ProxyInfo proxyInfo = new ProxyInfo();
-        proxyInfo.setHost( repository.getProxy().getHost() );
-        proxyInfo.setType( repository.getProxy().getProtocol() );
-        proxyInfo.setPort( repository.getProxy().getPort() );
-        proxyInfo.setNonProxyHosts( repository.getProxy().getNonProxyHosts() );
-        proxyInfo.setUserName( repository.getProxy().getUserName() );
-        proxyInfo.setPassword( repository.getProxy().getPassword() );
+        proxyInfo.setHost(repository.getProxy().getHost());
+        proxyInfo.setType(repository.getProxy().getProtocol());
+        proxyInfo.setPort(repository.getProxy().getPort());
+        proxyInfo.setNonProxyHosts(repository.getProxy().getNonProxyHosts());
+        proxyInfo.setUserName(repository.getProxy().getUserName());
+        proxyInfo.setPassword(repository.getProxy().getPassword());
         return proxyInfo;
     }
 
-    @SuppressWarnings( "checkstyle:methodlength" )
+    @SuppressWarnings("checkstyle:methodlength")
     @Override
-    public void getRemoteFile( ArtifactRepository repository, File destination, String remotePath,
-                               TransferListener downloadMonitor, String checksumPolicy, boolean force )
-        throws TransferFailedException, ResourceDoesNotExistException
-    {
+    public void getRemoteFile(
+            ArtifactRepository repository,
+            File destination,
+            String remotePath,
+            TransferListener downloadMonitor,
+            String checksumPolicy,
+            boolean force)
+            throws TransferFailedException, ResourceDoesNotExistException {
         String protocol = repository.getProtocol();
 
         Wagon wagon;
 
-        try
-        {
-            wagon = getWagon( protocol );
-        }
-        catch ( UnsupportedProtocolException e )
-        {
-            throw new TransferFailedException( "Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e );
+        try {
+            wagon = getWagon(protocol);
+        } catch (UnsupportedProtocolException e) {
+            throw new TransferFailedException("Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e);
         }
 
-        if ( downloadMonitor != null )
-        {
-            wagon.addTransferListener( downloadMonitor );
+        if (downloadMonitor != null) {
+            wagon.addTransferListener(downloadMonitor);
         }
 
-        File temp = new File( destination + ".tmp" );
+        File temp = new File(destination + ".tmp");
 
         temp.deleteOnExit();
 
         boolean downloaded = false;
 
-        try
-        {
-            connectWagon( wagon, repository );
+        try {
+            connectWagon(wagon, repository);
 
             boolean firstRun = true;
             boolean retry = true;
@@ -377,155 +338,116 @@
             // this will run at most twice. The first time, the firstRun flag is turned off, and if the retry flag
             // is set on the first run, it will be turned off and not re-set on the second try. This is because the
             // only way the retry flag can be set is if ( firstRun == true ).
-            while ( firstRun || retry )
-            {
+            while (firstRun || retry) {
                 ChecksumObserver md5ChecksumObserver = null;
                 ChecksumObserver sha1ChecksumObserver = null;
-                try
-                {
+                try {
                     // TODO configure on repository
                     int i = 0;
 
-                    md5ChecksumObserver = addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i++] );
-                    sha1ChecksumObserver = addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i++] );
+                    md5ChecksumObserver = addChecksumObserver(wagon, CHECKSUM_ALGORITHMS[i++]);
+                    sha1ChecksumObserver = addChecksumObserver(wagon, CHECKSUM_ALGORITHMS[i++]);
 
                     // reset the retry flag.
                     retry = false;
 
                     // This should take care of creating destination directory now on
-                    if ( destination.exists() && !force )
-                    {
-                        try
-                        {
-                            downloaded = wagon.getIfNewer( remotePath, temp, destination.lastModified() );
+                    if (destination.exists() && !force) {
+                        try {
+                            downloaded = wagon.getIfNewer(remotePath, temp, destination.lastModified());
 
-                            if ( !downloaded )
-                            {
+                            if (!downloaded) {
                                 // prevent additional checks of this artifact until it expires again
-                                destination.setLastModified( System.currentTimeMillis() );
+                                destination.setLastModified(System.currentTimeMillis());
                             }
-                        }
-                        catch ( UnsupportedOperationException e )
-                        {
+                        } catch (UnsupportedOperationException e) {
                             // older wagons throw this. Just get() instead
-                            wagon.get( remotePath, temp );
+                            wagon.get(remotePath, temp);
 
                             downloaded = true;
                         }
-                    }
-                    else
-                    {
-                        wagon.get( remotePath, temp );
+                    } else {
+                        wagon.get(remotePath, temp);
                         downloaded = true;
                     }
-                }
-                finally
-                {
-                    wagon.removeTransferListener( md5ChecksumObserver );
-                    wagon.removeTransferListener( sha1ChecksumObserver );
+                } finally {
+                    wagon.removeTransferListener(md5ChecksumObserver);
+                    wagon.removeTransferListener(sha1ChecksumObserver);
                 }
 
-                if ( downloaded )
-                {
+                if (downloaded) {
                     // keep the checksum files from showing up on the download monitor...
-                    if ( downloadMonitor != null )
-                    {
-                        wagon.removeTransferListener( downloadMonitor );
+                    if (downloadMonitor != null) {
+                        wagon.removeTransferListener(downloadMonitor);
                     }
 
                     // try to verify the SHA-1 checksum for this file.
-                    try
-                    {
-                        verifyChecksum( sha1ChecksumObserver, destination, temp, remotePath, ".sha1", wagon );
-                    }
-                    catch ( ChecksumFailedException e )
-                    {
+                    try {
+                        verifyChecksum(sha1ChecksumObserver, destination, temp, remotePath, ".sha1", wagon);
+                    } catch (ChecksumFailedException e) {
                         // if we catch a ChecksumFailedException, it means the transfer/read succeeded, but the
                         // checksum doesn't match. This could be a problem with the server (ibiblio HTTP-200 error
                         // page), so we'll try this up to two times. On the second try, we'll handle it as a bona-fide
                         // error, based on the repository's checksum checking policy.
-                        if ( firstRun )
-                        {
-                            logger.warn( "*** CHECKSUM FAILED - " + e.getMessage() + " - RETRYING" );
+                        if (firstRun) {
+                            logger.warn("*** CHECKSUM FAILED - " + e.getMessage() + " - RETRYING");
                             retry = true;
+                        } else {
+                            handleChecksumFailure(checksumPolicy, e.getMessage(), e.getCause());
                         }
-                        else
-                        {
-                            handleChecksumFailure( checksumPolicy, e.getMessage(), e.getCause() );
-                        }
-                    }
-                    catch ( ResourceDoesNotExistException sha1TryException )
-                    {
-                        logger.debug( "SHA1 not found, trying MD5: " + sha1TryException.getMessage() );
+                    } catch (ResourceDoesNotExistException sha1TryException) {
+                        logger.debug("SHA1 not found, trying MD5: " + sha1TryException.getMessage());
 
                         // if this IS NOT a ChecksumFailedException, it was a problem with transfer/read of the checksum
                         // file...we'll try again with the MD5 checksum.
-                        try
-                        {
-                            verifyChecksum( md5ChecksumObserver, destination, temp, remotePath, ".md5", wagon );
-                        }
-                        catch ( ChecksumFailedException e )
-                        {
+                        try {
+                            verifyChecksum(md5ChecksumObserver, destination, temp, remotePath, ".md5", wagon);
+                        } catch (ChecksumFailedException e) {
                             // if we also fail to verify based on the MD5 checksum, and the checksum transfer/read
                             // succeeded, then we need to determine whether to retry or handle it as a failure.
-                            if ( firstRun )
-                            {
+                            if (firstRun) {
                                 retry = true;
+                            } else {
+                                handleChecksumFailure(checksumPolicy, e.getMessage(), e.getCause());
                             }
-                            else
-                            {
-                                handleChecksumFailure( checksumPolicy, e.getMessage(), e.getCause() );
-                            }
-                        }
-                        catch ( ResourceDoesNotExistException md5TryException )
-                        {
+                        } catch (ResourceDoesNotExistException md5TryException) {
                             // this was a failed transfer, and we don't want to retry.
-                            handleChecksumFailure( checksumPolicy, "Error retrieving checksum file for " + remotePath,
-                                                   md5TryException );
+                            handleChecksumFailure(
+                                    checksumPolicy,
+                                    "Error retrieving checksum file for " + remotePath,
+                                    md5TryException);
                         }
                     }
 
                     // reinstate the download monitor...
-                    if ( downloadMonitor != null )
-                    {
-                        wagon.addTransferListener( downloadMonitor );
+                    if (downloadMonitor != null) {
+                        wagon.addTransferListener(downloadMonitor);
                     }
                 }
 
                 // unset the firstRun flag, so we don't get caught in an infinite loop...
                 firstRun = false;
             }
-        }
-        catch ( ConnectionException e )
-        {
-            throw new TransferFailedException( "Connection failed: " + e.getMessage(), e );
-        }
-        catch ( AuthenticationException e )
-        {
-            throw new TransferFailedException( "Authentication failed: " + e.getMessage(), e );
-        }
-        catch ( AuthorizationException e )
-        {
-            throw new TransferFailedException( "Authorization failed: " + e.getMessage(), e );
-        }
-        finally
-        {
+        } catch (ConnectionException e) {
+            throw new TransferFailedException("Connection failed: " + e.getMessage(), e);
+        } catch (AuthenticationException e) {
+            throw new TransferFailedException("Authentication failed: " + e.getMessage(), e);
+        } catch (AuthorizationException e) {
+            throw new TransferFailedException("Authorization failed: " + e.getMessage(), e);
+        } finally {
             // Remove remaining TransferListener instances (checksum handlers removed in above finally clause)
-            if ( downloadMonitor != null )
-            {
-                wagon.removeTransferListener( downloadMonitor );
+            if (downloadMonitor != null) {
+                wagon.removeTransferListener(downloadMonitor);
             }
 
-            disconnectWagon( wagon );
+            disconnectWagon(wagon);
 
-            releaseWagon( protocol, wagon );
+            releaseWagon(protocol, wagon);
         }
 
-        if ( downloaded )
-        {
-            if ( !temp.exists() )
-            {
-                throw new ResourceDoesNotExistException( "Downloaded file does not exist: " + temp );
+        if (downloaded) {
+            if (!temp.exists()) {
+                throw new ResourceDoesNotExistException("Downloaded file does not exist: " + temp);
             }
 
             // The temporary file is named destination + ".tmp" and is done this way to ensure
@@ -533,22 +455,20 @@
             // File.renameTo operation doesn't really work across file systems.
             // So we will attempt to do a File.renameTo for efficiency and atomicity, if this fails
             // then we will use a brute force copy and delete the temporary file.
-            if ( !temp.renameTo( destination ) )
-            {
-                try
-                {
-                    FileUtils.copyFile( temp, destination );
+            if (!temp.renameTo(destination)) {
+                try {
+                    Files.copy(
+                            temp.toPath(),
+                            destination.toPath(),
+                            StandardCopyOption.REPLACE_EXISTING,
+                            StandardCopyOption.COPY_ATTRIBUTES);
 
-                    if ( !temp.delete() )
-                    {
+                    if (!temp.delete()) {
                         temp.deleteOnExit();
                     }
-                }
-                catch ( IOException e )
-                {
-                    throw new TransferFailedException( "Error copying temporary file to the final destination: "
-                                                           + e.getMessage(), e );
-
+                } catch (IOException e) {
+                    throw new TransferFailedException(
+                            "Error copying temporary file to the final destination: " + e.getMessage(), e);
                 }
             }
         }
@@ -558,294 +478,232 @@
     // Publisher
     //
     @Override
-    public void putArtifact( File source, Artifact artifact, ArtifactRepository deploymentRepository,
-                             TransferListener downloadMonitor )
-        throws TransferFailedException
-    {
-        putRemoteFile( deploymentRepository, source, deploymentRepository.pathOf( artifact ), downloadMonitor );
+    public void putArtifact(
+            File source, Artifact artifact, ArtifactRepository deploymentRepository, TransferListener downloadMonitor)
+            throws TransferFailedException {
+        putRemoteFile(deploymentRepository, source, deploymentRepository.pathOf(artifact), downloadMonitor);
     }
 
     @Override
-    public void putArtifactMetadata( File source, ArtifactMetadata artifactMetadata, ArtifactRepository repository )
-        throws TransferFailedException
-    {
-        logger.info( "Uploading " + artifactMetadata );
-        putRemoteFile( repository, source, repository.pathOfRemoteRepositoryMetadata( artifactMetadata ), null );
+    public void putArtifactMetadata(File source, ArtifactMetadata artifactMetadata, ArtifactRepository repository)
+            throws TransferFailedException {
+        logger.info("Uploading " + artifactMetadata);
+        putRemoteFile(repository, source, repository.pathOfRemoteRepositoryMetadata(artifactMetadata), null);
     }
 
     @Override
-    public void putRemoteFile( ArtifactRepository repository, File source, String remotePath,
-                               TransferListener downloadMonitor )
-        throws TransferFailedException
-    {
+    public void putRemoteFile(
+            ArtifactRepository repository, File source, String remotePath, TransferListener downloadMonitor)
+            throws TransferFailedException {
         String protocol = repository.getProtocol();
 
         Wagon wagon;
-        try
-        {
-            wagon = getWagon( protocol );
-        }
-        catch ( UnsupportedProtocolException e )
-        {
-            throw new TransferFailedException( "Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e );
+        try {
+            wagon = getWagon(protocol);
+        } catch (UnsupportedProtocolException e) {
+            throw new TransferFailedException("Unsupported Protocol: '" + protocol + "': " + e.getMessage(), e);
         }
 
-        if ( downloadMonitor != null )
-        {
-            wagon.addTransferListener( downloadMonitor );
+        if (downloadMonitor != null) {
+            wagon.addTransferListener(downloadMonitor);
         }
 
-        Map<String, ChecksumObserver> checksums = new HashMap<>( 2 );
+        Map<String, ChecksumObserver> checksums = new HashMap<>(2);
 
-        Map<String, String> sums = new HashMap<>( 2 );
+        Map<String, String> sums = new HashMap<>(2);
 
         // TODO configure these on the repository
-        for ( int i = 0; i < CHECKSUM_IDS.length; i++ )
-        {
-            checksums.put( CHECKSUM_IDS[i], addChecksumObserver( wagon, CHECKSUM_ALGORITHMS[i] ) );
+        for (int i = 0; i < CHECKSUM_IDS.length; i++) {
+            checksums.put(CHECKSUM_IDS[i], addChecksumObserver(wagon, CHECKSUM_ALGORITHMS[i]));
         }
 
         List<File> temporaryFiles = new ArrayList<>();
 
-        try
-        {
-            try
-            {
-                connectWagon( wagon, repository );
+        try {
+            try {
+                connectWagon(wagon, repository);
 
-                wagon.put( source, remotePath );
-            }
-            finally
-            {
-                if ( downloadMonitor != null )
-                {
-                    wagon.removeTransferListener( downloadMonitor );
+                wagon.put(source, remotePath);
+            } finally {
+                if (downloadMonitor != null) {
+                    wagon.removeTransferListener(downloadMonitor);
                 }
             }
 
             // Pre-store the checksums as any future puts will overwrite them
-            for ( String extension : checksums.keySet() )
-            {
-                ChecksumObserver observer = checksums.get( extension );
-                sums.put( extension, observer.getActualChecksum() );
+            for (String extension : checksums.keySet()) {
+                ChecksumObserver observer = checksums.get(extension);
+                sums.put(extension, observer.getActualChecksum());
             }
 
             // We do this in here so we can checksum the artifact metadata too, otherwise it could be metadata itself
-            for ( String extension : checksums.keySet() )
-            {
+            for (String extension : checksums.keySet()) {
                 // TODO shouldn't need a file intermediary - improve wagon to take a stream
-                File temp = File.createTempFile( "maven-artifact", null );
+                File temp = File.createTempFile("maven-artifact", null);
                 temp.deleteOnExit();
-                FileUtils.fileWrite( temp.getAbsolutePath(), "UTF-8", sums.get( extension ) );
+                byte[] bytes = sums.get(extension).getBytes(StandardCharsets.UTF_8);
+                Files.write(
+                        Paths.get(temp.getAbsolutePath()), bytes, StandardOpenOption.APPEND, StandardOpenOption.CREATE);
 
-                temporaryFiles.add( temp );
-                wagon.put( temp, remotePath + "." + extension );
+                temporaryFiles.add(temp);
+                wagon.put(temp, remotePath + "." + extension);
             }
-        }
-        catch ( ConnectionException e )
-        {
-            throw new TransferFailedException( "Connection failed: " + e.getMessage(), e );
-        }
-        catch ( AuthenticationException e )
-        {
-            throw new TransferFailedException( "Authentication failed: " + e.getMessage(), e );
-        }
-        catch ( AuthorizationException e )
-        {
-            throw new TransferFailedException( "Authorization failed: " + e.getMessage(), e );
-        }
-        catch ( ResourceDoesNotExistException e )
-        {
-            throw new TransferFailedException( "Resource to deploy not found: " + e.getMessage(), e );
-        }
-        catch ( IOException e )
-        {
-            throw new TransferFailedException( "Error creating temporary file for deployment: " + e.getMessage(), e );
-        }
-        finally
-        {
+        } catch (ConnectionException e) {
+            throw new TransferFailedException("Connection failed: " + e.getMessage(), e);
+        } catch (AuthenticationException e) {
+            throw new TransferFailedException("Authentication failed: " + e.getMessage(), e);
+        } catch (AuthorizationException e) {
+            throw new TransferFailedException("Authorization failed: " + e.getMessage(), e);
+        } catch (ResourceDoesNotExistException e) {
+            throw new TransferFailedException("Resource to deploy not found: " + e.getMessage(), e);
+        } catch (IOException e) {
+            throw new TransferFailedException("Error creating temporary file for deployment: " + e.getMessage(), e);
+        } finally {
             // MNG-4543
-            cleanupTemporaryFiles( temporaryFiles );
+            cleanupTemporaryFiles(temporaryFiles);
 
             // Remove every checksum listener
-            for ( String id : CHECKSUM_IDS )
-            {
-                TransferListener checksumListener = checksums.get( id );
-                if ( checksumListener != null )
-                {
-                    wagon.removeTransferListener( checksumListener );
+            for (String id : CHECKSUM_IDS) {
+                TransferListener checksumListener = checksums.get(id);
+                if (checksumListener != null) {
+                    wagon.removeTransferListener(checksumListener);
                 }
             }
 
-            disconnectWagon( wagon );
+            disconnectWagon(wagon);
 
-            releaseWagon( protocol, wagon );
+            releaseWagon(protocol, wagon);
         }
     }
 
-    private void cleanupTemporaryFiles( List<File> files )
-    {
-        for ( File file : files )
-        {
+    private void cleanupTemporaryFiles(List<File> files) {
+        for (File file : files) {
             // really don't care if it failed here only log warning
-            if ( !file.delete() )
-            {
-                logger.warn( "skip failed to delete temporary file : " + file.getAbsolutePath() );
+            if (!file.delete()) {
+                logger.warn("skip failed to delete temporary file : " + file.getAbsolutePath());
                 file.deleteOnExit();
             }
         }
-
     }
 
-    private ChecksumObserver addChecksumObserver( Wagon wagon, String algorithm )
-        throws TransferFailedException
-    {
-        try
-        {
-            ChecksumObserver checksumObserver = new ChecksumObserver( algorithm );
-            wagon.addTransferListener( checksumObserver );
+    private ChecksumObserver addChecksumObserver(Wagon wagon, String algorithm) throws TransferFailedException {
+        try {
+            ChecksumObserver checksumObserver = new ChecksumObserver(algorithm);
+            wagon.addTransferListener(checksumObserver);
             return checksumObserver;
-        }
-        catch ( NoSuchAlgorithmException e )
-        {
-            throw new TransferFailedException( "Unable to add checksum for unsupported algorithm " + algorithm, e );
+        } catch (NoSuchAlgorithmException e) {
+            throw new TransferFailedException("Unable to add checksum for unsupported algorithm " + algorithm, e);
         }
     }
 
-    private void handleChecksumFailure( String checksumPolicy, String message, Throwable cause )
-        throws ChecksumFailedException
-    {
-        if ( ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL.equals( checksumPolicy ) )
-        {
-            throw new ChecksumFailedException( message, cause );
-        }
-        else if ( !ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals( checksumPolicy ) )
-        {
+    private void handleChecksumFailure(String checksumPolicy, String message, Throwable cause)
+            throws ChecksumFailedException {
+        if (ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL.equals(checksumPolicy)) {
+            throw new ChecksumFailedException(message, cause);
+        } else if (!ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE.equals(checksumPolicy)) {
             // warn if it is set to anything other than ignore
-            logger.warn( "*** CHECKSUM FAILED - " + message + " - IGNORING" );
+            logger.warn("*** CHECKSUM FAILED - " + message + " - IGNORING");
         }
         // otherwise it is ignore
     }
 
-    private void verifyChecksum( ChecksumObserver checksumObserver, File destination, File tempDestination,
-                                 String remotePath, String checksumFileExtension, Wagon wagon )
-        throws ResourceDoesNotExistException, TransferFailedException, AuthorizationException
-    {
-        try
-        {
+    private void verifyChecksum(
+            ChecksumObserver checksumObserver,
+            File destination,
+            File tempDestination,
+            String remotePath,
+            String checksumFileExtension,
+            Wagon wagon)
+            throws ResourceDoesNotExistException, TransferFailedException, AuthorizationException {
+        try {
             // grab it first, because it's about to change...
             String actualChecksum = checksumObserver.getActualChecksum();
 
-            File tempChecksumFile = new File( tempDestination + checksumFileExtension + ".tmp" );
+            File tempChecksumFile = new File(tempDestination + checksumFileExtension + ".tmp");
             tempChecksumFile.deleteOnExit();
-            wagon.get( remotePath + checksumFileExtension, tempChecksumFile );
-
-            String expectedChecksum = FileUtils.fileRead( tempChecksumFile, "UTF-8" );
+            wagon.get(remotePath + checksumFileExtension, tempChecksumFile);
+            byte[] bytes = Files.readAllBytes(tempChecksumFile.toPath());
+            String expectedChecksum = new String(bytes, StandardCharsets.UTF_8);
 
             // remove whitespaces at the end
             expectedChecksum = expectedChecksum.trim();
 
             // check for 'ALGO (name) = CHECKSUM' like used by openssl
-            if ( expectedChecksum.regionMatches( true, 0, "MD", 0, 2 )
-                     || expectedChecksum.regionMatches( true, 0, "SHA", 0, 3 ) )
-            {
-                int lastSpacePos = expectedChecksum.lastIndexOf( ' ' );
-                expectedChecksum = expectedChecksum.substring( lastSpacePos + 1 );
-            }
-            else
-            {
+            if (expectedChecksum.regionMatches(true, 0, "MD", 0, 2)
+                    || expectedChecksum.regionMatches(true, 0, "SHA", 0, 3)) {
+                int lastSpacePos = expectedChecksum.lastIndexOf(' ');
+                expectedChecksum = expectedChecksum.substring(lastSpacePos + 1);
+            } else {
                 // remove everything after the first space (if available)
-                int spacePos = expectedChecksum.indexOf( ' ' );
+                int spacePos = expectedChecksum.indexOf(' ');
 
-                if ( spacePos != -1 )
-                {
-                    expectedChecksum = expectedChecksum.substring( 0, spacePos );
+                if (spacePos != -1) {
+                    expectedChecksum = expectedChecksum.substring(0, spacePos);
                 }
             }
-            if ( expectedChecksum.equalsIgnoreCase( actualChecksum ) )
-            {
-                File checksumFile = new File( destination + checksumFileExtension );
-                if ( checksumFile.exists() )
-                {
+            if (expectedChecksum.equalsIgnoreCase(actualChecksum)) {
+                File checksumFile = new File(destination + checksumFileExtension);
+                if (checksumFile.exists()) {
                     checksumFile.delete(); // ignore if failed as we will overwrite
                 }
-                FileUtils.copyFile( tempChecksumFile, checksumFile );
-                if ( !tempChecksumFile.delete() )
-                {
+                Files.copy(
+                        tempChecksumFile.toPath(),
+                        checksumFile.toPath(),
+                        StandardCopyOption.REPLACE_EXISTING,
+                        StandardCopyOption.COPY_ATTRIBUTES);
+
+                if (!tempChecksumFile.delete()) {
                     tempChecksumFile.deleteOnExit();
                 }
+            } else {
+                throw new ChecksumFailedException("Checksum failed on download: local = '" + actualChecksum
+                        + "'; remote = '" + expectedChecksum + "'");
             }
-            else
-            {
-                throw new ChecksumFailedException( "Checksum failed on download: local = '" + actualChecksum
-                                                       + "'; remote = '" + expectedChecksum + "'" );
-
-            }
-        }
-        catch ( IOException e )
-        {
-            throw new ChecksumFailedException( "Invalid checksum file", e );
+        } catch (IOException e) {
+            throw new ChecksumFailedException("Invalid checksum file", e);
         }
     }
 
-    private void disconnectWagon( Wagon wagon )
-    {
-        try
-        {
+    private void disconnectWagon(Wagon wagon) {
+        try {
             wagon.disconnect();
-        }
-        catch ( ConnectionException e )
-        {
-            logger.error( "Problem disconnecting from wagon - ignoring: " + e.getMessage() );
+        } catch (ConnectionException e) {
+            logger.error("Problem disconnecting from wagon - ignoring: " + e.getMessage());
         }
     }
 
-    private void releaseWagon( String protocol, Wagon wagon )
-    {
-        try
-        {
-            container.release( wagon );
-        }
-        catch ( ComponentLifecycleException e )
-        {
-            logger.error( "Problem releasing wagon - ignoring: " + e.getMessage() );
-            logger.debug( "", e );
+    private void releaseWagon(String protocol, Wagon wagon) {
+        try {
+            container.release(wagon);
+        } catch (ComponentLifecycleException e) {
+            logger.error("Problem releasing wagon - ignoring: " + e.getMessage());
+            logger.debug("", e);
         }
     }
 
     @Override
     @Deprecated
-    public Wagon getWagon( Repository repository )
-        throws UnsupportedProtocolException
-    {
-        return getWagon( repository.getProtocol() );
+    public Wagon getWagon(Repository repository) throws UnsupportedProtocolException {
+        return getWagon(repository.getProtocol());
     }
 
     @Override
     @Deprecated
-    public Wagon getWagon( String protocol )
-        throws UnsupportedProtocolException
-    {
-        if ( protocol == null )
-        {
-            throw new UnsupportedProtocolException( "Unspecified protocol" );
+    public Wagon getWagon(String protocol) throws UnsupportedProtocolException {
+        if (protocol == null) {
+            throw new UnsupportedProtocolException("Unspecified protocol");
         }
 
-        String hint = protocol.toLowerCase( java.util.Locale.ENGLISH );
+        String hint = protocol.toLowerCase(java.util.Locale.ENGLISH);
 
         Wagon wagon;
-        try
-        {
-            wagon = container.lookup( Wagon.class, hint );
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new UnsupportedProtocolException( "Cannot find wagon which supports the requested protocol: "
-                                                        + protocol, e );
-
+        try {
+            wagon = container.lookup(Wagon.class, hint);
+        } catch (ComponentLookupException e) {
+            throw new UnsupportedProtocolException(
+                    "Cannot find wagon which supports the requested protocol: " + protocol, e);
         }
 
         return wagon;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java
index a89ea37..fac3efb 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/LegacyRepositorySystem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.io.IOException;
@@ -35,7 +38,6 @@
 import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
 import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.repository.legacy.repository.ArtifactRepositoryFactory;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.artifact.repository.Authentication;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
@@ -50,14 +52,15 @@
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.Repository;
 import org.apache.maven.model.RepositoryPolicy;
+import org.apache.maven.repository.ArtifactDoesNotExistException;
+import org.apache.maven.repository.ArtifactTransferFailedException;
+import org.apache.maven.repository.ArtifactTransferListener;
 import org.apache.maven.repository.DelegatingLocalArtifactRepository;
 import org.apache.maven.repository.LocalArtifactRepository;
-import org.apache.maven.repository.ArtifactTransferListener;
 import org.apache.maven.repository.MirrorSelector;
 import org.apache.maven.repository.Proxy;
 import org.apache.maven.repository.RepositorySystem;
-import org.apache.maven.repository.ArtifactDoesNotExistException;
-import org.apache.maven.repository.ArtifactTransferFailedException;
+import org.apache.maven.repository.legacy.repository.ArtifactRepositoryFactory;
 import org.apache.maven.settings.Mirror;
 import org.apache.maven.settings.Server;
 import org.apache.maven.settings.building.SettingsProblem;
@@ -68,11 +71,8 @@
 import org.apache.maven.wagon.proxy.ProxyInfo;
 import org.apache.maven.wagon.proxy.ProxyUtils;
 import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.logging.Logger;
-import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.repository.AuthenticationContext;
 import org.eclipse.aether.repository.AuthenticationSelector;
@@ -80,220 +80,201 @@
 import org.eclipse.aether.repository.RemoteRepository;
 
 /**
- * @author Jason van Zyl
  */
-@Component( role = RepositorySystem.class, hint = "default" )
-public class LegacyRepositorySystem
-    implements RepositorySystem
-{
+@Named("default")
+@Singleton
+@Deprecated
+public class LegacyRepositorySystem implements RepositorySystem {
 
-    @Requirement
+    @Inject
     private Logger logger;
 
-    @Requirement
+    @Inject
     private ArtifactFactory artifactFactory;
 
-    @Requirement
+    @Inject
     private ArtifactResolver artifactResolver;
 
-    @Requirement
+    @Inject
     private ArtifactRepositoryFactory artifactRepositoryFactory;
 
-    @Requirement( role = ArtifactRepositoryLayout.class )
+    @Inject
     private Map<String, ArtifactRepositoryLayout> layouts;
 
-    @Requirement
+    @Inject
     private WagonManager wagonManager;
 
-    @Requirement
+    @Inject
     private PlexusContainer plexus;
 
-    @Requirement
+    @Inject
     private MirrorSelector mirrorSelector;
 
-    @Requirement
+    @Inject
     private SettingsDecrypter settingsDecrypter;
 
-    public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type )
-    {
-        return artifactFactory.createArtifact( groupId, artifactId, version, scope, type );
+    public Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type) {
+        return artifactFactory.createArtifact(groupId, artifactId, version, scope, type);
     }
 
-    public Artifact createArtifact( String groupId, String artifactId, String version, String packaging )
-    {
-        return artifactFactory.createBuildArtifact( groupId, artifactId, version, packaging );
+    public Artifact createArtifact(String groupId, String artifactId, String version, String packaging) {
+        return artifactFactory.createBuildArtifact(groupId, artifactId, version, packaging);
     }
 
-    public Artifact createArtifactWithClassifier( String groupId, String artifactId, String version, String type,
-                                                  String classifier )
-    {
-        return artifactFactory.createArtifactWithClassifier( groupId, artifactId, version, type, classifier );
+    public Artifact createArtifactWithClassifier(
+            String groupId, String artifactId, String version, String type, String classifier) {
+        return artifactFactory.createArtifactWithClassifier(groupId, artifactId, version, type, classifier);
     }
 
-    public Artifact createProjectArtifact( String groupId, String artifactId, String metaVersionId )
-    {
-        return artifactFactory.createProjectArtifact( groupId, artifactId, metaVersionId );
+    public Artifact createProjectArtifact(String groupId, String artifactId, String metaVersionId) {
+        return artifactFactory.createProjectArtifact(groupId, artifactId, metaVersionId);
     }
 
-    public Artifact createDependencyArtifact( Dependency d )
-    {
+    public Artifact createDependencyArtifact(Dependency d) {
         VersionRange versionRange;
-        try
-        {
-            versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
+        try {
+            versionRange = VersionRange.createFromVersionSpec(d.getVersion());
+        } catch (InvalidVersionSpecificationException e) {
             // MNG-5368: Log a message instead of returning 'null' silently.
-            this.logger.error( String.format( "Invalid version specification '%s' creating dependency artifact '%s'.",
-                                              d.getVersion(), d ), e );
+            this.logger.error(
+                    String.format(
+                            "Invalid version specification '%s' creating dependency artifact '%s'.", d.getVersion(), d),
+                    e);
             return null;
         }
 
-        Artifact artifact =
-            artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(),
-                                                      d.getClassifier(), d.getScope(), d.isOptional() );
+        Artifact artifact = artifactFactory.createDependencyArtifact(
+                d.getGroupId(),
+                d.getArtifactId(),
+                versionRange,
+                d.getType(),
+                d.getClassifier(),
+                d.getScope(),
+                d.isOptional());
 
-        if ( Artifact.SCOPE_SYSTEM.equals( d.getScope() ) && d.getSystemPath() != null )
-        {
-            artifact.setFile( new File( d.getSystemPath() ) );
+        if (Artifact.SCOPE_SYSTEM.equals(d.getScope()) && d.getSystemPath() != null) {
+            artifact.setFile(new File(d.getSystemPath()));
         }
 
-        if ( !d.getExclusions().isEmpty() )
-        {
+        if (!d.getExclusions().isEmpty()) {
             List<String> exclusions = new ArrayList<>();
 
-            for ( Exclusion exclusion : d.getExclusions() )
-            {
-                exclusions.add( exclusion.getGroupId() + ':' + exclusion.getArtifactId() );
+            for (Exclusion exclusion : d.getExclusions()) {
+                exclusions.add(exclusion.getGroupId() + ':' + exclusion.getArtifactId());
             }
 
-            artifact.setDependencyFilter( new ExcludesArtifactFilter( exclusions ) );
+            artifact.setDependencyFilter(new ExcludesArtifactFilter(exclusions));
         }
 
         return artifact;
     }
 
-    public Artifact createExtensionArtifact( String groupId, String artifactId, String version )
-    {
+    public Artifact createExtensionArtifact(String groupId, String artifactId, String version) {
         VersionRange versionRange;
-        try
-        {
-            versionRange = VersionRange.createFromVersionSpec( version );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
+        try {
+            versionRange = VersionRange.createFromVersionSpec(version);
+        } catch (InvalidVersionSpecificationException e) {
             // MNG-5368: Log a message instead of returning 'null' silently.
-            this.logger.error( String.format(
-                "Invalid version specification '%s' creating extension artifact '%s:%s:%s'.",
-                version, groupId, artifactId, version ), e );
+            this.logger.error(
+                    String.format(
+                            "Invalid version specification '%s' creating extension artifact '%s:%s:%s'.",
+                            version, groupId, artifactId, version),
+                    e);
 
             return null;
         }
 
-        return artifactFactory.createExtensionArtifact( groupId, artifactId, versionRange );
+        return artifactFactory.createExtensionArtifact(groupId, artifactId, versionRange);
     }
 
-    public Artifact createParentArtifact( String groupId, String artifactId, String version )
-    {
-        return artifactFactory.createParentArtifact( groupId, artifactId, version );
+    public Artifact createParentArtifact(String groupId, String artifactId, String version) {
+        return artifactFactory.createParentArtifact(groupId, artifactId, version);
     }
 
-    public Artifact createPluginArtifact( Plugin plugin )
-    {
+    public Artifact createPluginArtifact(Plugin plugin) {
         String version = plugin.getVersion();
-        if ( StringUtils.isEmpty( version ) )
-        {
+        if (version == null || version.isEmpty()) {
             version = "RELEASE";
         }
 
         VersionRange versionRange;
-        try
-        {
-            versionRange = VersionRange.createFromVersionSpec( version );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
+        try {
+            versionRange = VersionRange.createFromVersionSpec(version);
+        } catch (InvalidVersionSpecificationException e) {
             // MNG-5368: Log a message instead of returning 'null' silently.
-            this.logger.error( String.format(
-                "Invalid version specification '%s' creating plugin artifact '%s'.",
-                version, plugin ), e );
+            this.logger.error(
+                    String.format("Invalid version specification '%s' creating plugin artifact '%s'.", version, plugin),
+                    e);
 
             return null;
         }
 
-        return artifactFactory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), versionRange );
+        return artifactFactory.createPluginArtifact(plugin.getGroupId(), plugin.getArtifactId(), versionRange);
     }
 
-    public ArtifactRepositoryPolicy buildArtifactRepositoryPolicy( RepositoryPolicy policy )
-    {
+    public ArtifactRepositoryPolicy buildArtifactRepositoryPolicy(RepositoryPolicy policy) {
         boolean enabled = true;
 
         String updatePolicy = null;
 
         String checksumPolicy = null;
 
-        if ( policy != null )
-        {
+        if (policy != null) {
             enabled = policy.isEnabled();
 
-            if ( policy.getUpdatePolicy() != null )
-            {
+            if (policy.getUpdatePolicy() != null) {
                 updatePolicy = policy.getUpdatePolicy();
             }
-            if ( policy.getChecksumPolicy() != null )
-            {
+            if (policy.getChecksumPolicy() != null) {
                 checksumPolicy = policy.getChecksumPolicy();
             }
         }
 
-        return new ArtifactRepositoryPolicy( enabled, updatePolicy, checksumPolicy );
+        return new ArtifactRepositoryPolicy(enabled, updatePolicy, checksumPolicy);
     }
 
-    public ArtifactRepository createDefaultLocalRepository()
-        throws InvalidRepositoryException
-    {
-        return createLocalRepository( RepositorySystem.defaultUserLocalRepository );
+    public ArtifactRepository createDefaultLocalRepository() throws InvalidRepositoryException {
+        return createLocalRepository(RepositorySystem.defaultUserLocalRepository);
     }
 
-    public ArtifactRepository createLocalRepository( File localRepository )
-        throws InvalidRepositoryException
-    {
-        return createRepository( "file://" + localRepository.toURI().getRawPath(),
-                                 RepositorySystem.DEFAULT_LOCAL_REPO_ID, true,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, true,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
-                                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
+    public ArtifactRepository createLocalRepository(File localRepository) throws InvalidRepositoryException {
+        return createRepository(
+                "file://" + localRepository.toURI().getRawPath(),
+                RepositorySystem.DEFAULT_LOCAL_REPO_ID,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
     }
 
-    public ArtifactRepository createDefaultRemoteRepository()
-        throws InvalidRepositoryException
-    {
-        return createRepository( RepositorySystem.DEFAULT_REMOTE_REPO_URL, RepositorySystem.DEFAULT_REMOTE_REPO_ID,
-                                 true, ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY, false,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
-                                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN );
+    public ArtifactRepository createDefaultRemoteRepository() throws InvalidRepositoryException {
+        return createRepository(
+                RepositorySystem.DEFAULT_REMOTE_REPO_URL,
+                RepositorySystem.DEFAULT_REMOTE_REPO_ID,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
+                false,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
+                ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN);
     }
 
-    public ArtifactRepository createLocalRepository( String url, String repositoryId )
-        throws IOException
-    {
-        return createRepository( canonicalFileUrl( url ), repositoryId, true,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, true,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
-                                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
+    public ArtifactRepository createLocalRepository(String url, String repositoryId) throws IOException {
+        return createRepository(
+                canonicalFileUrl(url),
+                repositoryId,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
     }
 
-    private String canonicalFileUrl( String url )
-        throws IOException
-    {
-        if ( !url.startsWith( "file:" ) )
-        {
+    private String canonicalFileUrl(String url) throws IOException {
+        if (!url.startsWith("file:")) {
             url = "file://" + url;
-        }
-        else if ( url.startsWith( "file:" ) && !url.startsWith( "file://" ) )
-        {
-            url = "file://" + url.substring( "file:".length() );
+        } else if (url.startsWith("file:") && !url.startsWith("file://")) {
+            url = "file://" + url.substring("file:".length());
         }
 
         // So now we have an url of the form file://<path>
@@ -303,202 +284,166 @@
         // when you are using a custom settings.xml that contains a relative path entry
         // for the local repository setting.
 
-        File localRepository = new File( url.substring( "file://".length() ) );
+        File localRepository = new File(url.substring("file://".length()));
 
-        if ( !localRepository.isAbsolute() )
-        {
+        if (!localRepository.isAbsolute()) {
             url = "file://" + localRepository.getCanonicalPath();
         }
 
         return url;
     }
 
-    public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
-    {
+    public ArtifactResolutionResult resolve(ArtifactResolutionRequest request) {
         /*
          * Probably is not worth it, but here I make sure I restore request
          * to its original state.
          */
-        try
-        {
+        try {
             LocalArtifactRepository ideWorkspace =
-                plexus.lookup( LocalArtifactRepository.class, LocalArtifactRepository.IDE_WORKSPACE );
+                    plexus.lookup(LocalArtifactRepository.class, LocalArtifactRepository.IDE_WORKSPACE);
 
-            if ( request.getLocalRepository() instanceof DelegatingLocalArtifactRepository )
-            {
+            if (request.getLocalRepository() instanceof DelegatingLocalArtifactRepository) {
                 DelegatingLocalArtifactRepository delegatingLocalRepository =
-                    (DelegatingLocalArtifactRepository) request.getLocalRepository();
+                        (DelegatingLocalArtifactRepository) request.getLocalRepository();
 
                 LocalArtifactRepository orig = delegatingLocalRepository.getIdeWorkspace();
 
-                delegatingLocalRepository.setIdeWorkspace( ideWorkspace );
+                delegatingLocalRepository.setIdeWorkspace(ideWorkspace);
 
-                try
-                {
-                    return artifactResolver.resolve( request );
+                try {
+                    return artifactResolver.resolve(request);
+                } finally {
+                    delegatingLocalRepository.setIdeWorkspace(orig);
                 }
-                finally
-                {
-                    delegatingLocalRepository.setIdeWorkspace( orig );
-                }
-            }
-            else
-            {
+            } else {
                 ArtifactRepository localRepository = request.getLocalRepository();
                 DelegatingLocalArtifactRepository delegatingLocalRepository =
-                    new DelegatingLocalArtifactRepository( localRepository );
-                delegatingLocalRepository.setIdeWorkspace( ideWorkspace );
-                request.setLocalRepository( delegatingLocalRepository );
-                try
-                {
-                    return artifactResolver.resolve( request );
-                }
-                finally
-                {
-                    request.setLocalRepository( localRepository );
+                        new DelegatingLocalArtifactRepository(localRepository);
+                delegatingLocalRepository.setIdeWorkspace(ideWorkspace);
+                request.setLocalRepository(delegatingLocalRepository);
+                try {
+                    return artifactResolver.resolve(request);
+                } finally {
+                    request.setLocalRepository(localRepository);
                 }
             }
-        }
-        catch ( ComponentLookupException e )
-        {
+        } catch (ComponentLookupException e) {
             // no ide workspace artifact resolution
         }
 
-        return artifactResolver.resolve( request );
+        return artifactResolver.resolve(request);
     }
 
-//    public void addProxy( String protocol, String host, int port, String username, String password,
-//                          String nonProxyHosts )
-//    {
-//        ProxyInfo proxyInfo = new ProxyInfo();
-//        proxyInfo.setHost( host );
-//        proxyInfo.setType( protocol );
-//        proxyInfo.setPort( port );
-//        proxyInfo.setNonProxyHosts( nonProxyHosts );
-//        proxyInfo.setUserName( username );
-//        proxyInfo.setPassword( password );
-//
-//        proxies.put( protocol, proxyInfo );
-//
-//        wagonManager.addProxy( protocol, host, port, username, password, nonProxyHosts );
-//    }
+    //    public void addProxy( String protocol, String host, int port, String username, String password,
+    //                          String nonProxyHosts )
+    //    {
+    //        ProxyInfo proxyInfo = new ProxyInfo();
+    //        proxyInfo.setHost( host );
+    //        proxyInfo.setType( protocol );
+    //        proxyInfo.setPort( port );
+    //        proxyInfo.setNonProxyHosts( nonProxyHosts );
+    //        proxyInfo.setUserName( username );
+    //        proxyInfo.setPassword( password );
+    //
+    //        proxies.put( protocol, proxyInfo );
+    //
+    //        wagonManager.addProxy( protocol, host, port, username, password, nonProxyHosts );
+    //    }
 
-    public List<ArtifactRepository> getEffectiveRepositories( List<ArtifactRepository> repositories )
-    {
-        if ( repositories == null )
-        {
+    public List<ArtifactRepository> getEffectiveRepositories(List<ArtifactRepository> repositories) {
+        if (repositories == null) {
             return null;
         }
 
         Map<String, List<ArtifactRepository>> reposByKey = new LinkedHashMap<>();
 
-        for ( ArtifactRepository repository : repositories )
-        {
+        for (ArtifactRepository repository : repositories) {
             String key = repository.getId();
 
-            List<ArtifactRepository> aliasedRepos = reposByKey.computeIfAbsent( key, k -> new ArrayList<>() );
+            List<ArtifactRepository> aliasedRepos = reposByKey.computeIfAbsent(key, k -> new ArrayList<>());
 
-            aliasedRepos.add( repository );
+            aliasedRepos.add(repository);
         }
 
         List<ArtifactRepository> effectiveRepositories = new ArrayList<>();
 
-        for ( List<ArtifactRepository> aliasedRepos : reposByKey.values() )
-        {
+        for (List<ArtifactRepository> aliasedRepos : reposByKey.values()) {
             List<ArtifactRepository> mirroredRepos = new ArrayList<>();
 
-            List<ArtifactRepositoryPolicy> releasePolicies =
-                new ArrayList<>( aliasedRepos.size() );
+            List<ArtifactRepositoryPolicy> releasePolicies = new ArrayList<>(aliasedRepos.size());
 
-            for ( ArtifactRepository aliasedRepo : aliasedRepos )
-            {
-                releasePolicies.add( aliasedRepo.getReleases() );
-                mirroredRepos.addAll( aliasedRepo.getMirroredRepositories() );
+            for (ArtifactRepository aliasedRepo : aliasedRepos) {
+                releasePolicies.add(aliasedRepo.getReleases());
+                mirroredRepos.addAll(aliasedRepo.getMirroredRepositories());
             }
 
-            ArtifactRepositoryPolicy releasePolicy = getEffectivePolicy( releasePolicies );
+            ArtifactRepositoryPolicy releasePolicy = getEffectivePolicy(releasePolicies);
 
-            List<ArtifactRepositoryPolicy> snapshotPolicies =
-                new ArrayList<>( aliasedRepos.size() );
+            List<ArtifactRepositoryPolicy> snapshotPolicies = new ArrayList<>(aliasedRepos.size());
 
-            for ( ArtifactRepository aliasedRepo : aliasedRepos )
-            {
-                snapshotPolicies.add( aliasedRepo.getSnapshots() );
+            for (ArtifactRepository aliasedRepo : aliasedRepos) {
+                snapshotPolicies.add(aliasedRepo.getSnapshots());
             }
 
-            ArtifactRepositoryPolicy snapshotPolicy = getEffectivePolicy( snapshotPolicies );
+            ArtifactRepositoryPolicy snapshotPolicy = getEffectivePolicy(snapshotPolicies);
 
-            ArtifactRepository aliasedRepo = aliasedRepos.get( 0 );
+            ArtifactRepository aliasedRepo = aliasedRepos.get(0);
 
-            ArtifactRepository effectiveRepository =
-                createArtifactRepository( aliasedRepo.getId(), aliasedRepo.getUrl(), aliasedRepo.getLayout(),
-                                          snapshotPolicy, releasePolicy );
+            ArtifactRepository effectiveRepository = createArtifactRepository(
+                    aliasedRepo.getId(), aliasedRepo.getUrl(), aliasedRepo.getLayout(), snapshotPolicy, releasePolicy);
 
-            effectiveRepository.setAuthentication( aliasedRepo.getAuthentication() );
+            effectiveRepository.setAuthentication(aliasedRepo.getAuthentication());
 
-            effectiveRepository.setProxy( aliasedRepo.getProxy() );
+            effectiveRepository.setProxy(aliasedRepo.getProxy());
 
-            effectiveRepository.setMirroredRepositories( mirroredRepos );
+            effectiveRepository.setMirroredRepositories(mirroredRepos);
 
-            effectiveRepository.setBlocked( aliasedRepo.isBlocked() );
+            effectiveRepository.setBlocked(aliasedRepo.isBlocked());
 
-            effectiveRepositories.add( effectiveRepository );
+            effectiveRepositories.add(effectiveRepository);
         }
 
         return effectiveRepositories;
     }
 
-    private ArtifactRepositoryPolicy getEffectivePolicy( Collection<ArtifactRepositoryPolicy> policies )
-    {
+    private ArtifactRepositoryPolicy getEffectivePolicy(Collection<ArtifactRepositoryPolicy> policies) {
         ArtifactRepositoryPolicy effectivePolicy = null;
 
-        for ( ArtifactRepositoryPolicy policy : policies )
-        {
-            if ( effectivePolicy == null )
-            {
-                effectivePolicy = new ArtifactRepositoryPolicy( policy );
-            }
-            else
-            {
-                effectivePolicy.merge( policy );
+        for (ArtifactRepositoryPolicy policy : policies) {
+            if (effectivePolicy == null) {
+                effectivePolicy = new ArtifactRepositoryPolicy(policy);
+            } else {
+                effectivePolicy.merge(policy);
             }
         }
 
         return effectivePolicy;
     }
 
-    public Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
-    {
-        return mirrorSelector.getMirror( repository, mirrors );
+    public Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors) {
+        return mirrorSelector.getMirror(repository, mirrors);
     }
 
-    public void injectMirror( List<ArtifactRepository> repositories, List<Mirror> mirrors )
-    {
-        if ( repositories != null && mirrors != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                Mirror mirror = getMirror( repository, mirrors );
-                injectMirror( repository, mirror );
+    public void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
+        if (repositories != null && mirrors != null) {
+            for (ArtifactRepository repository : repositories) {
+                Mirror mirror = getMirror(repository, mirrors);
+                injectMirror(repository, mirror);
             }
         }
     }
 
-    private Mirror getMirror( RepositorySystemSession session, ArtifactRepository repository )
-    {
-        if ( session != null )
-        {
+    private Mirror getMirror(RepositorySystemSession session, ArtifactRepository repository) {
+        if (session != null) {
             org.eclipse.aether.repository.MirrorSelector selector = session.getMirrorSelector();
-            if ( selector != null )
-            {
-                RemoteRepository repo = selector.getMirror( RepositoryUtils.toRepo( repository ) );
-                if ( repo != null )
-                {
+            if (selector != null) {
+                RemoteRepository repo = selector.getMirror(RepositoryUtils.toRepo(repository));
+                if (repo != null) {
                     Mirror mirror = new Mirror();
-                    mirror.setId( repo.getId() );
-                    mirror.setUrl( repo.getUrl() );
-                    mirror.setLayout( repo.getContentType() );
-                    mirror.setBlocked( repo.isBlocked() );
+                    mirror.setId(repo.getId());
+                    mirror.setUrl(repo.getUrl());
+                    mirror.setLayout(repo.getContentType());
+                    mirror.setBlocked(repo.isBlocked());
                     return mirror;
                 }
             }
@@ -506,107 +451,90 @@
         return null;
     }
 
-    public void injectMirror( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-        if ( repositories != null && session != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                Mirror mirror = getMirror( session, repository );
-                injectMirror( repository, mirror );
+    public void injectMirror(RepositorySystemSession session, List<ArtifactRepository> repositories) {
+        if (repositories != null && session != null) {
+            for (ArtifactRepository repository : repositories) {
+                Mirror mirror = getMirror(session, repository);
+                injectMirror(repository, mirror);
             }
         }
     }
 
-    private void injectMirror( ArtifactRepository repository, Mirror mirror )
-    {
-        if ( mirror != null )
-        {
-            ArtifactRepository original =
-                createArtifactRepository( repository.getId(), repository.getUrl(), repository.getLayout(),
-                                          repository.getSnapshots(), repository.getReleases() );
+    private void injectMirror(ArtifactRepository repository, Mirror mirror) {
+        if (mirror != null) {
+            ArtifactRepository original = createArtifactRepository(
+                    repository.getId(),
+                    repository.getUrl(),
+                    repository.getLayout(),
+                    repository.getSnapshots(),
+                    repository.getReleases());
 
-            repository.setMirroredRepositories( Collections.singletonList( original ) );
+            repository.setMirroredRepositories(Collections.singletonList(original));
 
-            repository.setId( mirror.getId() );
-            repository.setUrl( mirror.getUrl() );
+            repository.setId(mirror.getId());
+            repository.setUrl(mirror.getUrl());
 
-            if ( StringUtils.isNotEmpty( mirror.getLayout() ) )
-            {
-                repository.setLayout( getLayout( mirror.getLayout() ) );
+            if (mirror.getLayout() != null && !mirror.getLayout().isEmpty()) {
+                repository.setLayout(getLayout(mirror.getLayout()));
             }
 
-            repository.setBlocked( mirror.isBlocked() );
+            repository.setBlocked(mirror.isBlocked());
         }
     }
 
-    public void injectAuthentication( List<ArtifactRepository> repositories, List<Server> servers )
-    {
-        if ( repositories != null )
-        {
+    public void injectAuthentication(List<ArtifactRepository> repositories, List<Server> servers) {
+        if (repositories != null) {
             Map<String, Server> serversById = new HashMap<>();
 
-            if ( servers != null )
-            {
-                for ( Server server : servers )
-                {
-                    if ( !serversById.containsKey( server.getId() ) )
-                    {
-                        serversById.put( server.getId(), server );
+            if (servers != null) {
+                for (Server server : servers) {
+                    if (!serversById.containsKey(server.getId())) {
+                        serversById.put(server.getId(), server);
                     }
                 }
             }
 
-            for ( ArtifactRepository repository : repositories )
-            {
-                Server server = serversById.get( repository.getId() );
+            for (ArtifactRepository repository : repositories) {
+                Server server = serversById.get(repository.getId());
 
-                if ( server != null )
-                {
-                    SettingsDecryptionRequest request = new DefaultSettingsDecryptionRequest( server );
-                    SettingsDecryptionResult result = settingsDecrypter.decrypt( request );
+                if (server != null) {
+                    SettingsDecryptionRequest request = new DefaultSettingsDecryptionRequest(server);
+                    SettingsDecryptionResult result = settingsDecrypter.decrypt(request);
                     server = result.getServer();
 
-                    if ( logger.isDebugEnabled() )
-                    {
-                        for ( SettingsProblem problem : result.getProblems() )
-                        {
-                            logger.debug( problem.getMessage(), problem.getException() );
+                    if (logger.isDebugEnabled()) {
+                        for (SettingsProblem problem : result.getProblems()) {
+                            logger.debug(problem.getMessage(), problem.getException());
                         }
                     }
 
-                    Authentication authentication = new Authentication( server.getUsername(), server.getPassword() );
-                    authentication.setPrivateKey( server.getPrivateKey() );
-                    authentication.setPassphrase( server.getPassphrase() );
+                    Authentication authentication = new Authentication(server.getUsername(), server.getPassword());
+                    authentication.setPrivateKey(server.getPrivateKey());
+                    authentication.setPassphrase(server.getPassphrase());
 
-                    repository.setAuthentication( authentication );
-                }
-                else
-                {
-                    repository.setAuthentication( null );
+                    repository.setAuthentication(authentication);
+                } else {
+                    repository.setAuthentication(null);
                 }
             }
         }
     }
 
-    private Authentication getAuthentication( RepositorySystemSession session, ArtifactRepository repository )
-    {
-        if ( session != null )
-        {
+    private Authentication getAuthentication(RepositorySystemSession session, ArtifactRepository repository) {
+        if (session != null) {
             AuthenticationSelector selector = session.getAuthenticationSelector();
-            if ( selector != null )
-            {
-                RemoteRepository repo = RepositoryUtils.toRepo( repository );
-                org.eclipse.aether.repository.Authentication auth = selector.getAuthentication( repo );
-                if ( auth != null )
-                {
-                    repo = new RemoteRepository.Builder( repo ).setAuthentication( auth ).build();
-                    AuthenticationContext authCtx = AuthenticationContext.forRepository( session, repo );
-                    Authentication result =
-                        new Authentication( authCtx.get( AuthenticationContext.USERNAME ),
-                                            authCtx.get( AuthenticationContext.PASSWORD ) );
-                    result.setPrivateKey( authCtx.get( AuthenticationContext.PRIVATE_KEY_PATH ) );
-                    result.setPassphrase( authCtx.get( AuthenticationContext.PRIVATE_KEY_PASSPHRASE ) );
+            if (selector != null) {
+                RemoteRepository repo = RepositoryUtils.toRepo(repository);
+                org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
+                if (auth != null) {
+                    repo = new RemoteRepository.Builder(repo)
+                            .setAuthentication(auth)
+                            .build();
+                    AuthenticationContext authCtx = AuthenticationContext.forRepository(session, repo);
+                    Authentication result = new Authentication(
+                            authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
+                    result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
+                    result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
                     authCtx.close();
                     return result;
                 }
@@ -615,41 +543,32 @@
         return null;
     }
 
-    public void injectAuthentication( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-        if ( repositories != null && session != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                repository.setAuthentication( getAuthentication( session, repository ) );
+    public void injectAuthentication(RepositorySystemSession session, List<ArtifactRepository> repositories) {
+        if (repositories != null && session != null) {
+            for (ArtifactRepository repository : repositories) {
+                repository.setAuthentication(getAuthentication(session, repository));
             }
         }
     }
 
-    private org.apache.maven.settings.Proxy getProxy( ArtifactRepository repository,
-                                                      List<org.apache.maven.settings.Proxy> proxies )
-    {
-        if ( proxies != null && repository.getProtocol() != null )
-        {
-            for ( org.apache.maven.settings.Proxy proxy : proxies )
-            {
-                if ( proxy.isActive() && repository.getProtocol().equalsIgnoreCase( proxy.getProtocol() ) )
-                {
-                    if ( StringUtils.isNotEmpty( proxy.getNonProxyHosts() ) )
-                    {
+    private org.apache.maven.settings.Proxy getProxy(
+            ArtifactRepository repository, List<org.apache.maven.settings.Proxy> proxies) {
+        if (proxies != null && repository.getProtocol() != null) {
+            for (org.apache.maven.settings.Proxy proxy : proxies) {
+                if (proxy.isActive() && repository.getProtocol().equalsIgnoreCase(proxy.getProtocol())) {
+                    if (proxy.getNonProxyHosts() != null
+                            && !proxy.getNonProxyHosts().isEmpty()) {
                         ProxyInfo pi = new ProxyInfo();
-                        pi.setNonProxyHosts( proxy.getNonProxyHosts() );
+                        pi.setNonProxyHosts(proxy.getNonProxyHosts());
 
                         org.apache.maven.wagon.repository.Repository repo =
-                            new org.apache.maven.wagon.repository.Repository( repository.getId(), repository.getUrl() );
+                                new org.apache.maven.wagon.repository.Repository(
+                                        repository.getId(), repository.getUrl());
 
-                        if ( !ProxyUtils.validateNonProxyHosts( pi, repo.getHost() ) )
-                        {
+                        if (!ProxyUtils.validateNonProxyHosts(pi, repo.getHost())) {
                             return proxy;
                         }
-                    }
-                    else
-                    {
+                    } else {
                         return proxy;
                     }
                 }
@@ -659,69 +578,58 @@
         return null;
     }
 
-    public void injectProxy( List<ArtifactRepository> repositories, List<org.apache.maven.settings.Proxy> proxies )
-    {
-        if ( repositories != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                org.apache.maven.settings.Proxy proxy = getProxy( repository, proxies );
+    public void injectProxy(List<ArtifactRepository> repositories, List<org.apache.maven.settings.Proxy> proxies) {
+        if (repositories != null) {
+            for (ArtifactRepository repository : repositories) {
+                org.apache.maven.settings.Proxy proxy = getProxy(repository, proxies);
 
-                if ( proxy != null )
-                {
-                    SettingsDecryptionRequest request = new DefaultSettingsDecryptionRequest( proxy );
-                    SettingsDecryptionResult result = settingsDecrypter.decrypt( request );
+                if (proxy != null) {
+                    SettingsDecryptionRequest request = new DefaultSettingsDecryptionRequest(proxy);
+                    SettingsDecryptionResult result = settingsDecrypter.decrypt(request);
                     proxy = result.getProxy();
 
-                    if ( logger.isDebugEnabled() )
-                    {
-                        for ( SettingsProblem problem : result.getProblems() )
-                        {
-                            logger.debug( problem.getMessage(), problem.getException() );
+                    if (logger.isDebugEnabled()) {
+                        for (SettingsProblem problem : result.getProblems()) {
+                            logger.debug(problem.getMessage(), problem.getException());
                         }
                     }
 
                     Proxy p = new Proxy();
-                    p.setHost( proxy.getHost() );
-                    p.setProtocol( proxy.getProtocol() );
-                    p.setPort( proxy.getPort() );
-                    p.setNonProxyHosts( proxy.getNonProxyHosts() );
-                    p.setUserName( proxy.getUsername() );
-                    p.setPassword( proxy.getPassword() );
+                    p.setHost(proxy.getHost());
+                    p.setProtocol(proxy.getProtocol());
+                    p.setPort(proxy.getPort());
+                    p.setNonProxyHosts(proxy.getNonProxyHosts());
+                    p.setUserName(proxy.getUsername());
+                    p.setPassword(proxy.getPassword());
 
-                    repository.setProxy( p );
-                }
-                else
-                {
-                    repository.setProxy( null );
+                    repository.setProxy(p);
+                } else {
+                    repository.setProxy(null);
                 }
             }
         }
     }
 
-    private Proxy getProxy( RepositorySystemSession session, ArtifactRepository repository )
-    {
-        if ( session != null )
-        {
+    private Proxy getProxy(RepositorySystemSession session, ArtifactRepository repository) {
+        if (session != null) {
             ProxySelector selector = session.getProxySelector();
-            if ( selector != null )
-            {
-                RemoteRepository repo = RepositoryUtils.toRepo( repository );
-                org.eclipse.aether.repository.Proxy proxy = selector.getProxy( repo );
-                if ( proxy != null )
-                {
+            if (selector != null) {
+                RemoteRepository repo = RepositoryUtils.toRepo(repository);
+                org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
+                if (proxy != null) {
                     Proxy p = new Proxy();
-                    p.setHost( proxy.getHost() );
-                    p.setProtocol( proxy.getType() );
-                    p.setPort( proxy.getPort() );
-                    if ( proxy.getAuthentication() != null )
-                    {
-                        repo = new RemoteRepository.Builder( repo ).setProxy( proxy ).build();
-                        AuthenticationContext authCtx = AuthenticationContext.forProxy( session, repo );
-                        p.setUserName( authCtx.get( AuthenticationContext.USERNAME ) );
-                        p.setPassword( authCtx.get( AuthenticationContext.PASSWORD ) );
-                        p.setNtlmDomain( authCtx.get( AuthenticationContext.NTLM_DOMAIN ) );
-                        p.setNtlmHost( authCtx.get( AuthenticationContext.NTLM_WORKSTATION ) );
+                    p.setHost(proxy.getHost());
+                    p.setProtocol(proxy.getType());
+                    p.setPort(proxy.getPort());
+                    if (proxy.getAuthentication() != null) {
+                        repo = new RemoteRepository.Builder(repo)
+                                .setProxy(proxy)
+                                .build();
+                        AuthenticationContext authCtx = AuthenticationContext.forProxy(session, repo);
+                        p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
+                        p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
+                        p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
+                        p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
                         authCtx.close();
                     }
                     return p;
@@ -731,133 +639,119 @@
         return null;
     }
 
-    public void injectProxy( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-        if ( repositories != null && session != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                repository.setProxy( getProxy( session, repository ) );
+    public void injectProxy(RepositorySystemSession session, List<ArtifactRepository> repositories) {
+        if (repositories != null && session != null) {
+            for (ArtifactRepository repository : repositories) {
+                repository.setProxy(getProxy(session, repository));
             }
         }
     }
 
-    public void retrieve( ArtifactRepository repository, File destination, String remotePath,
-                          ArtifactTransferListener transferListener )
-        throws ArtifactTransferFailedException, ArtifactDoesNotExistException
-    {
-        try
-        {
-            wagonManager.getRemoteFile( repository, destination, remotePath,
-                                        TransferListenerAdapter.newAdapter( transferListener ),
-                                        ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN, true );
-        }
-        catch ( org.apache.maven.wagon.TransferFailedException e )
-        {
-            throw new ArtifactTransferFailedException( getMessage( e, "Error transferring artifact." ), e );
-        }
-        catch ( org.apache.maven.wagon.ResourceDoesNotExistException e )
-        {
-            throw new ArtifactDoesNotExistException( getMessage( e, "Requested artifact does not exist." ), e );
+    public void retrieve(
+            ArtifactRepository repository,
+            File destination,
+            String remotePath,
+            ArtifactTransferListener transferListener)
+            throws ArtifactTransferFailedException, ArtifactDoesNotExistException {
+        try {
+            wagonManager.getRemoteFile(
+                    repository,
+                    destination,
+                    remotePath,
+                    TransferListenerAdapter.newAdapter(transferListener),
+                    ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN,
+                    true);
+        } catch (org.apache.maven.wagon.TransferFailedException e) {
+            throw new ArtifactTransferFailedException(getMessage(e, "Error transferring artifact."), e);
+        } catch (org.apache.maven.wagon.ResourceDoesNotExistException e) {
+            throw new ArtifactDoesNotExistException(getMessage(e, "Requested artifact does not exist."), e);
         }
     }
 
-    public void publish( ArtifactRepository repository, File source, String remotePath,
-                         ArtifactTransferListener transferListener )
-        throws ArtifactTransferFailedException
-    {
-        try
-        {
-            wagonManager.putRemoteFile( repository, source, remotePath,
-                                        TransferListenerAdapter.newAdapter( transferListener ) );
-        }
-        catch ( org.apache.maven.wagon.TransferFailedException e )
-        {
-            throw new ArtifactTransferFailedException( getMessage( e, "Error transferring artifact." ), e );
+    public void publish(
+            ArtifactRepository repository, File source, String remotePath, ArtifactTransferListener transferListener)
+            throws ArtifactTransferFailedException {
+        try {
+            wagonManager.putRemoteFile(
+                    repository, source, remotePath, TransferListenerAdapter.newAdapter(transferListener));
+        } catch (org.apache.maven.wagon.TransferFailedException e) {
+            throw new ArtifactTransferFailedException(getMessage(e, "Error transferring artifact."), e);
         }
     }
 
     //
     // Artifact Repository Creation
     //
-    public ArtifactRepository buildArtifactRepository( Repository repo )
-        throws InvalidRepositoryException
-    {
-        if ( repo != null )
-        {
+    public ArtifactRepository buildArtifactRepository(Repository repo) throws InvalidRepositoryException {
+        if (repo != null) {
             String id = repo.getId();
 
-            if ( StringUtils.isEmpty( id ) )
-            {
-                throw new InvalidRepositoryException( "Repository identifier missing", "" );
+            if (id == null || id.isEmpty()) {
+                throw new InvalidRepositoryException("Repository identifier missing", "");
             }
 
             String url = repo.getUrl();
 
-            if ( StringUtils.isEmpty( url ) )
-            {
-                throw new InvalidRepositoryException( "URL missing for repository " + id, id );
+            if (url == null || url.isEmpty()) {
+                throw new InvalidRepositoryException("URL missing for repository " + id, id);
             }
 
-            ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy( repo.getSnapshots() );
+            ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy(repo.getSnapshots());
 
-            ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy( repo.getReleases() );
+            ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy(repo.getReleases());
 
-            return createArtifactRepository( id, url, getLayout( repo.getLayout() ), snapshots, releases );
-        }
-        else
-        {
+            return createArtifactRepository(id, url, getLayout(repo.getLayout()), snapshots, releases);
+        } else {
             return null;
         }
     }
 
-    private ArtifactRepository createRepository( String url, String repositoryId, boolean releases,
-                                                 String releaseUpdates, boolean snapshots, String snapshotUpdates,
-                                                 String checksumPolicy )
-    {
+    private ArtifactRepository createRepository(
+            String url,
+            String repositoryId,
+            boolean releases,
+            String releaseUpdates,
+            boolean snapshots,
+            String snapshotUpdates,
+            String checksumPolicy) {
         ArtifactRepositoryPolicy snapshotsPolicy =
-            new ArtifactRepositoryPolicy( snapshots, snapshotUpdates, checksumPolicy );
+                new ArtifactRepositoryPolicy(snapshots, snapshotUpdates, checksumPolicy);
 
         ArtifactRepositoryPolicy releasesPolicy =
-            new ArtifactRepositoryPolicy( releases, releaseUpdates, checksumPolicy );
+                new ArtifactRepositoryPolicy(releases, releaseUpdates, checksumPolicy);
 
-        return createArtifactRepository( repositoryId, url, null, snapshotsPolicy, releasesPolicy );
+        return createArtifactRepository(repositoryId, url, null, snapshotsPolicy, releasesPolicy);
     }
 
-    public ArtifactRepository createArtifactRepository( String repositoryId, String url,
-                                                        ArtifactRepositoryLayout repositoryLayout,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-    {
-        if ( repositoryLayout == null )
-        {
-            repositoryLayout = layouts.get( "default" );
+    public ArtifactRepository createArtifactRepository(
+            String repositoryId,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases) {
+        if (repositoryLayout == null) {
+            repositoryLayout = layouts.get("default");
         }
-        return artifactRepositoryFactory.createArtifactRepository( repositoryId, url, repositoryLayout, snapshots,
-                                                            releases );
+        return artifactRepositoryFactory.createArtifactRepository(
+                repositoryId, url, repositoryLayout, snapshots, releases);
     }
 
-    private static String getMessage( Throwable error, String def )
-    {
-        if ( error == null )
-        {
+    private static String getMessage(Throwable error, String def) {
+        if (error == null) {
             return def;
         }
         String msg = error.getMessage();
-        if ( StringUtils.isNotEmpty( msg ) )
-        {
+        if (msg != null && !msg.isEmpty()) {
             return msg;
         }
-        return getMessage( error.getCause(), def );
+        return getMessage(error.getCause(), def);
     }
 
-    private ArtifactRepositoryLayout getLayout( String id )
-    {
-        ArtifactRepositoryLayout layout = layouts.get( id );
+    private ArtifactRepositoryLayout getLayout(String id) {
+        ArtifactRepositoryLayout layout = layouts.get(id);
 
-        if ( layout == null )
-        {
-            layout = new UnknownRepositoryLayout( id, layouts.get( "default" ) );
+        if (layout == null) {
+            layout = new UnknownRepositoryLayout(id, layouts.get("default"));
         }
 
         return layout;
@@ -869,46 +763,36 @@
      * needs to retain the id of this layout so that the content type of the remote repository can still be accurately
      * described.
      */
-    static class UnknownRepositoryLayout
-        implements ArtifactRepositoryLayout
-    {
+    static class UnknownRepositoryLayout implements ArtifactRepositoryLayout {
 
         private final String id;
 
         private final ArtifactRepositoryLayout fallback;
 
-        UnknownRepositoryLayout( String id, ArtifactRepositoryLayout fallback )
-        {
+        UnknownRepositoryLayout(String id, ArtifactRepositoryLayout fallback) {
             this.id = id;
             this.fallback = fallback;
         }
 
-        public String getId()
-        {
+        public String getId() {
             return id;
         }
 
-        public String pathOf( Artifact artifact )
-        {
-            return fallback.pathOf( artifact );
+        public String pathOf(Artifact artifact) {
+            return fallback.pathOf(artifact);
         }
 
-        public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-        {
-            return fallback.pathOfLocalRepositoryMetadata( metadata, repository );
+        public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+            return fallback.pathOfLocalRepositoryMetadata(metadata, repository);
         }
 
-        public String pathOfRemoteRepositoryMetadata( ArtifactMetadata metadata )
-        {
-            return fallback.pathOfRemoteRepositoryMetadata( metadata );
+        public String pathOfRemoteRepositoryMetadata(ArtifactMetadata metadata) {
+            return fallback.pathOfRemoteRepositoryMetadata(metadata);
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return getId();
         }
-
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/MavenArtifact.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/MavenArtifact.java
index 07d2cdb..ccb18d2 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/MavenArtifact.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/MavenArtifact.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,13 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import org.apache.maven.repository.ArtifactTransferResource;
 import org.apache.maven.wagon.resource.Resource;
 
-class MavenArtifact
-    implements ArtifactTransferResource
-{
+@Deprecated
+class MavenArtifact implements ArtifactTransferResource {
 
     private String repositoryUrl;
 
@@ -32,18 +30,12 @@
 
     private long transferStartTime;
 
-    MavenArtifact( String repositoryUrl, Resource resource )
-    {
-        if ( repositoryUrl == null )
-        {
+    MavenArtifact(String repositoryUrl, Resource resource) {
+        if (repositoryUrl == null) {
             this.repositoryUrl = "";
-        }
-        else if ( !repositoryUrl.endsWith( "/" ) && repositoryUrl.length() > 0 )
-        {
+        } else if (!repositoryUrl.endsWith("/") && repositoryUrl.length() > 0) {
             this.repositoryUrl = repositoryUrl + '/';
-        }
-        else
-        {
+        } else {
             this.repositoryUrl = repositoryUrl;
         }
         this.resource = resource;
@@ -51,46 +43,36 @@
         this.transferStartTime = System.currentTimeMillis();
     }
 
-    public String getRepositoryUrl()
-    {
+    public String getRepositoryUrl() {
         return repositoryUrl;
     }
 
-    public String getName()
-    {
+    public String getName() {
         String name = resource.getName();
 
-        if ( name == null )
-        {
+        if (name == null) {
             name = "";
-        }
-        else if ( name.startsWith( "/" ) )
-        {
-            name = name.substring( 1 );
+        } else if (name.startsWith("/")) {
+            name = name.substring(1);
         }
 
         return name;
     }
 
-    public String getUrl()
-    {
+    public String getUrl() {
         return getRepositoryUrl() + getName();
     }
 
-    public long getContentLength()
-    {
+    public long getContentLength() {
         return resource.getContentLength();
     }
 
-    public long getTransferStartTime()
-    {
+    public long getTransferStartTime() {
         return transferStartTime;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getUrl();
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/TransferListenerAdapter.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/TransferListenerAdapter.java
index c3bc5e9..e6d5331 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/TransferListenerAdapter.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/TransferListenerAdapter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import java.util.IdentityHashMap;
 import java.util.Map;
@@ -33,9 +32,8 @@
 /**
  * TransferListenerAdapter
  */
-public class TransferListenerAdapter
-    implements TransferListener
-{
+@Deprecated
+public class TransferListenerAdapter implements TransferListener {
 
     private final ArtifactTransferListener listener;
 
@@ -43,148 +41,113 @@
 
     private final Map<Resource, Long> transfers;
 
-    public static TransferListener newAdapter( ArtifactTransferListener listener )
-    {
-        if ( listener == null )
-        {
+    public static TransferListener newAdapter(ArtifactTransferListener listener) {
+        if (listener == null) {
             return null;
-        }
-        else
-        {
-            return new TransferListenerAdapter( listener );
+        } else {
+            return new TransferListenerAdapter(listener);
         }
     }
 
-    private TransferListenerAdapter( ArtifactTransferListener listener )
-    {
+    private TransferListenerAdapter(ArtifactTransferListener listener) {
         this.listener = listener;
         this.artifacts = new IdentityHashMap<>();
         this.transfers = new IdentityHashMap<>();
     }
 
-    public void debug( String message )
-    {
-    }
+    public void debug(String message) {}
 
-    public void transferCompleted( TransferEvent transferEvent )
-    {
-        ArtifactTransferEvent event = wrap( transferEvent );
+    public void transferCompleted(TransferEvent transferEvent) {
+        ArtifactTransferEvent event = wrap(transferEvent);
 
         Long transferred;
-        synchronized ( transfers )
-        {
-            transferred = transfers.remove( transferEvent.getResource() );
+        synchronized (transfers) {
+            transferred = transfers.remove(transferEvent.getResource());
         }
-        if ( transferred != null )
-        {
-            event.setTransferredBytes( transferred );
+        if (transferred != null) {
+            event.setTransferredBytes(transferred);
         }
 
-        synchronized ( artifacts )
-        {
-            artifacts.remove( transferEvent.getResource() );
+        synchronized (artifacts) {
+            artifacts.remove(transferEvent.getResource());
         }
 
-        listener.transferCompleted( event );
+        listener.transferCompleted(event);
     }
 
-    public void transferError( TransferEvent transferEvent )
-    {
-        synchronized ( transfers )
-        {
-            transfers.remove( transferEvent.getResource() );
+    public void transferError(TransferEvent transferEvent) {
+        synchronized (transfers) {
+            transfers.remove(transferEvent.getResource());
         }
-        synchronized ( artifacts )
-        {
-            artifacts.remove( transferEvent.getResource() );
+        synchronized (artifacts) {
+            artifacts.remove(transferEvent.getResource());
         }
     }
 
-    public void transferInitiated( TransferEvent transferEvent )
-    {
-        listener.transferInitiated( wrap( transferEvent ) );
+    public void transferInitiated(TransferEvent transferEvent) {
+        listener.transferInitiated(wrap(transferEvent));
     }
 
-    public void transferProgress( TransferEvent transferEvent, byte[] buffer, int length )
-    {
+    public void transferProgress(TransferEvent transferEvent, byte[] buffer, int length) {
         Long transferred;
-        synchronized ( transfers )
-        {
-            transferred = transfers.get( transferEvent.getResource() );
-            if ( transferred == null )
-            {
+        synchronized (transfers) {
+            transferred = transfers.get(transferEvent.getResource());
+            if (transferred == null) {
                 transferred = (long) length;
-            }
-            else
-            {
+            } else {
                 transferred = transferred + length;
             }
-            transfers.put( transferEvent.getResource(), transferred );
+            transfers.put(transferEvent.getResource(), transferred);
         }
 
-        ArtifactTransferEvent event = wrap( transferEvent );
-        event.setDataBuffer( buffer );
-        event.setDataOffset( 0 );
-        event.setDataLength( length );
-        event.setTransferredBytes( transferred );
+        ArtifactTransferEvent event = wrap(transferEvent);
+        event.setDataBuffer(buffer);
+        event.setDataOffset(0);
+        event.setDataLength(length);
+        event.setTransferredBytes(transferred);
 
-        listener.transferProgress( event );
+        listener.transferProgress(event);
     }
 
-    public void transferStarted( TransferEvent transferEvent )
-    {
-        listener.transferStarted( wrap( transferEvent ) );
+    public void transferStarted(TransferEvent transferEvent) {
+        listener.transferStarted(wrap(transferEvent));
     }
 
-    private ArtifactTransferEvent wrap( TransferEvent event )
-    {
-        if ( event == null )
-        {
+    private ArtifactTransferEvent wrap(TransferEvent event) {
+        if (event == null) {
             return null;
-        }
-        else
-        {
+        } else {
             String wagon = event.getWagon().getClass().getName();
 
-            ArtifactTransferResource artifact = wrap( event.getWagon().getRepository(), event.getResource() );
+            ArtifactTransferResource artifact = wrap(event.getWagon().getRepository(), event.getResource());
 
             ArtifactTransferEvent evt;
-            if ( event.getException() != null )
-            {
-                evt = new ArtifactTransferEvent( wagon, event.getException(), event.getRequestType(), artifact );
-            }
-            else
-            {
-                evt = new ArtifactTransferEvent( wagon, event.getEventType(), event.getRequestType(), artifact );
+            if (event.getException() != null) {
+                evt = new ArtifactTransferEvent(wagon, event.getException(), event.getRequestType(), artifact);
+            } else {
+                evt = new ArtifactTransferEvent(wagon, event.getEventType(), event.getRequestType(), artifact);
             }
 
-            evt.setLocalFile( event.getLocalFile() );
+            evt.setLocalFile(event.getLocalFile());
 
             return evt;
         }
     }
 
-    private ArtifactTransferResource wrap( Repository repository, Resource resource )
-    {
-        if ( resource == null )
-        {
+    private ArtifactTransferResource wrap(Repository repository, Resource resource) {
+        if (resource == null) {
             return null;
-        }
-        else
-        {
-            synchronized ( artifacts )
-            {
-                ArtifactTransferResource artifact = artifacts.get( resource );
+        } else {
+            synchronized (artifacts) {
+                ArtifactTransferResource artifact = artifacts.get(resource);
 
-                if ( artifact == null )
-                {
-                    artifact = new MavenArtifact( repository.getUrl(), resource );
-                    artifacts.put( resource, artifact );
+                if (artifact == null) {
+                    artifact = new MavenArtifact(repository.getUrl(), resource);
+                    artifacts.put(resource, artifact);
                 }
 
                 return artifact;
             }
         }
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/UpdateCheckManager.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/UpdateCheckManager.java
index 0ef8c6a..957594f 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/UpdateCheckManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/UpdateCheckManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import java.io.File;
 
@@ -28,17 +27,16 @@
 /**
  * UpdateCheckManager
  */
-public interface UpdateCheckManager
-{
+@Deprecated
+public interface UpdateCheckManager {
 
-    boolean isUpdateRequired( Artifact artifact, ArtifactRepository repository );
+    boolean isUpdateRequired(Artifact artifact, ArtifactRepository repository);
 
-    void touch( Artifact artifact, ArtifactRepository repository, String error );
+    void touch(Artifact artifact, ArtifactRepository repository, String error);
 
-    String getError( Artifact artifact, ArtifactRepository repository );
+    String getError(Artifact artifact, ArtifactRepository repository);
 
-    boolean isUpdateRequired( RepositoryMetadata metadata, ArtifactRepository repository, File file );
+    boolean isUpdateRequired(RepositoryMetadata metadata, ArtifactRepository repository, File file);
 
-    void touch( RepositoryMetadata metadata, ArtifactRepository repository, File file );
-
+    void touch(RepositoryMetadata metadata, ArtifactRepository repository, File file);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonConfigurationException.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonConfigurationException.java
index 67b9ec7..1ebe551 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonConfigurationException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonConfigurationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,48 +16,40 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import org.apache.maven.wagon.TransferFailedException;
 
 /**
  * WagonConfigurationException
  */
-public class WagonConfigurationException
-    extends TransferFailedException
-{
+@Deprecated
+public class WagonConfigurationException extends TransferFailedException {
 
     static final long serialVersionUID = 1;
 
     private final String originalMessage;
     private final String repositoryId;
 
-    public WagonConfigurationException( String repositoryId,
-                                        String message,
-                                        Throwable cause )
-    {
-        super( "While configuring wagon for '" + repositoryId + "': " + message, cause );
+    public WagonConfigurationException(String repositoryId, String message, Throwable cause) {
+        super("While configuring wagon for '" + repositoryId + "': " + message, cause);
 
         this.repositoryId = repositoryId;
         this.originalMessage = message;
     }
 
-    public WagonConfigurationException( String repositoryId,
-                                        String message )
-    {
-        super( "While configuring wagon for '" + repositoryId + "': " + message );
+    public WagonConfigurationException(String repositoryId, String message) {
+        super("While configuring wagon for '" + repositoryId + "': " + message);
 
         this.repositoryId = repositoryId;
         this.originalMessage = message;
     }
 
-    public final String getRepositoryId()
-    {
+    public final String getRepositoryId() {
         return repositoryId;
     }
 
-    public final String getOriginalMessage()
-    {
+    public final String getOriginalMessage() {
         return originalMessage;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonManager.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonManager.java
index 6156818..697e86a 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/WagonManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import java.io.File;
 import java.util.List;
@@ -35,50 +34,54 @@
 /**
  * WagonManager
  */
-public interface WagonManager
-{
+@Deprecated
+public interface WagonManager {
     @Deprecated
-    Wagon getWagon( String protocol )
-        throws UnsupportedProtocolException;
+    Wagon getWagon(String protocol) throws UnsupportedProtocolException;
 
     @Deprecated
-    Wagon getWagon( Repository repository )
-        throws UnsupportedProtocolException, WagonConfigurationException;
+    Wagon getWagon(Repository repository) throws UnsupportedProtocolException, WagonConfigurationException;
 
     //
     // Retriever
     //
-    void getArtifact( Artifact artifact, ArtifactRepository repository, TransferListener transferListener,
-                      boolean force )
-        throws TransferFailedException, ResourceDoesNotExistException;
+    void getArtifact(Artifact artifact, ArtifactRepository repository, TransferListener transferListener, boolean force)
+            throws TransferFailedException, ResourceDoesNotExistException;
 
-    void getArtifact( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                      TransferListener transferListener, boolean force )
-        throws TransferFailedException, ResourceDoesNotExistException;
+    void getArtifact(
+            Artifact artifact,
+            List<ArtifactRepository> remoteRepositories,
+            TransferListener transferListener,
+            boolean force)
+            throws TransferFailedException, ResourceDoesNotExistException;
 
-    void getRemoteFile( ArtifactRepository repository, File destination, String remotePath,
-                        TransferListener downloadMonitor, String checksumPolicy, boolean force )
-        throws TransferFailedException, ResourceDoesNotExistException;
+    void getRemoteFile(
+            ArtifactRepository repository,
+            File destination,
+            String remotePath,
+            TransferListener downloadMonitor,
+            String checksumPolicy,
+            boolean force)
+            throws TransferFailedException, ResourceDoesNotExistException;
 
-    void getArtifactMetadata( ArtifactMetadata metadata, ArtifactRepository remoteRepository, File destination,
-                              String checksumPolicy )
-        throws TransferFailedException, ResourceDoesNotExistException;
+    void getArtifactMetadata(
+            ArtifactMetadata metadata, ArtifactRepository remoteRepository, File destination, String checksumPolicy)
+            throws TransferFailedException, ResourceDoesNotExistException;
 
-    void getArtifactMetadataFromDeploymentRepository( ArtifactMetadata metadata, ArtifactRepository remoteRepository,
-                                                      File file, String checksumPolicyWarn )
-        throws TransferFailedException, ResourceDoesNotExistException;
+    void getArtifactMetadataFromDeploymentRepository(
+            ArtifactMetadata metadata, ArtifactRepository remoteRepository, File file, String checksumPolicyWarn)
+            throws TransferFailedException, ResourceDoesNotExistException;
 
     //
     // Deployer
     //
-    void putArtifact( File source, Artifact artifact, ArtifactRepository deploymentRepository,
-                      TransferListener downloadMonitor )
-        throws TransferFailedException;
+    void putArtifact(
+            File source, Artifact artifact, ArtifactRepository deploymentRepository, TransferListener downloadMonitor)
+            throws TransferFailedException;
 
-    void putRemoteFile( ArtifactRepository repository, File source, String remotePath,
-                        TransferListener downloadMonitor )
-        throws TransferFailedException;
+    void putRemoteFile(ArtifactRepository repository, File source, String remotePath, TransferListener downloadMonitor)
+            throws TransferFailedException;
 
-    void putArtifactMetadata( File source, ArtifactMetadata artifactMetadata, ArtifactRepository repository )
-        throws TransferFailedException;
+    void putArtifactMetadata(File source, ArtifactMetadata artifactMetadata, ArtifactRepository repository)
+            throws TransferFailedException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/AbstractArtifactMetadata.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/AbstractArtifactMetadata.java
new file mode 100644
index 0000000..a02af14
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/AbstractArtifactMetadata.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository.legacy.metadata;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * Common elements of artifact metadata.
+ *
+ */
+@Deprecated
+public abstract class AbstractArtifactMetadata implements ArtifactMetadata {
+    private static final String LS = System.lineSeparator();
+
+    protected Artifact artifact;
+
+    protected AbstractArtifactMetadata(Artifact artifact) {
+        this.artifact = artifact;
+    }
+
+    public boolean storedInGroupDirectory() {
+        return false;
+    }
+
+    public String getGroupId() {
+        return artifact.getGroupId();
+    }
+
+    public String getArtifactId() {
+        return artifact.getArtifactId();
+    }
+
+    public String extendedToString() {
+        StringBuilder buffer = new StringBuilder(256);
+
+        buffer.append(LS).append("Artifact Metadata").append(LS).append("--------------------------");
+        buffer.append(LS).append("GroupId: ").append(getGroupId());
+        buffer.append(LS).append("ArtifactId: ").append(getArtifactId());
+        buffer.append(LS).append("Metadata Type: ").append(getClass().getName());
+
+        return buffer.toString();
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException.java
new file mode 100644
index 0000000..a065eed
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository.legacy.metadata;
+
+import org.apache.maven.artifact.Artifact;
+
+/**
+ * Error while retrieving repository metadata from the repository.
+ *
+ */
+@Deprecated
+public class ArtifactMetadataRetrievalException extends Exception {
+    private Artifact artifact;
+
+    /**
+     * @param message a message
+     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
+     */
+    @Deprecated
+    public ArtifactMetadataRetrievalException(String message) {
+        this(message, null, null);
+    }
+
+    /**
+     * @param cause a cause
+     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
+     */
+    @Deprecated
+    public ArtifactMetadataRetrievalException(Throwable cause) {
+        this(null, cause, null);
+    }
+
+    /**
+     * @param message a message
+     * @param cause a cause
+     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
+     */
+    @Deprecated
+    public ArtifactMetadataRetrievalException(String message, Throwable cause) {
+        this(message, cause, null);
+    }
+
+    public ArtifactMetadataRetrievalException(String message, Throwable cause, Artifact artifact) {
+        super(message, cause);
+        this.artifact = artifact;
+    }
+
+    public Artifact getArtifact() {
+        return artifact;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource.java
new file mode 100644
index 0000000..4509411
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository.legacy.metadata;
+
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+
+/**
+ * Provides some metadata operations, like querying the remote repository for a list of versions available for an
+ * artifact.
+ *
+ */
+@Deprecated
+public interface ArtifactMetadataSource {
+
+    ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException;
+
+    ResolutionGroup retrieve(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException;
+
+    /**
+     * Get a list of available versions for an artifact in the remote repository
+     *
+     * @param artifact           artifact we are interested in. Only <code>groupid</code> and <code>artifactId</code>
+     *                           are needed, for instance the following code will work
+     *                           <code>artifactFactory.createProjectArtifact( "org.apache.maven", "maven", "" )</code>
+     * @param localRepository    local repository
+     * @param remoteRepositories remote repositories, {@link List} $lt; {@link ArtifactRepository} &gt;
+     * @return {@link List} $lt; {@link ArtifactVersion} &gt;
+     * @throws ArtifactMetadataRetrievalException
+     *          in case of error while retrieving repository metadata from the repository.
+     */
+    List<ArtifactVersion> retrieveAvailableVersions(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException;
+
+    /**
+     * Get a list of available versions for an artifact in the remote deployment repository. This ignores any update
+     * policy checks and mirrors and always retrieves the latest information from the given repository.
+     *
+     * @param artifact artifact we are interested in. Only <code>groupid</code> and <code>artifactId</code> are
+     *            needed, for instance the following code will work
+     *            <code>artifactFactory.createProjectArtifact( "org.apache.maven", "maven", "" )</code>
+     * @param localRepository    local repository
+     * @param remoteRepository   remote repository
+     * @return {@link List} $lt; {@link ArtifactVersion} &gt;
+     * @throws ArtifactMetadataRetrievalException
+     *          in case of error while retrieving repository metadata from the repository.
+     */
+    List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws ArtifactMetadataRetrievalException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/DefaultMetadataResolutionRequest.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/DefaultMetadataResolutionRequest.java
new file mode 100644
index 0000000..6e09aa5
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/DefaultMetadataResolutionRequest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository.legacy.metadata;
+
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
+import org.apache.maven.artifact.repository.RepositoryRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+
+/**
+ * Forms a request to retrieve artifact metadata.
+ *
+ */
+@Deprecated
+public class DefaultMetadataResolutionRequest implements MetadataResolutionRequest {
+
+    private Artifact artifact;
+
+    private boolean resolveManagedVersions;
+
+    private RepositoryRequest repositoryRequest;
+
+    public DefaultMetadataResolutionRequest() {
+        repositoryRequest = new DefaultRepositoryRequest();
+    }
+
+    public DefaultMetadataResolutionRequest(RepositoryRequest repositoryRequest) {
+        this.repositoryRequest = new DefaultRepositoryRequest(repositoryRequest);
+    }
+
+    public DefaultMetadataResolutionRequest(ArtifactResolutionRequest resolutionRequest) {
+        this.repositoryRequest = new DefaultRepositoryRequest(resolutionRequest);
+    }
+
+    public Artifact getArtifact() {
+        return artifact;
+    }
+
+    public DefaultMetadataResolutionRequest setArtifact(Artifact artifact) {
+        this.artifact = artifact;
+
+        return this;
+    }
+
+    public ArtifactRepository getLocalRepository() {
+        return repositoryRequest.getLocalRepository();
+    }
+
+    public DefaultMetadataResolutionRequest setLocalRepository(ArtifactRepository localRepository) {
+        repositoryRequest.setLocalRepository(localRepository);
+
+        return this;
+    }
+
+    public List<ArtifactRepository> getRemoteRepositories() {
+        return repositoryRequest.getRemoteRepositories();
+    }
+
+    public DefaultMetadataResolutionRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories) {
+        repositoryRequest.setRemoteRepositories(remoteRepositories);
+
+        return this;
+    }
+
+    public boolean isResolveManagedVersions() {
+        return resolveManagedVersions;
+    }
+
+    public DefaultMetadataResolutionRequest setResolveManagedVersions(boolean resolveManagedVersions) {
+        this.resolveManagedVersions = resolveManagedVersions;
+
+        return this;
+    }
+
+    public boolean isOffline() {
+        return repositoryRequest.isOffline();
+    }
+
+    public DefaultMetadataResolutionRequest setOffline(boolean offline) {
+        repositoryRequest.setOffline(offline);
+
+        return this;
+    }
+
+    public boolean isForceUpdate() {
+        return repositoryRequest.isForceUpdate();
+    }
+
+    public DefaultMetadataResolutionRequest setForceUpdate(boolean forceUpdate) {
+        repositoryRequest.setForceUpdate(forceUpdate);
+
+        return this;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest.java
new file mode 100644
index 0000000..819e182
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository.legacy.metadata;
+
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.RepositoryRequest;
+
+/**
+ * Forms a request to retrieve artifact metadata.
+ *
+ */
+@Deprecated
+public interface MetadataResolutionRequest extends RepositoryRequest {
+
+    /**
+     * Indicates whether network access to remote repositories has been disabled.
+     *
+     * @return {@code true} if remote access has been disabled, {@code false} otherwise.
+     */
+    boolean isOffline();
+
+    /**
+     * Enables/disables network access to remote repositories.
+     *
+     * @param offline {@code true} to disable remote access, {@code false} to allow network access.
+     * @return This request, never {@code null}.
+     */
+    MetadataResolutionRequest setOffline(boolean offline);
+
+    /**
+     * Gets the artifact to resolve metadata for.
+     *
+     * @return The artifact to resolve metadata for or {@code null} if not set.
+     */
+    Artifact getArtifact();
+
+    /**
+     * Sets the artifact for which to resolve metadata.
+     *
+     * @param artifact The artifact for which to resolve metadata.
+     * @return This request, never {@code null}.
+     */
+    MetadataResolutionRequest setArtifact(Artifact artifact);
+
+    /**
+     * Gets the local repository to use for the resolution.
+     *
+     * @return The local repository to use for the resolution or {@code null} if not set.
+     */
+    ArtifactRepository getLocalRepository();
+
+    /**
+     * Sets the local repository to use for the resolution.
+     *
+     * @param localRepository The local repository to use for the resolution.
+     * @return This request, never {@code null}.
+     */
+    MetadataResolutionRequest setLocalRepository(ArtifactRepository localRepository);
+
+    /**
+     * Gets the remote repositories to use for the resolution.
+     *
+     * @return The remote repositories to use for the resolution, never {@code null}.
+     */
+    List<ArtifactRepository> getRemoteRepositories();
+
+    /**
+     * Sets the remote repositories to use for the resolution.
+     *
+     * @param remoteRepositories The remote repositories to use for the resolution.
+     * @return This request, never {@code null}.
+     */
+    MetadataResolutionRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories);
+
+    /**
+     * Determines whether the managed version information should be retrieved.
+     *
+     * @return {@code true} if the dependency management information should be retrieved, {@code false} otherwise.
+     */
+    boolean isResolveManagedVersions();
+
+    /**
+     * Enables/disables resolution of the dependency management information.
+     *
+     * @param resolveManagedVersions {@code true} if the dependency management information should be retrieved, {@code
+     *            false} otherwise.
+     * @return This request, never {@code null}.
+     */
+    MetadataResolutionRequest setResolveManagedVersions(boolean resolveManagedVersions);
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ResolutionGroup.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ResolutionGroup.java
new file mode 100644
index 0000000..1bb1c9c
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/metadata/ResolutionGroup.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository.legacy.metadata;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+
+/**
+ * ResolutionGroup
+ */
+@Deprecated
+public class ResolutionGroup {
+
+    private final Set<Artifact> artifacts;
+
+    private final List<ArtifactRepository> resolutionRepositories;
+
+    private final Artifact pomArtifact;
+
+    private final Artifact relocatedArtifact;
+
+    private final Map<String, Artifact> managedVersions;
+
+    public ResolutionGroup(
+            Artifact pomArtifact, Set<Artifact> artifacts, List<ArtifactRepository> resolutionRepositories) {
+        this(pomArtifact, null, artifacts, null, resolutionRepositories);
+    }
+
+    public ResolutionGroup(
+            Artifact pomArtifact,
+            Artifact relocatedArtifact,
+            Set<Artifact> artifacts,
+            Map<String, Artifact> managedVersions,
+            List<ArtifactRepository> resolutionRepositories) {
+        this.pomArtifact = pomArtifact;
+        this.relocatedArtifact = relocatedArtifact;
+        this.artifacts = artifacts;
+        this.managedVersions = managedVersions;
+        this.resolutionRepositories = resolutionRepositories;
+    }
+
+    public Artifact getPomArtifact() {
+        return pomArtifact;
+    }
+
+    public Artifact getRelocatedArtifact() {
+        return relocatedArtifact;
+    }
+
+    public Set<Artifact> getArtifacts() {
+        return artifacts;
+    }
+
+    public List<ArtifactRepository> getResolutionRepositories() {
+        return resolutionRepositories;
+    }
+
+    public Map<String, Artifact> getManagedVersions() {
+        return managedVersions;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/ArtifactRepositoryFactory.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/ArtifactRepositoryFactory.java
index aeb5739..2abe5ea 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/ArtifactRepositoryFactory.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/ArtifactRepositoryFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,41 +16,46 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.repository;
 
 import org.apache.maven.artifact.UnknownRepositoryLayoutException;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
 
-/** @author jdcasey */
-public interface ArtifactRepositoryFactory
-{
+@Deprecated
+public interface ArtifactRepositoryFactory {
 
     String DEFAULT_LAYOUT_ID = "default";
 
     String LOCAL_REPOSITORY_ID = "local";
 
     @Deprecated
-    ArtifactRepositoryLayout getLayout( String layoutId )
-        throws UnknownRepositoryLayoutException;
+    ArtifactRepositoryLayout getLayout(String layoutId) throws UnknownRepositoryLayoutException;
 
     @Deprecated
-    ArtifactRepository createDeploymentArtifactRepository( String id, String url, String layoutId,
-                                                           boolean uniqueVersion )
-        throws UnknownRepositoryLayoutException;
+    ArtifactRepository createDeploymentArtifactRepository(String id, String url, String layoutId, boolean uniqueVersion)
+            throws UnknownRepositoryLayoutException;
 
-    ArtifactRepository createDeploymentArtifactRepository( String id, String url, ArtifactRepositoryLayout layout,
-                                                           boolean uniqueVersion );
+    ArtifactRepository createDeploymentArtifactRepository(
+            String id, String url, ArtifactRepositoryLayout layout, boolean uniqueVersion);
 
-    ArtifactRepository createArtifactRepository( String id, String url, String layoutId,
-                                                 ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases )
-        throws UnknownRepositoryLayoutException;
+    ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            String layoutId,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases)
+            throws UnknownRepositoryLayoutException;
 
-    ArtifactRepository createArtifactRepository( String id, String url, ArtifactRepositoryLayout repositoryLayout,
-                                                 ArtifactRepositoryPolicy snapshots,
-                                                 ArtifactRepositoryPolicy releases );
+    ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases);
 
-    void setGlobalUpdatePolicy( String snapshotPolicy );
+    void setGlobalUpdatePolicy(String snapshotPolicy);
 
-    void setGlobalChecksumPolicy( String checksumPolicy );
+    void setGlobalChecksumPolicy(String checksumPolicy);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory.java
index fc6b441..34dd8e8 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/repository/DefaultArtifactRepositoryFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.repository;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Map;
 
@@ -27,118 +30,100 @@
 import org.apache.maven.artifact.repository.MavenArtifactRepository;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout2;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 
 /**
- * @author jdcasey
  */
-@Component( role = ArtifactRepositoryFactory.class )
-public class DefaultArtifactRepositoryFactory
-    implements ArtifactRepositoryFactory
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultArtifactRepositoryFactory implements ArtifactRepositoryFactory {
     // TODO use settings?
     private String globalUpdatePolicy;
 
     private String globalChecksumPolicy;
 
-    @Requirement( role = ArtifactRepositoryLayout.class )
+    @Inject
     private Map<String, ArtifactRepositoryLayout> repositoryLayouts;
 
-    public ArtifactRepositoryLayout getLayout( String layoutId )
-        throws UnknownRepositoryLayoutException
-    {
-        return repositoryLayouts.get( layoutId );
+    public ArtifactRepositoryLayout getLayout(String layoutId) throws UnknownRepositoryLayoutException {
+        return repositoryLayouts.get(layoutId);
     }
 
-    public ArtifactRepository createDeploymentArtifactRepository( String id, String url, String layoutId,
-                                                                  boolean uniqueVersion )
-        throws UnknownRepositoryLayoutException
-    {
-        ArtifactRepositoryLayout layout = repositoryLayouts.get( layoutId );
+    public ArtifactRepository createDeploymentArtifactRepository(
+            String id, String url, String layoutId, boolean uniqueVersion) throws UnknownRepositoryLayoutException {
+        ArtifactRepositoryLayout layout = repositoryLayouts.get(layoutId);
 
-        checkLayout( id, layoutId, layout );
+        checkLayout(id, layoutId, layout);
 
-        return createDeploymentArtifactRepository( id, url, layout, uniqueVersion );
+        return createDeploymentArtifactRepository(id, url, layout, uniqueVersion);
     }
 
-    private void checkLayout( String repositoryId, String layoutId, ArtifactRepositoryLayout layout )
-        throws UnknownRepositoryLayoutException
-    {
-        if ( layout == null )
-        {
-            throw new UnknownRepositoryLayoutException( repositoryId, layoutId );
+    private void checkLayout(String repositoryId, String layoutId, ArtifactRepositoryLayout layout)
+            throws UnknownRepositoryLayoutException {
+        if (layout == null) {
+            throw new UnknownRepositoryLayoutException(repositoryId, layoutId);
         }
     }
 
-    public ArtifactRepository createDeploymentArtifactRepository( String id, String url,
-                                                                  ArtifactRepositoryLayout repositoryLayout,
-                                                                  boolean uniqueVersion )
-    {
-        return createArtifactRepository( id, url, repositoryLayout, null, null );
+    public ArtifactRepository createDeploymentArtifactRepository(
+            String id, String url, ArtifactRepositoryLayout repositoryLayout, boolean uniqueVersion) {
+        return createArtifactRepository(id, url, repositoryLayout, null, null);
     }
 
-    public ArtifactRepository createArtifactRepository( String id, String url, String layoutId,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-        throws UnknownRepositoryLayoutException
-    {
-        ArtifactRepositoryLayout layout = repositoryLayouts.get( layoutId );
+    public ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            String layoutId,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases)
+            throws UnknownRepositoryLayoutException {
+        ArtifactRepositoryLayout layout = repositoryLayouts.get(layoutId);
 
-        checkLayout( id, layoutId, layout );
+        checkLayout(id, layoutId, layout);
 
-        return createArtifactRepository( id, url, layout, snapshots, releases );
+        return createArtifactRepository(id, url, layout, snapshots, releases);
     }
 
-    public ArtifactRepository createArtifactRepository( String id, String url,
-                                                        ArtifactRepositoryLayout repositoryLayout,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-    {
-        if ( snapshots == null )
-        {
+    public ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases) {
+        if (snapshots == null) {
             snapshots = new ArtifactRepositoryPolicy();
         }
 
-        if ( releases == null )
-        {
+        if (releases == null) {
             releases = new ArtifactRepositoryPolicy();
         }
 
-        if ( globalUpdatePolicy != null )
-        {
-            snapshots.setUpdatePolicy( globalUpdatePolicy );
-            releases.setUpdatePolicy( globalUpdatePolicy );
+        if (globalUpdatePolicy != null) {
+            snapshots.setUpdatePolicy(globalUpdatePolicy);
+            releases.setUpdatePolicy(globalUpdatePolicy);
         }
 
-        if ( globalChecksumPolicy != null )
-        {
-            snapshots.setChecksumPolicy( globalChecksumPolicy );
-            releases.setChecksumPolicy( globalChecksumPolicy );
+        if (globalChecksumPolicy != null) {
+            snapshots.setChecksumPolicy(globalChecksumPolicy);
+            releases.setChecksumPolicy(globalChecksumPolicy);
         }
 
         ArtifactRepository repository;
-        if ( repositoryLayout instanceof ArtifactRepositoryLayout2 )
-        {
-            repository =
-                ( (ArtifactRepositoryLayout2) repositoryLayout ).newMavenArtifactRepository( id, url, snapshots,
-                                                                                             releases );
-        }
-        else
-        {
-            repository = new MavenArtifactRepository( id, url, repositoryLayout, snapshots, releases );
+        if (repositoryLayout instanceof ArtifactRepositoryLayout2) {
+            repository = ((ArtifactRepositoryLayout2) repositoryLayout)
+                    .newMavenArtifactRepository(id, url, snapshots, releases);
+        } else {
+            repository = new MavenArtifactRepository(id, url, repositoryLayout, snapshots, releases);
         }
 
         return repository;
     }
 
-    public void setGlobalUpdatePolicy( String updatePolicy )
-    {
+    public void setGlobalUpdatePolicy(String updatePolicy) {
         globalUpdatePolicy = updatePolicy;
     }
 
-    public void setGlobalChecksumPolicy( String checksumPolicy )
-    {
+    public void setGlobalChecksumPolicy(String checksumPolicy) {
         globalChecksumPolicy = checksumPolicy;
     }
- }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/DefaultLegacyArtifactCollector.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/DefaultLegacyArtifactCollector.java
index a14db6c..01ace06 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/DefaultLegacyArtifactCollector.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/DefaultLegacyArtifactCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -51,155 +54,142 @@
 import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
 import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
 import org.apache.maven.repository.legacy.resolver.conflict.ConflictResolver;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.logging.Logger;
 
 /**
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- * @author Jason van Zyl
  */
-@Component( role = LegacyArtifactCollector.class )
-public class DefaultLegacyArtifactCollector
-    implements LegacyArtifactCollector
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultLegacyArtifactCollector implements LegacyArtifactCollector {
 
-    @Requirement( hint = "nearest" )
+    @Inject
+    @Named("nearest")
     private ConflictResolver defaultConflictResolver;
 
-    @Requirement
+    @Inject
     private Logger logger;
 
-    @Requirement
+    @Inject
     private LegacySupport legacySupport;
 
-    private void injectSession( ArtifactResolutionRequest request )
-    {
+    private void injectSession(ArtifactResolutionRequest request) {
         MavenSession session = legacySupport.getSession();
 
-        if ( session != null )
-        {
-            request.setOffline( session.isOffline() );
-            request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
-            request.setServers( session.getRequest().getServers() );
-            request.setMirrors( session.getRequest().getMirrors() );
-            request.setProxies( session.getRequest().getProxies() );
+        if (session != null) {
+            request.setOffline(session.isOffline());
+            request.setForceUpdate(session.getRequest().isUpdateSnapshots());
+            request.setServers(session.getRequest().getServers());
+            request.setMirrors(session.getRequest().getMirrors());
+            request.setProxies(session.getRequest().getProxies());
         }
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                             Map<String, Artifact> managedVersions, ArtifactRepository localRepository,
-                                             List<ArtifactRepository> remoteRepositories,
-                                             ArtifactMetadataSource source, ArtifactFilter filter,
-                                             List<ResolutionListener> listeners,
-                                             List<ConflictResolver> conflictResolvers )
-    {
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners,
+            List<ConflictResolver> conflictResolvers) {
         ArtifactResolutionRequest request = new ArtifactResolutionRequest();
-        request.setLocalRepository( localRepository );
-        request.setRemoteRepositories( remoteRepositories );
-        injectSession( request );
-        return collect( artifacts, originatingArtifact, managedVersions, request, source, filter, listeners,
-                        conflictResolvers );
+        request.setLocalRepository(localRepository);
+        request.setRemoteRepositories(remoteRepositories);
+        injectSession(request);
+        return collect(
+                artifacts, originatingArtifact, managedVersions, request, source, filter, listeners, conflictResolvers);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                             Map<String, Artifact> managedVersions,
-                                             ArtifactResolutionRequest repositoryRequest,
-                                             ArtifactMetadataSource source, ArtifactFilter filter,
-                                             List<ResolutionListener> listeners,
-                                             List<ConflictResolver> conflictResolvers )
-    {
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactResolutionRequest repositoryRequest,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners,
+            List<ConflictResolver> conflictResolvers) {
         ArtifactResolutionResult result = new ArtifactResolutionResult();
 
-        result.setOriginatingArtifact( originatingArtifact );
+        result.setOriginatingArtifact(originatingArtifact);
 
-        if ( conflictResolvers == null )
-        {
-            conflictResolvers = Collections.singletonList( defaultConflictResolver );
+        if (conflictResolvers == null) {
+            conflictResolvers = Collections.singletonList(defaultConflictResolver);
         }
 
         Map<Object, List<ResolutionNode>> resolvedArtifacts = new LinkedHashMap<>();
 
-        ResolutionNode root = new ResolutionNode( originatingArtifact, repositoryRequest.getRemoteRepositories() );
+        ResolutionNode root = new ResolutionNode(originatingArtifact, repositoryRequest.getRemoteRepositories());
 
-        try
-        {
-            root.addDependencies( artifacts, repositoryRequest.getRemoteRepositories(), filter );
-        }
-        catch ( CyclicDependencyException e )
-        {
-            result.addCircularDependencyException( e );
+        try {
+            root.addDependencies(artifacts, repositoryRequest.getRemoteRepositories(), filter);
+        } catch (CyclicDependencyException e) {
+            result.addCircularDependencyException(e);
 
             return result;
-        }
-        catch ( OverConstrainedVersionException e )
-        {
-            result.addVersionRangeViolation( e );
+        } catch (OverConstrainedVersionException e) {
+            result.addVersionRangeViolation(e);
 
             return result;
         }
 
-        ManagedVersionMap versionMap = getManagedVersionsMap( originatingArtifact, managedVersions );
+        ManagedVersionMap versionMap = getManagedVersionsMap(originatingArtifact, managedVersions);
 
-        try
-        {
-            recurse( result, root, resolvedArtifacts, versionMap, repositoryRequest, source, filter, listeners,
-                     conflictResolvers );
-        }
-        catch ( CyclicDependencyException e )
-        {
-            logger.debug( "While recursing: " + e.getMessage(), e );
-            result.addCircularDependencyException( e );
-        }
-        catch ( OverConstrainedVersionException e )
-        {
-            logger.debug( "While recursing: " + e.getMessage(), e );
-            result.addVersionRangeViolation( e );
-        }
-        catch ( ArtifactResolutionException e )
-        {
-            logger.debug( "While recursing: " + e.getMessage(), e );
-            result.addErrorArtifactException( e );
+        try {
+            recurse(
+                    result,
+                    root,
+                    resolvedArtifacts,
+                    versionMap,
+                    repositoryRequest,
+                    source,
+                    filter,
+                    listeners,
+                    conflictResolvers);
+        } catch (CyclicDependencyException e) {
+            logger.debug("While recursing: " + e.getMessage(), e);
+            result.addCircularDependencyException(e);
+        } catch (OverConstrainedVersionException e) {
+            logger.debug("While recursing: " + e.getMessage(), e);
+            result.addVersionRangeViolation(e);
+        } catch (ArtifactResolutionException e) {
+            logger.debug("While recursing: " + e.getMessage(), e);
+            result.addErrorArtifactException(e);
         }
 
         Set<ResolutionNode> set = new LinkedHashSet<>();
 
-        for ( List<ResolutionNode> nodes : resolvedArtifacts.values() )
-        {
-            for ( ResolutionNode node : nodes )
-            {
-                if ( !node.equals( root ) && node.isActive() )
-                {
+        for (List<ResolutionNode> nodes : resolvedArtifacts.values()) {
+            for (ResolutionNode node : nodes) {
+                if (!node.equals(root) && node.isActive()) {
                     Artifact artifact = node.getArtifact();
 
-                    try
-                    {
-                        if ( node.filterTrail( filter ) )
-                        {
+                    try {
+                        if (node.filterTrail(filter)) {
                             // If it was optional and not a direct dependency,
                             // we don't add it or its children, just allow the update of the version and artifactScope
-                            if ( node.isChildOfRootNode() || !artifact.isOptional() )
-                            {
-                                artifact.setDependencyTrail( node.getDependencyTrail() );
+                            if (node.isChildOfRootNode() || !artifact.isOptional()) {
+                                artifact.setDependencyTrail(node.getDependencyTrail());
 
-                                set.add( node );
+                                set.add(node);
 
                                 // This is required right now.
-                                result.addArtifact( artifact );
+                                result.addArtifact(artifact);
                             }
                         }
-                    }
-                    catch ( OverConstrainedVersionException e )
-                    {
-                        result.addVersionRangeViolation( e );
+                    } catch (OverConstrainedVersionException e) {
+                        result.addVersionRangeViolation(e);
                     }
                 }
             }
         }
 
-        result.setArtifactResolutionNodes( set );
+        result.setArtifactResolutionNodes(set);
 
         return result;
     }
@@ -210,179 +200,158 @@
      * @param originatingArtifact artifact we are processing
      * @param managedVersions original managed versions
      */
-    private ManagedVersionMap getManagedVersionsMap( Artifact originatingArtifact,
-                                                     Map<String, Artifact> managedVersions )
-    {
+    private ManagedVersionMap getManagedVersionsMap(
+            Artifact originatingArtifact, Map<String, Artifact> managedVersions) {
         ManagedVersionMap versionMap;
-        if ( managedVersions instanceof ManagedVersionMap )
-        {
+        if (managedVersions instanceof ManagedVersionMap) {
             versionMap = (ManagedVersionMap) managedVersions;
-        }
-        else
-        {
-            versionMap = new ManagedVersionMap( managedVersions );
+        } else {
+            versionMap = new ManagedVersionMap(managedVersions);
         }
 
         // remove the originating artifact if it is also in managed versions to avoid being modified during resolution
-        Artifact managedOriginatingArtifact = versionMap.get( originatingArtifact.getDependencyConflictId() );
+        Artifact managedOriginatingArtifact = versionMap.get(originatingArtifact.getDependencyConflictId());
 
-        if ( managedOriginatingArtifact != null )
-        {
+        if (managedOriginatingArtifact != null) {
             // TODO we probably want to warn the user that he is building an artifact with
             // different values than in dependencyManagement
-            if ( managedVersions instanceof ManagedVersionMap )
-            {
+            if (managedVersions instanceof ManagedVersionMap) {
                 /* avoid modifying the managedVersions parameter creating a new map */
-                versionMap = new ManagedVersionMap( managedVersions );
+                versionMap = new ManagedVersionMap(managedVersions);
             }
-            versionMap.remove( originatingArtifact.getDependencyConflictId() );
+            versionMap.remove(originatingArtifact.getDependencyConflictId());
         }
 
         return versionMap;
     }
 
-    @SuppressWarnings( { "checkstyle:parameternumber", "checkstyle:methodlength" } )
-    private void recurse( ArtifactResolutionResult result, ResolutionNode node,
-                          Map<Object, List<ResolutionNode>> resolvedArtifacts, ManagedVersionMap managedVersions,
-                          ArtifactResolutionRequest request, ArtifactMetadataSource source, ArtifactFilter filter,
-                          List<ResolutionListener> listeners, List<ConflictResolver> conflictResolvers )
-        throws ArtifactResolutionException
-    {
-        fireEvent( ResolutionListener.TEST_ARTIFACT, listeners, node );
+    @SuppressWarnings({"checkstyle:parameternumber", "checkstyle:methodlength"})
+    private void recurse(
+            ArtifactResolutionResult result,
+            ResolutionNode node,
+            Map<Object, List<ResolutionNode>> resolvedArtifacts,
+            ManagedVersionMap managedVersions,
+            ArtifactResolutionRequest request,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners,
+            List<ConflictResolver> conflictResolvers)
+            throws ArtifactResolutionException {
+        fireEvent(ResolutionListener.TEST_ARTIFACT, listeners, node);
 
         Object key = node.getKey();
 
         // TODO Does this check need to happen here? Had to add the same call
         // below when we iterate on child nodes -- will that suffice?
-        if ( managedVersions.containsKey( key ) )
-        {
-            manageArtifact( node, managedVersions, listeners );
+        if (managedVersions.containsKey(key)) {
+            manageArtifact(node, managedVersions, listeners);
         }
 
-        List<ResolutionNode> previousNodes = resolvedArtifacts.get( key );
+        List<ResolutionNode> previousNodes = resolvedArtifacts.get(key);
 
-        if ( previousNodes != null )
-        {
-            for ( ResolutionNode previous : previousNodes )
-            {
-                try
-                {
-                    if ( previous.isActive() )
-                    {
+        if (previousNodes != null) {
+            for (ResolutionNode previous : previousNodes) {
+                try {
+                    if (previous.isActive()) {
                         // Version mediation
                         VersionRange previousRange = previous.getArtifact().getVersionRange();
                         VersionRange currentRange = node.getArtifact().getVersionRange();
 
-                        if ( ( previousRange != null ) && ( currentRange != null ) )
-                        {
+                        if ((previousRange != null) && (currentRange != null)) {
                             // TODO shouldn't need to double up on this work, only done for simplicity of handling
                             // recommended
                             // version but the restriction is identical
-                            VersionRange newRange = previousRange.restrict( currentRange );
+                            VersionRange newRange = previousRange.restrict(currentRange);
                             // TODO ick. this forces the OCE that should have come from the previous call. It is still
                             // correct
-                            if ( newRange.isSelectedVersionKnown( previous.getArtifact() ) )
-                            {
-                                fireEvent( ResolutionListener.RESTRICT_RANGE, listeners, node, previous.getArtifact(),
-                                           newRange );
+                            if (newRange.isSelectedVersionKnown(previous.getArtifact())) {
+                                fireEvent(
+                                        ResolutionListener.RESTRICT_RANGE,
+                                        listeners,
+                                        node,
+                                        previous.getArtifact(),
+                                        newRange);
                             }
-                            previous.getArtifact().setVersionRange( newRange );
-                            node.getArtifact().setVersionRange( currentRange.restrict( previousRange ) );
+                            previous.getArtifact().setVersionRange(newRange);
+                            node.getArtifact().setVersionRange(currentRange.restrict(previousRange));
 
                             // Select an appropriate available version from the (now restricted) range
                             // Note this version was selected before to get the appropriate POM
                             // But it was reset by the call to setVersionRange on restricting the version
-                            ResolutionNode[] resetNodes =
-                            {
-                                previous, node
-                            };
-                            for ( int j = 0; j < 2; j++ )
-                            {
+                            ResolutionNode[] resetNodes = {previous, node};
+                            for (int j = 0; j < 2; j++) {
                                 Artifact resetArtifact = resetNodes[j].getArtifact();
 
                                 // MNG-2123: if the previous node was not a range, then it wouldn't have any available
                                 // versions. We just clobbered the selected version above. (why? I have no idea.)
                                 // So since we are here and this is ranges we must go figure out the version (for a
                                 // third time...)
-                                if ( resetArtifact.getVersion() == null && resetArtifact.getVersionRange() != null )
-                                {
+                                if (resetArtifact.getVersion() == null && resetArtifact.getVersionRange() != null) {
 
                                     // go find the version. This is a total hack. See previous comment.
                                     List<ArtifactVersion> versions = resetArtifact.getAvailableVersions();
-                                    if ( versions == null )
-                                    {
-                                        try
-                                        {
+                                    if (versions == null) {
+                                        try {
                                             MetadataResolutionRequest metadataRequest =
-                                                new DefaultMetadataResolutionRequest( request );
+                                                    new DefaultMetadataResolutionRequest(request);
 
-                                            metadataRequest.setArtifact( resetArtifact );
-                                            versions = source.retrieveAvailableVersions( metadataRequest );
-                                            resetArtifact.setAvailableVersions( versions );
-                                        }
-                                        catch ( ArtifactMetadataRetrievalException e )
-                                        {
-                                            resetArtifact.setDependencyTrail( node.getDependencyTrail() );
+                                            metadataRequest.setArtifact(resetArtifact);
+                                            versions = source.retrieveAvailableVersions(metadataRequest);
+                                            resetArtifact.setAvailableVersions(versions);
+                                        } catch (ArtifactMetadataRetrievalException e) {
+                                            resetArtifact.setDependencyTrail(node.getDependencyTrail());
                                             throw new ArtifactResolutionException(
-                                                "Unable to get dependency information: "
-                                                    + e.getMessage(), resetArtifact, request.getRemoteRepositories(),
-                                                e );
-
+                                                    "Unable to get dependency information: " + e.getMessage(),
+                                                    resetArtifact,
+                                                    request.getRemoteRepositories(),
+                                                    e);
                                         }
                                     }
                                     // end hack
 
                                     // MNG-2861: match version can return null
-                                    ArtifactVersion selectedVersion = resetArtifact.getVersionRange().
-                                        matchVersion( resetArtifact.getAvailableVersions() );
+                                    ArtifactVersion selectedVersion = resetArtifact
+                                            .getVersionRange()
+                                            .matchVersion(resetArtifact.getAvailableVersions());
 
-                                    if ( selectedVersion != null )
-                                    {
-                                        resetArtifact.selectVersion( selectedVersion.toString() );
-                                    }
-                                    else
-                                    {
+                                    if (selectedVersion != null) {
+                                        resetArtifact.selectVersion(selectedVersion.toString());
+                                    } else {
                                         throw new OverConstrainedVersionException(
-                                            "Unable to find a version in " + resetArtifact.getAvailableVersions()
-                                                + " to match the range " + resetArtifact.getVersionRange(),
-                                            resetArtifact );
-
+                                                "Unable to find a version in " + resetArtifact.getAvailableVersions()
+                                                        + " to match the range " + resetArtifact.getVersionRange(),
+                                                resetArtifact);
                                     }
 
-                                    fireEvent( ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, resetNodes[j] );
+                                    fireEvent(ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, resetNodes[j]);
                                 }
                             }
                         }
 
                         // Conflict Resolution
                         ResolutionNode resolved = null;
-                        for ( Iterator<ConflictResolver> j = conflictResolvers.iterator();
-                              resolved == null && j.hasNext(); )
-                        {
+                        for (Iterator<ConflictResolver> j = conflictResolvers.iterator();
+                                resolved == null && j.hasNext(); ) {
                             ConflictResolver conflictResolver = j.next();
 
-                            resolved = conflictResolver.resolveConflict( previous, node );
+                            resolved = conflictResolver.resolveConflict(previous, node);
                         }
 
-                        if ( resolved == null )
-                        {
+                        if (resolved == null) {
                             // TODO add better exception that can detail the two conflicting artifacts
-                            ArtifactResolutionException are =
-                                new ArtifactResolutionException( "Cannot resolve artifact version conflict between "
-                                                                     + previous.getArtifact().getVersion() + " and "
-                                                                     + node.getArtifact().getVersion(),
-                                                                 previous.getArtifact() );
+                            ArtifactResolutionException are = new ArtifactResolutionException(
+                                    "Cannot resolve artifact version conflict between "
+                                            + previous.getArtifact().getVersion() + " and "
+                                            + node.getArtifact().getVersion(),
+                                    previous.getArtifact());
 
-                            result.addVersionRangeViolation( are );
+                            result.addVersionRangeViolation(are);
                         }
 
-                        if ( ( resolved != previous ) && ( resolved != node ) )
-                        {
+                        if ((resolved != previous) && (resolved != node)) {
                             // TODO add better exception
-                            result.addVersionRangeViolation( new ArtifactResolutionException(
-                                "Conflict resolver returned unknown resolution node: ",
-                                resolved.getArtifact() ) );
-
+                            result.addVersionRangeViolation(new ArtifactResolutionException(
+                                    "Conflict resolver returned unknown resolution node: ", resolved.getArtifact()));
                         }
 
                         // TODO should this be part of mediation?
@@ -390,176 +359,146 @@
                         ResolutionNode nearest;
                         ResolutionNode farthest;
 
-                        if ( resolved == previous )
-                        {
+                        if (resolved == previous) {
                             nearest = previous;
                             farthest = node;
-                        }
-                        else
-                        {
+                        } else {
                             nearest = node;
                             farthest = previous;
                         }
 
-                        if ( checkScopeUpdate( farthest, nearest, listeners ) )
-                        {
+                        if (checkScopeUpdate(farthest, nearest, listeners)) {
                             // if we need to update artifactScope of nearest to use farthest artifactScope, use the
                             // nearest version, but farthest artifactScope
                             nearest.disable();
-                            farthest.getArtifact().setVersion( nearest.getArtifact().getVersion() );
-                            fireEvent( ResolutionListener.OMIT_FOR_NEARER, listeners, nearest, farthest.getArtifact() );
-                        }
-                        else
-                        {
+                            farthest.getArtifact()
+                                    .setVersion(nearest.getArtifact().getVersion());
+                            fireEvent(ResolutionListener.OMIT_FOR_NEARER, listeners, nearest, farthest.getArtifact());
+                        } else {
                             farthest.disable();
-                            fireEvent( ResolutionListener.OMIT_FOR_NEARER, listeners, farthest, nearest.getArtifact() );
+                            fireEvent(ResolutionListener.OMIT_FOR_NEARER, listeners, farthest, nearest.getArtifact());
                         }
                     }
-                }
-                catch ( OverConstrainedVersionException e )
-                {
-                    result.addVersionRangeViolation( e );
+                } catch (OverConstrainedVersionException e) {
+                    result.addVersionRangeViolation(e);
                 }
             }
-        }
-        else
-        {
+        } else {
             previousNodes = new ArrayList<>();
 
-            resolvedArtifacts.put( key, previousNodes );
+            resolvedArtifacts.put(key, previousNodes);
         }
-        previousNodes.add( node );
+        previousNodes.add(node);
 
-        if ( node.isActive() )
-        {
-            fireEvent( ResolutionListener.INCLUDE_ARTIFACT, listeners, node );
+        if (node.isActive()) {
+            fireEvent(ResolutionListener.INCLUDE_ARTIFACT, listeners, node);
         }
 
         // don't pull in the transitive deps of a system-scoped dependency.
-        if ( node.isActive() && !Artifact.SCOPE_SYSTEM.equals( node.getArtifact().getScope() ) )
-        {
-            fireEvent( ResolutionListener.PROCESS_CHILDREN, listeners, node );
+        if (node.isActive() && !Artifact.SCOPE_SYSTEM.equals(node.getArtifact().getScope())) {
+            fireEvent(ResolutionListener.PROCESS_CHILDREN, listeners, node);
 
             Artifact parentArtifact = node.getArtifact();
 
-            for ( Iterator<ResolutionNode> i = node.getChildrenIterator(); i.hasNext(); )
-            {
+            for (Iterator<ResolutionNode> i = node.getChildrenIterator(); i.hasNext(); ) {
                 ResolutionNode child = i.next();
 
-                try
-                {
+                try {
 
                     // We leave in optional ones, but don't pick up its dependencies
-                    if ( !child.isResolved() && ( !child.getArtifact().isOptional() || child.isChildOfRootNode() ) )
-                    {
+                    if (!child.isResolved() && (!child.getArtifact().isOptional() || child.isChildOfRootNode())) {
                         Artifact artifact = child.getArtifact();
-                        artifact.setDependencyTrail( node.getDependencyTrail() );
+                        artifact.setDependencyTrail(node.getDependencyTrail());
                         List<ArtifactRepository> childRemoteRepositories = child.getRemoteRepositories();
 
-                        MetadataResolutionRequest metadataRequest =
-                            new DefaultMetadataResolutionRequest( request );
-                        metadataRequest.setArtifact( artifact );
-                        metadataRequest.setRemoteRepositories( childRemoteRepositories );
+                        MetadataResolutionRequest metadataRequest = new DefaultMetadataResolutionRequest(request);
+                        metadataRequest.setArtifact(artifact);
+                        metadataRequest.setRemoteRepositories(childRemoteRepositories);
 
-                        try
-                        {
+                        try {
                             ResolutionGroup rGroup;
 
                             Object childKey;
-                            do
-                            {
+                            do {
                                 childKey = child.getKey();
 
-                                if ( managedVersions.containsKey( childKey ) )
-                                {
+                                if (managedVersions.containsKey(childKey)) {
                                     // If this child node is a managed dependency, ensure
                                     // we are using the dependency management version
                                     // of this child if applicable b/c we want to use the
                                     // managed version's POM, *not* any other version's POM.
                                     // We retrieve the POM below in the retrieval step.
-                                    manageArtifact( child, managedVersions, listeners );
+                                    manageArtifact(child, managedVersions, listeners);
 
                                     // Also, we need to ensure that any exclusions it presents are
                                     // added to the artifact before we retrieve the metadata
                                     // for the artifact; otherwise we may end up with unwanted
                                     // dependencies.
-                                    Artifact ma = managedVersions.get( childKey );
+                                    Artifact ma = managedVersions.get(childKey);
                                     ArtifactFilter managedExclusionFilter = ma.getDependencyFilter();
-                                    if ( null != managedExclusionFilter )
-                                    {
-                                        if ( null != artifact.getDependencyFilter() )
-                                        {
+                                    if (null != managedExclusionFilter) {
+                                        if (null != artifact.getDependencyFilter()) {
                                             AndArtifactFilter aaf = new AndArtifactFilter();
-                                            aaf.add( artifact.getDependencyFilter() );
-                                            aaf.add( managedExclusionFilter );
-                                            artifact.setDependencyFilter( aaf );
-                                        }
-                                        else
-                                        {
-                                            artifact.setDependencyFilter( managedExclusionFilter );
+                                            aaf.add(artifact.getDependencyFilter());
+                                            aaf.add(managedExclusionFilter);
+                                            artifact.setDependencyFilter(aaf);
+                                        } else {
+                                            artifact.setDependencyFilter(managedExclusionFilter);
                                         }
                                     }
                                 }
 
-                                if ( artifact.getVersion() == null )
-                                {
+                                if (artifact.getVersion() == null) {
                                     // set the recommended version
                                     // TODO maybe its better to just pass the range through to retrieval and use a
                                     // transformation?
                                     ArtifactVersion version;
-                                    if ( !artifact.isSelectedVersionKnown() )
-                                    {
+                                    if (!artifact.isSelectedVersionKnown()) {
                                         List<ArtifactVersion> versions = artifact.getAvailableVersions();
-                                        if ( versions == null )
-                                        {
-                                            versions = source.retrieveAvailableVersions( metadataRequest );
-                                            artifact.setAvailableVersions( versions );
+                                        if (versions == null) {
+                                            versions = source.retrieveAvailableVersions(metadataRequest);
+                                            artifact.setAvailableVersions(versions);
                                         }
 
-                                        Collections.sort( versions );
+                                        Collections.sort(versions);
 
                                         VersionRange versionRange = artifact.getVersionRange();
 
-                                        version = versionRange.matchVersion( versions );
+                                        version = versionRange.matchVersion(versions);
 
-                                        if ( version == null )
-                                        {
-                                            if ( versions.isEmpty() )
-                                            {
+                                        if (version == null) {
+                                            if (versions.isEmpty()) {
                                                 throw new OverConstrainedVersionException(
-                                                    "No versions are present in the repository for the artifact"
-                                                        + " with a range " + versionRange, artifact,
-                                                    childRemoteRepositories );
-
+                                                        "No versions are present in the repository for the artifact"
+                                                                + " with a range " + versionRange,
+                                                        artifact,
+                                                        childRemoteRepositories);
                                             }
 
                                             throw new OverConstrainedVersionException(
-                                                "Couldn't find a version in " + versions + " to match range "
-                                                    + versionRange, artifact, childRemoteRepositories );
-
+                                                    "Couldn't find a version in " + versions + " to match range "
+                                                            + versionRange,
+                                                    artifact,
+                                                    childRemoteRepositories);
                                         }
-                                    }
-                                    else
-                                    {
+                                    } else {
                                         version = artifact.getSelectedVersion();
                                     }
 
-                                    artifact.selectVersion( version.toString() );
-                                    fireEvent( ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, child );
+                                    artifact.selectVersion(version.toString());
+                                    fireEvent(ResolutionListener.SELECT_VERSION_FROM_RANGE, listeners, child);
                                 }
 
-                                rGroup = source.retrieve( metadataRequest );
+                                rGroup = source.retrieve(metadataRequest);
 
-                                if ( rGroup == null )
-                                {
+                                if (rGroup == null) {
                                     break;
                                 }
-                            }
-                            while ( !childKey.equals( child.getKey() ) );
+                            } while (!childKey.equals(child.getKey()));
 
-                            if ( parentArtifact != null && parentArtifact.getDependencyFilter() != null
-                                     && !parentArtifact.getDependencyFilter().include( artifact ) )
-                            {
+                            if (parentArtifact != null
+                                    && parentArtifact.getDependencyFilter() != null
+                                    && !parentArtifact.getDependencyFilter().include(artifact)) {
                                 // MNG-3769: the [probably relocated] artifact is excluded.
                                 // We could process exclusions on relocated artifact details in the
                                 // MavenMetadataSource.createArtifacts(..) step, BUT that would
@@ -571,60 +510,61 @@
                             // TODO might be better to have source.retrieve() throw a specific exception for this
                             // situation
                             // and catch here rather than have it return null
-                            if ( rGroup == null )
-                            {
+                            if (rGroup == null) {
                                 // relocated dependency artifact is declared excluded, no need to add and recurse
                                 // further
                                 continue;
                             }
 
-                            child.addDependencies( rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter );
+                            child.addDependencies(rGroup.getArtifacts(), rGroup.getResolutionRepositories(), filter);
 
-                        }
-                        catch ( CyclicDependencyException e )
-                        {
+                        } catch (CyclicDependencyException e) {
                             // would like to throw this, but we have crappy stuff in the repo
 
-                            fireEvent( ResolutionListener.OMIT_FOR_CYCLE, listeners,
-                                       new ResolutionNode( e.getArtifact(), childRemoteRepositories, child ) );
-                        }
-                        catch ( ArtifactMetadataRetrievalException e )
-                        {
-                            artifact.setDependencyTrail( node.getDependencyTrail() );
+                            fireEvent(
+                                    ResolutionListener.OMIT_FOR_CYCLE,
+                                    listeners,
+                                    new ResolutionNode(e.getArtifact(), childRemoteRepositories, child));
+                        } catch (ArtifactMetadataRetrievalException e) {
+                            artifact.setDependencyTrail(node.getDependencyTrail());
 
-                            throw new ArtifactResolutionException( "Unable to get dependency information for "
-                                                                       + artifact.getId() + ": " + e.getMessage(),
-                                                                   artifact, childRemoteRepositories, e );
-
+                            throw new ArtifactResolutionException(
+                                    "Unable to get dependency information for " + artifact.getId() + ": "
+                                            + e.getMessage(),
+                                    artifact,
+                                    childRemoteRepositories,
+                                    e);
                         }
 
-                        ArtifactResolutionRequest subRequest = new ArtifactResolutionRequest( metadataRequest );
-                        subRequest.setServers( request.getServers() );
-                        subRequest.setMirrors( request.getMirrors() );
-                        subRequest.setProxies( request.getProxies() );
-                        recurse( result, child, resolvedArtifacts, managedVersions, subRequest, source, filter,
-                                 listeners, conflictResolvers );
-
+                        ArtifactResolutionRequest subRequest = new ArtifactResolutionRequest(metadataRequest);
+                        subRequest.setServers(request.getServers());
+                        subRequest.setMirrors(request.getMirrors());
+                        subRequest.setProxies(request.getProxies());
+                        recurse(
+                                result,
+                                child,
+                                resolvedArtifacts,
+                                managedVersions,
+                                subRequest,
+                                source,
+                                filter,
+                                listeners,
+                                conflictResolvers);
                     }
-                }
-                catch ( OverConstrainedVersionException e )
-                {
-                    result.addVersionRangeViolation( e );
-                }
-                catch ( ArtifactResolutionException e )
-                {
-                    result.addMetadataResolutionException( e );
+                } catch (OverConstrainedVersionException e) {
+                    result.addVersionRangeViolation(e);
+                } catch (ArtifactResolutionException e) {
+                    result.addMetadataResolutionException(e);
                 }
             }
 
-            fireEvent( ResolutionListener.FINISH_PROCESSING_CHILDREN, listeners, node );
+            fireEvent(ResolutionListener.FINISH_PROCESSING_CHILDREN, listeners, node);
         }
     }
 
-    private void manageArtifact( ResolutionNode node, ManagedVersionMap managedVersions,
-                                 List<ResolutionListener> listeners )
-    {
-        Artifact artifact = managedVersions.get( node.getKey() );
+    private void manageArtifact(
+            ResolutionNode node, ManagedVersionMap managedVersions, List<ResolutionListener> listeners) {
+        Artifact artifact = managedVersions.get(node.getKey());
 
         // Before we update the version of the artifact, we need to know
         // whether we are working on a transitive dependency or not. This
@@ -632,24 +572,23 @@
         // explicit child override depMgmt (viz. depMgmt should only
         // provide defaults to children, but should override transitives).
         // We can do this by calling isChildOfRootNode on the current node.
-        if ( ( artifact.getVersion() != null )
-                 && ( !node.isChildOfRootNode() || node.getArtifact().getVersion() == null ) )
-        {
-            fireEvent( ResolutionListener.MANAGE_ARTIFACT_VERSION, listeners, node, artifact );
-            node.getArtifact().setVersion( artifact.getVersion() );
+        if ((artifact.getVersion() != null)
+                && (!node.isChildOfRootNode() || node.getArtifact().getVersion() == null)) {
+            fireEvent(ResolutionListener.MANAGE_ARTIFACT_VERSION, listeners, node, artifact);
+            node.getArtifact().setVersion(artifact.getVersion());
         }
 
-        if ( ( artifact.getScope() != null ) && ( !node.isChildOfRootNode() || node.getArtifact().getScope() == null ) )
-        {
-            fireEvent( ResolutionListener.MANAGE_ARTIFACT_SCOPE, listeners, node, artifact );
-            node.getArtifact().setScope( artifact.getScope() );
+        if ((artifact.getScope() != null)
+                && (!node.isChildOfRootNode() || node.getArtifact().getScope() == null)) {
+            fireEvent(ResolutionListener.MANAGE_ARTIFACT_SCOPE, listeners, node, artifact);
+            node.getArtifact().setScope(artifact.getScope());
         }
 
-        if ( Artifact.SCOPE_SYSTEM.equals( node.getArtifact().getScope() ) && ( node.getArtifact().getFile() == null )
-                 && ( artifact.getFile() != null ) )
-        {
-            fireEvent( ResolutionListener.MANAGE_ARTIFACT_SYSTEM_PATH, listeners, node, artifact );
-            node.getArtifact().setFile( artifact.getFile() );
+        if (Artifact.SCOPE_SYSTEM.equals(node.getArtifact().getScope())
+                && (node.getArtifact().getFile() == null)
+                && (artifact.getFile() != null)) {
+            fireEvent(ResolutionListener.MANAGE_ARTIFACT_SYSTEM_PATH, listeners, node, artifact);
+            node.getArtifact().setFile(artifact.getFile());
         }
     }
 
@@ -661,158 +600,154 @@
      * @param nearest nearest resolution node
      * @param listeners
      */
-    boolean checkScopeUpdate( ResolutionNode farthest, ResolutionNode nearest, List<ResolutionListener> listeners )
-    {
+    boolean checkScopeUpdate(ResolutionNode farthest, ResolutionNode nearest, List<ResolutionListener> listeners) {
         boolean updateScope = false;
         Artifact farthestArtifact = farthest.getArtifact();
         Artifact nearestArtifact = nearest.getArtifact();
 
         /* farthest is runtime and nearest has lower priority, change to runtime */
-        if ( Artifact.SCOPE_RUNTIME.equals( farthestArtifact.getScope() )
-                 && ( Artifact.SCOPE_TEST.equals( nearestArtifact.getScope() )
-                      || Artifact.SCOPE_PROVIDED.equals( nearestArtifact.getScope() ) ) )
-        {
+        if (Artifact.SCOPE_RUNTIME.equals(farthestArtifact.getScope())
+                && (Artifact.SCOPE_TEST.equals(nearestArtifact.getScope())
+                        || Artifact.SCOPE_PROVIDED.equals(nearestArtifact.getScope()))) {
             updateScope = true;
         }
 
         /* farthest is compile and nearest is not (has lower priority), change to compile */
-        if ( Artifact.SCOPE_COMPILE.equals( farthestArtifact.getScope() )
-                 && !Artifact.SCOPE_COMPILE.equals( nearestArtifact.getScope() ) )
-        {
+        if (Artifact.SCOPE_COMPILE.equals(farthestArtifact.getScope())
+                && !Artifact.SCOPE_COMPILE.equals(nearestArtifact.getScope())) {
             updateScope = true;
         }
 
         /* current POM rules all, if nearest is in current pom, do not update its artifactScope */
-        if ( ( nearest.getDepth() < 2 ) && updateScope )
-        {
+        if ((nearest.getDepth() < 2) && updateScope) {
             updateScope = false;
 
-            fireEvent( ResolutionListener.UPDATE_SCOPE_CURRENT_POM, listeners, nearest, farthestArtifact );
+            fireEvent(ResolutionListener.UPDATE_SCOPE_CURRENT_POM, listeners, nearest, farthestArtifact);
         }
 
-        if ( updateScope )
-        {
-            fireEvent( ResolutionListener.UPDATE_SCOPE, listeners, nearest, farthestArtifact );
+        if (updateScope) {
+            fireEvent(ResolutionListener.UPDATE_SCOPE, listeners, nearest, farthestArtifact);
 
             // previously we cloned the artifact, but it is more efficient to just update the artifactScope
             // if problems are later discovered that the original object needs its original artifactScope value,
             // cloning may
             // again be appropriate
-            nearestArtifact.setScope( farthestArtifact.getScope() );
+            nearestArtifact.setScope(farthestArtifact.getScope());
         }
 
         return updateScope;
     }
 
-    private void fireEvent( int event, List<ResolutionListener> listeners, ResolutionNode node )
-    {
-        fireEvent( event, listeners, node, null );
+    private void fireEvent(int event, List<ResolutionListener> listeners, ResolutionNode node) {
+        fireEvent(event, listeners, node, null);
     }
 
-    private void fireEvent( int event, List<ResolutionListener> listeners, ResolutionNode node, Artifact replacement )
-    {
-        fireEvent( event, listeners, node, replacement, null );
+    private void fireEvent(int event, List<ResolutionListener> listeners, ResolutionNode node, Artifact replacement) {
+        fireEvent(event, listeners, node, replacement, null);
     }
 
-    private void fireEvent( int event, List<ResolutionListener> listeners, ResolutionNode node, Artifact replacement,
-                            VersionRange newRange )
-    {
-        for ( ResolutionListener listener : listeners )
-        {
-            switch ( event )
-            {
+    private void fireEvent(
+            int event,
+            List<ResolutionListener> listeners,
+            ResolutionNode node,
+            Artifact replacement,
+            VersionRange newRange) {
+        for (ResolutionListener listener : listeners) {
+            switch (event) {
                 case ResolutionListener.TEST_ARTIFACT:
-                    listener.testArtifact( node.getArtifact() );
+                    listener.testArtifact(node.getArtifact());
                     break;
                 case ResolutionListener.PROCESS_CHILDREN:
-                    listener.startProcessChildren( node.getArtifact() );
+                    listener.startProcessChildren(node.getArtifact());
                     break;
                 case ResolutionListener.FINISH_PROCESSING_CHILDREN:
-                    listener.endProcessChildren( node.getArtifact() );
+                    listener.endProcessChildren(node.getArtifact());
                     break;
                 case ResolutionListener.INCLUDE_ARTIFACT:
-                    listener.includeArtifact( node.getArtifact() );
+                    listener.includeArtifact(node.getArtifact());
                     break;
                 case ResolutionListener.OMIT_FOR_NEARER:
-                    listener.omitForNearer( node.getArtifact(), replacement );
+                    listener.omitForNearer(node.getArtifact(), replacement);
                     break;
                 case ResolutionListener.OMIT_FOR_CYCLE:
-                    listener.omitForCycle( node.getArtifact() );
+                    listener.omitForCycle(node.getArtifact());
                     break;
                 case ResolutionListener.UPDATE_SCOPE:
-                    listener.updateScope( node.getArtifact(), replacement.getScope() );
+                    listener.updateScope(node.getArtifact(), replacement.getScope());
                     break;
                 case ResolutionListener.UPDATE_SCOPE_CURRENT_POM:
-                    listener.updateScopeCurrentPom( node.getArtifact(), replacement.getScope() );
+                    listener.updateScopeCurrentPom(node.getArtifact(), replacement.getScope());
                     break;
                 case ResolutionListener.MANAGE_ARTIFACT_VERSION:
-                    if ( listener instanceof ResolutionListenerForDepMgmt )
-                    {
+                    if (listener instanceof ResolutionListenerForDepMgmt) {
                         ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
-                        asImpl.manageArtifactVersion( node.getArtifact(), replacement );
-                    }
-                    else
-                    {
-                        listener.manageArtifact( node.getArtifact(), replacement );
+                        asImpl.manageArtifactVersion(node.getArtifact(), replacement);
+                    } else {
+                        listener.manageArtifact(node.getArtifact(), replacement);
                     }
                     break;
                 case ResolutionListener.MANAGE_ARTIFACT_SCOPE:
-                    if ( listener instanceof ResolutionListenerForDepMgmt )
-                    {
+                    if (listener instanceof ResolutionListenerForDepMgmt) {
                         ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
-                        asImpl.manageArtifactScope( node.getArtifact(), replacement );
-                    }
-                    else
-                    {
-                        listener.manageArtifact( node.getArtifact(), replacement );
+                        asImpl.manageArtifactScope(node.getArtifact(), replacement);
+                    } else {
+                        listener.manageArtifact(node.getArtifact(), replacement);
                     }
                     break;
                 case ResolutionListener.MANAGE_ARTIFACT_SYSTEM_PATH:
-                    if ( listener instanceof ResolutionListenerForDepMgmt )
-                    {
+                    if (listener instanceof ResolutionListenerForDepMgmt) {
                         ResolutionListenerForDepMgmt asImpl = (ResolutionListenerForDepMgmt) listener;
-                        asImpl.manageArtifactSystemPath( node.getArtifact(), replacement );
-                    }
-                    else
-                    {
-                        listener.manageArtifact( node.getArtifact(), replacement );
+                        asImpl.manageArtifactSystemPath(node.getArtifact(), replacement);
+                    } else {
+                        listener.manageArtifact(node.getArtifact(), replacement);
                     }
                     break;
                 case ResolutionListener.SELECT_VERSION_FROM_RANGE:
-                    listener.selectVersionFromRange( node.getArtifact() );
+                    listener.selectVersionFromRange(node.getArtifact());
                     break;
                 case ResolutionListener.RESTRICT_RANGE:
-                    if ( node.getArtifact().getVersionRange().hasRestrictions()
-                             || replacement.getVersionRange().hasRestrictions() )
-                    {
-                        listener.restrictRange( node.getArtifact(), replacement, newRange );
+                    if (node.getArtifact().getVersionRange().hasRestrictions()
+                            || replacement.getVersionRange().hasRestrictions()) {
+                        listener.restrictRange(node.getArtifact(), replacement, newRange);
                     }
                     break;
                 default:
-                    throw new IllegalStateException( "Unknown event: " + event );
+                    throw new IllegalStateException("Unknown event: " + event);
             }
         }
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                             Map<String, Artifact> managedVersions, ArtifactRepository localRepository,
-                                             List<ArtifactRepository> remoteRepositories,
-                                             ArtifactMetadataSource source, ArtifactFilter filter,
-                                             List<ResolutionListener> listeners )
-    {
-        return collect( artifacts, originatingArtifact, managedVersions, localRepository, remoteRepositories, source,
-                        filter, listeners, null );
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners) {
+        return collect(
+                artifacts,
+                originatingArtifact,
+                managedVersions,
+                localRepository,
+                remoteRepositories,
+                source,
+                filter,
+                listeners,
+                null);
     }
 
-    public ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                             ArtifactRepository localRepository,
-                                             List<ArtifactRepository> remoteRepositories,
-                                             ArtifactMetadataSource source, ArtifactFilter filter,
-                                             List<ResolutionListener> listeners )
-    {
-        return collect( artifacts, originatingArtifact, null, localRepository, remoteRepositories, source, filter,
-                        listeners );
+    public ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners) {
+        return collect(
+                artifacts, originatingArtifact, null, localRepository, remoteRepositories, source, filter, listeners);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/LegacyArtifactCollector.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/LegacyArtifactCollector.java
index 90b869f..945a1e2 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/LegacyArtifactCollector.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/LegacyArtifactCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver;
 
 import java.util.List;
 import java.util.Map;
@@ -36,31 +35,41 @@
  * Artifact collector - takes a set of original artifacts and resolves all of the best versions to use
  * along with their metadata. No artifacts are downloaded.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
 @Deprecated
-@SuppressWarnings( "checkstyle:parameternumber" )
-public interface LegacyArtifactCollector
-{
+@SuppressWarnings("checkstyle:parameternumber")
+public interface LegacyArtifactCollector {
 
-    ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                      Map<String, Artifact> managedVersions,
-                                      ArtifactResolutionRequest repositoryRequest, ArtifactMetadataSource source,
-                                      ArtifactFilter filter, List<ResolutionListener> listeners,
-                                      List<ConflictResolver> conflictResolvers );
+    ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactResolutionRequest repositoryRequest,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners,
+            List<ConflictResolver> conflictResolvers);
 
-    ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                      Map<String, Artifact> managedVersions,
-                                      ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories,
-                                      ArtifactMetadataSource source, ArtifactFilter filter,
-                                      List<ResolutionListener> listeners, List<ConflictResolver> conflictResolvers );
+    ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners,
+            List<ConflictResolver> conflictResolvers);
 
     // used by maven-dependency-tree and maven-dependency-plugin
     @Deprecated
-    ArtifactResolutionResult collect( Set<Artifact> artifacts, Artifact originatingArtifact,
-                                      Map<String, Artifact> managedVersions,
-                                      ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories,
-                                      ArtifactMetadataSource source, ArtifactFilter filter,
-                                      List<ResolutionListener> listeners );
-
+    ArtifactResolutionResult collect(
+            Set<Artifact> artifacts,
+            Artifact originatingArtifact,
+            Map<String, Artifact> managedVersions,
+            ArtifactRepository localRepository,
+            List<ArtifactRepository> remoteRepositories,
+            ArtifactMetadataSource source,
+            ArtifactFilter filter,
+            List<ResolutionListener> listeners);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolver.java
index 4d129b7..00846bf 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
 
 /**
  * Determines which version of an artifact to use when there are conflicting declarations.
  *
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  */
-public interface ConflictResolver
-{
+@Deprecated
+public interface ConflictResolver {
     String ROLE = ConflictResolver.class.getName();
 
     /**
@@ -40,5 +37,5 @@
      *         this conflict cannot be resolved
      * @since 3.0
      */
-    ResolutionNode resolveConflict( ResolutionNode node1, ResolutionNode node2 );
+    ResolutionNode resolveConflict(ResolutionNode node1, ResolutionNode node2);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverFactory.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverFactory.java
index 8f3f9f4..ecda460 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverFactory.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
 /**
  * A factory that produces conflict resolvers of various types.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @see ConflictResolver
  * @since 3.0
  */
-public interface ConflictResolverFactory
-{
+@Deprecated
+public interface ConflictResolverFactory {
     // constants --------------------------------------------------------------
 
     /** The plexus role for this component. */
@@ -43,6 +41,5 @@
      * @throws ConflictResolverNotFoundException
      *          if the specified type was not found
      */
-    ConflictResolver getConflictResolver( String type )
-        throws ConflictResolverNotFoundException;
+    ConflictResolver getConflictResolver(String type) throws ConflictResolverNotFoundException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverNotFoundException.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverNotFoundException.java
index b5f61ed..e8213c4 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverNotFoundException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/ConflictResolverNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
 /**
  * Indicates that a specified conflict resolver implementation could not be found.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @since 3.0
  */
-public class ConflictResolverNotFoundException
-    extends Exception
-{
+@Deprecated
+public class ConflictResolverNotFoundException extends Exception {
     // constants --------------------------------------------------------------
 
     /** The serial version ID. */
@@ -40,8 +37,7 @@
      *
      * @param message the message
      */
-    public ConflictResolverNotFoundException( String message )
-    {
-        super( message );
+    public ConflictResolverNotFoundException(String message) {
+        super(message);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolver.java
index 76f1929..a3a0680 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
-import org.codehaus.plexus.component.annotations.Component;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 /**
  * The default conflict resolver that delegates to the nearest strategy.
  *
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  * @see NearestConflictResolver
  * @deprecated As of 3.0, use a specific implementation instead, e.g. {@link NearestConflictResolver}
  */
 @Deprecated
-@Component( role = ConflictResolver.class )
-public class DefaultConflictResolver
-    extends NearestConflictResolver
-{
-}
+@Named
+@Singleton
+public class DefaultConflictResolver extends NearestConflictResolver {}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolverFactory.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolverFactory.java
index 9192b18..cfe9cd4 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolverFactory.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/DefaultConflictResolverFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,11 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.codehaus.plexus.PlexusConstants;
 import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.context.Context;
 import org.codehaus.plexus.context.ContextException;
@@ -31,38 +32,32 @@
 /**
  * A conflict resolver factory that obtains instances from a plexus container.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * TODO you don't need the container in here with the active maps (jvz).
  * @since 3.0
  */
-@Component( role = ConflictResolverFactory.class )
-public class DefaultConflictResolverFactory
-    implements ConflictResolverFactory, Contextualizable
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultConflictResolverFactory implements ConflictResolverFactory, Contextualizable {
     // fields -----------------------------------------------------------------
 
     /**
      * The plexus container used to obtain instances from.
      */
-    @Requirement
+    @Inject
     private PlexusContainer container;
 
     // ConflictResolverFactory methods ----------------------------------------
 
     /*
-    * @see org.apache.maven.artifact.resolver.conflict.ConflictResolverFactory#getConflictResolver(java.lang.String)
-    */
+     * @see org.apache.maven.artifact.resolver.conflict.ConflictResolverFactory#getConflictResolver(java.lang.String)
+     */
 
-    public ConflictResolver getConflictResolver( String type )
-        throws ConflictResolverNotFoundException
-    {
-        try
-        {
-            return (ConflictResolver) container.lookup( ConflictResolver.ROLE, type );
-        }
-        catch ( ComponentLookupException exception )
-        {
-            throw new ConflictResolverNotFoundException( "Cannot find conflict resolver of type: " + type );
+    public ConflictResolver getConflictResolver(String type) throws ConflictResolverNotFoundException {
+        try {
+            return (ConflictResolver) container.lookup(ConflictResolver.ROLE, type);
+        } catch (ComponentLookupException exception) {
+            throw new ConflictResolverNotFoundException("Cannot find conflict resolver of type: " + type);
         }
     }
 
@@ -72,9 +67,7 @@
      * @see org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable#contextualize(org.codehaus.plexus.context.Context)
      */
 
-    public void contextualize( Context context )
-        throws ContextException
-    {
-        container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
+    public void contextualize(Context context) throws ContextException {
+        container = (PlexusContainer) context.get(PlexusConstants.PLEXUS_KEY);
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolver.java
index 726e9a6..b3dc477 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,30 +16,31 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * Resolves conflicting artifacts by always selecting the <em>farthest</em> declaration. Farthest is defined as the
  * declaration that has the most transitive steps away from the project being built.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @since 3.0
  */
-@Component( role = ConflictResolver.class, hint = "farthest" )
-public class FarthestConflictResolver
-    implements ConflictResolver
-{
+@Named("farthest")
+@Singleton
+@Deprecated
+public class FarthestConflictResolver implements ConflictResolver {
     // ConflictResolver methods -----------------------------------------------
 
     /*
-    * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
-    *      org.apache.maven.artifact.resolver.ResolutionNode)
-    */
+     * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
+     *      org.apache.maven.artifact.resolver.ResolutionNode)
+     */
 
-    public ResolutionNode resolveConflict( ResolutionNode node1, ResolutionNode node2 )
-    {
+    public ResolutionNode resolveConflict(ResolutionNode node1, ResolutionNode node2) {
         return node1.getDepth() >= node2.getDepth() ? node1 : node2;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver.java
index 338baed..7d2bccc 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,31 +16,31 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * Resolves conflicting artifacts by always selecting the <em>nearest</em> declaration. Nearest is defined as the
  * declaration that has the least transitive steps away from the project being built.
  *
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @since 3.0
  */
-@Component( role = ConflictResolver.class, hint = "nearest" )
-public class NearestConflictResolver
-    implements ConflictResolver
-{
+@Named("nearest")
+@Singleton
+@Deprecated
+public class NearestConflictResolver implements ConflictResolver {
     // ConflictResolver methods -----------------------------------------------
 
     /*
-    * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
-    *      org.apache.maven.artifact.resolver.ResolutionNode)
-    */
+     * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
+     *      org.apache.maven.artifact.resolver.ResolutionNode)
+     */
 
-    public ResolutionNode resolveConflict( ResolutionNode node1, ResolutionNode node2 )
-    {
+    public ResolutionNode resolveConflict(ResolutionNode node1, ResolutionNode node2) {
         return node1.getDepth() <= node2.getDepth() ? node1 : node2;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolver.java
index e5bf558..10cadb2 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,42 +16,40 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * Resolves conflicting artifacts by always selecting the <em>newest</em> declaration. Newest is defined as the
  * declaration whose version is greater according to <code>ArtifactVersion.compareTo</code>.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @see ArtifactVersion#compareTo
  * @since 3.0
  */
-@Component( role = ConflictResolver.class, hint = "newest" )
-public class NewestConflictResolver
-    implements ConflictResolver
-{
+@Named("newest")
+@Singleton
+@Deprecated
+public class NewestConflictResolver implements ConflictResolver {
     // ConflictResolver methods -----------------------------------------------
 
     /*
-    * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
-    *      org.apache.maven.artifact.resolver.ResolutionNode)
-    */
+     * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
+     *      org.apache.maven.artifact.resolver.ResolutionNode)
+     */
 
-    public ResolutionNode resolveConflict( ResolutionNode node1, ResolutionNode node2 )
-    {
-        try
-        {
+    public ResolutionNode resolveConflict(ResolutionNode node1, ResolutionNode node2) {
+        try {
             ArtifactVersion version1 = node1.getArtifact().getSelectedVersion();
             ArtifactVersion version2 = node2.getArtifact().getSelectedVersion();
 
-            return version1.compareTo( version2 ) > 0 ? node1 : node2;
-        }
-        catch ( OverConstrainedVersionException exception )
-        {
+            return version1.compareTo(version2) > 0 ? node1 : node2;
+        } catch (OverConstrainedVersionException exception) {
             // TODO log message or throw exception?
 
             return null;
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolver.java
index d5e880c..bd15924 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,42 +16,40 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * Resolves conflicting artifacts by always selecting the <em>oldest</em> declaration. Oldest is defined as the
  * declaration whose version is less according to <code>ArtifactVersion.compareTo</code>.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @see ArtifactVersion#compareTo
  * @since 3.0
  */
-@Component( role = ConflictResolver.class, hint = "oldest" )
-public class OldestConflictResolver
-    implements ConflictResolver
-{
+@Named("oldest")
+@Singleton
+@Deprecated
+public class OldestConflictResolver implements ConflictResolver {
     // ConflictResolver methods -----------------------------------------------
 
     /*
-    * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
-    *      org.apache.maven.artifact.resolver.ResolutionNode)
-    */
+     * @see org.apache.maven.artifact.resolver.conflict.ConflictResolver#resolveConflict(org.apache.maven.artifact.resolver.ResolutionNode,
+     *      org.apache.maven.artifact.resolver.ResolutionNode)
+     */
 
-    public ResolutionNode resolveConflict( ResolutionNode node1, ResolutionNode node2 )
-    {
-        try
-        {
+    public ResolutionNode resolveConflict(ResolutionNode node1, ResolutionNode node2) {
+        try {
             ArtifactVersion version1 = node1.getArtifact().getSelectedVersion();
             ArtifactVersion version2 = node2.getArtifact().getSelectedVersion();
 
-            return version1.compareTo( version2 ) <= 0 ? node1 : node2;
-        }
-        catch ( OverConstrainedVersionException exception )
-        {
+            return version1.compareTo(version2) <= 0 ? node1 : node2;
+        } catch (OverConstrainedVersionException exception) {
             // TODO log message or throw exception?
 
             return null;
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/AbstractVersionTransformation.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/AbstractVersionTransformation.java
index 1ce5458..f86ea3b 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/AbstractVersionTransformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/AbstractVersionTransformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.transform;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.transform;
+
+import javax.inject.Inject;
 
 import java.util.List;
 
@@ -35,101 +36,82 @@
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
 import org.apache.maven.repository.legacy.WagonManager;
-import org.codehaus.plexus.component.annotations.Requirement;
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 
 /**
  * Describes a version transformation during artifact resolution.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  * TODO try and refactor to remove abstract methods - not particular happy about current design
  */
-public abstract class AbstractVersionTransformation
-    extends AbstractLogEnabled
-    implements ArtifactTransformation
-{
-    @Requirement
+@Deprecated
+public abstract class AbstractVersionTransformation extends AbstractLogEnabled implements ArtifactTransformation {
+    @Inject
     protected RepositoryMetadataManager repositoryMetadataManager;
 
-    @Requirement
+    @Inject
     protected WagonManager wagonManager;
 
-    public void transformForResolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                     ArtifactRepository localRepository )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
+    public void transformForResolve(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
         RepositoryRequest request = new DefaultRepositoryRequest();
-        request.setLocalRepository( localRepository );
-        request.setRemoteRepositories( remoteRepositories );
-        transformForResolve( artifact, request );
+        request.setLocalRepository(localRepository);
+        request.setRemoteRepositories(remoteRepositories);
+        transformForResolve(artifact, request);
     }
 
-    protected String resolveVersion( Artifact artifact, ArtifactRepository localRepository,
-                                     List<ArtifactRepository> remoteRepositories )
-        throws RepositoryMetadataResolutionException
-    {
+    protected String resolveVersion(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws RepositoryMetadataResolutionException {
         RepositoryRequest request = new DefaultRepositoryRequest();
-        request.setLocalRepository( localRepository );
-        request.setRemoteRepositories( remoteRepositories );
-        return resolveVersion( artifact, request );
+        request.setLocalRepository(localRepository);
+        request.setRemoteRepositories(remoteRepositories);
+        return resolveVersion(artifact, request);
     }
 
-    protected String resolveVersion( Artifact artifact, RepositoryRequest request )
-        throws RepositoryMetadataResolutionException
-    {
+    protected String resolveVersion(Artifact artifact, RepositoryRequest request)
+            throws RepositoryMetadataResolutionException {
         RepositoryMetadata metadata;
         // Don't use snapshot metadata for LATEST (which isSnapshot returns true for)
-        if ( !artifact.isSnapshot() || Artifact.LATEST_VERSION.equals( artifact.getBaseVersion() ) )
-        {
-            metadata = new ArtifactRepositoryMetadata( artifact );
-        }
-        else
-        {
-            metadata = new SnapshotArtifactRepositoryMetadata( artifact );
+        if (!artifact.isSnapshot() || Artifact.LATEST_VERSION.equals(artifact.getBaseVersion())) {
+            metadata = new ArtifactRepositoryMetadata(artifact);
+        } else {
+            metadata = new SnapshotArtifactRepositoryMetadata(artifact);
         }
 
-        repositoryMetadataManager.resolve( metadata, request );
+        repositoryMetadataManager.resolve(metadata, request);
 
-        artifact.addMetadata( metadata );
+        artifact.addMetadata(metadata);
 
         Metadata repoMetadata = metadata.getMetadata();
         String version = null;
-        if ( repoMetadata != null && repoMetadata.getVersioning() != null )
-        {
-            version = constructVersion( repoMetadata.getVersioning(), artifact.getBaseVersion() );
+        if (repoMetadata != null && repoMetadata.getVersioning() != null) {
+            version = constructVersion(repoMetadata.getVersioning(), artifact.getBaseVersion());
         }
 
-        if ( version == null )
-        {
+        if (version == null) {
             // use the local copy, or if it doesn't exist - go to the remote repo for it
             version = artifact.getBaseVersion();
         }
 
         // TODO also do this logging for other metadata?
         // TODO figure out way to avoid duplicated message
-        if ( getLogger().isDebugEnabled() )
-        {
-            if ( !version.equals( artifact.getBaseVersion() ) )
-            {
+        if (getLogger().isDebugEnabled()) {
+            if (!version.equals(artifact.getBaseVersion())) {
                 String message = artifact.getArtifactId() + ": resolved to version " + version;
-                if ( artifact.getRepository() != null )
-                {
+                if (artifact.getRepository() != null) {
                     message += " from repository " + artifact.getRepository().getId();
-                }
-                else
-                {
+                } else {
                     message += " from local repository";
                 }
-                getLogger().debug( message );
-            }
-            else
-            {
+                getLogger().debug(message);
+            } else {
                 // Locally installed file is newer, don't use the resolved version
-                getLogger().debug( artifact.getArtifactId() + ": using locally installed snapshot" );
+                getLogger().debug(artifact.getArtifactId() + ": using locally installed snapshot");
             }
         }
         return version;
     }
 
-    protected abstract String constructVersion( Versioning versioning, String baseVersion );
+    protected abstract String constructVersion(Versioning versioning, String baseVersion);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformation.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformation.java
index 4d20391..ddda640 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.transform;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.transform;
 
 import java.util.List;
 
@@ -30,10 +29,9 @@
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
 
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
  */
-public interface ArtifactTransformation
-{
+@Deprecated
+public interface ArtifactTransformation {
     String ROLE = ArtifactTransformation.class.getName();
 
     /**
@@ -43,8 +41,8 @@
      * @param artifact           Artifact to be transformed.
      * @param request the repositories to check
      */
-    void transformForResolve( Artifact artifact, RepositoryRequest request )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+    void transformForResolve(Artifact artifact, RepositoryRequest request)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     /**
      * Take in an artifact and return the transformed artifact for locating in the remote repository. If no
@@ -54,10 +52,9 @@
      * @param remoteRepositories the repositories to check
      * @param localRepository    the local repository
      */
-    void transformForResolve( Artifact artifact,
-                              List<ArtifactRepository> remoteRepositories,
-                              ArtifactRepository localRepository )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+    void transformForResolve(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     /**
      * Take in an artifact and return the transformed artifact for locating in the local repository. If no
@@ -66,9 +63,8 @@
      * @param artifact        Artifact to be transformed.
      * @param localRepository the local repository it will be stored in
      */
-    void transformForInstall( Artifact artifact,
-                              ArtifactRepository localRepository )
-        throws ArtifactInstallationException;
+    void transformForInstall(Artifact artifact, ArtifactRepository localRepository)
+            throws ArtifactInstallationException;
 
     /**
      * Take in an artifact and return the transformed artifact for distributing to remote repository. If no
@@ -78,9 +74,7 @@
      * @param remoteRepository the repository to deploy to
      * @param localRepository  the local repository
      */
-    void transformForDeployment( Artifact artifact,
-                                 ArtifactRepository remoteRepository,
-                                 ArtifactRepository localRepository )
-        throws ArtifactDeploymentException;
-
+    void transformForDeployment(
+            Artifact artifact, ArtifactRepository remoteRepository, ArtifactRepository localRepository)
+            throws ArtifactDeploymentException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformationManager.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformationManager.java
index de88de8..f86d9a1 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformationManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ArtifactTransformationManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.transform;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.transform;
 
 import java.util.List;
 
@@ -32,8 +31,8 @@
 /**
  * Manages multiple ArtifactTransformation instances and applies them in succession.
  */
-public interface ArtifactTransformationManager
-{
+@Deprecated
+public interface ArtifactTransformationManager {
     String ROLE = ArtifactTransformationManager.class.getName();
 
     /**
@@ -43,8 +42,8 @@
      * @param artifact           Artifact to be transformed.
      * @param request the repositories to check
      */
-    void transformForResolve( Artifact artifact, RepositoryRequest request )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+    void transformForResolve(Artifact artifact, RepositoryRequest request)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     /**
      * Take in an artifact and return the transformed artifact for locating in the remote repository. If no
@@ -54,9 +53,9 @@
      * @param remoteRepositories the repositories to check
      * @param localRepository    the local repository
      */
-    void transformForResolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                              ArtifactRepository localRepository )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
+    void transformForResolve(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException;
 
     /**
      * Take in an artifact and return the transformed artifact for locating in the local repository. If no
@@ -65,8 +64,8 @@
      * @param artifact        Artifact to be transformed.
      * @param localRepository the local repository it will be stored in
      */
-    void transformForInstall( Artifact artifact, ArtifactRepository localRepository )
-        throws ArtifactInstallationException;
+    void transformForInstall(Artifact artifact, ArtifactRepository localRepository)
+            throws ArtifactInstallationException;
 
     /**
      * Take in an artifact and return the transformed artifact for distributing to a remote repository. If no
@@ -76,9 +75,9 @@
      * @param remoteRepository the repository to deploy to
      * @param localRepository  the local repository the metadata is stored in
      */
-    void transformForDeployment( Artifact artifact, ArtifactRepository remoteRepository,
-                                 ArtifactRepository localRepository )
-        throws ArtifactDeploymentException;
+    void transformForDeployment(
+            Artifact artifact, ArtifactRepository remoteRepository, ArtifactRepository localRepository)
+            throws ArtifactDeploymentException;
 
     List<ArtifactTransformation> getArtifactTransformations();
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/DefaultArtifactTransformationManager.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/DefaultArtifactTransformationManager.java
index 024778d..8eef94e 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/DefaultArtifactTransformationManager.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/DefaultArtifactTransformationManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.transform;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,8 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.transform;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.deployer.ArtifactDeploymentException;
@@ -28,59 +35,55 @@
 import org.apache.maven.artifact.repository.RepositoryRequest;
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 
 /**
- * @author Jason van Zyl
  */
-@Component( role = ArtifactTransformationManager.class )
-public class DefaultArtifactTransformationManager
-    implements ArtifactTransformationManager
-{
-    @Requirement( role = ArtifactTransformation.class, hints = { "release", "latest", "snapshot" } )
+@Named
+@Singleton
+@Deprecated
+public class DefaultArtifactTransformationManager implements ArtifactTransformationManager {
+
     private List<ArtifactTransformation> artifactTransformations;
 
-    public void transformForResolve( Artifact artifact, RepositoryRequest request )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        for ( ArtifactTransformation transform : artifactTransformations )
-        {
-            transform.transformForResolve( artifact, request );
+    @Inject
+    public DefaultArtifactTransformationManager(Map<String, ArtifactTransformation> artifactTransformations) {
+        this.artifactTransformations = Stream.of("release", "latest", "snapshot")
+                .map(artifactTransformations::get)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toList());
+    }
+
+    public void transformForResolve(Artifact artifact, RepositoryRequest request)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        for (ArtifactTransformation transform : artifactTransformations) {
+            transform.transformForResolve(artifact, request);
         }
     }
 
-    public void transformForResolve( Artifact artifact, List<ArtifactRepository> remoteRepositories,
-                                     ArtifactRepository localRepository )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        for ( ArtifactTransformation transform : artifactTransformations )
-        {
-            transform.transformForResolve( artifact, remoteRepositories, localRepository );
+    public void transformForResolve(
+            Artifact artifact, List<ArtifactRepository> remoteRepositories, ArtifactRepository localRepository)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        for (ArtifactTransformation transform : artifactTransformations) {
+            transform.transformForResolve(artifact, remoteRepositories, localRepository);
         }
     }
 
-    public void transformForInstall( Artifact artifact, ArtifactRepository localRepository )
-        throws ArtifactInstallationException
-    {
-        for ( ArtifactTransformation transform : artifactTransformations )
-        {
-            transform.transformForInstall( artifact, localRepository );
+    public void transformForInstall(Artifact artifact, ArtifactRepository localRepository)
+            throws ArtifactInstallationException {
+        for (ArtifactTransformation transform : artifactTransformations) {
+            transform.transformForInstall(artifact, localRepository);
         }
     }
 
-    public void transformForDeployment( Artifact artifact, ArtifactRepository remoteRepository,
-                                        ArtifactRepository localRepository )
-        throws ArtifactDeploymentException
-    {
-        for ( ArtifactTransformation transform : artifactTransformations )
-        {
-            transform.transformForDeployment( artifact, remoteRepository, localRepository );
+    public void transformForDeployment(
+            Artifact artifact, ArtifactRepository remoteRepository, ArtifactRepository localRepository)
+            throws ArtifactDeploymentException {
+        for (ArtifactTransformation transform : artifactTransformations) {
+            transform.transformForDeployment(artifact, remoteRepository, localRepository);
         }
     }
 
-    public List<ArtifactTransformation> getArtifactTransformations()
-    {
+    public List<ArtifactTransformation> getArtifactTransformations() {
         return artifactTransformations;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/LatestArtifactTransformation.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/LatestArtifactTransformation.java
index 0bc89c1..5346890 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/LatestArtifactTransformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/LatestArtifactTransformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.transform;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.transform;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
@@ -26,52 +28,42 @@
 import org.apache.maven.artifact.repository.metadata.Versioning;
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * Describes a version transformation during artifact resolution - "latest" type
  */
-@Component( role = ArtifactTransformation.class, hint = "latest" )
-public class LatestArtifactTransformation
-    extends AbstractVersionTransformation
-{
+@Named("latest")
+@Singleton
+@Deprecated
+public class LatestArtifactTransformation extends AbstractVersionTransformation {
 
-    public void transformForResolve( Artifact artifact, RepositoryRequest request )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        if ( Artifact.LATEST_VERSION.equals( artifact.getVersion() ) )
-        {
-            try
-            {
-                String version = resolveVersion( artifact, request );
-                if ( Artifact.LATEST_VERSION.equals( version ) )
-                {
-                    throw new ArtifactNotFoundException( "Unable to determine the latest version", artifact );
+    public void transformForResolve(Artifact artifact, RepositoryRequest request)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        if (Artifact.LATEST_VERSION.equals(artifact.getVersion())) {
+            try {
+                String version = resolveVersion(artifact, request);
+                if (Artifact.LATEST_VERSION.equals(version)) {
+                    throw new ArtifactNotFoundException("Unable to determine the latest version", artifact);
                 }
 
-                artifact.setBaseVersion( version );
-                artifact.updateVersion( version, request.getLocalRepository() );
-            }
-            catch ( RepositoryMetadataResolutionException e )
-            {
-                throw new ArtifactResolutionException( e.getMessage(), artifact, e );
+                artifact.setBaseVersion(version);
+                artifact.updateVersion(version, request.getLocalRepository());
+            } catch (RepositoryMetadataResolutionException e) {
+                throw new ArtifactResolutionException(e.getMessage(), artifact, e);
             }
         }
     }
 
-    public void transformForInstall( Artifact artifact, ArtifactRepository localRepository )
-    {
+    public void transformForInstall(Artifact artifact, ArtifactRepository localRepository) {
         // metadata is added via addPluginArtifactMetadata
     }
 
-    public void transformForDeployment( Artifact artifact, ArtifactRepository remoteRepository,
-                                        ArtifactRepository localRepository )
-    {
+    public void transformForDeployment(
+            Artifact artifact, ArtifactRepository remoteRepository, ArtifactRepository localRepository) {
         // metadata is added via addPluginArtifactMetadata
     }
 
-    protected String constructVersion( Versioning versioning, String baseVersion )
-    {
+    protected String constructVersion(Versioning versioning, String baseVersion) {
         return versioning.getLatest();
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ReleaseArtifactTransformation.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ReleaseArtifactTransformation.java
index b1d2c71..abc20e2 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ReleaseArtifactTransformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/ReleaseArtifactTransformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.transform;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.transform;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.metadata.ArtifactMetadata;
@@ -28,74 +30,61 @@
 import org.apache.maven.artifact.repository.metadata.Versioning;
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.codehaus.plexus.component.annotations.Component;
 
 /**
  * Change the version <code>RELEASE</code> to the appropriate release version from the remote repository.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-@Component( role = ArtifactTransformation.class, hint = "release" )
-public class ReleaseArtifactTransformation
-    extends AbstractVersionTransformation
-{
+@Named("release")
+@Singleton
+@Deprecated
+public class ReleaseArtifactTransformation extends AbstractVersionTransformation {
 
-    public void transformForResolve( Artifact artifact, RepositoryRequest request )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        if ( Artifact.RELEASE_VERSION.equals( artifact.getVersion() ) )
-        {
-            try
-            {
-                String version = resolveVersion( artifact, request );
+    public void transformForResolve(Artifact artifact, RepositoryRequest request)
+            throws ArtifactResolutionException, ArtifactNotFoundException {
+        if (Artifact.RELEASE_VERSION.equals(artifact.getVersion())) {
+            try {
+                String version = resolveVersion(artifact, request);
 
-                if ( Artifact.RELEASE_VERSION.equals( version ) )
-                {
-                    throw new ArtifactNotFoundException( "Unable to determine the release version", artifact );
+                if (Artifact.RELEASE_VERSION.equals(version)) {
+                    throw new ArtifactNotFoundException("Unable to determine the release version", artifact);
                 }
 
-                artifact.setBaseVersion( version );
-                artifact.updateVersion( version, request.getLocalRepository() );
-            }
-            catch ( RepositoryMetadataResolutionException e )
-            {
-                throw new ArtifactResolutionException( e.getMessage(), artifact, e );
+                artifact.setBaseVersion(version);
+                artifact.updateVersion(version, request.getLocalRepository());
+            } catch (RepositoryMetadataResolutionException e) {
+                throw new ArtifactResolutionException(e.getMessage(), artifact, e);
             }
         }
     }
 
-    public void transformForInstall( Artifact artifact, ArtifactRepository localRepository )
-    {
-        ArtifactMetadata metadata = createMetadata( artifact );
+    public void transformForInstall(Artifact artifact, ArtifactRepository localRepository) {
+        ArtifactMetadata metadata = createMetadata(artifact);
 
-        artifact.addMetadata( metadata );
+        artifact.addMetadata(metadata);
     }
 
-    public void transformForDeployment( Artifact artifact, ArtifactRepository remoteRepository,
-                                        ArtifactRepository localRepository )
-    {
-        ArtifactMetadata metadata = createMetadata( artifact );
+    public void transformForDeployment(
+            Artifact artifact, ArtifactRepository remoteRepository, ArtifactRepository localRepository) {
+        ArtifactMetadata metadata = createMetadata(artifact);
 
-        artifact.addMetadata( metadata );
+        artifact.addMetadata(metadata);
     }
 
-    private ArtifactMetadata createMetadata( Artifact artifact )
-    {
+    private ArtifactMetadata createMetadata(Artifact artifact) {
         Versioning versioning = new Versioning();
         // TODO Should this be changed for MNG-6754 too?
         versioning.updateTimestamp();
-        versioning.addVersion( artifact.getVersion() );
+        versioning.addVersion(artifact.getVersion());
 
-        if ( artifact.isRelease() )
-        {
-            versioning.setRelease( artifact.getVersion() );
+        if (artifact.isRelease()) {
+            versioning.setRelease(artifact.getVersion());
         }
 
-        return new ArtifactRepositoryMetadata( artifact, versioning );
+        return new ArtifactRepositoryMetadata(artifact, versioning);
     }
 
-    protected String constructVersion( Versioning versioning, String baseVersion )
-    {
+    protected String constructVersion(Versioning versioning, String baseVersion) {
         return versioning.getRelease();
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/SnapshotTransformation.java b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/SnapshotTransformation.java
index 1a79049..4f2e505 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/SnapshotTransformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/transform/SnapshotTransformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.transform;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.transform;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
@@ -36,139 +38,114 @@
 import org.apache.maven.artifact.repository.metadata.SnapshotArtifactRepositoryMetadata;
 import org.apache.maven.artifact.repository.metadata.Versioning;
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- * @author <a href="mailto:mmaczka@interia.pl">Michal Maczka</a>
  */
-@Component( role = ArtifactTransformation.class, hint = "snapshot" )
-public class SnapshotTransformation
-    extends AbstractVersionTransformation
-{
+@Named("snapshot")
+@Singleton
+@Deprecated
+public class SnapshotTransformation extends AbstractVersionTransformation {
     private static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss";
 
-    private static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone( "Etc/UTC" );
+    private static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone("Etc/UTC");
 
     private String deploymentTimestamp;
 
-    public void transformForResolve( Artifact artifact, RepositoryRequest request )
-        throws ArtifactResolutionException
-    {
+    public void transformForResolve(Artifact artifact, RepositoryRequest request) throws ArtifactResolutionException {
         // Only select snapshots that are unresolved (eg 1.0-SNAPSHOT, not 1.0-20050607.123456)
-        if ( artifact.isSnapshot() && artifact.getBaseVersion().equals( artifact.getVersion() ) )
-        {
-            try
-            {
-                String version = resolveVersion( artifact, request );
-                artifact.updateVersion( version, request.getLocalRepository() );
-            }
-            catch ( RepositoryMetadataResolutionException e )
-            {
-                throw new ArtifactResolutionException( e.getMessage(), artifact, e );
+        if (artifact.isSnapshot() && artifact.getBaseVersion().equals(artifact.getVersion())) {
+            try {
+                String version = resolveVersion(artifact, request);
+                artifact.updateVersion(version, request.getLocalRepository());
+            } catch (RepositoryMetadataResolutionException e) {
+                throw new ArtifactResolutionException(e.getMessage(), artifact, e);
             }
         }
     }
 
-    public void transformForInstall( Artifact artifact, ArtifactRepository localRepository )
-    {
-        if ( artifact.isSnapshot() )
-        {
+    public void transformForInstall(Artifact artifact, ArtifactRepository localRepository) {
+        if (artifact.isSnapshot()) {
             Snapshot snapshot = new Snapshot();
-            snapshot.setLocalCopy( true );
-            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact, snapshot );
+            snapshot.setLocalCopy(true);
+            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata(artifact, snapshot);
 
-            artifact.addMetadata( metadata );
+            artifact.addMetadata(metadata);
         }
     }
 
-    public void transformForDeployment( Artifact artifact, ArtifactRepository remoteRepository,
-                                        ArtifactRepository localRepository )
-        throws ArtifactDeploymentException
-    {
-        if ( artifact.isSnapshot() )
-        {
+    public void transformForDeployment(
+            Artifact artifact, ArtifactRepository remoteRepository, ArtifactRepository localRepository)
+            throws ArtifactDeploymentException {
+        if (artifact.isSnapshot()) {
             Snapshot snapshot = new Snapshot();
 
             // TODO Should this be changed for MNG-6754 too?
-            snapshot.setTimestamp( getDeploymentTimestamp() );
+            snapshot.setTimestamp(getDeploymentTimestamp());
 
             // we update the build number anyway so that it doesn't get lost. It requires the timestamp to take effect
-            try
-            {
-                int buildNumber = resolveLatestSnapshotBuildNumber( artifact, localRepository, remoteRepository );
+            try {
+                int buildNumber = resolveLatestSnapshotBuildNumber(artifact, localRepository, remoteRepository);
 
-                snapshot.setBuildNumber( buildNumber + 1 );
-            }
-            catch ( RepositoryMetadataResolutionException e )
-            {
-                throw new ArtifactDeploymentException( "Error retrieving previous build number for artifact '"
-                    + artifact.getDependencyConflictId() + "': " + e.getMessage(), e );
+                snapshot.setBuildNumber(buildNumber + 1);
+            } catch (RepositoryMetadataResolutionException e) {
+                throw new ArtifactDeploymentException(
+                        "Error retrieving previous build number for artifact '" + artifact.getDependencyConflictId()
+                                + "': " + e.getMessage(),
+                        e);
             }
 
-            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact, snapshot );
+            RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata(artifact, snapshot);
 
             artifact.setResolvedVersion(
-                constructVersion( metadata.getMetadata().getVersioning(), artifact.getBaseVersion() ) );
+                    constructVersion(metadata.getMetadata().getVersioning(), artifact.getBaseVersion()));
 
-            artifact.addMetadata( metadata );
+            artifact.addMetadata(metadata);
         }
     }
 
-    public String getDeploymentTimestamp()
-    {
-        if ( deploymentTimestamp == null )
-        {
-            deploymentTimestamp = getUtcDateFormatter().format( new Date() );
+    public String getDeploymentTimestamp() {
+        if (deploymentTimestamp == null) {
+            deploymentTimestamp = getUtcDateFormatter().format(new Date());
         }
         return deploymentTimestamp;
     }
 
-    protected String constructVersion( Versioning versioning, String baseVersion )
-    {
+    protected String constructVersion(Versioning versioning, String baseVersion) {
         String version = null;
         Snapshot snapshot = versioning.getSnapshot();
-        if ( snapshot != null )
-        {
-            if ( snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0 )
-            {
+        if (snapshot != null) {
+            if (snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0) {
                 String newVersion = snapshot.getTimestamp() + "-" + snapshot.getBuildNumber();
-                version = StringUtils.replace( baseVersion, Artifact.SNAPSHOT_VERSION, newVersion );
-            }
-            else
-            {
+                version = baseVersion.replace(Artifact.SNAPSHOT_VERSION, newVersion);
+            } else {
                 version = baseVersion;
             }
         }
         return version;
     }
 
-    private int resolveLatestSnapshotBuildNumber( Artifact artifact, ArtifactRepository localRepository,
-                                                  ArtifactRepository remoteRepository )
-        throws RepositoryMetadataResolutionException
-    {
-        RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata( artifact );
+    private int resolveLatestSnapshotBuildNumber(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws RepositoryMetadataResolutionException {
+        RepositoryMetadata metadata = new SnapshotArtifactRepositoryMetadata(artifact);
 
-        getLogger().info( "Retrieving previous build number from " + remoteRepository.getId() );
-        repositoryMetadataManager.resolveAlways( metadata, localRepository, remoteRepository );
+        getLogger().info("Retrieving previous build number from " + remoteRepository.getId());
+        repositoryMetadataManager.resolveAlways(metadata, localRepository, remoteRepository);
 
         int buildNumber = 0;
         Metadata repoMetadata = metadata.getMetadata();
-        if ( ( repoMetadata != null )
-            && ( repoMetadata.getVersioning() != null && repoMetadata.getVersioning().getSnapshot() != null ) )
-        {
+        if ((repoMetadata != null)
+                && (repoMetadata.getVersioning() != null
+                        && repoMetadata.getVersioning().getSnapshot() != null)) {
             buildNumber = repoMetadata.getVersioning().getSnapshot().getBuildNumber();
         }
         return buildNumber;
     }
 
-    public static DateFormat getUtcDateFormatter()
-    {
-        DateFormat utcDateFormatter = new SimpleDateFormat( DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT );
-        utcDateFormatter.setCalendar( new GregorianCalendar() );
-        utcDateFormatter.setTimeZone( DEFAULT_SNAPSHOT_TIME_ZONE );
+    public static DateFormat getUtcDateFormatter() {
+        DateFormat utcDateFormatter = new SimpleDateFormat(DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT);
+        utcDateFormatter.setCalendar(new GregorianCalendar());
+        utcDateFormatter.setTimeZone(DEFAULT_SNAPSHOT_TIME_ZONE);
         return utcDateFormatter;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/ArtifactMetadata.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/ArtifactMetadata.java
index 8d03a31..b0a231f 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/ArtifactMetadata.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/ArtifactMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import java.util.Collection;
 
@@ -27,14 +26,14 @@
 /**
  * Artifact Metadata that is resolved independent of Artifact itself.
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  */
-public class ArtifactMetadata
-{
+@Deprecated
+public class ArtifactMetadata {
     /**
      * standard glorified artifact coordinates
      */
     protected String groupId;
+
     protected String artifactId;
     protected String version;
     protected String type;
@@ -64,67 +63,75 @@
     /** error message  */
     private String error;
 
-    //------------------------------------------------------------------
+    // ------------------------------------------------------------------
     /**
      *
      */
-    public ArtifactMetadata( String name )
-    {
-        if ( name == null )
-        {
+    public ArtifactMetadata(String name) {
+        if (name == null) {
             return;
         }
-        int ind1 = name.indexOf( ':' );
-        int ind2 = name.lastIndexOf( ':' );
+        int ind1 = name.indexOf(':');
+        int ind2 = name.lastIndexOf(':');
 
-        if ( ind1 == -1 || ind2 == -1 )
-        {
+        if (ind1 == -1 || ind2 == -1) {
             return;
         }
 
-        this.groupId = name.substring( 0, ind1 );
-        if ( ind1 == ind2 )
-        {
-            this.artifactId = name.substring( ind1 + 1 );
-        }
-        else
-        {
-            this.artifactId = name.substring( ind1 + 1, ind2 );
-            this.version = name.substring( ind2 + 1 );
+        this.groupId = name.substring(0, ind1);
+        if (ind1 == ind2) {
+            this.artifactId = name.substring(ind1 + 1);
+        } else {
+            this.artifactId = name.substring(ind1 + 1, ind2);
+            this.version = name.substring(ind2 + 1);
         }
     }
 
-    public ArtifactMetadata( String groupId, String name, String version )
-    {
-        this( groupId, name, version, null );
+    public ArtifactMetadata(String groupId, String name, String version) {
+        this(groupId, name, version, null);
     }
 
-    public ArtifactMetadata( String groupId, String name, String version, String type )
-    {
-        this( groupId, name, version, type, null );
+    public ArtifactMetadata(String groupId, String name, String version, String type) {
+        this(groupId, name, version, type, null);
     }
 
-    public ArtifactMetadata( String groupId, String name, String version, String type, ArtifactScopeEnum artifactScope )
-    {
-        this( groupId, name, version, type, artifactScope, null );
+    public ArtifactMetadata(String groupId, String name, String version, String type, ArtifactScopeEnum artifactScope) {
+        this(groupId, name, version, type, artifactScope, null);
     }
 
-    public ArtifactMetadata( String groupId, String name, String version, String type, ArtifactScopeEnum artifactScope,
-                             String classifier )
-    {
-        this( groupId, name, version, type, artifactScope, classifier, null );
+    public ArtifactMetadata(
+            String groupId,
+            String name,
+            String version,
+            String type,
+            ArtifactScopeEnum artifactScope,
+            String classifier) {
+        this(groupId, name, version, type, artifactScope, classifier, null);
     }
 
-    public ArtifactMetadata( String groupId, String name, String version, String type, ArtifactScopeEnum artifactScope,
-                             String classifier, String artifactUri )
-    {
-        this( groupId, name, version, type, artifactScope, classifier, artifactUri, null, true, null );
+    public ArtifactMetadata(
+            String groupId,
+            String name,
+            String version,
+            String type,
+            ArtifactScopeEnum artifactScope,
+            String classifier,
+            String artifactUri) {
+        this(groupId, name, version, type, artifactScope, classifier, artifactUri, null, true, null);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactMetadata( String groupId, String name, String version, String type, ArtifactScopeEnum artifactScope,
-                             String classifier, String artifactUri, String why, boolean resolved, String error )
-    {
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactMetadata(
+            String groupId,
+            String name,
+            String version,
+            String type,
+            ArtifactScopeEnum artifactScope,
+            String classifier,
+            String artifactUri,
+            String why,
+            boolean resolved,
+            String error) {
         this.groupId = groupId;
         this.artifactId = name;
         this.version = version;
@@ -137,17 +144,32 @@
         this.error = error;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public ArtifactMetadata( String groupId, String name, String version, String type, String scopeString,
-                             String classifier, String artifactUri, String why, boolean resolved, String error )
-    {
-        this( groupId, name, version, type,
-              scopeString == null ? ArtifactScopeEnum.DEFAULT_SCOPE : ArtifactScopeEnum.valueOf( scopeString ),
-              classifier, artifactUri, why, resolved, error );
+    @SuppressWarnings("checkstyle:parameternumber")
+    public ArtifactMetadata(
+            String groupId,
+            String name,
+            String version,
+            String type,
+            String scopeString,
+            String classifier,
+            String artifactUri,
+            String why,
+            boolean resolved,
+            String error) {
+        this(
+                groupId,
+                name,
+                version,
+                type,
+                scopeString == null ? ArtifactScopeEnum.DEFAULT_SCOPE : ArtifactScopeEnum.valueOf(scopeString),
+                classifier,
+                artifactUri,
+                why,
+                resolved,
+                error);
     }
 
-    public ArtifactMetadata( Artifact af )
-    {
+    public ArtifactMetadata(Artifact af) {
         /*
         if ( af != null )
         {
@@ -155,190 +177,154 @@
         }
         */
     }
-    //------------------------------------------------------------------
-//    public void init( ArtifactMetadata af )
-//    {
-//        setGroupId( af.getGroupId() );
-//        setArtifactId( af.getArtifactId() );
-//        setVersion( af.getVersion() );
-//        setType( af.getType() );
-//        setScope( af.getScope() );
-//        setClassifier( af.getClassifier() );
-//        //setUri( af.getDownloadUrl() );
-//
-//        this.resolved = af.isResolved();
-//    }
+    // ------------------------------------------------------------------
+    //    public void init( ArtifactMetadata af )
+    //    {
+    //        setGroupId( af.getGroupId() );
+    //        setArtifactId( af.getArtifactId() );
+    //        setVersion( af.getVersion() );
+    //        setType( af.getType() );
+    //        setScope( af.getScope() );
+    //        setClassifier( af.getClassifier() );
+    //        //setUri( af.getDownloadUrl() );
+    //
+    //        this.resolved = af.isResolved();
+    //    }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return groupId + ":" + artifactId + ":" + version;
     }
 
-    public String toDomainString()
-    {
+    public String toDomainString() {
         return groupId + ":" + artifactId;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public void setGroupId( String groupId )
-    {
+    public void setGroupId(String groupId) {
         this.groupId = groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public void setArtifactId( String name )
-    {
+    public void setArtifactId(String name) {
         this.artifactId = name;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
-    public void setVersion( String version )
-    {
+    public void setVersion(String version) {
         this.version = version;
     }
 
-    public String getType()
-    {
+    public String getType() {
         return type;
     }
 
-    public String getCheckedType()
-    {
+    public String getCheckedType() {
         return type == null ? "jar" : type;
     }
 
-    public void setType( String type )
-    {
+    public void setType(String type) {
         this.type = type;
     }
 
-    public ArtifactScopeEnum getArtifactScope()
-    {
+    public ArtifactScopeEnum getArtifactScope() {
         return artifactScope == null ? ArtifactScopeEnum.DEFAULT_SCOPE : artifactScope;
     }
 
-    public void setArtifactScope( ArtifactScopeEnum artifactScope )
-    {
+    public void setArtifactScope(ArtifactScopeEnum artifactScope) {
         this.artifactScope = artifactScope;
     }
 
-    public void setScope( String scope )
-    {
-        this.artifactScope = scope == null ? ArtifactScopeEnum.DEFAULT_SCOPE : ArtifactScopeEnum.valueOf( scope );
+    public void setScope(String scope) {
+        this.artifactScope = scope == null ? ArtifactScopeEnum.DEFAULT_SCOPE : ArtifactScopeEnum.valueOf(scope);
     }
 
-    public String getClassifier()
-    {
+    public String getClassifier() {
         return classifier;
     }
 
-    public void setClassifier( String classifier )
-    {
+    public void setClassifier(String classifier) {
         this.classifier = classifier;
     }
 
-    public boolean isResolved()
-    {
+    public boolean isResolved() {
         return resolved;
     }
 
-    public void setResolved( boolean resolved )
-    {
+    public void setResolved(boolean resolved) {
         this.resolved = resolved;
     }
 
-    public String getUri()
-    {
+    public String getUri() {
         return uri;
     }
 
-    public void setUri( String uri )
-    {
+    public void setUri(String uri) {
         this.uri = uri;
     }
 
-    public String getScope()
-    {
+    public String getScope() {
         return getArtifactScope().getScope();
     }
 
-    public ArtifactScopeEnum getScopeAsEnum()
-    {
+    public ArtifactScopeEnum getScopeAsEnum() {
         return artifactScope == null ? ArtifactScopeEnum.DEFAULT_SCOPE : artifactScope;
     }
 
-    public boolean isArtifactExists()
-    {
+    public boolean isArtifactExists() {
         return artifactExists;
     }
 
-    public void setArtifactExists( boolean artifactExists )
-    {
+    public void setArtifactExists(boolean artifactExists) {
         this.artifactExists = artifactExists;
     }
 
-
-    public Collection<ArtifactMetadata> getDependencies()
-    {
+    public Collection<ArtifactMetadata> getDependencies() {
         return dependencies;
     }
 
-    public void setDependencies( Collection<ArtifactMetadata> dependencies )
-    {
+    public void setDependencies(Collection<ArtifactMetadata> dependencies) {
         this.dependencies = dependencies;
     }
 
-    public String getArtifactUri()
-    {
+    public String getArtifactUri() {
         return artifactUri;
     }
 
-    public void setArtifactUri( String artifactUri )
-    {
+    public void setArtifactUri(String artifactUri) {
         this.artifactUri = artifactUri;
     }
 
-
-    public String getWhy()
-    {
+    public String getWhy() {
         return why;
     }
 
-    public void setWhy( String why )
-    {
+    public void setWhy(String why) {
         this.why = why;
     }
 
-    public String getError()
-    {
+    public String getError() {
         return error;
     }
 
-    public void setError( String error )
-    {
+    public void setError(String error) {
         this.error = error;
     }
 
-    public boolean isError()
-    {
+    public boolean isError() {
         return error == null;
     }
 
-    public String getDependencyConflictId()
-    {
+    public String getDependencyConflictId() {
         return groupId + ":" + artifactId;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathContainer.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathContainer.java
index 0630b68..ad1937a 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathContainer.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathContainer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -28,115 +27,98 @@
 /**
  * classpath container that is aware of the classpath scope
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-public class ClasspathContainer
-implements Iterable<ArtifactMetadata>
-{
+@Deprecated
+public class ClasspathContainer implements Iterable<ArtifactMetadata> {
     private List<ArtifactMetadata> classpath;
 
     private ArtifactScopeEnum scope;
 
     // -------------------------------------------------------------------------------------------
-    public ClasspathContainer( ArtifactScopeEnum scope )
-    {
-        this.scope = ArtifactScopeEnum.checkScope( scope );
+    public ClasspathContainer(ArtifactScopeEnum scope) {
+        this.scope = ArtifactScopeEnum.checkScope(scope);
     }
 
     // -------------------------------------------------------------------------------------------
-    public ClasspathContainer( List<ArtifactMetadata> classpath, ArtifactScopeEnum scope )
-    {
-        this( scope );
+    public ClasspathContainer(List<ArtifactMetadata> classpath, ArtifactScopeEnum scope) {
+        this(scope);
         this.classpath = classpath;
     }
 
     // -------------------------------------------------------------------------------------------
-    public Iterator<ArtifactMetadata> iterator()
-    {
+    public Iterator<ArtifactMetadata> iterator() {
         return classpath == null ? null : classpath.iterator();
     }
 
     // -------------------------------------------------------------------------------------------
-    public ClasspathContainer add( ArtifactMetadata md )
-    {
-        if ( classpath == null )
-        {
-            classpath = new ArrayList<>( 16 );
+    public ClasspathContainer add(ArtifactMetadata md) {
+        if (classpath == null) {
+            classpath = new ArrayList<>(16);
         }
 
-        classpath.add( md );
+        classpath.add(md);
 
         return this;
     }
 
     // -------------------------------------------------------------------------------------------
-    public List<ArtifactMetadata> getClasspath()
-    {
+    public List<ArtifactMetadata> getClasspath() {
         return classpath;
     }
 
     // -------------------------------------------------------------------------------------------
-    public MetadataTreeNode getClasspathAsTree()
-        throws MetadataResolutionException
-    {
-        if ( classpath == null || classpath.size() < 1 )
-        {
+    public MetadataTreeNode getClasspathAsTree() throws MetadataResolutionException {
+        if (classpath == null || classpath.size() < 1) {
             return null;
         }
 
         MetadataTreeNode tree = null;
         MetadataTreeNode parent = null;
 
-        for ( ArtifactMetadata md : classpath )
-        {
-            MetadataTreeNode node = new MetadataTreeNode( md, parent, md.isResolved(), md.getArtifactScope() );
-            if ( tree == null )
-            {
+        for (ArtifactMetadata md : classpath) {
+            MetadataTreeNode node = new MetadataTreeNode(md, parent, md.isResolved(), md.getArtifactScope());
+            if (tree == null) {
                 tree = node;
             }
 
-            if ( parent != null )
-            {
-                parent.setNChildren( 1 );
-                parent.addChild( 0, node );
+            if (parent != null) {
+                parent.setNChildren(1);
+                parent.addChild(0, node);
             }
 
             parent = node;
-
         }
         return tree;
     }
 
-    public void setClasspath( List<ArtifactMetadata> classpath )
-    {
+    public void setClasspath(List<ArtifactMetadata> classpath) {
         this.classpath = classpath;
     }
 
-    public ArtifactScopeEnum getScope()
-    {
+    public ArtifactScopeEnum getScope() {
         return scope;
     }
 
-    public void setScope( ArtifactScopeEnum scope )
-    {
+    public void setScope(ArtifactScopeEnum scope) {
         this.scope = scope;
     }
 
     // -------------------------------------------------------------------------------------------
     @Override
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 256 );
-        sb.append( "[scope=" ).append( scope.getScope() );
-        if ( classpath != null )
-        {
-            for ( ArtifactMetadata md : classpath )
-            {
-                sb.append( ": " ).append( md.toString() ).append( '{' ).append( md.getArtifactUri() ).append( '}' );
+    public String toString() {
+        StringBuilder sb = new StringBuilder(256);
+        sb.append("[scope=").append(scope.getScope());
+        if (classpath != null) {
+            for (ArtifactMetadata md : classpath) {
+                sb.append(": ")
+                        .append(md.toString())
+                        .append('{')
+                        .append(md.getArtifactUri())
+                        .append('}');
             }
         }
-        sb.append( ']' );
+        sb.append(']');
         return sb.toString();
     }
     // -------------------------------------------------------------------------------------------
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathTransformation.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathTransformation.java
index 26d5f3e..746ea81 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathTransformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/ClasspathTransformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
 
 /**
  * Helper class to convert a metadata Graph into some form of a classpath
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-public interface ClasspathTransformation
-{
+@Deprecated
+public interface ClasspathTransformation {
     String ROLE = ClasspathTransformation.class.getName();
 
     /**
@@ -41,6 +39,6 @@
      * @return Collection of metadata objects in the linked subgraph of the graph which
      *             contains the graph.getEntry() vertice
      */
-    ClasspathContainer transform( MetadataGraph dirtyGraph, ArtifactScopeEnum scope, boolean resolve )
-        throws MetadataGraphTransformationException;
+    ClasspathContainer transform(MetadataGraph dirtyGraph, ArtifactScopeEnum scope, boolean resolve)
+            throws MetadataGraphTransformationException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultClasspathTransformation.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultClasspathTransformation.java
index a2bac9c..5a41c60 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultClasspathTransformation.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultClasspathTransformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,76 +16,68 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 
 /**
  * default implementation of the metadata classpath transformer
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-@Component( role = ClasspathTransformation.class )
-public class DefaultClasspathTransformation
-    implements ClasspathTransformation
-{
-    @Requirement
+@Named
+@Singleton
+@Deprecated
+public class DefaultClasspathTransformation implements ClasspathTransformation {
+    @Inject
     GraphConflictResolver conflictResolver;
 
-    //----------------------------------------------------------------------------------------------------
-    public ClasspathContainer transform( MetadataGraph dirtyGraph, ArtifactScopeEnum scope, boolean resolve )
-        throws MetadataGraphTransformationException
-    {
-        try
-        {
-            if ( dirtyGraph == null || dirtyGraph.isEmpty() )
-            {
+    // ----------------------------------------------------------------------------------------------------
+    public ClasspathContainer transform(MetadataGraph dirtyGraph, ArtifactScopeEnum scope, boolean resolve)
+            throws MetadataGraphTransformationException {
+        try {
+            if (dirtyGraph == null || dirtyGraph.isEmpty()) {
                 return null;
             }
 
-            MetadataGraph cleanGraph = conflictResolver.resolveConflicts( dirtyGraph, scope );
+            MetadataGraph cleanGraph = conflictResolver.resolveConflicts(dirtyGraph, scope);
 
-            if ( cleanGraph == null || cleanGraph.isEmpty() )
-            {
+            if (cleanGraph == null || cleanGraph.isEmpty()) {
                 return null;
             }
 
-            ClasspathContainer cpc = new ClasspathContainer( scope );
-            if ( cleanGraph.isEmptyEdges() )
-            {
+            ClasspathContainer cpc = new ClasspathContainer(scope);
+            if (cleanGraph.isEmptyEdges()) {
                 // single entry in the classpath, populated from itself
                 ArtifactMetadata amd = cleanGraph.getEntry().getMd();
-                cpc.add( amd );
-            }
-            else
-            {
-                ClasspathGraphVisitor v = new ClasspathGraphVisitor( cleanGraph, cpc );
+                cpc.add(amd);
+            } else {
+                ClasspathGraphVisitor v = new ClasspathGraphVisitor(cleanGraph, cpc);
                 MetadataGraphVertex entry = cleanGraph.getEntry();
                 // entry point
-                v.visit( entry );
+                v.visit(entry);
             }
 
             return cpc;
-        }
-        catch ( GraphConflictResolutionException e )
-        {
-            throw new MetadataGraphTransformationException( e );
+        } catch (GraphConflictResolutionException e) {
+            throw new MetadataGraphTransformationException(e);
         }
     }
 
-    //===================================================================================================
+    // ===================================================================================================
     /**
      * Helper class to traverse graph. Required to make the containing method thread-safe
      * and yet use class level data to lessen stack usage in recursion
      */
-    private class ClasspathGraphVisitor
-    {
+    private class ClasspathGraphVisitor {
         MetadataGraph graph;
 
         ClasspathContainer cpc;
@@ -95,79 +85,71 @@
         List<MetadataGraphVertex> visited;
 
         // -----------------------------------------------------------------------
-        protected ClasspathGraphVisitor( MetadataGraph cleanGraph, ClasspathContainer cpc )
-        {
+        protected ClasspathGraphVisitor(MetadataGraph cleanGraph, ClasspathContainer cpc) {
             this.cpc = cpc;
             this.graph = cleanGraph;
 
-            visited = new ArrayList<>( cleanGraph.getVertices().size() );
+            visited = new ArrayList<>(cleanGraph.getVertices().size());
         }
 
         // -----------------------------------------------------------------------
-        protected void visit( MetadataGraphVertex node ) // , String version, String artifactUri )
-        {
+        protected void visit(MetadataGraphVertex node) // , String version, String artifactUri )
+                {
             ArtifactMetadata md = node.getMd();
-            if ( visited.contains( node ) )
-            {
+            if (visited.contains(node)) {
                 return;
             }
 
-            cpc.add( md );
-//
-//            TreeSet<MetadataGraphEdge> deps = new TreeSet<MetadataGraphEdge>(
-//                        new Comparator<MetadataGraphEdge>()
-//                        {
-//                            public int compare( MetadataGraphEdge e1
-//                                              , MetadataGraphEdge e2
-//                                              )
-//                            {
-//                                if( e1.getDepth() == e2.getDepth() )
-//                                {
-//                                    if( e2.getPomOrder() == e1.getPomOrder() )
-//                                        return e1.getTarget().toString().compareTo(e2.getTarget().toString() );
-//
-//                                    return e2.getPomOrder() - e1.getPomOrder();
-//                                }
-//
-//                                return e2.getDepth() - e1.getDepth();
-//                            }
-//                        }
-//                    );
+            cpc.add(md);
+            //
+            //            TreeSet<MetadataGraphEdge> deps = new TreeSet<MetadataGraphEdge>(
+            //                        new Comparator<MetadataGraphEdge>()
+            //                        {
+            //                            public int compare( MetadataGraphEdge e1
+            //                                              , MetadataGraphEdge e2
+            //                                              )
+            //                            {
+            //                                if( e1.getDepth() == e2.getDepth() )
+            //                                {
+            //                                    if( e2.getPomOrder() == e1.getPomOrder() )
+            //                                        return
+            // e1.getTarget().toString().compareTo(e2.getTarget().toString() );
+            //
+            //                                    return e2.getPomOrder() - e1.getPomOrder();
+            //                                }
+            //
+            //                                return e2.getDepth() - e1.getDepth();
+            //                            }
+            //                        }
+            //                    );
 
-            List<MetadataGraphEdge> exits = graph.getExcidentEdges( node );
+            List<MetadataGraphEdge> exits = graph.getExcidentEdges(node);
 
-            if ( exits != null && exits.size() > 0 )
-            {
-                MetadataGraphEdge[] sortedExits = exits.toArray( new MetadataGraphEdge[0] );
-                Arrays.sort( sortedExits, ( e1, e2 ) ->
-                {
-                    if ( e1.getDepth() == e2.getDepth() )
-                    {
-                        if ( e2.getPomOrder() == e1.getPomOrder() )
-                        {
-                            return e1.getTarget().toString().compareTo( e2.getTarget().toString() );
+            if (exits != null && exits.size() > 0) {
+                MetadataGraphEdge[] sortedExits = exits.toArray(new MetadataGraphEdge[0]);
+                Arrays.sort(sortedExits, (e1, e2) -> {
+                    if (e1.getDepth() == e2.getDepth()) {
+                        if (e2.getPomOrder() == e1.getPomOrder()) {
+                            return e1.getTarget()
+                                    .toString()
+                                    .compareTo(e2.getTarget().toString());
                         }
                         return e2.getPomOrder() - e1.getPomOrder();
                     }
                     return e2.getDepth() - e1.getDepth();
-                } );
+                });
 
-                for ( MetadataGraphEdge e : sortedExits )
-                {
+                for (MetadataGraphEdge e : sortedExits) {
                     MetadataGraphVertex targetNode = e.getTarget();
-                    targetNode.getMd().setArtifactScope( e.getScope() );
-                    targetNode.getMd().setWhy( e.getSource().getMd().toString() );
-                    visit( targetNode );
+                    targetNode.getMd().setArtifactScope(e.getScope());
+                    targetNode.getMd().setWhy(e.getSource().getMd().toString());
+                    visit(targetNode);
                 }
             }
-
         }
-        //-----------------------------------------------------------------------
-        //-----------------------------------------------------------------------
+        // -----------------------------------------------------------------------
+        // -----------------------------------------------------------------------
     }
-    //----------------------------------------------------------------------------------------------------
-    //----------------------------------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------------------------------
 }
-
-
-
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicy.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicy.java
index bb76422..71a6689 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicy.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,56 +16,53 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
-import org.codehaus.plexus.component.annotations.Component;
 import org.codehaus.plexus.component.annotations.Configuration;
 
 /**
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-@Component( role = GraphConflictResolutionPolicy.class )
-public class DefaultGraphConflictResolutionPolicy
-    implements GraphConflictResolutionPolicy
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultGraphConflictResolutionPolicy implements GraphConflictResolutionPolicy {
     /**
      * artifact, closer to the entry point, is selected
      */
-    @Configuration( name = "closer-first", value = "true" )
+    @Configuration(name = "closer-first", value = "true")
     private boolean closerFirst = true;
 
     /**
      * newer artifact is selected
      */
-    @Configuration( name = "newer-first", value = "true" )
+    @Configuration(name = "newer-first", value = "true")
     private boolean newerFirst = true;
 
-    public MetadataGraphEdge apply( MetadataGraphEdge e1, MetadataGraphEdge e2 )
-    {
+    public MetadataGraphEdge apply(MetadataGraphEdge e1, MetadataGraphEdge e2) {
         int depth1 = e1.getDepth();
         int depth2 = e2.getDepth();
 
-        if ( depth1 == depth2 )
-        {
-            ArtifactVersion v1 = new DefaultArtifactVersion( e1.getVersion() );
-            ArtifactVersion v2 = new DefaultArtifactVersion( e2.getVersion() );
+        if (depth1 == depth2) {
+            ArtifactVersion v1 = new DefaultArtifactVersion(e1.getVersion());
+            ArtifactVersion v2 = new DefaultArtifactVersion(e2.getVersion());
 
-            if ( newerFirst )
-            {
-                return v1.compareTo( v2 ) > 0 ? e1 : e2;
+            if (newerFirst) {
+                return v1.compareTo(v2) > 0 ? e1 : e2;
             }
 
-            return v1.compareTo( v2 ) > 0 ? e2 : e1;
+            return v1.compareTo(v2) > 0 ? e2 : e1;
         }
 
-        if ( closerFirst )
-        {
+        if (closerFirst) {
             return depth1 < depth2 ? e1 : e2;
         }
 
         return depth1 < depth2 ? e2 : e1;
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolver.java
index 976fcb8..55bad67 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,204 +16,184 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.TreeSet;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
-import org.codehaus.plexus.component.annotations.Component;
-import org.codehaus.plexus.component.annotations.Requirement;
 
 /**
  * Default conflict resolver.Implements closer newer first policy by default, but could be configured via plexus
  *
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  */
-@Component( role = GraphConflictResolver.class )
-public class DefaultGraphConflictResolver
-    implements GraphConflictResolver
-{
+@Named
+@Singleton
+@Deprecated
+public class DefaultGraphConflictResolver implements GraphConflictResolver {
     /**
      * artifact, closer to the entry point, is selected
      */
-    @Requirement( role = GraphConflictResolutionPolicy.class )
+    @Inject
     protected GraphConflictResolutionPolicy policy;
 
     // -------------------------------------------------------------------------------------
     // -------------------------------------------------------------------------------------
-    public MetadataGraph resolveConflicts( MetadataGraph graph, ArtifactScopeEnum scope )
-        throws GraphConflictResolutionException
-    {
-        if ( policy == null )
-        {
-            throw new GraphConflictResolutionException( "no GraphConflictResolutionPolicy injected" );
+    public MetadataGraph resolveConflicts(MetadataGraph graph, ArtifactScopeEnum scope)
+            throws GraphConflictResolutionException {
+        if (policy == null) {
+            throw new GraphConflictResolutionException("no GraphConflictResolutionPolicy injected");
         }
 
-        if ( graph == null )
-        {
+        if (graph == null) {
             return null;
         }
 
         final MetadataGraphVertex entry = graph.getEntry();
-        if ( entry == null )
-        {
+        if (entry == null) {
             return null;
         }
 
-        if ( graph.isEmpty() )
-        {
-            throw new GraphConflictResolutionException( "graph with an entry, but not vertices do not exist" );
+        if (graph.isEmpty()) {
+            throw new GraphConflictResolutionException("graph with an entry, but not vertices do not exist");
         }
 
-        if ( graph.isEmptyEdges() )
-        {
+        if (graph.isEmptyEdges()) {
             return null; // no edges - nothing to worry about
         }
 
         final TreeSet<MetadataGraphVertex> vertices = graph.getVertices();
 
-        try
-        {
+        try {
             // edge case - single vertex graph
-            if ( vertices.size() == 1 )
-            {
-                return new MetadataGraph( entry );
+            if (vertices.size() == 1) {
+                return new MetadataGraph(entry);
             }
 
-            final ArtifactScopeEnum requestedScope = ArtifactScopeEnum.checkScope( scope );
+            final ArtifactScopeEnum requestedScope = ArtifactScopeEnum.checkScope(scope);
 
-            MetadataGraph res = new MetadataGraph( vertices.size() );
-            res.setVersionedVertices( false );
-            res.setScopedVertices( false );
+            MetadataGraph res = new MetadataGraph(vertices.size());
+            res.setVersionedVertices(false);
+            res.setScopedVertices(false);
 
-            MetadataGraphVertex resEntry = res.addVertex( entry.getMd() );
-            res.setEntry( resEntry );
+            MetadataGraphVertex resEntry = res.addVertex(entry.getMd());
+            res.setEntry(resEntry);
 
-            res.setScope( requestedScope );
+            res.setScope(requestedScope);
 
-            for ( MetadataGraphVertex v : vertices )
-            {
-                final List<MetadataGraphEdge> ins = graph.getIncidentEdges( v );
-                final MetadataGraphEdge edge = cleanEdges( v, ins, requestedScope );
+            for (MetadataGraphVertex v : vertices) {
+                final List<MetadataGraphEdge> ins = graph.getIncidentEdges(v);
+                final MetadataGraphEdge edge = cleanEdges(v, ins, requestedScope);
 
-                if ( edge == null )
-                { // no edges - don't need this vertex anymore
-                    if ( entry.equals( v ) )
-                    { // unless it's an entry point.
+                if (edge == null) { // no edges - don't need this vertex anymore
+                    if (entry.equals(v)) { // unless it's an entry point.
                         // currently processing the entry point - it should not have any entry incident edges
-                        res.getEntry().getMd().setWhy( "This is a graph entry point. No links." );
-                    }
-                    else
-                    {
+                        res.getEntry().getMd().setWhy("This is a graph entry point. No links.");
+                    } else {
                         // System.out.println("--->"+v.getMd().toDomainString()
                         // +" has been terminated on this entry set\n-------------------\n"
                         // +ins
                         // +"\n-------------------\n"
                         // );
                     }
-                }
-                else
-                {
+                } else {
                     // System.out.println("+++>"+v.getMd().toDomainString()+" still has "+edge.toString() );
                     // fill in domain md with actual version data
                     ArtifactMetadata md = v.getMd();
-                    ArtifactMetadata newMd =
-                        new ArtifactMetadata( md.getGroupId(), md.getArtifactId(), edge.getVersion(), md.getType(),
-                                              md.getScopeAsEnum(), md.getClassifier(), edge.getArtifactUri(),
-                                              edge.getSource() == null ? "" : edge.getSource().getMd().toString(),
-                                              edge.isResolved(), edge.getTarget() == null ? null
-                                                              : edge.getTarget().getMd().getError() );
-                    MetadataGraphVertex newV = res.addVertex( newMd );
-                    MetadataGraphVertex sourceV = res.addVertex( edge.getSource().getMd() );
+                    ArtifactMetadata newMd = new ArtifactMetadata(
+                            md.getGroupId(),
+                            md.getArtifactId(),
+                            edge.getVersion(),
+                            md.getType(),
+                            md.getScopeAsEnum(),
+                            md.getClassifier(),
+                            edge.getArtifactUri(),
+                            edge.getSource() == null
+                                    ? ""
+                                    : edge.getSource().getMd().toString(),
+                            edge.isResolved(),
+                            edge.getTarget() == null
+                                    ? null
+                                    : edge.getTarget().getMd().getError());
+                    MetadataGraphVertex newV = res.addVertex(newMd);
+                    MetadataGraphVertex sourceV = res.addVertex(edge.getSource().getMd());
 
-                    res.addEdge( sourceV, newV, edge );
+                    res.addEdge(sourceV, newV, edge);
                 }
             }
             // System.err.println("Original graph("+graph.getVertices().size()+"):\n"+graph.toString());
             // System.err.println("Cleaned("+requestedScope+") graph("+res.getVertices().size()+"):\n"+res.toString());
             // System.err.println("Linked("+requestedScope+")
             // subgraph("+linkedRes.getVertices().size()+"):\n"+linkedRes.toString());
-            return findLinkedSubgraph( res );
-        }
-        catch ( MetadataResolutionException e )
-        {
-            throw new GraphConflictResolutionException( e );
+            return findLinkedSubgraph(res);
+        } catch (MetadataResolutionException e) {
+            throw new GraphConflictResolutionException(e);
         }
     }
 
     // -------------------------------------------------------------------------------------
-    private MetadataGraph findLinkedSubgraph( MetadataGraph g )
-    {
-        if ( g.getVertices().size() == 1 )
-        {
+    private MetadataGraph findLinkedSubgraph(MetadataGraph g) {
+        if (g.getVertices().size() == 1) {
             return g;
         }
 
-        List<MetadataGraphVertex> visited = new ArrayList<>( g.getVertices().size() );
-        visit( g.getEntry(), visited, g );
+        List<MetadataGraphVertex> visited = new ArrayList<>(g.getVertices().size());
+        visit(g.getEntry(), visited, g);
 
-        List<MetadataGraphVertex> dropList = new ArrayList<>( g.getVertices().size() );
+        List<MetadataGraphVertex> dropList = new ArrayList<>(g.getVertices().size());
 
         // collect drop list
-        for ( MetadataGraphVertex v : g.getVertices() )
-        {
-            if ( !visited.contains( v ) )
-            {
-                dropList.add( v );
+        for (MetadataGraphVertex v : g.getVertices()) {
+            if (!visited.contains(v)) {
+                dropList.add(v);
             }
         }
 
-        if ( dropList.size() < 1 )
-        {
+        if (dropList.size() < 1) {
             return g;
         }
 
         // now - drop vertices
         TreeSet<MetadataGraphVertex> vertices = g.getVertices();
-        for ( MetadataGraphVertex v : dropList )
-        {
-            vertices.remove( v );
+        for (MetadataGraphVertex v : dropList) {
+            vertices.remove(v);
         }
 
         return g;
     }
 
     // -------------------------------------------------------------------------------------
-    private void visit( MetadataGraphVertex from, List<MetadataGraphVertex> visited, MetadataGraph graph )
-    {
-        if ( visited.contains( from ) )
-        {
+    private void visit(MetadataGraphVertex from, List<MetadataGraphVertex> visited, MetadataGraph graph) {
+        if (visited.contains(from)) {
             return;
         }
 
-        visited.add( from );
+        visited.add(from);
 
-        List<MetadataGraphEdge> exitList = graph.getExcidentEdges( from );
+        List<MetadataGraphEdge> exitList = graph.getExcidentEdges(from);
         // String s = "|---> "+from.getMd().toString()+" - "+(exitList == null ? -1 : exitList.size()) + " exit links";
-        if ( exitList != null && exitList.size() > 0 )
-        {
-            for ( MetadataGraphEdge e : graph.getExcidentEdges( from ) )
-            {
-                visit( e.getTarget(), visited, graph );
+        if (exitList != null && exitList.size() > 0) {
+            for (MetadataGraphEdge e : graph.getExcidentEdges(from)) {
+                visit(e.getTarget(), visited, graph);
             }
         }
     }
 
     // -------------------------------------------------------------------------------------
-    private MetadataGraphEdge cleanEdges( MetadataGraphVertex v, List<MetadataGraphEdge> edges,
-                                          ArtifactScopeEnum scope )
-    {
-        if ( edges == null || edges.isEmpty() )
-        {
+    private MetadataGraphEdge cleanEdges(
+            MetadataGraphVertex v, List<MetadataGraphEdge> edges, ArtifactScopeEnum scope) {
+        if (edges == null || edges.isEmpty()) {
             return null;
         }
 
-        if ( edges.size() == 1 )
-        {
-            MetadataGraphEdge e = edges.get( 0 );
-            if ( scope.encloses( e.getScope() ) )
-            {
+        if (edges.size() == 1) {
+            MetadataGraphEdge e = edges.get(0);
+            if (scope.encloses(e.getScope())) {
                 return e;
             }
 
@@ -224,20 +202,15 @@
 
         MetadataGraphEdge res = null;
 
-        for ( MetadataGraphEdge e : edges )
-        {
-            if ( !scope.encloses( e.getScope() ) )
-            {
+        for (MetadataGraphEdge e : edges) {
+            if (!scope.encloses(e.getScope())) {
                 continue;
             }
 
-            if ( res == null )
-            {
+            if (res == null) {
                 res = e;
-            }
-            else
-            {
-                res = policy.apply( e, res );
+            } else {
+                res = policy.apply(e, res);
             }
         }
 
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionException.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionException.java
index 035904a..68a22c9 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,34 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 /**
  *
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-public class GraphConflictResolutionException
-    extends Exception
-{
+@Deprecated
+public class GraphConflictResolutionException extends Exception {
     private static final long serialVersionUID = 2677613140287940255L;
 
-    public GraphConflictResolutionException()
-    {
+    public GraphConflictResolutionException() {}
+
+    public GraphConflictResolutionException(String message) {
+        super(message);
     }
 
-    public GraphConflictResolutionException( String message )
-    {
-        super( message );
+    public GraphConflictResolutionException(Throwable cause) {
+        super(cause);
     }
 
-    public GraphConflictResolutionException( Throwable cause )
-    {
-        super( cause );
+    public GraphConflictResolutionException(String message, Throwable cause) {
+        super(message, cause);
     }
-
-    public GraphConflictResolutionException( String message, Throwable cause )
-    {
-        super( message, cause );
-    }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionPolicy.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionPolicy.java
index 979d383..0662dff 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionPolicy.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolutionPolicy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,18 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 /**
  *  MetadataGraph edge selection policy. Complements
  *  GraphConflictResolver by being injected into it
  *
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-
-public interface GraphConflictResolutionPolicy
-{
+@Deprecated
+public interface GraphConflictResolutionPolicy {
     String ROLE = GraphConflictResolutionPolicy.class.getName();
 
-    MetadataGraphEdge apply( MetadataGraphEdge e1, MetadataGraphEdge e2 );
+    MetadataGraphEdge apply(MetadataGraphEdge e1, MetadataGraphEdge e2);
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolver.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolver.java
index ef70baa..e573f82 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolver.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/GraphConflictResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
 
@@ -25,10 +24,9 @@
  * Resolves conflicts in the supplied dependency graph.
  * Different implementations will implement different conflict resolution policies.
  *
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  */
-public interface GraphConflictResolver
-{
+@Deprecated
+public interface GraphConflictResolver {
     String ROLE = GraphConflictResolver.class.getName();
 
     /**
@@ -43,6 +41,6 @@
      *
      * @since 3.0
      */
-    MetadataGraph resolveConflicts( MetadataGraph graph, ArtifactScopeEnum scope )
-        throws GraphConflictResolutionException;
+    MetadataGraph resolveConflicts(MetadataGraph graph, ArtifactScopeEnum scope)
+            throws GraphConflictResolutionException;
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraph.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraph.java
index c6ec048..1ed579b 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraph.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraph.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -30,20 +29,19 @@
 /**
  * maven dependency metadata graph
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-public class MetadataGraph
-{
+@Deprecated
+public class MetadataGraph {
     public static final int DEFAULT_VERTICES = 32;
-    public static final int DEFAULT_EDGES    = 64;
+    public static final int DEFAULT_EDGES = 64;
 
     // flags to indicate the granularity of vertices
     private boolean versionedVertices = false;
-    private boolean scopedVertices    = false;
+    private boolean scopedVertices = false;
     /**
-    * the entry point we started building the graph from
-    */
+     * the entry point we started building the graph from
+     */
     MetadataGraphVertex entry;
 
     // graph vertices
@@ -53,6 +51,7 @@
      * incident and excident edges per node
      */
     Map<MetadataGraphVertex, List<MetadataGraphEdge>> incidentEdges;
+
     Map<MetadataGraphVertex, List<MetadataGraphEdge>> excidentEdges;
 
     /**
@@ -61,44 +60,39 @@
      */
     ArtifactScopeEnum scope;
 
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
     /**
      * init graph
      */
-    public MetadataGraph( int nVertices )
-    {
-        init( nVertices, 2 * nVertices );
+    public MetadataGraph(int nVertices) {
+        init(nVertices, 2 * nVertices);
     }
-    public MetadataGraph( int nVertices, int nEdges )
-    {
-        init( nVertices, nEdges );
+
+    public MetadataGraph(int nVertices, int nEdges) {
+        init(nVertices, nEdges);
     }
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
     /**
      * construct a single vertex
      */
-    public MetadataGraph( MetadataGraphVertex entry )
-        throws MetadataResolutionException
-    {
-        checkVertex( entry );
-        checkVertices( 1 );
+    public MetadataGraph(MetadataGraphVertex entry) throws MetadataResolutionException {
+        checkVertex(entry);
+        checkVertices(1);
 
-        entry.setCompareVersion( versionedVertices );
-        entry.setCompareScope( scopedVertices );
+        entry.setCompareVersion(versionedVertices);
+        entry.setCompareScope(scopedVertices);
 
-        vertices.add( entry );
+        vertices.add(entry);
         this.entry = entry;
     }
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
     /**
      * construct graph from a "dirty" tree
      */
-    public MetadataGraph( MetadataTreeNode tree )
-        throws MetadataResolutionException
-    {
-        this( tree, false, false );
+    public MetadataGraph(MetadataTreeNode tree) throws MetadataResolutionException {
+        this(tree, false, false);
     }
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
     /**
      * construct graph from a "dirty" tree
      *
@@ -108,407 +102,334 @@
      * (different versions and/or scopes -&gt; different nodes)
      *
      */
-    public MetadataGraph( MetadataTreeNode tree, boolean versionedVertices, boolean scopedVertices )
-        throws MetadataResolutionException
-    {
-        if ( tree == null )
-        {
-            throw new MetadataResolutionException( "tree is null" );
+    public MetadataGraph(MetadataTreeNode tree, boolean versionedVertices, boolean scopedVertices)
+            throws MetadataResolutionException {
+        if (tree == null) {
+            throw new MetadataResolutionException("tree is null");
         }
 
-        setVersionedVertices( versionedVertices );
-        setScopedVertices( scopedVertices );
+        setVersionedVertices(versionedVertices);
+        setScopedVertices(scopedVertices);
 
         this.versionedVertices = scopedVertices || versionedVertices;
         this.scopedVertices = scopedVertices;
 
-        int count = countNodes( tree );
+        int count = countNodes(tree);
 
-        init( count, count + ( count / 2 ) );
+        init(count, count + (count / 2));
 
-        processTreeNodes( null, tree, 0, 0 );
+        processTreeNodes(null, tree, 0, 0);
     }
-    //------------------------------------------------------------------------
-    private void processTreeNodes( MetadataGraphVertex parentVertex, MetadataTreeNode node, int depth, int pomOrder )
-        throws MetadataResolutionException
-    {
-        if ( node == null )
-        {
+    // ------------------------------------------------------------------------
+    private void processTreeNodes(MetadataGraphVertex parentVertex, MetadataTreeNode node, int depth, int pomOrder)
+            throws MetadataResolutionException {
+        if (node == null) {
             return;
         }
 
-        MetadataGraphVertex vertex = new MetadataGraphVertex( node.md, versionedVertices, scopedVertices );
-        if ( !vertices.contains( vertex ) )
-        {
-            vertices.add( vertex );
+        MetadataGraphVertex vertex = new MetadataGraphVertex(node.md, versionedVertices, scopedVertices);
+        if (!vertices.contains(vertex)) {
+            vertices.add(vertex);
         }
 
-        if ( parentVertex != null ) // then create the edge
+        if (parentVertex != null) // then create the edge
         {
             ArtifactMetadata md = node.getMd();
             MetadataGraphEdge e =
-                new MetadataGraphEdge( md.version, md.resolved, md.artifactScope, md.artifactUri, depth, pomOrder );
-            addEdge( parentVertex, vertex, e );
-        }
-        else
-        {
+                    new MetadataGraphEdge(md.version, md.resolved, md.artifactScope, md.artifactUri, depth, pomOrder);
+            addEdge(parentVertex, vertex, e);
+        } else {
             entry = vertex;
         }
 
         MetadataTreeNode[] kids = node.getChildren();
-        if ( kids == null || kids.length < 1 )
-        {
+        if (kids == null || kids.length < 1) {
             return;
         }
 
-        for ( int i = 0; i < kids.length; i++ )
-        {
+        for (int i = 0; i < kids.length; i++) {
             MetadataTreeNode n = kids[i];
-            processTreeNodes( vertex, n, depth + 1, i );
+            processTreeNodes(vertex, n, depth + 1, i);
         }
     }
-    //------------------------------------------------------------------------
-    public MetadataGraphVertex findVertex( ArtifactMetadata md )
-    {
-        if ( md == null || vertices == null || vertices.size() < 1 )
-        {
+    // ------------------------------------------------------------------------
+    public MetadataGraphVertex findVertex(ArtifactMetadata md) {
+        if (md == null || vertices == null || vertices.size() < 1) {
             return null;
         }
 
-        MetadataGraphVertex v = new MetadataGraphVertex( md );
-        v.setCompareVersion( versionedVertices );
-        v.setCompareScope( scopedVertices );
+        MetadataGraphVertex v = new MetadataGraphVertex(md);
+        v.setCompareVersion(versionedVertices);
+        v.setCompareScope(scopedVertices);
 
-        for ( MetadataGraphVertex gv : vertices )
-        {
-            if ( gv.equals( v ) )
-            {
+        for (MetadataGraphVertex gv : vertices) {
+            if (gv.equals(v)) {
                 return gv;
             }
         }
 
         return null;
     }
-    //------------------------------------------------------------------------
-    public MetadataGraphVertex addVertex( ArtifactMetadata md )
-    {
-        if ( md == null )
-        {
+    // ------------------------------------------------------------------------
+    public MetadataGraphVertex addVertex(ArtifactMetadata md) {
+        if (md == null) {
             return null;
         }
 
         checkVertices();
 
-        MetadataGraphVertex v = findVertex( md );
-        if ( v != null )
-        {
+        MetadataGraphVertex v = findVertex(md);
+        if (v != null) {
             return v;
         }
 
-        v = new MetadataGraphVertex( md );
+        v = new MetadataGraphVertex(md);
 
-        v.setCompareVersion( versionedVertices );
-        v.setCompareScope( scopedVertices );
+        v.setCompareVersion(versionedVertices);
+        v.setCompareScope(scopedVertices);
 
-        vertices.add( v );
+        vertices.add(v);
         return v;
     }
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
     /**
      * init graph
      */
-    private void init( int nVertices, int nEdges )
-    {
+    private void init(int nVertices, int nEdges) {
         int nV = nVertices;
-        if ( nVertices < 1 )
-        {
+        if (nVertices < 1) {
             nV = 1;
         }
 
-        checkVertices( nV );
+        checkVertices(nV);
 
         int nE = nVertices;
-        if ( nEdges <= nV )
-        {
+        if (nEdges <= nV) {
             nE = 2 * nE;
         }
 
-        checkEdges( nE );
+        checkEdges(nE);
     }
 
-    private void checkVertices()
-    {
-        checkVertices( DEFAULT_VERTICES );
+    private void checkVertices() {
+        checkVertices(DEFAULT_VERTICES);
     }
 
-    private void checkVertices( int nVertices )
-    {
-        if ( vertices == null )
-        {
+    private void checkVertices(int nVertices) {
+        if (vertices == null) {
             vertices = new TreeSet<>();
         }
     }
-    private void checkEdges()
-    {
+
+    private void checkEdges() {
         int count = DEFAULT_EDGES;
 
-        if ( vertices != null )
-        {
+        if (vertices != null) {
             count = vertices.size() + vertices.size() / 2;
         }
 
-        checkEdges( count );
+        checkEdges(count);
     }
-    private void checkEdges( int nEdges )
-    {
-        if ( incidentEdges == null )
-        {
-            incidentEdges = new HashMap<>( nEdges );
+
+    private void checkEdges(int nEdges) {
+        if (incidentEdges == null) {
+            incidentEdges = new HashMap<>(nEdges);
         }
-        if ( excidentEdges == null )
-        {
-            excidentEdges = new HashMap<>( nEdges );
+        if (excidentEdges == null) {
+            excidentEdges = new HashMap<>(nEdges);
         }
     }
-    //------------------------------------------------------------------------
-    private static void checkVertex( MetadataGraphVertex v )
-        throws MetadataResolutionException
-    {
-        if ( v == null )
-        {
-            throw new MetadataResolutionException( "null vertex" );
+    // ------------------------------------------------------------------------
+    private static void checkVertex(MetadataGraphVertex v) throws MetadataResolutionException {
+        if (v == null) {
+            throw new MetadataResolutionException("null vertex");
         }
-        if ( v.getMd() == null )
-        {
-            throw new MetadataResolutionException( "vertex without metadata" );
+        if (v.getMd() == null) {
+            throw new MetadataResolutionException("vertex without metadata");
         }
     }
-    //------------------------------------------------------------------------
-    private static void checkEdge( MetadataGraphEdge e )
-        throws MetadataResolutionException
-    {
-        if ( e == null )
-        {
-            throw new MetadataResolutionException( "badly formed edge" );
+    // ------------------------------------------------------------------------
+    private static void checkEdge(MetadataGraphEdge e) throws MetadataResolutionException {
+        if (e == null) {
+            throw new MetadataResolutionException("badly formed edge");
         }
     }
-    //------------------------------------------------------------------------
-    public List<MetadataGraphEdge> getEdgesBetween( MetadataGraphVertex vFrom, MetadataGraphVertex vTo )
-    {
-        List<MetadataGraphEdge> edges = getIncidentEdges( vTo );
-        if ( edges == null || edges.isEmpty() )
-        {
+    // ------------------------------------------------------------------------
+    public List<MetadataGraphEdge> getEdgesBetween(MetadataGraphVertex vFrom, MetadataGraphVertex vTo) {
+        List<MetadataGraphEdge> edges = getIncidentEdges(vTo);
+        if (edges == null || edges.isEmpty()) {
             return null;
         }
 
-        List<MetadataGraphEdge> res = new ArrayList<>( edges.size() );
+        List<MetadataGraphEdge> res = new ArrayList<>(edges.size());
 
-        for ( MetadataGraphEdge e : edges )
-        {
-            if ( e.getSource().equals( vFrom ) )
-            {
-                res.add( e );
+        for (MetadataGraphEdge e : edges) {
+            if (e.getSource().equals(vFrom)) {
+                res.add(e);
             }
         }
 
         return res;
     }
-    //------------------------------------------------------------------------
-    public MetadataGraph addEdge( MetadataGraphVertex vFrom, MetadataGraphVertex vTo, MetadataGraphEdge e )
-        throws MetadataResolutionException
-    {
-        checkVertex( vFrom );
-        checkVertex( vTo );
+    // ------------------------------------------------------------------------
+    public MetadataGraph addEdge(MetadataGraphVertex vFrom, MetadataGraphVertex vTo, MetadataGraphEdge e)
+            throws MetadataResolutionException {
+        checkVertex(vFrom);
+        checkVertex(vTo);
 
         checkVertices();
 
-        checkEdge( e );
+        checkEdge(e);
         checkEdges();
 
-        e.setSource( vFrom );
-        e.setTarget( vTo );
+        e.setSource(vFrom);
+        e.setTarget(vTo);
 
-        vFrom.setCompareVersion( versionedVertices );
-        vFrom.setCompareScope( scopedVertices );
+        vFrom.setCompareVersion(versionedVertices);
+        vFrom.setCompareScope(scopedVertices);
 
-        List<MetadataGraphEdge> exList = excidentEdges.computeIfAbsent( vFrom, k -> new ArrayList<>() );
+        List<MetadataGraphEdge> exList = excidentEdges.computeIfAbsent(vFrom, k -> new ArrayList<>());
 
-        if ( !exList.contains( e ) )
-        {
-            exList.add( e );
+        if (!exList.contains(e)) {
+            exList.add(e);
         }
 
-        List<MetadataGraphEdge> inList = incidentEdges.computeIfAbsent( vTo, k -> new ArrayList<>() );
+        List<MetadataGraphEdge> inList = incidentEdges.computeIfAbsent(vTo, k -> new ArrayList<>());
 
-        if ( !inList.contains( e ) )
-        {
-            inList.add( e );
+        if (!inList.contains(e)) {
+            inList.add(e);
         }
 
         return this;
     }
-    //------------------------------------------------------------------------
-    public MetadataGraph removeVertex( MetadataGraphVertex v )
-    {
-        if ( vertices != null && v != null )
-        {
-            vertices.remove( v );
+    // ------------------------------------------------------------------------
+    public MetadataGraph removeVertex(MetadataGraphVertex v) {
+        if (vertices != null && v != null) {
+            vertices.remove(v);
         }
 
-        if ( incidentEdges != null )
-        {
-            incidentEdges.remove( v );
+        if (incidentEdges != null) {
+            incidentEdges.remove(v);
         }
 
-        if ( excidentEdges != null )
-        {
-            excidentEdges.remove( v );
+        if (excidentEdges != null) {
+            excidentEdges.remove(v);
         }
 
         return this;
-
     }
-    //------------------------------------------------------------------------
-    private static int countNodes( MetadataTreeNode tree )
-    {
-        if ( tree == null )
-        {
+    // ------------------------------------------------------------------------
+    private static int countNodes(MetadataTreeNode tree) {
+        if (tree == null) {
             return 0;
         }
 
         int count = 1;
         MetadataTreeNode[] kids = tree.getChildren();
-        if ( kids == null || kids.length < 1 )
-        {
+        if (kids == null || kids.length < 1) {
             return count;
         }
-        for ( MetadataTreeNode n : kids )
-        {
-            count += countNodes( n );
+        for (MetadataTreeNode n : kids) {
+            count += countNodes(n);
         }
 
         return count;
     }
 
-    //------------------------------------------------------------------------
-    public MetadataGraphVertex getEntry()
-    {
+    // ------------------------------------------------------------------------
+    public MetadataGraphVertex getEntry() {
         return entry;
     }
 
-    public void setEntry( MetadataGraphVertex entry )
-    {
+    public void setEntry(MetadataGraphVertex entry) {
         this.entry = entry;
     }
 
-    public TreeSet<MetadataGraphVertex> getVertices()
-    {
+    public TreeSet<MetadataGraphVertex> getVertices() {
         return vertices;
     }
 
-    public List<MetadataGraphEdge> getIncidentEdges( MetadataGraphVertex vertex )
-    {
+    public List<MetadataGraphEdge> getIncidentEdges(MetadataGraphVertex vertex) {
         checkEdges();
-        return incidentEdges.get( vertex );
+        return incidentEdges.get(vertex);
     }
 
-    public List<MetadataGraphEdge> getExcidentEdges( MetadataGraphVertex vertex )
-    {
+    public List<MetadataGraphEdge> getExcidentEdges(MetadataGraphVertex vertex) {
         checkEdges();
-        return excidentEdges.get( vertex );
+        return excidentEdges.get(vertex);
     }
 
-    public boolean isVersionedVertices()
-    {
+    public boolean isVersionedVertices() {
         return versionedVertices;
     }
 
-    public void setVersionedVertices( boolean versionedVertices )
-    {
+    public void setVersionedVertices(boolean versionedVertices) {
         this.versionedVertices = versionedVertices;
     }
 
-    public boolean isScopedVertices()
-    {
+    public boolean isScopedVertices() {
         return scopedVertices;
     }
 
-    public void setScopedVertices( boolean scopedVertices )
-    {
+    public void setScopedVertices(boolean scopedVertices) {
         this.scopedVertices = scopedVertices;
 
         // scoped graph is versioned by definition
-        if ( scopedVertices )
-        {
+        if (scopedVertices) {
             versionedVertices = true;
         }
     }
 
-    public ArtifactScopeEnum getScope()
-    {
+    public ArtifactScopeEnum getScope() {
         return scope;
     }
 
-    public void setScope( ArtifactScopeEnum scope )
-    {
+    public void setScope(ArtifactScopeEnum scope) {
         this.scope = scope;
     }
 
     // ------------------------------------------------------------------------
-    public boolean isEmpty()
-    {
+    public boolean isEmpty() {
         return entry == null || vertices == null || vertices.isEmpty();
     }
 
-    //------------------------------------------------------------------------
-    public boolean isEmptyEdges()
-    {
+    // ------------------------------------------------------------------------
+    public boolean isEmptyEdges() {
         return isEmpty() || incidentEdges == null || incidentEdges.isEmpty();
     }
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
     @Override
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 512 );
-        if ( isEmpty() )
-        {
+    public String toString() {
+        if (isEmpty()) {
             return "empty";
         }
-        for ( MetadataGraphVertex v : vertices )
-        {
-            sb.append( "Vertex:  " ).append( v.getMd().toString() ).append( '\n' );
-            List<MetadataGraphEdge> ins = getIncidentEdges( v );
-            if ( ins != null )
-            {
-                for ( MetadataGraphEdge e : ins )
-                {
-                    sb.append( "       from :  " ).append( e.toString() ).append( '\n' );
+        StringBuilder sb = new StringBuilder(512);
+        for (MetadataGraphVertex v : vertices) {
+            sb.append("Vertex:  ").append(v.getMd().toString()).append('\n');
+            List<MetadataGraphEdge> ins = getIncidentEdges(v);
+            if (ins != null) {
+                for (MetadataGraphEdge e : ins) {
+                    sb.append("       from :  ").append(e.toString()).append('\n');
                 }
-            }
-            else
-            {
-                sb.append( "      no entries\n" );
+            } else {
+                sb.append("      no entries\n");
             }
 
-            List<MetadataGraphEdge> outs = getExcidentEdges( v );
-            if ( outs != null )
-            {
-                for ( MetadataGraphEdge e : outs )
-                {
-                    sb.append( "        to :  " ).append( e.toString() ).append( '\n' );
+            List<MetadataGraphEdge> outs = getExcidentEdges(v);
+            if (outs != null) {
+                for (MetadataGraphEdge e : outs) {
+                    sb.append("        to :  ").append(e.toString()).append('\n');
                 }
-            }
-            else
-            {
-                sb.append( "      no exit\n" );
+            } else {
+                sb.append("      no exit\n");
             }
 
-            sb.append( "-------------------------------------------------\n" );
+            sb.append("-------------------------------------------------\n");
         }
-        sb.append( "=============================================================\n" );
+        sb.append("=============================================================\n");
         return sb.toString();
     }
 
-    //------------------------------------------------------------------------
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphEdge.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphEdge.java
index 16fe9bc..161b9be 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphEdge.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphEdge.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
 
@@ -25,18 +24,16 @@
  * metadata graph edge - combination of version, scope and depth define
  * an edge in the graph
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-
-public class MetadataGraphEdge
-{
-    String            version;
+@Deprecated
+public class MetadataGraphEdge {
+    String version;
     ArtifactScopeEnum scope;
-    int               depth = -1;
-    int               pomOrder = -1;
-    boolean           resolved = true;
-    String            artifactUri;
+    int depth = -1;
+    int pomOrder = -1;
+    boolean resolved = true;
+    String artifactUri;
 
     /**
      * capturing where this link came from
@@ -44,13 +41,13 @@
      *
      *   In the first implementation only source used for explanatory function
      */
-    MetadataGraphVertex  source;
-    MetadataGraphVertex  target;
+    MetadataGraphVertex source;
 
-    //----------------------------------------------------------------------------
-    public MetadataGraphEdge( String version, boolean resolved, ArtifactScopeEnum scope, String artifactUri, int depth,
-                              int pomOrder )
-    {
+    MetadataGraphVertex target;
+
+    // ----------------------------------------------------------------------------
+    public MetadataGraphEdge(
+            String version, boolean resolved, ArtifactScopeEnum scope, String artifactUri, int depth, int pomOrder) {
         super();
         this.version = version;
         this.scope = scope;
@@ -59,133 +56,112 @@
         this.resolved = resolved;
         this.pomOrder = pomOrder;
     }
-    //----------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------
     /**
      * helper for equals
      */
-    private static boolean objectsEqual( Object o1, Object o2 )
-    {
-        if ( o1 == null && o2 == null )
-        {
+    private static boolean objectsEqual(Object o1, Object o2) {
+        if (o1 == null && o2 == null) {
             return true;
         }
-        if ( o1 == null || o2 == null )
-        {
+        if (o1 == null || o2 == null) {
             return false; // as they are not both null
         }
-        return o1.equals( o2 );
+        return o1.equals(o2);
     }
 
-    //----------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------
     /**
      * used to eliminate exact duplicates in the edge list
      */
     @Override
-    @SuppressWarnings( "checkstyle:equalshashcode" )
-    public boolean equals( Object o )
-    {
-        if ( o instanceof MetadataGraphEdge )
-        {
+    @SuppressWarnings("checkstyle:equalshashcode")
+    public boolean equals(Object o) {
+        if (o instanceof MetadataGraphEdge) {
             MetadataGraphEdge e = (MetadataGraphEdge) o;
 
-            return objectsEqual( version, e.version )
-                && ArtifactScopeEnum.checkScope( scope ).getScope().
-                    equals( ArtifactScopeEnum.checkScope( e.scope ).getScope() )
-                && depth == e.depth;
+            return objectsEqual(version, e.version)
+                    && ArtifactScopeEnum.checkScope(scope)
+                            .getScope()
+                            .equals(ArtifactScopeEnum.checkScope(e.scope).getScope())
+                    && depth == e.depth;
         }
         return false;
     }
 
-    //----------------------------------------------------------------------------
-    public String getVersion()
-    {
+    // ----------------------------------------------------------------------------
+    public String getVersion() {
         return version;
     }
 
-    public void setVersion( String version )
-    {
+    public void setVersion(String version) {
         this.version = version;
     }
 
-    public ArtifactScopeEnum getScope()
-    {
+    public ArtifactScopeEnum getScope() {
         return scope;
     }
 
-    public void setScope( ArtifactScopeEnum scope )
-    {
+    public void setScope(ArtifactScopeEnum scope) {
         this.scope = scope;
     }
 
-    public int getDepth()
-    {
+    public int getDepth() {
         return depth;
     }
 
-    public void setDepth( int depth )
-    {
+    public void setDepth(int depth) {
         this.depth = depth;
     }
 
-    public boolean isResolved()
-    {
+    public boolean isResolved() {
         return resolved;
     }
 
-    public void setResolved( boolean resolved )
-    {
+    public void setResolved(boolean resolved) {
         this.resolved = resolved;
     }
 
-    public int getPomOrder()
-    {
+    public int getPomOrder() {
         return pomOrder;
     }
 
-    public void setPomOrder( int pomOrder )
-    {
+    public void setPomOrder(int pomOrder) {
         this.pomOrder = pomOrder;
     }
 
-    public String getArtifactUri()
-    {
+    public String getArtifactUri() {
         return artifactUri;
     }
 
-    public void setArtifactUri( String artifactUri )
-    {
+    public void setArtifactUri(String artifactUri) {
         this.artifactUri = artifactUri;
     }
 
-    public MetadataGraphVertex getSource()
-    {
+    public MetadataGraphVertex getSource() {
         return source;
     }
 
-    public void setSource( MetadataGraphVertex source )
-    {
+    public void setSource(MetadataGraphVertex source) {
         this.source = source;
     }
 
-    public MetadataGraphVertex getTarget()
-    {
+    public MetadataGraphVertex getTarget() {
         return target;
     }
 
-    public void setTarget( MetadataGraphVertex target )
-    {
+    public void setTarget(MetadataGraphVertex target) {
         this.target = target;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return "[ " + "FROM:("
-            + ( source == null ? "no source" : ( source.md == null ? "no source MD" : source.md.toString() ) ) + ") "
-            + "TO:(" + ( target == null ? "no target" : ( target.md == null ? "no target MD" : target.md.toString() ) )
-            + ") " + "version=" + version + ", scope=" + ( scope == null ? "null" : scope.getScope() ) + ", depth="
-            + depth + "]";
+                + (source == null ? "no source" : (source.md == null ? "no source MD" : source.md.toString())) + ") "
+                + "TO:(" + (target == null ? "no target" : (target.md == null ? "no target MD" : target.md.toString()))
+                + ") " + "version=" + version + ", scope=" + (scope == null ? "null" : scope.getScope()) + ", depth="
+                + depth + "]";
     }
-    //----------------------------------------------------------------------------
-    //----------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphTransformationException.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphTransformationException.java
index 7861b48..85e79fe 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphTransformationException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphTransformationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,33 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 /**
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  */
-public class MetadataGraphTransformationException
-    extends Exception
-{
+@Deprecated
+public class MetadataGraphTransformationException extends Exception {
 
     private static final long serialVersionUID = -4029897098314019152L;
 
-    public MetadataGraphTransformationException()
-    {
+    public MetadataGraphTransformationException() {}
+
+    public MetadataGraphTransformationException(String message) {
+        super(message);
     }
 
-    public MetadataGraphTransformationException( String message )
-    {
-        super( message );
+    public MetadataGraphTransformationException(Throwable cause) {
+        super(cause);
     }
 
-    public MetadataGraphTransformationException( Throwable cause )
-    {
-        super( cause );
+    public MetadataGraphTransformationException(String message, Throwable cause) {
+        super(message, cause);
     }
-
-    public MetadataGraphTransformationException( String message, Throwable cause )
-    {
-        super( message, cause );
-    }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphVertex.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphVertex.java
index f24c395..ee8a3b5 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphVertex.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataGraphVertex.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,152 +16,122 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
 
 /**
  * metadata graph vertice - just a wrapper around artifact's metadata
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  */
-public class MetadataGraphVertex
-    implements Comparable<MetadataGraphVertex>
-{
+@Deprecated
+public class MetadataGraphVertex implements Comparable<MetadataGraphVertex> {
     ArtifactMetadata md;
 
     // indications to use these in comparison
     private boolean compareVersion = false;
-    private boolean compareScope   = false;
+    private boolean compareScope = false;
 
-    public MetadataGraphVertex( ArtifactMetadata md )
-    {
+    public MetadataGraphVertex(ArtifactMetadata md) {
         super();
         this.md = md;
     }
 
-    public MetadataGraphVertex( ArtifactMetadata md, boolean compareVersion, boolean compareScope )
-    {
-        this( md );
+    public MetadataGraphVertex(ArtifactMetadata md, boolean compareVersion, boolean compareScope) {
+        this(md);
         this.compareVersion = compareVersion;
         this.compareScope = compareScope;
     }
 
-    public ArtifactMetadata getMd()
-    {
+    public ArtifactMetadata getMd() {
         return md;
     }
 
-    public void setMd( ArtifactMetadata md )
-    {
+    public void setMd(ArtifactMetadata md) {
         this.md = md;
     }
 
     // ---------------------------------------------------------------------
-    public boolean isCompareVersion()
-    {
+    public boolean isCompareVersion() {
         return compareVersion;
     }
 
-    public void setCompareVersion( boolean compareVersion )
-    {
+    public void setCompareVersion(boolean compareVersion) {
         this.compareVersion = compareVersion;
     }
 
-    public boolean isCompareScope()
-    {
+    public boolean isCompareScope() {
         return compareScope;
     }
 
-    public void setCompareScope( boolean compareScope )
-    {
+    public void setCompareScope(boolean compareScope) {
         this.compareScope = compareScope;
     }
 
     // ---------------------------------------------------------------------
     @Override
-    public String toString()
-    {
-        return "[" + ( md == null ? "no metadata" : md.toString() ) + "]";
+    public String toString() {
+        return "[" + (md == null ? "no metadata" : md.toString()) + "]";
     }
 
     // ---------------------------------------------------------------------
-    private static int compareStrings( String s1, String s2 )
-    {
-        if ( s1 == null && s2 == null )
-        {
+    private static int compareStrings(String s1, String s2) {
+        if (s1 == null && s2 == null) {
             return 0;
         }
 
-        if ( s1 == null /* && s2 != null */ )
-        {
+        if (s1 == null /* && s2 != null */) {
             return -1;
         }
 
-        if ( /* s1 != null && */ s2 == null )
-        {
+        if (
+        /* s1 != null && */ s2 == null) {
             return 1;
         }
 
-        return s1.compareTo( s2 );
+        return s1.compareTo(s2);
     }
 
     // ---------------------------------------------------------------------
-    public int compareTo( MetadataGraphVertex vertex )
-    {
-        if ( vertex == null || vertex.getMd() == null )
-        {
+    public int compareTo(MetadataGraphVertex vertex) {
+        if (vertex == null || vertex.getMd() == null) {
             return 1;
         }
 
         ArtifactMetadata vmd = vertex.getMd();
 
-        if ( vmd == null )
-        {
-            if ( md == null )
-            {
+        if (vmd == null) {
+            if (md == null) {
                 return 0;
-            }
-            else
-            {
+            } else {
                 return 1;
             }
         }
 
-        int g = compareStrings( md.groupId, vmd.groupId );
+        int g = compareStrings(md.groupId, vmd.groupId);
 
-        if ( g == 0 )
-        {
-            int a = compareStrings( md.artifactId, vmd.artifactId );
-            if ( a == 0 )
-            {
-                if ( compareVersion )
-                {
-                    int v = compareStrings( md.version, vmd.version );
-                    if ( v == 0 )
-                    {
-                        if ( compareScope )
-                        {
-                            String s1 = ArtifactScopeEnum.checkScope( md.artifactScope ).getScope();
-                            String s2 = ArtifactScopeEnum.checkScope( vmd.artifactScope ).getScope();
-                            return s1.compareTo( s2 );
-                        }
-                        else
-                        {
+        if (g == 0) {
+            int a = compareStrings(md.artifactId, vmd.artifactId);
+            if (a == 0) {
+                if (compareVersion) {
+                    int v = compareStrings(md.version, vmd.version);
+                    if (v == 0) {
+                        if (compareScope) {
+                            String s1 = ArtifactScopeEnum.checkScope(md.artifactScope)
+                                    .getScope();
+                            String s2 = ArtifactScopeEnum.checkScope(vmd.artifactScope)
+                                    .getScope();
+                            return s1.compareTo(s2);
+                        } else {
                             return 0;
                         }
-                    }
-                    else
-                    {
+                    } else {
                         return v;
                     }
-                }
-                else
-                {
+                } else {
                     return 0;
                 }
-            }
-            else
-            {
+            } else {
                 return a;
             }
         }
@@ -173,36 +141,30 @@
 
     // ---------------------------------------------------------------------
     @Override
-    public boolean equals( Object vo )
-    {
-        if ( !( vo instanceof MetadataGraphVertex ) )
-        {
+    public boolean equals(Object vo) {
+        if (!(vo instanceof MetadataGraphVertex)) {
             return false;
         }
-        return compareTo( (MetadataGraphVertex) vo ) == 0;
+        return compareTo((MetadataGraphVertex) vo) == 0;
     }
 
     // ---------------------------------------------------------------------
 
     @Override
-    public int hashCode()
-    {
-        if ( md == null )
-        {
+    public int hashCode() {
+        if (md == null) {
             return super.hashCode();
         }
-        StringBuilder hashString = new StringBuilder( 128 );
-        hashString.append( md.groupId ).append( '|' );
-        hashString.append( md.artifactId ).append( '|' );
+        StringBuilder hashString = new StringBuilder(128);
+        hashString.append(md.groupId).append('|');
+        hashString.append(md.artifactId).append('|');
 
-        if ( compareVersion )
-        {
-            hashString.append( md.version ).append( '|' );
+        if (compareVersion) {
+            hashString.append(md.version).append('|');
         }
 
-        if ( compareScope )
-        {
-            hashString.append( md.getArtifactScope() ).append( '|' );
+        if (compareScope) {
+            hashString.append(md.getArtifactScope()).append('|');
         }
 
         return hashString.toString().hashCode();
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolution.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolution.java
index 9a9130b..21d4836 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolution.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolution.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import java.util.Collection;
 
@@ -25,47 +24,40 @@
 
 /**
  *
- * @author Jason van Zyl
  *
  */
-public class MetadataResolution
-{
+@Deprecated
+public class MetadataResolution {
     /** resolved MD  */
     private ArtifactMetadata artifactMetadata;
 
     /** repositories, added by this POM  */
     private Collection<ArtifactRepository> metadataRepositories;
-    //-------------------------------------------------------------------
-    public MetadataResolution( ArtifactMetadata artifactMetadata )
-    {
+    // -------------------------------------------------------------------
+    public MetadataResolution(ArtifactMetadata artifactMetadata) {
         this.artifactMetadata = artifactMetadata;
     }
-    //-------------------------------------------------------------------
-    public MetadataResolution( ArtifactMetadata artifactMetadata, Collection<ArtifactRepository> metadataRepositories )
-    {
-        this( artifactMetadata );
+    // -------------------------------------------------------------------
+    public MetadataResolution(ArtifactMetadata artifactMetadata, Collection<ArtifactRepository> metadataRepositories) {
+        this(artifactMetadata);
         this.metadataRepositories = metadataRepositories;
     }
-    //-------------------------------------------------------------------
-    public Collection<ArtifactRepository> getMetadataRepositories()
-    {
+    // -------------------------------------------------------------------
+    public Collection<ArtifactRepository> getMetadataRepositories() {
         return metadataRepositories;
     }
 
-    public void setMetadataRepositories( Collection<ArtifactRepository> metadataRepositories )
-    {
+    public void setMetadataRepositories(Collection<ArtifactRepository> metadataRepositories) {
         this.metadataRepositories = metadataRepositories;
     }
-    //-------------------------------------------------------------------
-    public ArtifactMetadata getArtifactMetadata()
-    {
+    // -------------------------------------------------------------------
+    public ArtifactMetadata getArtifactMetadata() {
         return artifactMetadata;
     }
 
-    public void setArtifactMetadata( ArtifactMetadata artifactMetadata )
-    {
+    public void setArtifactMetadata(ArtifactMetadata artifactMetadata) {
         this.artifactMetadata = artifactMetadata;
     }
-    //-------------------------------------------------------------------
-    //-------------------------------------------------------------------
+    // -------------------------------------------------------------------
+    // -------------------------------------------------------------------
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionException.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionException.java
index 149d2ac..ab18144 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,35 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 /**
  * MetadataResolutionException
  */
-public class MetadataResolutionException
-    extends Exception
-{
+@Deprecated
+public class MetadataResolutionException extends Exception {
 
-    public MetadataResolutionException()
-    {
+    public MetadataResolutionException() {
         // TODO Auto-generated constructor stub
     }
 
-    public MetadataResolutionException( String message )
-    {
-        super( message );
+    public MetadataResolutionException(String message) {
+        super(message);
         // TODO Auto-generated constructor stub
     }
 
-    public MetadataResolutionException( Throwable cause )
-    {
-        super( cause );
+    public MetadataResolutionException(Throwable cause) {
+        super(cause);
         // TODO Auto-generated constructor stub
     }
 
-    public MetadataResolutionException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public MetadataResolutionException(String message, Throwable cause) {
+        super(message, cause);
         // TODO Auto-generated constructor stub
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequest.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequest.java
index e1f6fe1..ec2bbec 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequest.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,62 +16,53 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import java.util.List;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
 
-/** @author Oleg Gusakov */
-public class MetadataResolutionRequest
-{
+@Deprecated
+public class MetadataResolutionRequest {
     protected ArtifactMetadata query;
     protected ArtifactRepository localRepository;
     protected List<ArtifactRepository> remoteRepositories;
 
-    //--------------------------------------------------------------------
-    public MetadataResolutionRequest()
-    {
-    }
+    // --------------------------------------------------------------------
+    public MetadataResolutionRequest() {}
 
-    //--------------------------------------------------------------------
-    public MetadataResolutionRequest( ArtifactMetadata query, ArtifactRepository localRepository,
-                                      List<ArtifactRepository> remoteRepositories )
-    {
+    // --------------------------------------------------------------------
+    public MetadataResolutionRequest(
+            ArtifactMetadata query, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories) {
         this.query = query;
         this.localRepository = localRepository;
         this.remoteRepositories = remoteRepositories;
     }
 
-    //--------------------------------------------------------------------
-    public ArtifactMetadata getQuery()
-    {
+    // --------------------------------------------------------------------
+    public ArtifactMetadata getQuery() {
         return query;
     }
 
-    public void setQuery( ArtifactMetadata query )
-    {
+    public void setQuery(ArtifactMetadata query) {
         this.query = query;
     }
 
-    public ArtifactRepository getLocalRepository()
-    {
+    public ArtifactRepository getLocalRepository() {
         return localRepository;
     }
 
-    public void setLocalRepository( ArtifactRepository localRepository )
-    {
+    public void setLocalRepository(ArtifactRepository localRepository) {
         this.localRepository = localRepository;
     }
 
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
+    public List<ArtifactRepository> getRemoteRepositories() {
         return remoteRepositories;
     }
 
-    public void setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
-    {
+    public void setRemoteRepositories(List<ArtifactRepository> remoteRepositories) {
         this.remoteRepositories = remoteRepositories;
     }
-    //--------------------------------------------------------------------
-    //--------------------------------------------------------------------
+    // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequestTypeEnum.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequestTypeEnum.java
index 31e3e91..927464b 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequestTypeEnum.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionRequestTypeEnum.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,31 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 /**
  * MetadataResolutionRequestTypeEnum
  */
-public enum MetadataResolutionRequestTypeEnum
-{
-      tree( 1 )
-    , graph( 2 )
-    , classpathCompile( 3 )
-    , classpathTest( 4 )
-    , classpathRuntime( 5 )
-    , versionedGraph( 6 )
-    , scopedGraph( 7 )
-    ;
+@Deprecated
+public enum MetadataResolutionRequestTypeEnum {
+    tree(1),
+    graph(2),
+    classpathCompile(3),
+    classpathTest(4),
+    classpathRuntime(5),
+    versionedGraph(6),
+    scopedGraph(7);
 
     private int id;
 
     // Constructor
-    MetadataResolutionRequestTypeEnum( int id )
-    {
+    MetadataResolutionRequestTypeEnum(int id) {
         this.id = id;
     }
 
-    int getId()
-    {
+    int getId() {
         return id;
     }
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionResult.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionResult.java
index 0f35bd6..e5bd8f1 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionResult.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataResolutionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
 import org.codehaus.plexus.PlexusContainer;
@@ -27,10 +26,9 @@
  * This object is tinted with ClasspathTransformation and GraphConflictResolver.
  * Get rid of them after debugging
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  */
-public class MetadataResolutionResult
-{
+@Deprecated
+public class MetadataResolutionResult {
     MetadataTreeNode treeRoot;
 
     /**
@@ -38,131 +36,100 @@
      * explicit call of the initTreeProcessing()
      */
     ClasspathTransformation classpathTransformation;
+
     GraphConflictResolver conflictResolver;
 
-    //----------------------------------------------------------------------------
-    public MetadataResolutionResult( )
-    {
-    }
-    //----------------------------------------------------------------------------
-    public MetadataResolutionResult( MetadataTreeNode root )
-    {
+    // ----------------------------------------------------------------------------
+    public MetadataResolutionResult() {}
+    // ----------------------------------------------------------------------------
+    public MetadataResolutionResult(MetadataTreeNode root) {
         this.treeRoot = root;
     }
-    //----------------------------------------------------------------------------
-    public MetadataTreeNode getTree()
-    {
+    // ----------------------------------------------------------------------------
+    public MetadataTreeNode getTree() {
         return treeRoot;
     }
-    //----------------------------------------------------------------------------
-    public void setTree( MetadataTreeNode root )
-    {
+    // ----------------------------------------------------------------------------
+    public void setTree(MetadataTreeNode root) {
         this.treeRoot = root;
     }
 
-    public void initTreeProcessing( PlexusContainer plexus )
-        throws ComponentLookupException
-    {
-        classpathTransformation = plexus.lookup( ClasspathTransformation.class );
-        conflictResolver = plexus.lookup( GraphConflictResolver.class );
+    public void initTreeProcessing(PlexusContainer plexus) throws ComponentLookupException {
+        classpathTransformation = plexus.lookup(ClasspathTransformation.class);
+        conflictResolver = plexus.lookup(GraphConflictResolver.class);
     }
-    //----------------------------------------------------------------------------
-    public MetadataGraph getGraph()
-        throws MetadataResolutionException
-    {
-        return treeRoot == null ? null : new MetadataGraph( treeRoot );
+    // ----------------------------------------------------------------------------
+    public MetadataGraph getGraph() throws MetadataResolutionException {
+        return treeRoot == null ? null : new MetadataGraph(treeRoot);
     }
-    //----------------------------------------------------------------------------
-    public MetadataGraph getGraph( ArtifactScopeEnum scope )
-        throws MetadataResolutionException, GraphConflictResolutionException
-    {
-        if ( treeRoot == null )
-        {
+    // ----------------------------------------------------------------------------
+    public MetadataGraph getGraph(ArtifactScopeEnum scope)
+            throws MetadataResolutionException, GraphConflictResolutionException {
+        if (treeRoot == null) {
             return null;
         }
 
-        if ( conflictResolver == null )
-        {
+        if (conflictResolver == null) {
             return null;
         }
 
-        return conflictResolver.resolveConflicts( getGraph(), scope );
+        return conflictResolver.resolveConflicts(getGraph(), scope);
     }
-    //----------------------------------------------------------------------------
-    public MetadataGraph getGraph( MetadataResolutionRequestTypeEnum requestType )
-        throws MetadataResolutionException, GraphConflictResolutionException
-    {
-        if ( requestType == null )
-        {
+    // ----------------------------------------------------------------------------
+    public MetadataGraph getGraph(MetadataResolutionRequestTypeEnum requestType)
+            throws MetadataResolutionException, GraphConflictResolutionException {
+        if (requestType == null) {
             return null;
         }
 
-        if ( treeRoot == null )
-        {
+        if (treeRoot == null) {
             return null;
         }
 
-        if ( conflictResolver == null )
-        {
+        if (conflictResolver == null) {
             return null;
         }
 
-        if ( requestType.equals( MetadataResolutionRequestTypeEnum.classpathCompile ) )
-        {
-            return conflictResolver.resolveConflicts( getGraph(), ArtifactScopeEnum.compile );
-        }
-        else if ( requestType.equals( MetadataResolutionRequestTypeEnum.classpathRuntime ) )
-        {
-            return conflictResolver.resolveConflicts( getGraph(), ArtifactScopeEnum.runtime );
-        }
-        else if ( requestType.equals( MetadataResolutionRequestTypeEnum.classpathTest ) )
-        {
-            return conflictResolver.resolveConflicts( getGraph(), ArtifactScopeEnum.test );
-        }
-        else if ( requestType.equals( MetadataResolutionRequestTypeEnum.graph ) )
-        {
+        if (requestType.equals(MetadataResolutionRequestTypeEnum.classpathCompile)) {
+            return conflictResolver.resolveConflicts(getGraph(), ArtifactScopeEnum.compile);
+        } else if (requestType.equals(MetadataResolutionRequestTypeEnum.classpathRuntime)) {
+            return conflictResolver.resolveConflicts(getGraph(), ArtifactScopeEnum.runtime);
+        } else if (requestType.equals(MetadataResolutionRequestTypeEnum.classpathTest)) {
+            return conflictResolver.resolveConflicts(getGraph(), ArtifactScopeEnum.test);
+        } else if (requestType.equals(MetadataResolutionRequestTypeEnum.graph)) {
             return getGraph();
-        }
-        else if ( requestType.equals( MetadataResolutionRequestTypeEnum.versionedGraph ) )
-        {
-            return new MetadataGraph( getTree(), true, false );
-        }
-        else if ( requestType.equals( MetadataResolutionRequestTypeEnum.scopedGraph ) )
-        {
-            return new MetadataGraph( getTree(), true, true );
+        } else if (requestType.equals(MetadataResolutionRequestTypeEnum.versionedGraph)) {
+            return new MetadataGraph(getTree(), true, false);
+        } else if (requestType.equals(MetadataResolutionRequestTypeEnum.scopedGraph)) {
+            return new MetadataGraph(getTree(), true, true);
         }
         return null;
     }
-    //----------------------------------------------------------------------------
-    public ClasspathContainer getClasspath( ArtifactScopeEnum scope )
-        throws MetadataGraphTransformationException, MetadataResolutionException
-    {
-        if ( classpathTransformation == null )
-        {
+    // ----------------------------------------------------------------------------
+    public ClasspathContainer getClasspath(ArtifactScopeEnum scope)
+            throws MetadataGraphTransformationException, MetadataResolutionException {
+        if (classpathTransformation == null) {
             return null;
         }
 
         MetadataGraph dirtyGraph = getGraph();
-        if ( dirtyGraph == null )
-        {
+        if (dirtyGraph == null) {
             return null;
         }
 
-        return classpathTransformation.transform( dirtyGraph, scope, false );
+        return classpathTransformation.transform(dirtyGraph, scope, false);
     }
 
-    //----------------------------------------------------------------------------
-    public MetadataTreeNode getClasspathTree( ArtifactScopeEnum scope )
-        throws MetadataGraphTransformationException, MetadataResolutionException
-    {
-        ClasspathContainer cpc = getClasspath( scope );
-        if ( cpc == null )
-        {
+    // ----------------------------------------------------------------------------
+    public MetadataTreeNode getClasspathTree(ArtifactScopeEnum scope)
+            throws MetadataGraphTransformationException, MetadataResolutionException {
+        ClasspathContainer cpc = getClasspath(scope);
+        if (cpc == null) {
             return null;
         }
 
         return cpc.getClasspathAsTree();
     }
-    //----------------------------------------------------------------------------
-    //----------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------
+    // ----------------------------------------------------------------------------
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataRetrievalException.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataRetrievalException.java
index f5461d7..dd7d51e 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataRetrievalException.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataRetrievalException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,42 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 /**
  * Error while retrieving repository metadata from the repository.
  *
- * @author Jason van Zyl
  */
-public class MetadataRetrievalException
-    extends Exception
-{
+@Deprecated
+public class MetadataRetrievalException extends Exception {
 
     private ArtifactMetadata artifact;
 
-    public MetadataRetrievalException( String message )
-    {
-        this( message, null, null );
+    public MetadataRetrievalException(String message) {
+        this(message, null, null);
     }
 
-    public MetadataRetrievalException( Throwable cause )
-    {
-        this( null, cause, null );
+    public MetadataRetrievalException(Throwable cause) {
+        this(null, cause, null);
     }
 
-    public MetadataRetrievalException( String message, Throwable cause )
-    {
-        this( message, cause, null );
+    public MetadataRetrievalException(String message, Throwable cause) {
+        this(message, cause, null);
     }
 
-    public MetadataRetrievalException( String message, Throwable cause, ArtifactMetadata artifact )
-    {
-        super( message, cause );
+    public MetadataRetrievalException(String message, Throwable cause, ArtifactMetadata artifact) {
+        super(message, cause);
 
         this.artifact = artifact;
     }
 
-    public ArtifactMetadata getArtifactMetadata()
-    {
+    public ArtifactMetadata getArtifactMetadata() {
         return artifact;
     }
-}
\ No newline at end of file
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataSource.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataSource.java
index 3ca6ce8..bab22f7 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataSource.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import java.util.List;
 
@@ -27,13 +26,12 @@
  * Provides some metadata operations, like querying the remote repository for a list of versions available for an
  * artifact.
  *
- * @author Jason van Zyl
  */
-public interface MetadataSource
-{
+@Deprecated
+public interface MetadataSource {
     String ROLE = MetadataSource.class.getName();
 
-    MetadataResolution retrieve( ArtifactMetadata artifact, ArtifactRepository localRepository,
-                                 List<ArtifactRepository> remoteRepositories )
-        throws MetadataRetrievalException;
-}
\ No newline at end of file
+    MetadataResolution retrieve(
+            ArtifactMetadata artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws MetadataRetrievalException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataTreeNode.java b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataTreeNode.java
index dd720d3..7fbe882 100644
--- a/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataTreeNode.java
+++ b/maven-compat/src/main/java/org/apache/maven/repository/metadata/MetadataTreeNode.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.ArtifactScopeEnum;
@@ -25,11 +24,10 @@
 /**
  * metadata [dirty] Tree
  *
- * @author <a href="oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-public class MetadataTreeNode
-{
+@Deprecated
+public class MetadataTreeNode {
     ArtifactMetadata md; // this node
 
     MetadataTreeNode parent; // papa
@@ -39,110 +37,89 @@
 
     MetadataTreeNode[] children; // of cause
 
-    public int getNChildren()
-    {
+    public int getNChildren() {
         return nChildren;
     }
 
-    public void setNChildren( int children )
-    {
+    public void setNChildren(int children) {
         nChildren = children;
     }
 
-    //------------------------------------------------------------------------
-    public MetadataTreeNode()
-    {
-    }
-    //------------------------------------------------------------------------
-    public MetadataTreeNode( ArtifactMetadata md, MetadataTreeNode parent, boolean resolved, ArtifactScopeEnum scope )
-    {
-        if ( md != null )
-        {
-            md.setArtifactScope( ArtifactScopeEnum.checkScope( scope ) );
-            md.setResolved( resolved );
+    // ------------------------------------------------------------------------
+    public MetadataTreeNode() {}
+    // ------------------------------------------------------------------------
+    public MetadataTreeNode(ArtifactMetadata md, MetadataTreeNode parent, boolean resolved, ArtifactScopeEnum scope) {
+        if (md != null) {
+            md.setArtifactScope(ArtifactScopeEnum.checkScope(scope));
+            md.setResolved(resolved);
         }
 
         this.md = md;
         this.parent = parent;
     }
-    //------------------------------------------------------------------------
-    public MetadataTreeNode( Artifact af, MetadataTreeNode parent, boolean resolved, ArtifactScopeEnum scope )
-    {
-        this( new ArtifactMetadata( af ), parent, resolved, scope );
+    // ------------------------------------------------------------------------
+    public MetadataTreeNode(Artifact af, MetadataTreeNode parent, boolean resolved, ArtifactScopeEnum scope) {
+        this(new ArtifactMetadata(af), parent, resolved, scope);
     }
 
     // ------------------------------------------------------------------------
-    public void addChild( int index, MetadataTreeNode kid )
-    {
-        if ( kid == null )
-        {
+    public void addChild(int index, MetadataTreeNode kid) {
+        if (kid == null) {
             return;
         }
 
-        if ( children == null )
-        {
+        if (children == null) {
             children = new MetadataTreeNode[nChildren];
         }
 
         children[index % nChildren] = kid;
     }
 
-    //------------------------------------------------------------------
+    // ------------------------------------------------------------------
     @Override
-    public String toString()
-    {
+    public String toString() {
         return md == null ? "no metadata" : md.toString();
     }
 
-    //------------------------------------------------------------------
-    public String graphHash()
-        throws MetadataResolutionException
-    {
-        if ( md == null )
-        {
-            throw new MetadataResolutionException( "treenode without metadata, parent: "
-                + ( parent == null ? "null" : parent.toString() ) );
+    // ------------------------------------------------------------------
+    public String graphHash() throws MetadataResolutionException {
+        if (md == null) {
+            throw new MetadataResolutionException(
+                    "treenode without metadata, parent: " + (parent == null ? "null" : parent.toString()));
         }
 
         return md.groupId + ":" + md.artifactId;
     }
 
-    //------------------------------------------------------------------------
-    public boolean hasChildren()
-    {
+    // ------------------------------------------------------------------------
+    public boolean hasChildren() {
         return children != null;
     }
-    //------------------------------------------------------------------------
-    public ArtifactMetadata getMd()
-    {
+    // ------------------------------------------------------------------------
+    public ArtifactMetadata getMd() {
         return md;
     }
 
-    public void setMd( ArtifactMetadata md )
-    {
+    public void setMd(ArtifactMetadata md) {
         this.md = md;
     }
 
-    public MetadataTreeNode getParent()
-    {
+    public MetadataTreeNode getParent() {
         return parent;
     }
 
-    public void setParent( MetadataTreeNode parent )
-    {
+    public void setParent(MetadataTreeNode parent) {
         this.parent = parent;
     }
 
-    public MetadataTreeNode[] getChildren()
-    {
+    public MetadataTreeNode[] getChildren() {
         return children;
     }
 
-    public void setChildren( MetadataTreeNode[] children )
-    {
+    public void setChildren(MetadataTreeNode[] children) {
         this.children = children;
     }
-    //------------------------------------------------------------------------
-    //------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
+    // ------------------------------------------------------------------------
 
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java b/maven-compat/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java
new file mode 100644
index 0000000..c669fcc
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.settings;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.properties.internal.SystemProperties;
+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuilder;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.apache.maven.settings.building.SettingsBuildingRequest;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ */
+@Deprecated
+@Named
+@Singleton
+public class DefaultMavenSettingsBuilder extends AbstractLogEnabled implements MavenSettingsBuilder {
+
+    private final SettingsBuilder settingsBuilder;
+
+    @Inject
+    public DefaultMavenSettingsBuilder(SettingsBuilder settingsBuilder) {
+        this.settingsBuilder = settingsBuilder;
+    }
+
+    public Settings buildSettings() throws IOException, XmlPullParserException {
+        File userSettingsFile = getFile(
+                "${user.home}/.m2/settings.xml", "user.home", MavenSettingsBuilder.ALT_USER_SETTINGS_XML_LOCATION);
+
+        return buildSettings(userSettingsFile);
+    }
+
+    public Settings buildSettings(boolean useCachedSettings) throws IOException, XmlPullParserException {
+        return buildSettings();
+    }
+
+    public Settings buildSettings(File userSettingsFile) throws IOException, XmlPullParserException {
+        File globalSettingsFile = getFile(
+                "${maven.conf}/settings.xml", "maven.conf", MavenSettingsBuilder.ALT_GLOBAL_SETTINGS_XML_LOCATION);
+
+        SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
+        request.setUserSettingsFile(userSettingsFile);
+        request.setGlobalSettingsFile(globalSettingsFile);
+        request.setSystemProperties(SystemProperties.getSystemProperties());
+        return build(request);
+    }
+
+    public Settings buildSettings(File userSettingsFile, boolean useCachedSettings)
+            throws IOException, XmlPullParserException {
+        return buildSettings(userSettingsFile);
+    }
+
+    private Settings build(SettingsBuildingRequest request) throws IOException, XmlPullParserException {
+        try {
+            return settingsBuilder.build(request).getEffectiveSettings();
+        } catch (SettingsBuildingException e) {
+            throw new IOException(e.getMessage(), e);
+        }
+    }
+
+    /** @since 2.1 */
+    public Settings buildSettings(MavenExecutionRequest request) throws IOException, XmlPullParserException {
+        SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest();
+        settingsRequest.setUserSettingsFile(request.getUserSettingsFile());
+        settingsRequest.setProjectSettingsFile(request.getProjectSettingsFile());
+        settingsRequest.setGlobalSettingsFile(request.getGlobalSettingsFile());
+        settingsRequest.setUserProperties(request.getUserProperties());
+        settingsRequest.setSystemProperties(request.getSystemProperties());
+
+        return build(settingsRequest);
+    }
+
+    private File getFile(String pathPattern, String basedirSysProp, String altLocationSysProp) {
+        // -------------------------------------------------------------------------------------
+        // Alright, here's the justification for all the regexp wizardry below...
+        //
+        // Continuum and other server-like apps may need to locate the user-level and
+        // global-level settings somewhere other than ${user.home} and ${maven.home},
+        // respectively. Using a simple replacement of these patterns will allow them
+        // to specify the absolute path to these files in a customized components.xml
+        // file. Ideally, we'd do full pattern-evaluation against the sysprops, but this
+        // is a first step. There are several replacements below, in order to normalize
+        // the path character before we operate on the string as a regex input, and
+        // in order to avoid surprises with the File construction...
+        // -------------------------------------------------------------------------------------
+
+        String path = System.getProperty(altLocationSysProp);
+
+        if (path == null || path.isEmpty()) {
+            // TODO This replacing shouldn't be necessary as user.home should be in the
+            // context of the container and thus the value would be interpolated by Plexus
+            String basedir = System.getProperty(basedirSysProp);
+            if (basedir == null) {
+                basedir = System.getProperty("user.dir");
+            }
+
+            basedir = basedir.replace("\\", "/");
+            basedir = basedir.replace("$", "\\$");
+
+            // basedirSysProp is non regexp and basedir too
+            path = pathPattern.replace("${" + basedirSysProp + "}", basedir);
+            path = path.replace("\\", "/");
+            // ---------------------------------------------------------------------------------
+            // I'm not sure if this last regexp was really intended to disallow the usage of
+            // network paths as user.home directory. Unfortunately it did. I removed it and
+            // have not detected any problems yet.
+            // ---------------------------------------------------------------------------------
+            // path = path.replaceAll( "//", "/" );
+
+        }
+        return new File(path).getAbsoluteFile();
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java b/maven-compat/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java
new file mode 100644
index 0000000..ea39c20
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.settings;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ */
+@Deprecated
+public interface MavenSettingsBuilder {
+
+    String ROLE = MavenSettingsBuilder.class.getName();
+
+    String ALT_USER_SETTINGS_XML_LOCATION = "org.apache.maven.user-settings";
+    String ALT_GLOBAL_SETTINGS_XML_LOCATION = "org.apache.maven.global-settings";
+    String ALT_LOCAL_REPOSITORY_LOCATION = "maven.repo.local";
+
+    Settings buildSettings(MavenExecutionRequest request) throws IOException, XmlPullParserException;
+
+    /**
+     * @return a <code>Settings</code> object from the user settings file.
+     * @throws IOException if any
+     * @throws XmlPullParserException if any
+     */
+    Settings buildSettings() throws IOException, XmlPullParserException;
+
+    /**
+     * @param useCachedSettings if true, doesn't reload the user settings
+     * @return a <code>Settings</code> object from the user settings file.
+     * @throws IOException if any
+     * @throws XmlPullParserException if any
+     */
+    Settings buildSettings(boolean useCachedSettings) throws IOException, XmlPullParserException;
+
+    /**
+     * @param userSettingsFile a given user settings file
+     * @return a <code>Settings</code> object from the user settings file.
+     * @throws IOException if any
+     * @throws XmlPullParserException if any
+     */
+    Settings buildSettings(File userSettingsFile) throws IOException, XmlPullParserException;
+
+    /**
+     * @param userSettingsFile a given user settings file
+     * @param useCachedSettings if true, doesn't reload the user settings
+     * @return a <code>Settings</code> object from the user settings file.
+     * @throws IOException if any
+     * @throws XmlPullParserException if any
+     */
+    Settings buildSettings(File userSettingsFile, boolean useCachedSettings) throws IOException, XmlPullParserException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java b/maven-compat/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java
new file mode 100644
index 0000000..e78fd2c
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.toolchain;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Files;
+
+import org.apache.maven.toolchain.model.PersistedToolchains;
+import org.apache.maven.toolchain.v4.MavenToolchainsStaxReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @deprecated instead use {@link org.apache.maven.toolchain.building.DefaultToolchainsBuilder}
+ */
+@Deprecated
+@Named("default")
+@Singleton
+public class DefaultToolchainsBuilder implements ToolchainsBuilder {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    public PersistedToolchains build(File userToolchainsFile) throws MisconfiguredToolchainException {
+        PersistedToolchains toolchains = null;
+
+        if (userToolchainsFile != null && userToolchainsFile.isFile()) {
+            try (InputStream in = Files.newInputStream(userToolchainsFile.toPath())) {
+                toolchains = new PersistedToolchains(new MavenToolchainsStaxReader().read(in));
+            } catch (Exception e) {
+                throw new MisconfiguredToolchainException(
+                        "Cannot read toolchains file at " + userToolchainsFile.getAbsolutePath(), e);
+            }
+
+        } else if (userToolchainsFile != null) {
+            logger.debug("Toolchains configuration was not found at {}", userToolchainsFile);
+        }
+
+        return toolchains;
+    }
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/toolchain/ToolchainsBuilder.java b/maven-compat/src/main/java/org/apache/maven/toolchain/ToolchainsBuilder.java
new file mode 100644
index 0000000..2f16b8f
--- /dev/null
+++ b/maven-compat/src/main/java/org/apache/maven/toolchain/ToolchainsBuilder.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.toolchain;
+
+import java.io.File;
+
+import org.apache.maven.toolchain.model.PersistedToolchains;
+
+/**
+ * Builds the toolchains model from a previously configured filesystem path to the toolchains file.
+ * <strong>Note:</strong> This is an internal component whose interface can change without prior notice.
+ *
+ * @deprecated use {@link org.apache.maven.toolchain.building.ToolchainsBuilder} instead
+ */
+@Deprecated
+public interface ToolchainsBuilder {
+
+    /**
+     * Builds the toolchains model from the configured toolchain files.
+     *
+     * @param userToolchainsFile The path to the toolchains file, may be <code>null</code> to disable parsing.
+     * @return The toolchains model or <code>null</code> if no toolchain file was configured or the configured file does
+     *         not exist.
+     * @throws MisconfiguredToolchainException If the toolchain file exists but cannot be parsed.
+     */
+    PersistedToolchains build(File userToolchainsFile) throws MisconfiguredToolchainException;
+}
diff --git a/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumentationException.java b/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumentationException.java
index d001562..1378ab2 100644
--- a/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumentationException.java
+++ b/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumentationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.usability.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.usability.plugin;
 
 /**
  * ExpressionDocumentationException
  */
-public class ExpressionDocumentationException
-    extends Exception
-{
+@Deprecated
+public class ExpressionDocumentationException extends Exception {
     static final long serialVersionUID = 1;
 
-    public ExpressionDocumentationException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public ExpressionDocumentationException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public ExpressionDocumentationException( String message )
-    {
-        super( message );
+    public ExpressionDocumentationException(String message) {
+        super(message);
     }
-
 }
diff --git a/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumenter.java b/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumenter.java
index f4e7bf9..55b1a4a 100644
--- a/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumenter.java
+++ b/maven-compat/src/main/java/org/apache/maven/usability/plugin/ExpressionDocumenter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.usability.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.usability.plugin;
 
-import org.apache.maven.usability.plugin.io.xpp3.ParamdocXpp3Reader;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.Reader;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
@@ -35,53 +28,42 @@
 import java.util.List;
 import java.util.Map;
 
+import org.apache.maven.usability.plugin.io.xpp3.ParamdocXpp3Reader;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
 /**
  * ExpressionDocumenter
  */
-public class ExpressionDocumenter
-{
+@Deprecated
+public class ExpressionDocumenter {
 
-    private static final String[] EXPRESSION_ROOTS =
-    {
-        "project", "settings", "session", "plugin", "rootless"
-    };
+    private static final String[] EXPRESSION_ROOTS = {"project", "settings", "session", "plugin", "rootless"};
 
     private static final String EXPRESSION_DOCO_ROOTPATH = "META-INF/maven/plugin-expressions/";
 
     private static Map<String, Expression> expressionDocumentation;
 
-    public static Map<String, Expression> load()
-        throws ExpressionDocumentationException
-    {
-        if ( expressionDocumentation == null )
-        {
+    public static Map<String, Expression> load() throws ExpressionDocumentationException {
+        if (expressionDocumentation == null) {
             expressionDocumentation = new HashMap<>();
 
             ClassLoader docLoader = initializeDocLoader();
 
-            for ( String root : EXPRESSION_ROOTS )
-            {
-                try ( InputStream docStream = docLoader.getResourceAsStream(
-                    EXPRESSION_DOCO_ROOTPATH + root + ".paramdoc.xml" ) )
-                {
-                    if ( docStream != null )
-                    {
-                        Map<String, Expression> doco = parseExpressionDocumentation( docStream );
+            for (String root : EXPRESSION_ROOTS) {
+                try (InputStream docStream =
+                        docLoader.getResourceAsStream(EXPRESSION_DOCO_ROOTPATH + root + ".paramdoc.xml")) {
+                    if (docStream != null) {
+                        Map<String, Expression> doco = parseExpressionDocumentation(docStream);
 
-                        expressionDocumentation.putAll( doco );
+                        expressionDocumentation.putAll(doco);
                     }
-                }
-                catch ( IOException e )
-                {
+                } catch (IOException e) {
                     throw new ExpressionDocumentationException(
-                        "Failed to read documentation for expression root: " + root, e );
-                }
-                catch ( XmlPullParserException e )
-                {
+                            "Failed to read documentation for expression root: " + root, e);
+                } catch (XmlPullParserException e) {
                     throw new ExpressionDocumentationException(
-                        "Failed to parse documentation for expression root: " + root, e );
+                            "Failed to parse documentation for expression root: " + root, e);
                 }
-
             }
         }
 
@@ -114,63 +96,48 @@
      * @throws IOException
      * @throws XmlPullParserException
      */
-    private static Map<String, Expression> parseExpressionDocumentation( InputStream docStream )
-        throws IOException, XmlPullParserException
-    {
-        Reader reader = new BufferedReader( ReaderFactory.newXmlReader( docStream ) );
-
+    private static Map<String, Expression> parseExpressionDocumentation(InputStream docStream)
+            throws IOException, XmlPullParserException {
         ParamdocXpp3Reader paramdocReader = new ParamdocXpp3Reader();
 
-        ExpressionDocumentation documentation = paramdocReader.read( reader, true );
+        ExpressionDocumentation documentation = paramdocReader.read(docStream, true);
 
         List<Expression> expressions = documentation.getExpressions();
 
         Map<String, Expression> bySyntax = new HashMap<>();
 
-        if ( expressions != null && !expressions.isEmpty() )
-        {
-            for ( Expression expression : expressions )
-            {
-                bySyntax.put( expression.getSyntax(), expression );
+        if (expressions != null && !expressions.isEmpty()) {
+            for (Expression expression : expressions) {
+                bySyntax.put(expression.getSyntax(), expression);
             }
         }
 
         return bySyntax;
     }
 
-    private static ClassLoader initializeDocLoader()
-        throws ExpressionDocumentationException
-    {
-        String myResourcePath = ExpressionDocumenter.class.getName().replace( '.', '/' ) + ".class";
+    private static ClassLoader initializeDocLoader() throws ExpressionDocumentationException {
+        String myResourcePath = ExpressionDocumenter.class.getName().replace('.', '/') + ".class";
 
-        URL myResource = ExpressionDocumenter.class.getClassLoader().getResource( myResourcePath );
+        URL myResource = ExpressionDocumenter.class.getClassLoader().getResource(myResourcePath);
 
         assert myResource != null : "The resource is this class itself loaded by its own classloader and must exist";
 
         String myClasspathEntry = myResource.getPath();
 
-        myClasspathEntry = myClasspathEntry.substring( 0, myClasspathEntry.length() - ( myResourcePath.length() + 2 ) );
+        myClasspathEntry = myClasspathEntry.substring(0, myClasspathEntry.length() - (myResourcePath.length() + 2));
 
-        if ( myClasspathEntry.startsWith( "file:" ) )
-        {
-            myClasspathEntry = myClasspathEntry.substring( "file:".length() );
+        if (myClasspathEntry.startsWith("file:")) {
+            myClasspathEntry = myClasspathEntry.substring("file:".length());
         }
 
         URL docResource;
-        try
-        {
-            docResource = new File( myClasspathEntry ).toURL();
-        }
-        catch ( MalformedURLException e )
-        {
+        try {
+            docResource = new File(myClasspathEntry).toURL();
+        } catch (MalformedURLException e) {
             throw new ExpressionDocumentationException(
-                "Cannot construct expression documentation classpath" + " resource base.", e );
+                    "Cannot construct expression documentation classpath" + " resource base.", e);
         }
 
-        return new URLClassLoader( new URL[]
-        {
-            docResource
-        } );
+        return new URLClassLoader(new URL[] {docResource});
     }
-
 }
diff --git a/maven-compat/src/main/mdo/profiles.mdo b/maven-compat/src/main/mdo/profiles.mdo
index 5132490..2843e80 100644
--- a/maven-compat/src/main/mdo/profiles.mdo
+++ b/maven-compat/src/main/mdo/profiles.mdo
@@ -24,8 +24,8 @@
   <id>profiles</id>
   <name>Profiles</name>
   <description><![CDATA[
-    Project-local overrides to the build process based on detected or user-provided environmental parameters.
-    This is the model specification for ${basedir}/profiles.xml.
+    <b>Deprecated in Maven 2</b> Project-local overrides to the build process based on detected or user-provided environmental parameters.
+    This is the model specification for <code>${basedir}/profiles.xml</code>.
   ]]></description>
   <defaults>
     <default>
@@ -162,7 +162,7 @@
           <name>property</name>
           <version>1.0.0</version>
           <description><![CDATA[
-            Specifies that this profile will be activated when this System property is specified.
+            Specifies that this profile will be activated when this property is specified.
           ]]></description>
           <association>
             <type>ActivationProperty</type>
diff --git a/maven-compat/src/site/site.xml b/maven-compat/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-compat/src/site/site.xml
+++ b/maven-compat/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-compat/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-compat/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java
new file mode 100644
index 0000000..85fd0c1
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java
@@ -0,0 +1,287 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven;
+
+import javax.inject.Inject;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.InvalidRepositoryException;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.impl.DefaultSession;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Exclusion;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.RepositoryPolicy;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.repository.RepositorySystem;
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.codehaus.plexus.util.FileUtils;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
+import org.eclipse.aether.repository.LocalRepository;
+
+import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
+import static org.mockito.Mockito.mock;
+
+@PlexusTest
+public abstract class AbstractCoreMavenComponentTestCase {
+
+    @Inject
+    protected PlexusContainer container;
+
+    @Inject
+    protected RepositorySystem repositorySystem;
+
+    @Inject
+    protected org.apache.maven.project.ProjectBuilder projectBuilder;
+
+    protected abstract String getProjectsDirectory();
+
+    protected PlexusContainer getContainer() {
+        return container;
+    }
+
+    protected File getProject(String name) throws Exception {
+        File source = new File(new File(getBasedir(), getProjectsDirectory()), name);
+        File target = new File(new File(getBasedir(), "target"), name);
+        FileUtils.copyDirectoryStructureIfModified(source, target);
+        return new File(target, "pom.xml");
+    }
+
+    protected MavenExecutionRequest createMavenExecutionRequest(File pom) throws Exception {
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest()
+                .setPom(pom)
+                .setProjectPresent(true)
+                .setShowErrors(true)
+                .setPluginGroups(Arrays.asList("org.apache.maven.plugins"))
+                .setLocalRepository(getLocalRepository())
+                .setRemoteRepositories(getRemoteRepositories())
+                .setPluginArtifactRepositories(getPluginArtifactRepositories())
+                .setGoals(Arrays.asList("package"));
+
+        if (pom != null) {
+            request.setMultiModuleProjectDirectory(pom.getParentFile());
+        }
+
+        return request;
+    }
+
+    // layer the creation of a project builder configuration with a request, but this will need to be
+    // a Maven subclass because we don't want to couple maven to the project builder which we need to
+    // separate.
+    protected MavenSession createMavenSession(File pom) throws Exception {
+        return createMavenSession(pom, new Properties());
+    }
+
+    protected MavenSession createMavenSession(File pom, Properties executionProperties) throws Exception {
+        return createMavenSession(pom, executionProperties, false);
+    }
+
+    protected MavenSession createMavenSession(File pom, Properties executionProperties, boolean includeModules)
+            throws Exception {
+        MavenExecutionRequest request = createMavenExecutionRequest(pom);
+
+        ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest()
+                .setLocalRepository(request.getLocalRepository())
+                .setRemoteRepositories(request.getRemoteRepositories())
+                .setPluginArtifactRepositories(request.getPluginArtifactRepositories())
+                .setSystemProperties(executionProperties)
+                .setUserProperties(new Properties());
+
+        List<MavenProject> projects = new ArrayList<>();
+
+        if (pom != null) {
+            MavenProject project = projectBuilder.build(pom, configuration).getProject();
+
+            projects.add(project);
+            if (includeModules) {
+                for (String module : project.getModules()) {
+                    File modulePom = new File(pom.getParentFile(), module);
+                    if (modulePom.isDirectory()) {
+                        modulePom = new File(modulePom, "pom.xml");
+                    }
+                    projects.add(projectBuilder.build(modulePom, configuration).getProject());
+                }
+            }
+        } else {
+            MavenProject project = createStubMavenProject();
+            project.setRemoteArtifactRepositories(request.getRemoteRepositories());
+            project.setPluginArtifactRepositories(request.getPluginArtifactRepositories());
+            projects.add(project);
+        }
+
+        initRepoSession(configuration);
+
+        MavenSession session = new MavenSession(
+                getContainer(), configuration.getRepositorySession(), request, new DefaultMavenExecutionResult());
+        session.setProjects(projects);
+        session.setAllProjects(session.getProjects());
+        session.setSession(
+                new DefaultSession(session, mock(org.eclipse.aether.RepositorySystem.class), null, null, null, null));
+
+        return session;
+    }
+
+    protected void initRepoSession(ProjectBuildingRequest request) throws Exception {
+        File localRepoDir = new File(request.getLocalRepository().getBasedir());
+        LocalRepository localRepo = new LocalRepository(localRepoDir);
+        DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
+        session.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory().newInstance(session, localRepo));
+        request.setRepositorySession(session);
+    }
+
+    protected MavenProject createStubMavenProject() {
+        Model model = new Model();
+        model.setGroupId("org.apache.maven.test");
+        model.setArtifactId("maven-test");
+        model.setVersion("1.0");
+        return new MavenProject(model);
+    }
+
+    protected List<ArtifactRepository> getRemoteRepositories() throws InvalidRepositoryException {
+        File repoDir = new File(getBasedir(), "src/test/remote-repo").getAbsoluteFile();
+
+        RepositoryPolicy policy = new RepositoryPolicy();
+        policy.setEnabled(true);
+        policy.setChecksumPolicy("ignore");
+        policy.setUpdatePolicy("always");
+
+        Repository repository = new Repository();
+        repository.setId(MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID);
+        repository.setUrl("file://" + repoDir.toURI().getPath());
+        repository.setReleases(policy);
+        repository.setSnapshots(policy);
+
+        return Arrays.asList(repositorySystem.buildArtifactRepository(repository));
+    }
+
+    protected List<ArtifactRepository> getPluginArtifactRepositories() throws InvalidRepositoryException {
+        return getRemoteRepositories();
+    }
+
+    protected ArtifactRepository getLocalRepository() throws InvalidRepositoryException {
+        File repoDir = new File(getBasedir(), "target/local-repo").getAbsoluteFile();
+
+        return repositorySystem.createLocalRepository(repoDir);
+    }
+
+    protected class ProjectBuilder {
+        private MavenProject project;
+
+        public ProjectBuilder(MavenProject project) {
+            this.project = project;
+        }
+
+        public ProjectBuilder(String groupId, String artifactId, String version) {
+            Model model = new Model();
+            model.setModelVersion("4.0.0");
+            model.setGroupId(groupId);
+            model.setArtifactId(artifactId);
+            model.setVersion(version);
+            model.setBuild(new Build());
+            project = new MavenProject(model);
+        }
+
+        public ProjectBuilder setGroupId(String groupId) {
+            project.setGroupId(groupId);
+            return this;
+        }
+
+        public ProjectBuilder setArtifactId(String artifactId) {
+            project.setArtifactId(artifactId);
+            return this;
+        }
+
+        public ProjectBuilder setVersion(String version) {
+            project.setVersion(version);
+            return this;
+        }
+
+        // Dependencies
+        //
+        public ProjectBuilder addDependency(String groupId, String artifactId, String version, String scope) {
+            return addDependency(groupId, artifactId, version, scope, (Exclusion) null);
+        }
+
+        public ProjectBuilder addDependency(
+                String groupId, String artifactId, String version, String scope, Exclusion exclusion) {
+            return addDependency(groupId, artifactId, version, scope, null, exclusion);
+        }
+
+        public ProjectBuilder addDependency(
+                String groupId, String artifactId, String version, String scope, String systemPath) {
+            return addDependency(groupId, artifactId, version, scope, systemPath, null);
+        }
+
+        public ProjectBuilder addDependency(
+                String groupId,
+                String artifactId,
+                String version,
+                String scope,
+                String systemPath,
+                Exclusion exclusion) {
+            Dependency d = new Dependency();
+            d.setGroupId(groupId);
+            d.setArtifactId(artifactId);
+            d.setVersion(version);
+            d.setScope(scope);
+
+            if (systemPath != null && scope.equals(Artifact.SCOPE_SYSTEM)) {
+                d.setSystemPath(systemPath);
+            }
+
+            if (exclusion != null) {
+                d.addExclusion(exclusion);
+            }
+
+            project.getDependencies().add(d);
+
+            return this;
+        }
+
+        // Plugins
+        //
+        public ProjectBuilder addPlugin(Plugin plugin) {
+            project.getBuildPlugins().add(plugin);
+            return this;
+        }
+
+        public MavenProject get() {
+            return project;
+        }
+    }
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/ProjectDependenciesResolverTest.java b/maven-compat/src/test/java/org/apache/maven/ProjectDependenciesResolverTest.java
new file mode 100644
index 0000000..ceb2475
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/ProjectDependenciesResolverTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven;
+
+import javax.inject.Inject;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.Test;
+
+import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.endsWith;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ProjectDependenciesResolverTest extends AbstractCoreMavenComponentTestCase {
+    @Inject
+    private ProjectDependenciesResolver resolver;
+
+    protected String getProjectsDirectory() {
+        return "src/test/projects/project-dependencies-resolver";
+    }
+
+    /*
+    @Test
+    public void testExclusionsInDependencies()
+        throws Exception
+    {
+        MavenSession session = createMavenSession( null );
+        MavenProject project = session.getCurrentProject();
+
+        Exclusion exclusion = new Exclusion();
+        exclusion.setGroupId( "org.apache.maven.its" );
+        exclusion.setArtifactId( "a" );
+
+        new ProjectBuilder( project ).addDependency( "org.apache.maven.its", "b", "0.1", Artifact.SCOPE_RUNTIME,
+                                                     exclusion );
+
+        Set<Artifact> artifactDependencies =
+            resolver.resolve( project, Collections.singleton( Artifact.SCOPE_COMPILE ), session );
+        assertEquals( 0, artifactDependencies.size() );
+
+        artifactDependencies = resolver.resolve( project, Collections.singleton( Artifact.SCOPE_RUNTIME ), session );
+        assertEquals( 1, artifactDependencies.size() );
+        assertEquals( "b", artifactDependencies.iterator().next().getArtifactId() );
+    }
+    */
+
+    @Test
+    void testSystemScopeDependencies() throws Exception {
+        MavenSession session = createMavenSession(null);
+        MavenProject project = session.getCurrentProject();
+
+        new ProjectBuilder(project)
+                .addDependency(
+                        "com.mycompany",
+                        "system-dependency",
+                        "1.0",
+                        Artifact.SCOPE_SYSTEM,
+                        new File(getBasedir(), "pom.xml").getAbsolutePath());
+
+        Set<Artifact> artifactDependencies =
+                resolver.resolve(project, Collections.singleton(Artifact.SCOPE_COMPILE), session);
+        assertEquals(1, artifactDependencies.size());
+    }
+
+    @Test
+    void testSystemScopeDependencyIsPresentInTheCompileClasspathElements() throws Exception {
+        File pom = getProject("it0063");
+
+        Properties eps = new Properties();
+        eps.setProperty("jre.home", new File(pom.getParentFile(), "jdk/jre").getPath());
+
+        MavenSession session = createMavenSession(pom, eps);
+        MavenProject project = session.getCurrentProject();
+
+        project.setArtifacts(resolver.resolve(project, Collections.singleton(Artifact.SCOPE_COMPILE), session));
+
+        List<String> elements = project.getCompileClasspathElements();
+        assertEquals(2, elements.size());
+
+        @SuppressWarnings("deprecation")
+        List<Artifact> artifacts = project.getCompileArtifacts();
+        assertEquals(1, artifacts.size());
+        assertThat(artifacts.get(0).getFile().getName(), endsWith("tools.jar"));
+    }
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java b/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java
index 735c649..9746b24 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/AbstractArtifactComponentTestCase.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
+
+import javax.inject.Inject;
+import javax.inject.Named;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -29,21 +31,22 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.codehaus.plexus.testing.PlexusTest;
 import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.impl.DefaultSessionFactory;
 import org.apache.maven.plugin.LegacySupport;
 import org.apache.maven.repository.legacy.repository.ArtifactRepositoryFactory;
+import org.apache.maven.rtinfo.RuntimeInformation;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.collection.DependencyGraphTransformer;
 import org.eclipse.aether.collection.DependencyManager;
@@ -72,11 +75,10 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
  */
 @PlexusTest
-public abstract class AbstractArtifactComponentTestCase //extends PlexusTestCase
-{
+public abstract class AbstractArtifactComponentTestCase // extends PlexusTestCase
+ {
     @Inject
     protected ArtifactFactory artifactFactory;
 
@@ -86,7 +88,8 @@
     @Inject
     LegacySupport legacySupport;
 
-    @Inject @Named( "default" )
+    @Inject
+    @Named("default")
     ArtifactRepositoryLayout repoLayout;
 
     @Inject
@@ -97,14 +100,18 @@
     }
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
+    public void setUp() throws Exception {
         RepositorySystemSession repoSession = initRepoSession();
-        MavenSession session = new MavenSession( getContainer(), repoSession, new DefaultMavenExecutionRequest(),
-                                                 new DefaultMavenExecutionResult() );
+        MavenSession session = new MavenSession(
+                getContainer(), repoSession, new DefaultMavenExecutionRequest(), new DefaultMavenExecutionResult());
+        new DefaultSessionFactory(
+                        getContainer().lookup(RepositorySystem.class),
+                        getContainer().lookup(MavenRepositorySystem.class),
+                        getContainer(),
+                        getContainer().lookup(RuntimeInformation.class))
+                .getSession(session);
 
-        legacySupport.setSession( session );
+        legacySupport.setSession(session);
     }
 
     protected abstract String component();
@@ -114,112 +121,96 @@
      *
      * @throws Exception
      */
-    protected ArtifactRepository badLocalRepository()
-        throws Exception
-    {
+    protected ArtifactRepository badLocalRepository() throws Exception {
         String path = "target/test-repositories/" + component() + "/bad-local-repository";
 
-        File f = new File( getBasedir(), path );
+        File f = new File(getBasedir(), path);
 
         f.createNewFile();
 
-        return artifactRepositoryFactory.createArtifactRepository( "test", "file://" + f.getPath(), repoLayout, null,
-                                                                   null );
+        return artifactRepositoryFactory.createArtifactRepository(
+                "test", "file://" + f.getPath(), repoLayout, null, null);
     }
 
-    protected String getRepositoryLayout()
-    {
+    protected String getRepositoryLayout() {
         return "default";
     }
 
-    protected ArtifactRepository localRepository()
-        throws Exception
-    {
+    protected ArtifactRepository localRepository() throws Exception {
         String path = "target/test-repositories/" + component() + "/local-repository";
 
-        File f = new File( getBasedir(), path );
+        File f = new File(getBasedir(), path);
 
-        return artifactRepositoryFactory.createArtifactRepository( "local", "file://" + f.getPath(), repoLayout, null,
-                                                                   null );
+        return artifactRepositoryFactory.createArtifactRepository(
+                "local", "file://" + f.getPath(), repoLayout, null, null);
     }
 
-    protected ArtifactRepository remoteRepository()
-        throws Exception
-    {
+    protected ArtifactRepository remoteRepository() throws Exception {
         String path = "target/test-repositories/" + component() + "/remote-repository";
 
-        File f = new File( getBasedir(), path );
+        File f = new File(getBasedir(), path);
 
-        return artifactRepositoryFactory.createArtifactRepository( "test", "file://" + f.getPath(), repoLayout,
-                                                                   new ArtifactRepositoryPolicy(),
-                                                                   new ArtifactRepositoryPolicy() );
+        return artifactRepositoryFactory.createArtifactRepository(
+                "test",
+                "file://" + f.getPath(),
+                repoLayout,
+                new ArtifactRepositoryPolicy(),
+                new ArtifactRepositoryPolicy());
     }
 
-    protected ArtifactRepository badRemoteRepository()
-        throws Exception
-    {
-        return artifactRepositoryFactory.createArtifactRepository( "test", "http://foo.bar/repository", repoLayout,
-                                                                   null, null );
+    protected ArtifactRepository badRemoteRepository() throws Exception {
+        return artifactRepositoryFactory.createArtifactRepository(
+                "test", "http://foo.bar/repository", repoLayout, null, null);
     }
 
-    protected void assertRemoteArtifactPresent( Artifact artifact )
-        throws Exception
-    {
+    protected void assertRemoteArtifactPresent(Artifact artifact) throws Exception {
         ArtifactRepository remoteRepo = remoteRepository();
 
-        String path = remoteRepo.pathOf( artifact );
+        String path = remoteRepo.pathOf(artifact);
 
-        File file = new File( remoteRepo.getBasedir(), path );
+        File file = new File(remoteRepo.getBasedir(), path);
 
-        assertTrue( file.exists(), "Remote artifact " + file + " should be present." );
+        assertTrue(file.exists(), "Remote artifact " + file + " should be present.");
     }
 
-    protected void assertLocalArtifactPresent( Artifact artifact )
-        throws Exception
-    {
+    protected void assertLocalArtifactPresent(Artifact artifact) throws Exception {
         ArtifactRepository localRepo = localRepository();
 
-        String path = localRepo.pathOf( artifact );
+        String path = localRepo.pathOf(artifact);
 
-        File file = new File( localRepo.getBasedir(), path );
+        File file = new File(localRepo.getBasedir(), path);
 
-        assertTrue( file.exists(), "Local artifact " + file + " should be present." );
+        assertTrue(file.exists(), "Local artifact " + file + " should be present.");
     }
 
-    protected void assertRemoteArtifactNotPresent( Artifact artifact )
-        throws Exception
-    {
+    protected void assertRemoteArtifactNotPresent(Artifact artifact) throws Exception {
         ArtifactRepository remoteRepo = remoteRepository();
 
-        String path = remoteRepo.pathOf( artifact );
+        String path = remoteRepo.pathOf(artifact);
 
-        File file = new File( remoteRepo.getBasedir(), path );
+        File file = new File(remoteRepo.getBasedir(), path);
 
-        assertFalse( file.exists(), "Remote artifact " + file + " should not be present." );
+        assertFalse(file.exists(), "Remote artifact " + file + " should not be present.");
     }
 
-    protected void assertLocalArtifactNotPresent( Artifact artifact )
-        throws Exception
-    {
+    protected void assertLocalArtifactNotPresent(Artifact artifact) throws Exception {
         ArtifactRepository localRepo = localRepository();
 
-        String path = localRepo.pathOf( artifact );
+        String path = localRepo.pathOf(artifact);
 
-        File file = new File( localRepo.getBasedir(), path );
+        File file = new File(localRepo.getBasedir(), path);
 
-        assertFalse( file.exists(), "Local artifact " + file + " should not be present." );
+        assertFalse(file.exists(), "Local artifact " + file + " should not be present.");
     }
 
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
 
-    protected List<ArtifactRepository> remoteRepositories()
-        throws Exception
-    {
+    protected List<ArtifactRepository> remoteRepositories() throws Exception {
         List<ArtifactRepository> remoteRepositories = new ArrayList<>();
 
-        remoteRepositories.add( remoteRepository() );
+        remoteRepositories.add(remoteRepository());
 
         return remoteRepositories;
     }
@@ -228,148 +219,118 @@
     // Test artifact generation for unit tests
     // ----------------------------------------------------------------------
 
-    protected Artifact createLocalArtifact( String artifactId, String version )
-        throws Exception
-    {
-        Artifact artifact = createArtifact( artifactId, version );
+    protected Artifact createLocalArtifact(String artifactId, String version) throws Exception {
+        Artifact artifact = createArtifact(artifactId, version);
 
-        createArtifact( artifact, localRepository() );
+        createArtifact(artifact, localRepository());
 
         return artifact;
     }
 
-    protected Artifact createRemoteArtifact( String artifactId, String version )
-        throws Exception
-    {
-        Artifact artifact = createArtifact( artifactId, version );
+    protected Artifact createRemoteArtifact(String artifactId, String version) throws Exception {
+        Artifact artifact = createArtifact(artifactId, version);
 
-        createArtifact( artifact, remoteRepository() );
+        createArtifact(artifact, remoteRepository());
 
         return artifact;
     }
 
-    protected void createLocalArtifact( Artifact artifact )
-        throws Exception
-    {
-        createArtifact( artifact, localRepository() );
+    protected void createLocalArtifact(Artifact artifact) throws Exception {
+        createArtifact(artifact, localRepository());
     }
 
-    protected void createRemoteArtifact( Artifact artifact )
-        throws Exception
-    {
-        createArtifact( artifact, remoteRepository() );
+    protected void createRemoteArtifact(Artifact artifact) throws Exception {
+        createArtifact(artifact, remoteRepository());
     }
 
-    protected void createArtifact( Artifact artifact, ArtifactRepository repository )
-        throws Exception
-    {
-        String path = repository.pathOf( artifact );
+    protected void createArtifact(Artifact artifact, ArtifactRepository repository) throws Exception {
+        String path = repository.pathOf(artifact);
 
-        File artifactFile = new File( repository.getBasedir(), path );
+        File artifactFile = new File(repository.getBasedir(), path);
 
-        if ( !artifactFile.getParentFile().exists() )
-        {
+        if (!artifactFile.getParentFile().exists()) {
             artifactFile.getParentFile().mkdirs();
         }
-        try ( Writer writer = new OutputStreamWriter( new FileOutputStream( artifactFile ), StandardCharsets.ISO_8859_1) )
-        {
-            writer.write( artifact.getId() );
+        try (Writer writer = new OutputStreamWriter(new FileOutputStream(artifactFile), StandardCharsets.ISO_8859_1)) {
+            writer.write(artifact.getId());
         }
 
-        MessageDigest md = MessageDigest.getInstance( "MD5" );
-        md.update( artifact.getId().getBytes() );
+        MessageDigest md = MessageDigest.getInstance("MD5");
+        md.update(artifact.getId().getBytes());
         byte[] digest = md.digest();
 
-        String md5path = repository.pathOf( artifact ) + ".md5";
-        File md5artifactFile = new File( repository.getBasedir(), md5path );
-        try ( Writer writer = new OutputStreamWriter( new FileOutputStream( md5artifactFile ), StandardCharsets.ISO_8859_1) )
-        {
-            writer.append( printHexBinary( digest ) );
+        String md5path = repository.pathOf(artifact) + ".md5";
+        File md5artifactFile = new File(repository.getBasedir(), md5path);
+        try (Writer writer =
+                new OutputStreamWriter(new FileOutputStream(md5artifactFile), StandardCharsets.ISO_8859_1)) {
+            writer.append(printHexBinary(digest));
         }
     }
 
-    protected Artifact createArtifact( String artifactId, String version )
-        throws Exception
-    {
-        return createArtifact( artifactId, version, "jar" );
+    protected Artifact createArtifact(String artifactId, String version) throws Exception {
+        return createArtifact(artifactId, version, "jar");
     }
 
-    protected Artifact createArtifact( String artifactId, String version, String type )
-        throws Exception
-    {
-        return createArtifact( "org.apache.maven", artifactId, version, type );
+    protected Artifact createArtifact(String artifactId, String version, String type) throws Exception {
+        return createArtifact("org.apache.maven", artifactId, version, type);
     }
 
-    protected Artifact createArtifact( String groupId, String artifactId, String version, String type )
-        throws Exception
-    {
-        Artifact a = artifactFactory.createBuildArtifact( groupId, artifactId, version, type );
+    protected Artifact createArtifact(String groupId, String artifactId, String version, String type) throws Exception {
+        Artifact a = artifactFactory.createBuildArtifact(groupId, artifactId, version, type);
 
         return a;
     }
 
-    protected void deleteLocalArtifact( Artifact artifact )
-        throws Exception
-    {
-        deleteArtifact( artifact, localRepository() );
+    protected void deleteLocalArtifact(Artifact artifact) throws Exception {
+        deleteArtifact(artifact, localRepository());
     }
 
-    protected void deleteArtifact( Artifact artifact, ArtifactRepository repository )
-        throws Exception
-    {
-        String path = repository.pathOf( artifact );
+    protected void deleteArtifact(Artifact artifact, ArtifactRepository repository) throws Exception {
+        String path = repository.pathOf(artifact);
 
-        File artifactFile = new File( repository.getBasedir(), path );
+        File artifactFile = new File(repository.getBasedir(), path);
 
-        if ( artifactFile.exists() )
-        {
-            if ( !artifactFile.delete() )
-            {
-                throw new IOException( "Failure while attempting to delete artifact " + artifactFile );
+        if (artifactFile.exists()) {
+            if (!artifactFile.delete()) {
+                throw new IOException("Failure while attempting to delete artifact " + artifactFile);
             }
         }
     }
 
-    protected RepositorySystemSession initRepoSession()
-        throws Exception
-    {
+    protected DefaultRepositorySystemSession initRepoSession() throws Exception {
         DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
-        session.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, true ) );
+        session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(true, true));
         DependencyTraverser depTraverser = new FatArtifactTraverser();
-        session.setDependencyTraverser( depTraverser );
+        session.setDependencyTraverser(depTraverser);
 
         DependencyManager depManager = new ClassicDependencyManager();
-        session.setDependencyManager( depManager );
+        session.setDependencyManager(depManager);
 
-        DependencySelector depFilter = new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ),
-                                                                  new OptionalDependencySelector(),
-                                                                  new ExclusionDependencySelector() );
-        session.setDependencySelector( depFilter );
+        DependencySelector depFilter = new AndDependencySelector(
+                new ScopeDependencySelector("test", "provided"),
+                new OptionalDependencySelector(),
+                new ExclusionDependencySelector());
+        session.setDependencySelector(depFilter);
 
-        DependencyGraphTransformer transformer =
-            new ConflictResolver( new NearestVersionSelector(), new JavaScopeSelector(),
-                                  new SimpleOptionalitySelector(), new JavaScopeDeriver() );
-        transformer = new ChainedDependencyGraphTransformer( transformer, new JavaDependencyContextRefiner() );
-        session.setDependencyGraphTransformer( transformer );
+        DependencyGraphTransformer transformer = new ConflictResolver(
+                new NearestVersionSelector(), new JavaScopeSelector(),
+                new SimpleOptionalitySelector(), new JavaScopeDeriver());
+        transformer = new ChainedDependencyGraphTransformer(transformer, new JavaDependencyContextRefiner());
+        session.setDependencyGraphTransformer(transformer);
 
-        LocalRepository localRepo = new LocalRepository( localRepository().getBasedir() );
-        session.setLocalRepositoryManager(
-            new SimpleLocalRepositoryManagerFactory().newInstance( session, localRepo ) );
-
+        LocalRepository localRepo = new LocalRepository(localRepository().getBasedir());
+        session.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory().newInstance(session, localRepo));
         return session;
     }
 
     private static final char[] hexCode = "0123456789ABCDEF".toCharArray();
 
-    private static final String printHexBinary( byte[] data )
-    {
-        StringBuilder r = new StringBuilder( data.length * 2 );
-        for ( byte b : data )
-        {
-            r.append( hexCode[( b >> 4 ) & 0xF] );
-            r.append( hexCode[( b & 0xF )] );
+    private static final String printHexBinary(byte[] data) {
+        StringBuilder r = new StringBuilder(data.length * 2);
+        for (byte b : data) {
+            r.append(hexCode[(b >> 4) & 0xF]);
+            r.append(hexCode[(b & 0xF)]);
         }
         return r.toString();
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/deployer/ArtifactDeployerTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/deployer/ArtifactDeployerTest.java
index 3f33fa1..f6c94d3 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/deployer/ArtifactDeployerTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/deployer/ArtifactDeployerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.deployer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.deployer;
+
+import javax.inject.Inject;
 
 import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 
 import org.apache.maven.artifact.AbstractArtifactComponentTestCase;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.session.scope.internal.SessionScope;
-import org.codehaus.plexus.util.FileUtils;
 import org.junit.jupiter.api.Test;
 
 import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
@@ -34,51 +36,40 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.Mockito.mock;
 
-import javax.inject.Inject;
-
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-public class ArtifactDeployerTest
-    extends AbstractArtifactComponentTestCase
-{
+class ArtifactDeployerTest extends AbstractArtifactComponentTestCase {
     @Inject
     private ArtifactDeployer artifactDeployer;
 
     @Inject
     private SessionScope sessionScope;
 
-    protected String component()
-    {
+    protected String component() {
         return "deployer";
     }
 
     @Test
-    public void testArtifactInstallation()
-        throws Exception
-    {
+    void testArtifactInstallation() throws Exception {
         sessionScope.enter();
-        try
-        {
+        try {
             sessionScope.seed(MavenSession.class, mock(MavenSession.class));
 
-            String artifactBasedir = new File( getBasedir(), "src/test/resources/artifact-install" ).getAbsolutePath();
+            String artifactBasedir = new File(getBasedir(), "src/test/resources/artifact-install").getAbsolutePath();
 
-            Artifact artifact = createArtifact( "artifact", "1.0" );
+            Artifact artifact = createArtifact("artifact", "1.0");
 
-            File file = new File( artifactBasedir, "artifact-1.0.jar" );
-            assertEquals( "dummy", FileUtils.fileRead( file, "UTF-8" ).trim() );
+            File file = new File(artifactBasedir, "artifact-1.0.jar");
+            assertEquals("dummy", new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8).trim());
 
-            artifactDeployer.deploy( file, artifact, remoteRepository(), localRepository() );
+            artifactDeployer.deploy(file, artifact, remoteRepository(), localRepository());
 
             ArtifactRepository remoteRepository = remoteRepository();
-            File deployedFile = new File( remoteRepository.getBasedir(), remoteRepository.pathOf( artifact ) );
-            assertTrue( deployedFile.exists() );
-            assertEquals( "dummy", FileUtils.fileRead( deployedFile, "UTF-8" ).trim() );
-        }
-        finally
-        {
+            File deployedFile = new File(remoteRepository.getBasedir(), remoteRepository.pathOf(artifact));
+            assertTrue(deployedFile.exists());
+            assertEquals("dummy", new String(Files.readAllBytes(deployedFile.toPath()), StandardCharsets.UTF_8).trim());
+        } finally {
             sessionScope.exit();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/deployer/SimpleArtifactMetadataSource.java b/maven-compat/src/test/java/org/apache/maven/artifact/deployer/SimpleArtifactMetadataSource.java
index 5864f1b..e5472a4 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/deployer/SimpleArtifactMetadataSource.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/deployer/SimpleArtifactMetadataSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.deployer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.deployer;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Collections;
 import java.util.List;
@@ -30,37 +32,25 @@
 import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
 import org.apache.maven.repository.legacy.metadata.ResolutionGroup;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-/** @author Jason van Zyl */
-@Named( "classpath" )
+@Named("classpath")
 @Singleton
-public class SimpleArtifactMetadataSource
-    implements ArtifactMetadataSource
-{
-    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                                     List<ArtifactRepository> remoteRepositories )
-    {
-        throw new UnsupportedOperationException( "Cannot retrieve metadata in this test case" );
+public class SimpleArtifactMetadataSource implements ArtifactMetadataSource {
+    public ResolutionGroup retrieve(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories) {
+        throw new UnsupportedOperationException("Cannot retrieve metadata in this test case");
     }
 
-    public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
-                                                            List<ArtifactRepository> remoteRepositories )
-    {
-        return Collections.singletonList( new DefaultArtifactVersion( "10.1.3" ) );
+    public List<ArtifactVersion> retrieveAvailableVersions(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories) {
+        return Collections.singletonList(new DefaultArtifactVersion("10.1.3"));
     }
 
-    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact,
-                                                                                    ArtifactRepository localRepository,
-                                                                                    ArtifactRepository remoteRepository )
-    {
-        return Collections.singletonList( new DefaultArtifactVersion( "10.1.3" ) );
+    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository) {
+        return Collections.singletonList(new DefaultArtifactVersion("10.1.3"));
     }
 
-    public ResolutionGroup retrieve( MetadataResolutionRequest request )
-    {
-        return retrieve( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+    public ResolutionGroup retrieve(MetadataResolutionRequest request) {
+        return retrieve(request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/factory/DefaultArtifactFactoryTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/factory/DefaultArtifactFactoryTest.java
index d124894..8e19747 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/factory/DefaultArtifactFactoryTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/factory/DefaultArtifactFactoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.factory;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,39 +16,54 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.factory;
 
 import javax.inject.Inject;
 
-import org.codehaus.plexus.testing.PlexusTest;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.versioning.VersionRange;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 @PlexusTest
-public class DefaultArtifactFactoryTest
-{
+class DefaultArtifactFactoryTest {
 
     @Inject
     ArtifactFactory factory;
 
     @Test
-    public void testPropagationOfSystemScopeRegardlessOfInheritedScope()
-    {
-        Artifact artifact = factory.createDependencyArtifact( "test-grp", "test-artifact", VersionRange.createFromVersion("1.0"), "type", null, "system", "provided" );
-        Artifact artifact2 = factory.createDependencyArtifact( "test-grp", "test-artifact-2", VersionRange.createFromVersion("1.0"), "type", null, "system", "test" );
-        Artifact artifact3 = factory.createDependencyArtifact( "test-grp", "test-artifact-3", VersionRange.createFromVersion("1.0"), "type", null, "system", "runtime" );
-        Artifact artifact4 = factory.createDependencyArtifact( "test-grp", "test-artifact-4", VersionRange.createFromVersion("1.0"), "type", null, "system", "compile" );
+    void testPropagationOfSystemScopeRegardlessOfInheritedScope() {
+        Artifact artifact = factory.createDependencyArtifact(
+                "test-grp", "test-artifact", VersionRange.createFromVersion("1.0"), "type", null, "system", "provided");
+        Artifact artifact2 = factory.createDependencyArtifact(
+                "test-grp", "test-artifact-2", VersionRange.createFromVersion("1.0"), "type", null, "system", "test");
+        Artifact artifact3 = factory.createDependencyArtifact(
+                "test-grp",
+                "test-artifact-3",
+                VersionRange.createFromVersion("1.0"),
+                "type",
+                null,
+                "system",
+                "runtime");
+        Artifact artifact4 = factory.createDependencyArtifact(
+                "test-grp",
+                "test-artifact-4",
+                VersionRange.createFromVersion("1.0"),
+                "type",
+                null,
+                "system",
+                "compile");
 
         // this one should never happen in practice...
-        Artifact artifact5 = factory.createDependencyArtifact( "test-grp", "test-artifact-5", VersionRange.createFromVersion("1.0"), "type", null, "system", "system" );
+        Artifact artifact5 = factory.createDependencyArtifact(
+                "test-grp", "test-artifact-5", VersionRange.createFromVersion("1.0"), "type", null, "system", "system");
 
-        assertEquals( "system", artifact.getScope() );
-        assertEquals( "system", artifact2.getScope() );
-        assertEquals( "system", artifact3.getScope() );
-        assertEquals( "system", artifact4.getScope() );
-        assertEquals( "system", artifact5.getScope() );
+        assertEquals("system", artifact.getScope());
+        assertEquals("system", artifact2.getScope());
+        assertEquals("system", artifact3.getScope());
+        assertEquals("system", artifact4.getScope());
+        assertEquals("system", artifact5.getScope());
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java
index afa2761..cf7ac67 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/installer/ArtifactInstallerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.installer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.installer;
+
+import javax.inject.Inject;
 
 import java.io.File;
 
@@ -27,50 +28,39 @@
 import org.apache.maven.session.scope.internal.SessionScope;
 import org.junit.jupiter.api.Test;
 
-import javax.inject.Inject;
-
 import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
 import static org.mockito.Mockito.mock;
 
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-public class ArtifactInstallerTest
-    extends AbstractArtifactComponentTestCase
-{
+class ArtifactInstallerTest extends AbstractArtifactComponentTestCase {
     @Inject
     private ArtifactInstaller artifactInstaller;
 
     @Inject
     private SessionScope sessionScope;
 
-    protected String component()
-    {
+    protected String component() {
         return "installer";
     }
 
     @Test
-    public void testArtifactInstallation()
-        throws Exception
-    {
+    void testArtifactInstallation() throws Exception {
         sessionScope.enter();
-        try
-        {
+        try {
             sessionScope.seed(MavenSession.class, mock(MavenSession.class));
 
-            String artifactBasedir = new File( getBasedir(), "src/test/resources/artifact-install" ).getAbsolutePath();
+            String artifactBasedir = new File(getBasedir(), "src/test/resources/artifact-install").getAbsolutePath();
 
-            Artifact artifact = createArtifact( "artifact", "1.0" );
+            Artifact artifact = createArtifact("artifact", "1.0");
 
-            File source = new File( artifactBasedir, "artifact-1.0.jar" );
+            File source = new File(artifactBasedir, "artifact-1.0.jar");
 
-            artifactInstaller.install( source, artifact, localRepository() );
+            artifactInstaller.install(source, artifact, localRepository());
 
-            assertLocalArtifactPresent( artifact );
-        }
-        finally
-        {
+            assertLocalArtifactPresent(artifact);
+        } finally {
             sessionScope.exit();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/metadata/SwitchableMetadataSource.java b/maven-compat/src/test/java/org/apache/maven/artifact/metadata/SwitchableMetadataSource.java
new file mode 100644
index 0000000..a06fb8b
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/metadata/SwitchableMetadataSource.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.metadata;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.List;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
+import org.eclipse.sisu.Priority;
+
+@Singleton
+@Priority(10)
+@Named
+public class SwitchableMetadataSource implements ArtifactMetadataSource {
+    private ArtifactMetadataSource delegate;
+
+    @Inject
+    public SwitchableMetadataSource(@Named("test") ArtifactMetadataSource delegate) {
+        this.delegate = delegate;
+    }
+
+    public void setDelegate(ArtifactMetadataSource delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException {
+        return delegate.retrieve(request);
+    }
+
+    @Override
+    public ResolutionGroup retrieve(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
+        return delegate.retrieve(artifact, localRepository, remoteRepositories);
+    }
+
+    @Override
+    public List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request)
+            throws ArtifactMetadataRetrievalException {
+        return delegate.retrieveAvailableVersions(request);
+    }
+
+    @Override
+    public List<ArtifactVersion> retrieveAvailableVersions(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
+        return delegate.retrieveAvailableVersions(artifact, localRepository, remoteRepositories);
+    }
+
+    @Override
+    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws ArtifactMetadataRetrievalException {
+        return delegate.retrieveAvailableVersionsFromDeploymentRepository(artifact, localRepository, remoteRepository);
+    }
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/metadata/TestMetadataSource.java b/maven-compat/src/test/java/org/apache/maven/artifact/metadata/TestMetadataSource.java
index f1973f9..516d0b9 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/metadata/TestMetadataSource.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/metadata/TestMetadataSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.metadata;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.HashSet;
 import java.util.List;
@@ -29,77 +32,59 @@
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-@Named( "test" )
+@Named("test")
 @Singleton
-public class TestMetadataSource
-    implements ArtifactMetadataSource
-{
+public class TestMetadataSource implements ArtifactMetadataSource {
     @Inject
     private ArtifactFactory factory;
 
-    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException
-    {
+    public ResolutionGroup retrieve(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
         Set<Artifact> dependencies = new HashSet<>();
 
-        if ( "g".equals( artifact.getArtifactId() ) )
-        {
+        if ("g".equals(artifact.getArtifactId())) {
             Artifact a = null;
-            try
-            {
-                a = factory.createBuildArtifact( "org.apache.maven", "h", "1.0", "jar" );
-                dependencies.add( a );
-            }
-            catch ( Exception e )
-            {
-                throw new ArtifactMetadataRetrievalException( "Error retrieving metadata", e, a );
+            try {
+                a = factory.createBuildArtifact("org.apache.maven", "h", "1.0", "jar");
+                dependencies.add(a);
+            } catch (Exception e) {
+                throw new ArtifactMetadataRetrievalException("Error retrieving metadata", e, a);
             }
         }
 
-        if ( "i".equals( artifact.getArtifactId() ) )
-        {
+        if ("i".equals(artifact.getArtifactId())) {
             Artifact a = null;
-            try
-            {
-                a = factory.createBuildArtifact( "org.apache.maven", "j", "1.0-SNAPSHOT", "jar" );
-                dependencies.add( a );
-            }
-            catch ( Exception e )
-            {
-                throw new ArtifactMetadataRetrievalException( "Error retrieving metadata", e, a );
+            try {
+                a = factory.createBuildArtifact("org.apache.maven", "j", "1.0-SNAPSHOT", "jar");
+                dependencies.add(a);
+            } catch (Exception e) {
+                throw new ArtifactMetadataRetrievalException("Error retrieving metadata", e, a);
             }
         }
 
-
-        return new ResolutionGroup( artifact, dependencies, remoteRepositories );
+        return new ResolutionGroup(artifact, dependencies, remoteRepositories);
     }
 
-    public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException
-    {
-        throw new UnsupportedOperationException( "Cannot get available versions in this test case" );
+    public List<ArtifactVersion> retrieveAvailableVersions(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
+        throw new UnsupportedOperationException("Cannot get available versions in this test case");
     }
 
-    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository )
-        throws ArtifactMetadataRetrievalException
-    {
-        throw new UnsupportedOperationException( "Cannot get available versions in this test case" );
+    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws ArtifactMetadataRetrievalException {
+        throw new UnsupportedOperationException("Cannot get available versions in this test case");
     }
 
-    public ResolutionGroup retrieve( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException
-    {
-        return retrieve( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+    public ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException {
+        return retrieve(request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
     }
 
-    public List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException
-    {
-        return retrieveAvailableVersions( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+    public List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request)
+            throws ArtifactMetadataRetrievalException {
+        return retrieveAvailableVersions(
+                request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/repository/MavenArtifactRepositoryTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/repository/MavenArtifactRepositoryTest.java
index 4e7b5dc..9ba2d57 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/repository/MavenArtifactRepositoryTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/repository/MavenArtifactRepositoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,45 +16,40 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
+package org.apache.maven.artifact.repository;
 
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class MavenArtifactRepositoryTest
-{
-    private static class MavenArtifactRepositorySubclass extends MavenArtifactRepository
-    {
+class MavenArtifactRepositoryTest {
+    private static class MavenArtifactRepositorySubclass extends MavenArtifactRepository {
         String id;
 
-        public MavenArtifactRepositorySubclass(String id)
-        {
+        public MavenArtifactRepositorySubclass(String id) {
             this.id = id;
         }
 
         @Override
-        public String getId()
-        {
+        public String getId() {
             return id;
         }
     }
 
     @Test
-    public void testHashCodeEquals()
-    {
-        MavenArtifactRepositorySubclass r1 = new MavenArtifactRepositorySubclass( "foo" );
-        MavenArtifactRepositorySubclass r2 = new MavenArtifactRepositorySubclass( "foo" );
-        MavenArtifactRepositorySubclass r3 = new MavenArtifactRepositorySubclass( "bar" );
+    void testHashCodeEquals() {
+        MavenArtifactRepositorySubclass r1 = new MavenArtifactRepositorySubclass("foo");
+        MavenArtifactRepositorySubclass r2 = new MavenArtifactRepositorySubclass("foo");
+        MavenArtifactRepositorySubclass r3 = new MavenArtifactRepositorySubclass("bar");
 
-        assertTrue( r1.hashCode() == r2.hashCode() );
-        assertFalse( r1.hashCode() == r3.hashCode() );
+        assertTrue(r1.hashCode() == r2.hashCode());
+        assertFalse(r1.hashCode() == r3.hashCode());
 
-        assertTrue( r1.equals( r2 ) );
-        assertTrue( r2.equals( r1 ) );
+        assertTrue(r1.equals(r2));
+        assertTrue(r2.equals(r1));
 
-        assertFalse( r1.equals( r3 ) );
-        assertFalse( r3.equals( r1 ) );
+        assertFalse(r1.equals(r3));
+        assertFalse(r3.equals(r1));
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java
index e6b0e56..3856603 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolutionExceptionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.Arrays;
 import java.util.List;
@@ -29,15 +28,12 @@
 /**
  * Test the artifact resolution exception message
  *
- * @author Mauro Talevi
  */
-public class ArtifactResolutionExceptionTest
-{
+class ArtifactResolutionExceptionTest {
     private static final String LS = System.lineSeparator();
 
     @Test
-    public void testMissingArtifactMessageFormat()
-    {
+    void testMissingArtifactMessageFormat() {
         String message = "Missing artifact";
         String indentation = "  ";
         String groupId = "aGroupId";
@@ -46,9 +42,8 @@
         String type = "jar";
         String classifier = "aClassifier";
         String downloadUrl = "http://somewhere.com/download";
-        List<String> path = Arrays.asList( "dependency1", "dependency2" );
-        String expected =
-            "Missing artifact" + LS + LS + "  Try downloading the file manually from: " + LS
+        List<String> path = Arrays.asList("dependency1", "dependency2");
+        String expected = "Missing artifact" + LS + LS + "  Try downloading the file manually from: " + LS
                 + "      http://somewhere.com/download" + LS + LS + "  Then, install it using the command: " + LS
                 + "      mvn install:install-file -DgroupId=aGroupId -DartifactId=anArtifactId -Dversion=aVersion "
                 + "-Dclassifier=aClassifier -Dpackaging=jar -Dfile=/path/to/file" + LS + LS
@@ -57,10 +52,8 @@
                 + " -Dversion=aVersion -Dclassifier=aClassifier -Dpackaging=jar -Dfile=/path/to/file"
                 + " -Durl=[url] -DrepositoryId=[id]" + LS + LS + "  Path to dependency: " + LS + "  \t1) dependency1"
                 + LS + "  \t2) dependency2" + LS + LS;
-        String actual =
-            AbstractArtifactResolutionException.constructMissingArtifactMessage( message, indentation, groupId,
-                                                                                 artifactId, version, type, classifier,
-                                                                                 downloadUrl, path );
-        assertEquals( expected, actual );
+        String actual = AbstractArtifactResolutionException.constructMissingArtifactMessage(
+                message, indentation, groupId, artifactId, version, type, classifier, downloadUrl, path);
+        assertEquals(expected, actual);
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java
index 9a3934e..2b8bc61 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/ArtifactResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
+
+import javax.inject.Inject;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -34,6 +35,7 @@
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
+import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
@@ -41,8 +43,6 @@
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
 // It would be cool if there was a hook that I could use to set up a test environment.
 // I want to set up a local/remote repositories for testing but I don't want to have
 // to change them when I change the layout of the repositories. So I want to generate
@@ -50,11 +50,8 @@
 // the layout used for a particular artifact type.
 
 /**
- * @author Jason van Zyl
  */
-public class ArtifactResolverTest
-    extends AbstractArtifactComponentTestCase
-{
+class ArtifactResolverTest extends AbstractArtifactComponentTestCase {
     @Inject
     private ArtifactResolver artifactResolver;
 
@@ -62,216 +59,215 @@
 
     @BeforeEach
     @Override
-    public void setUp()
-        throws Exception
-    {
+    public void setUp() throws Exception {
         super.setUp();
 
-        projectArtifact = createLocalArtifact( "project", "3.0" );
+        projectArtifact = createLocalArtifact("project", "3.0");
     }
 
     @Override
-    protected String component()
-    {
+    protected DefaultRepositorySystemSession initRepoSession() throws Exception {
+        DefaultRepositorySystemSession session = super.initRepoSession();
+        session.setWorkspaceReader(new TestMavenWorkspaceReader());
+        return session;
+    }
+
+    @Override
+    protected String component() {
         return "resolver";
     }
 
     @Test
-    public void testResolutionOfASingleArtifactWhereTheArtifactIsPresentInTheLocalRepository()
-        throws Exception
-    {
-        Artifact a = createLocalArtifact( "a", "1.0" );
+    void testResolutionOfASingleArtifactWhereTheArtifactIsPresentInTheLocalRepository() throws Exception {
+        Artifact a = createLocalArtifact("a", "1.0");
 
-        artifactResolver.resolve( a, remoteRepositories(), localRepository() );
+        artifactResolver.resolve(a, remoteRepositories(), localRepository());
 
-        assertLocalArtifactPresent( a );
+        assertLocalArtifactPresent(a);
     }
 
     @Test
-    public void testResolutionOfASingleArtifactWhereTheArtifactIsNotPresentLocallyAndMustBeRetrievedFromTheRemoteRepository()
-        throws Exception
-    {
-        Artifact b = createRemoteArtifact( "b", "1.0-SNAPSHOT" );
-        deleteLocalArtifact( b );
-        artifactResolver.resolve( b, remoteRepositories(), localRepository() );
-        assertLocalArtifactPresent( b );
+    void testResolutionOfASingleArtifactWhereTheArtifactIsNotPresentLocallyAndMustBeRetrievedFromTheRemoteRepository()
+            throws Exception {
+        Artifact b = createRemoteArtifact("b", "1.0-SNAPSHOT");
+        deleteLocalArtifact(b);
+        artifactResolver.resolve(b, remoteRepositories(), localRepository());
+        assertLocalArtifactPresent(b);
     }
 
     @Override
-    protected Artifact createArtifact( String groupId, String artifactId, String version, String type )
-        throws Exception
-    {
+    protected Artifact createArtifact(String groupId, String artifactId, String version, String type) throws Exception {
         // for the anonymous classes
-        return super.createArtifact( groupId, artifactId, version, type );
+        return super.createArtifact(groupId, artifactId, version, type);
     }
 
     @Test
-    public void testTransitiveResolutionWhereAllArtifactsArePresentInTheLocalRepository()
-        throws Exception
-    {
-        Artifact g = createLocalArtifact( "g", "1.0" );
+    void testTransitiveResolutionWhereAllArtifactsArePresentInTheLocalRepository() throws Exception {
+        Artifact g = createLocalArtifact("g", "1.0");
 
-        Artifact h = createLocalArtifact( "h", "1.0" );
+        Artifact h = createLocalArtifact("h", "1.0");
 
-        ArtifactResolutionResult result = artifactResolver.resolveTransitively( Collections.singleton( g ), projectArtifact, remoteRepositories(), localRepository(), null );
+        ArtifactResolutionResult result = artifactResolver.resolveTransitively(
+                Collections.singleton(g), projectArtifact, remoteRepositories(), localRepository(), null);
 
-        printErrors( result );
+        printErrors(result);
 
-        assertEquals( 2, result.getArtifacts().size() );
+        assertEquals(2, result.getArtifacts().size());
 
-        assertTrue( result.getArtifacts().contains( g ) );
+        assertTrue(result.getArtifacts().contains(g));
 
-        assertTrue( result.getArtifacts().contains( h ) );
+        assertTrue(result.getArtifacts().contains(h));
 
-        assertLocalArtifactPresent( g );
+        assertLocalArtifactPresent(g);
 
-        assertLocalArtifactPresent( h );
+        assertLocalArtifactPresent(h);
     }
 
     @Test
-    public void testTransitiveResolutionWhereAllArtifactsAreNotPresentInTheLocalRepositoryAndMustBeRetrievedFromTheRemoteRepository()
-        throws Exception
-    {
-        Artifact i = createRemoteArtifact( "i", "1.0-SNAPSHOT" );
-        deleteLocalArtifact( i );
+    void
+            testTransitiveResolutionWhereAllArtifactsAreNotPresentInTheLocalRepositoryAndMustBeRetrievedFromTheRemoteRepository()
+                    throws Exception {
+        Artifact i = createRemoteArtifact("i", "1.0-SNAPSHOT");
+        deleteLocalArtifact(i);
 
-        Artifact j = createRemoteArtifact( "j", "1.0-SNAPSHOT" );
-        deleteLocalArtifact( j );
+        Artifact j = createRemoteArtifact("j", "1.0-SNAPSHOT");
+        deleteLocalArtifact(j);
 
-        ArtifactResolutionResult result = artifactResolver.resolveTransitively( Collections.singleton( i ), projectArtifact, remoteRepositories(), localRepository(), null );
+        ArtifactResolutionResult result = artifactResolver.resolveTransitively(
+                Collections.singleton(i), projectArtifact, remoteRepositories(), localRepository(), null);
 
-        printErrors( result );
+        printErrors(result);
 
-        assertEquals( 2, result.getArtifacts().size() );
+        assertEquals(2, result.getArtifacts().size());
 
-        assertTrue( result.getArtifacts().contains( i ) );
+        assertTrue(result.getArtifacts().contains(i));
 
-        assertTrue( result.getArtifacts().contains( j ) );
+        assertTrue(result.getArtifacts().contains(j));
 
-        assertLocalArtifactPresent( i );
+        assertLocalArtifactPresent(i);
 
-        assertLocalArtifactPresent( j );
+        assertLocalArtifactPresent(j);
     }
 
     @Test
-    public void testResolutionFailureWhenArtifactNotPresentInRemoteRepository()
-        throws Exception
-    {
-        Artifact k = createArtifact( "k", "1.0" );
+    void testResolutionFailureWhenArtifactNotPresentInRemoteRepository() throws Exception {
+        Artifact k = createArtifact("k", "1.0");
 
         assertThrows(
                 ArtifactNotFoundException.class,
-                () -> artifactResolver.resolve( k, remoteRepositories(), localRepository() ),
-                "Resolution succeeded when it should have failed" );
+                () -> artifactResolver.resolve(k, remoteRepositories(), localRepository()),
+                "Resolution succeeded when it should have failed");
     }
 
     @Test
-    public void testResolutionOfAnArtifactWhereOneRemoteRepositoryIsBadButOneIsGood()
-        throws Exception
-    {
-        Artifact l = createRemoteArtifact( "l", "1.0-SNAPSHOT" );
-        deleteLocalArtifact( l );
+    void testResolutionOfAnArtifactWhereOneRemoteRepositoryIsBadButOneIsGood() throws Exception {
+        Artifact l = createRemoteArtifact("l", "1.0-SNAPSHOT");
+        deleteLocalArtifact(l);
 
         List<ArtifactRepository> repositories = new ArrayList<>();
-        repositories.add( remoteRepository() );
-        repositories.add( badRemoteRepository() );
+        repositories.add(remoteRepository());
+        repositories.add(badRemoteRepository());
 
-        artifactResolver.resolve( l, repositories, localRepository() );
+        artifactResolver.resolve(l, repositories, localRepository());
 
-        assertLocalArtifactPresent( l );
+        assertLocalArtifactPresent(l);
+    }
+
+    public void testReadRepoFromModel() throws Exception {
+        Artifact m = createArtifact(TestMavenWorkspaceReader.ARTIFACT_ID, TestMavenWorkspaceReader.VERSION);
+        ArtifactMetadataSource source = getContainer().lookup(ArtifactMetadataSource.class, "maven");
+        ResolutionGroup group = source.retrieve(m, localRepository(), new ArrayList<>());
+        List<ArtifactRepository> repositories = group.getResolutionRepositories();
+        assertEquals(1, repositories.size(), "There should be one repository!");
+        ArtifactRepository repository = repositories.get(0);
+        assertEquals(TestMavenWorkspaceReader.REPO_ID, repository.getId());
+        assertEquals(TestMavenWorkspaceReader.REPO_URL, repository.getUrl());
     }
 
     @Test
-    public void testTransitiveResolutionOrder()
-        throws Exception
-    {
-        Artifact m = createLocalArtifact( "m", "1.0" );
+    void testTransitiveResolutionOrder() throws Exception {
+        Artifact m = createLocalArtifact("m", "1.0");
 
-        Artifact n = createLocalArtifact( "n", "1.0" );
+        Artifact n = createLocalArtifact("n", "1.0");
 
-        ArtifactMetadataSource mds = new ArtifactMetadataSource()
-        {
-            public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                                             List<ArtifactRepository> remoteRepositories )
-            {
+        ArtifactMetadataSource mds = new ArtifactMetadataSource() {
+            @Override
+            public ResolutionGroup retrieve(
+                    Artifact artifact,
+                    ArtifactRepository localRepository,
+                    List<ArtifactRepository> remoteRepositories) {
                 Set<Artifact> dependencies = new HashSet<>();
 
-                return new ResolutionGroup( artifact, dependencies, remoteRepositories );
+                return new ResolutionGroup(artifact, dependencies, remoteRepositories);
             }
 
-            public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact,
-                                                                    ArtifactRepository localRepository,
-                                                                    List<ArtifactRepository> remoteRepositories )
-            {
-                throw new UnsupportedOperationException( "Cannot get available versions in this test case" );
+            @Override
+            public List<ArtifactVersion> retrieveAvailableVersions(
+                    Artifact artifact,
+                    ArtifactRepository localRepository,
+                    List<ArtifactRepository> remoteRepositories) {
+                throw new UnsupportedOperationException("Cannot get available versions in this test case");
             }
 
+            @Override
             public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
-                                                                                            Artifact artifact,
-                                                                                            ArtifactRepository localRepository,
-                                                                                            ArtifactRepository remoteRepository )
-            {
-                throw new UnsupportedOperationException( "Cannot get available versions in this test case" );
+                    Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository) {
+                throw new UnsupportedOperationException("Cannot get available versions in this test case");
             }
 
-            public ResolutionGroup retrieve( MetadataResolutionRequest request )
-            {
-                return retrieve( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+            @Override
+            public ResolutionGroup retrieve(MetadataResolutionRequest request) {
+                return retrieve(request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
             }
 
-            public List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
-            {
-                return retrieveAvailableVersions( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+            @Override
+            public List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request) {
+                return retrieveAvailableVersions(
+                        request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
             }
         };
 
         ArtifactResolutionResult result = null;
 
         Set<Artifact> set = new LinkedHashSet<>();
-        set.add( n );
-        set.add( m );
+        set.add(n);
+        set.add(m);
 
-        result =
-            artifactResolver.resolveTransitively( set, projectArtifact, remoteRepositories(), localRepository(), mds );
+        result = artifactResolver.resolveTransitively(
+                set, projectArtifact, remoteRepositories(), localRepository(), mds);
 
-        printErrors( result );
+        printErrors(result);
 
         Iterator<Artifact> i = result.getArtifacts().iterator();
-        assertEquals( n, i.next(), "n should be first" );
-        assertEquals( m, i.next(), "m should be second" );
+        assertEquals(n, i.next(), "n should be first");
+        assertEquals(m, i.next(), "m should be second");
 
         // inverse order
         set = new LinkedHashSet<>();
-        set.add( m );
-        set.add( n );
+        set.add(m);
+        set.add(n);
 
-        result =
-            artifactResolver.resolveTransitively( set, projectArtifact, remoteRepositories(), localRepository(), mds );
+        result = artifactResolver.resolveTransitively(
+                set, projectArtifact, remoteRepositories(), localRepository(), mds);
 
-        printErrors( result );
+        printErrors(result);
 
         i = result.getArtifacts().iterator();
-        assertEquals( m, i.next(), "m should be first" );
-        assertEquals( n, i.next(), "n should be second" );
+        assertEquals(m, i.next(), "m should be first");
+        assertEquals(n, i.next(), "n should be second");
     }
 
-    private void printErrors( ArtifactResolutionResult result )
-    {
-        if ( result.hasMissingArtifacts() )
-        {
-            for ( Artifact artifact : result.getMissingArtifacts() )
-            {
-                System.err.println( "Missing: " + artifact );
+    private void printErrors(ArtifactResolutionResult result) {
+        if (result.hasMissingArtifacts()) {
+            for (Artifact artifact : result.getMissingArtifacts()) {
+                System.err.println("Missing: " + artifact);
             }
         }
 
-        if ( result.hasExceptions() )
-        {
-            for ( Exception e : result.getExceptions() )
-            {
+        if (result.hasExceptions()) {
+            for (Exception e : result.getExceptions()) {
                 e.printStackTrace();
             }
         }
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactResolverTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactResolverTest.java
index 30458d5..f1a6f77 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/DefaultArtifactResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
+
+import javax.inject.Inject;
 
 import java.util.Collections;
 
@@ -29,11 +30,7 @@
 
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
-public class DefaultArtifactResolverTest
-    extends AbstractArtifactComponentTestCase
-{
+class DefaultArtifactResolverTest extends AbstractArtifactComponentTestCase {
     @Inject
     private ArtifactResolver artifactResolver;
 
@@ -41,44 +38,36 @@
 
     @BeforeEach
     @Override
-    public void setUp()
-        throws Exception
-    {
+    public void setUp() throws Exception {
         super.setUp();
-        projectArtifact = createLocalArtifact( "project", "3.0" );
+        projectArtifact = createLocalArtifact("project", "3.0");
     }
 
     @Override
-    protected String component()
-    {
+    protected String component() {
         return "resolver";
     }
 
     @Test
-    public void testMNG4738()
-        throws Exception
-    {
-        Artifact g = createLocalArtifact( "g", "1.0" );
-        createLocalArtifact( "h", "1.0" );
-        artifactResolver.resolveTransitively( Collections.singleton( g ), projectArtifact, remoteRepositories(),
-                                              localRepository(), null );
+    void testMNG4738() throws Exception {
+        Artifact g = createLocalArtifact("g", "1.0");
+        createLocalArtifact("h", "1.0");
+        artifactResolver.resolveTransitively(
+                Collections.singleton(g), projectArtifact, remoteRepositories(), localRepository(), null);
 
         // we want to see all top-level thread groups
         ThreadGroup tg = Thread.currentThread().getThreadGroup();
-        while ( tg.getParent() == null )
-        {
+        while (tg.getParent() == null) {
             tg = tg.getParent();
         }
 
         ThreadGroup[] tgList = new ThreadGroup[tg.activeGroupCount()];
-        tg.enumerate( tgList );
+        tg.enumerate(tgList);
 
         boolean seen = false;
 
-        for ( ThreadGroup aTgList : tgList )
-        {
-            if ( !aTgList.getName().equals( DaemonThreadCreator.THREADGROUP_NAME ) )
-            {
+        for (ThreadGroup aTgList : tgList) {
+            if (!aTgList.getName().equals(DaemonThreadCreator.THREADGROUP_NAME)) {
                 continue;
             }
 
@@ -86,24 +75,20 @@
 
             tg = aTgList;
             Thread[] ts = new Thread[tg.activeCount()];
-            tg.enumerate( ts );
+            tg.enumerate(ts);
 
-            for ( Thread active : ts )
-            {
+            for (Thread active : ts) {
                 String name = active.getName();
                 boolean daemon = active.isDaemon();
-                assertTrue( daemon, name + " is no daemon Thread." );
+                assertTrue(daemon, name + " is no daemon Thread.");
             }
-
         }
 
-        assertTrue( seen, "Could not find ThreadGroup: " + DaemonThreadCreator.THREADGROUP_NAME );
+        assertTrue(seen, "Could not find ThreadGroup: " + DaemonThreadCreator.THREADGROUP_NAME);
     }
 
     @Test
-    public void testLookup()
-        throws Exception
-    {
-        ArtifactResolver resolver = getContainer().lookup( ArtifactResolver.class, "default" );
+    void testLookup() throws Exception {
+        ArtifactResolver resolver = getContainer().lookup(ArtifactResolver.class, "default");
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java
index 4e24fe8..5bc9eee 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestFileWagon.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.io.File;
 import java.io.InputStream;
@@ -32,63 +31,45 @@
 /**
  * Wagon used for test cases that annotate some methods. Note that this is not a thread-safe implementation.
  */
-public class TestFileWagon
-    extends FileWagon
-{
+public class TestFileWagon extends FileWagon {
     private TestTransferListener testTransferListener;
     private boolean insideGet;
 
-    protected void getTransfer( Resource resource,
-                                File destination,
-                                InputStream input,
-                                boolean closeInput,
-                                int maxSize )
-        throws TransferFailedException
-    {
-        addTransfer( "getTransfer " + resource.getName() );
-        super.getTransfer( resource, destination, input, closeInput, maxSize );
+    protected void getTransfer(Resource resource, File destination, InputStream input, boolean closeInput, int maxSize)
+            throws TransferFailedException {
+        addTransfer("getTransfer " + resource.getName());
+        super.getTransfer(resource, destination, input, closeInput, maxSize);
     }
 
-    public void get( String resourceName, File destination )
-        throws TransferFailedException,
-               ResourceDoesNotExistException,
-               AuthorizationException
-    {
-        addTransfer( "get " + resourceName );
+    public void get(String resourceName, File destination)
+            throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
+        addTransfer("get " + resourceName);
 
         insideGet = true;
 
-        super.get( resourceName, destination );
+        super.get(resourceName, destination);
 
         insideGet = false;
     }
 
-    private void addTransfer( String resourceName )
-    {
-        if ( testTransferListener != null )
-        {
-            testTransferListener.addTransfer( resourceName );
+    private void addTransfer(String resourceName) {
+        if (testTransferListener != null) {
+            testTransferListener.addTransfer(resourceName);
         }
     }
 
-    public boolean getIfNewer( String resourceName, File destination, long timestamp )
-        throws TransferFailedException,
-               ResourceDoesNotExistException,
-               AuthorizationException
-    {
-        if ( !insideGet )
-        {
-            addTransfer( "getIfNewer " + resourceName );
+    public boolean getIfNewer(String resourceName, File destination, long timestamp)
+            throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
+        if (!insideGet) {
+            addTransfer("getIfNewer " + resourceName);
         }
-        return super.getIfNewer( resourceName, destination, timestamp );
+        return super.getIfNewer(resourceName, destination, timestamp);
     }
 
-    public void addTransferListener( TransferListener listener )
-    {
-        if ( listener instanceof TestTransferListener )
-        {
+    public void addTransferListener(TransferListener listener) {
+        if (listener instanceof TestTransferListener) {
             testTransferListener = (TestTransferListener) listener;
         }
-        super.addTransferListener( listener );
+        super.addTransferListener(listener);
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestMavenWorkspaceReader.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestMavenWorkspaceReader.java
new file mode 100644
index 0000000..432584f
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestMavenWorkspaceReader.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.resolver;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Repository;
+import org.apache.maven.repository.internal.MavenWorkspaceReader;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.repository.WorkspaceRepository;
+
+public class TestMavenWorkspaceReader implements MavenWorkspaceReader {
+
+    static final String REPO_LAYOUT = "test";
+
+    static final String REPO_URL = "https://test/me";
+
+    static final String REPO_ID = "custom";
+
+    static final String GROUP_ID = "org.apache.maven";
+
+    static final String ARTIFACT_ID = "this.is.a.test";
+
+    static final String VERSION = "99.99";
+
+    private static final WorkspaceRepository WORKSPACE_REPOSITORY = new WorkspaceRepository(REPO_LAYOUT);
+
+    @Override
+    public WorkspaceRepository getRepository() {
+        return WORKSPACE_REPOSITORY;
+    }
+
+    @Override
+    public File findArtifact(Artifact artifact) {
+        return null;
+    }
+
+    @Override
+    public List<String> findVersions(Artifact artifact) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Model findModel(Artifact artifact) {
+        if (GROUP_ID.equals(artifact.getGroupId())
+                && ARTIFACT_ID.equals(artifact.getArtifactId())
+                && VERSION.equals(artifact.getVersion())) {
+            Model m = new Model();
+            m.setArtifactId(ARTIFACT_ID);
+            m.setGroupId(GROUP_ID);
+            m.setVersion(VERSION);
+            Repository repository = new Repository();
+            repository.setId(REPO_ID);
+            repository.setUrl(REPO_URL);
+            repository.setLayout(REPO_LAYOUT);
+            m.getRepositories().add(repository);
+            return m;
+        }
+        return null;
+    }
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java
index 82ee63e..2709cc5 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/TestTransferListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,26 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver;
 
 import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.maven.wagon.observers.AbstractTransferListener;
 
-public class TestTransferListener
-    extends AbstractTransferListener
-{
+public class TestTransferListener extends AbstractTransferListener {
 
     private final List<String> transfers = new ArrayList<>();
 
-    public List<String> getTransfers()
-    {
+    public List<String> getTransfers() {
         return transfers;
     }
 
-    public void addTransfer( String name )
-    {
-        transfers.add( name );
+    public void addTransfer(String name) {
+        transfers.add(name);
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilterTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilterTest.java
index 96a8882..fe0343c 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilterTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilterTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Arrays;
 
@@ -30,29 +29,24 @@
 /**
  * Tests {@link AndArtifactFilter}.
  *
- * @author Benjamin Bentmann
  */
-public class AndArtifactFilterTest
-{
+class AndArtifactFilterTest {
 
-    private ArtifactFilter newSubFilter()
-    {
+    private ArtifactFilter newSubFilter() {
         return artifact -> false;
     }
 
     @Test
-    public void testEquals()
-    {
+    void testEquals() {
         AndArtifactFilter filter1 = new AndArtifactFilter();
 
-        AndArtifactFilter filter2 = new AndArtifactFilter( Arrays.asList( newSubFilter() ) );
+        AndArtifactFilter filter2 = new AndArtifactFilter(Arrays.asList(newSubFilter()));
 
-        assertFalse( filter1.equals( null ) );
-        assertTrue( filter1.equals( filter1 ) );
-        assertEquals( filter1.hashCode(), filter1.hashCode() );
+        assertFalse(filter1.equals(null));
+        assertTrue(filter1.equals(filter1));
+        assertEquals(filter1.hashCode(), filter1.hashCode());
 
-        assertFalse( filter1.equals( filter2 ) );
-        assertFalse( filter2.equals( filter1 ) );
+        assertFalse(filter1.equals(filter2));
+        assertFalse(filter2.equals(filter1));
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/FilterHashEqualsTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/FilterHashEqualsTest.java
index 6c3df9e..53a26db 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/FilterHashEqualsTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/FilterHashEqualsTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Arrays;
 import java.util.List;
@@ -27,26 +26,23 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author Igor Fedorenko
  */
-public class FilterHashEqualsTest
-{
+class FilterHashEqualsTest {
 
     @Test
-    public void testIncludesExcludesArtifactFilter()
-    {
-        List<String> patterns = Arrays.asList( "c", "d", "e" );
+    void testIncludesExcludesArtifactFilter() {
+        List<String> patterns = Arrays.asList("c", "d", "e");
 
-        IncludesArtifactFilter f1 = new IncludesArtifactFilter( patterns );
+        IncludesArtifactFilter f1 = new IncludesArtifactFilter(patterns);
 
-        IncludesArtifactFilter f2 = new IncludesArtifactFilter( patterns );
+        IncludesArtifactFilter f2 = new IncludesArtifactFilter(patterns);
 
-        assertTrue( f1.equals(f2) );
-        assertTrue( f2.equals(f1) );
-        assertTrue( f1.hashCode() == f2.hashCode() );
+        assertTrue(f1.equals(f2));
+        assertTrue(f2.equals(f1));
+        assertTrue(f1.hashCode() == f2.hashCode());
 
-        IncludesArtifactFilter f3 = new IncludesArtifactFilter( Arrays.asList( "d", "c", "e" ) );
-        assertTrue( f1.equals( f3 ) );
-        assertTrue( f1.hashCode() == f3.hashCode() );
+        IncludesArtifactFilter f3 = new IncludesArtifactFilter(Arrays.asList("d", "c", "e"));
+        assertTrue(f1.equals(f3));
+        assertTrue(f1.hashCode() == f3.hashCode());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilterTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilterTest.java
index 65d9caa..fec856f 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilterTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/OrArtifactFilterTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Arrays;
 
@@ -30,29 +29,24 @@
 /**
  * Tests {@link OrArtifactFilter}.
  *
- * @author Benjamin Bentmann
  */
-public class OrArtifactFilterTest
-{
+class OrArtifactFilterTest {
 
-    private ArtifactFilter newSubFilter()
-    {
+    private ArtifactFilter newSubFilter() {
         return artifact -> false;
     }
 
     @Test
-    public void testEquals()
-    {
+    void testEquals() {
         OrArtifactFilter filter1 = new OrArtifactFilter();
 
-        OrArtifactFilter filter2 = new OrArtifactFilter( Arrays.asList( newSubFilter() ) );
+        OrArtifactFilter filter2 = new OrArtifactFilter(Arrays.asList(newSubFilter()));
 
-        assertFalse( filter1.equals( null ) );
-        assertTrue( filter1.equals( filter1 ) );
-        assertEquals( filter1.hashCode(), filter1.hashCode() );
+        assertFalse(filter1.equals(null));
+        assertTrue(filter1.equals(filter1));
+        assertEquals(filter1.hashCode(), filter1.hashCode());
 
-        assertFalse( filter1.equals( filter2 ) );
-        assertFalse( filter2.equals( filter1 ) );
+        assertFalse(filter1.equals(filter2));
+        assertFalse(filter2.equals(filter1));
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilterTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilterTest.java
index 914ff99..6a52c1a 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilterTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilterTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.DefaultArtifact;
@@ -29,74 +28,65 @@
 /**
  * Tests {@link ScopeArtifactFilter}.
  *
- * @author Benjamin Bentmann
  */
-public class ScopeArtifactFilterTest
-{
+class ScopeArtifactFilterTest {
 
-    private Artifact newArtifact( String scope )
-    {
-        return new DefaultArtifact( "g", "a", "1.0", scope, "jar", "", null );
+    private Artifact newArtifact(String scope) {
+        return new DefaultArtifact("g", "a", "1.0", scope, "jar", "", null);
     }
 
     @Test
-    public void testInclude_Compile()
-    {
-        ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE );
+    void testInclude_Compile() {
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE);
 
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_COMPILE ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_SYSTEM ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_PROVIDED ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_RUNTIME ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_TEST ) ) );
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_COMPILE)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_SYSTEM)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_PROVIDED)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_RUNTIME)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_TEST)));
     }
 
     @Test
-    public void testInclude_CompilePlusRuntime()
-    {
-        ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE_PLUS_RUNTIME );
+    void testInclude_CompilePlusRuntime() {
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE_PLUS_RUNTIME);
 
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_COMPILE ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_SYSTEM ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_PROVIDED ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_RUNTIME ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_TEST ) ) );
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_COMPILE)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_SYSTEM)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_PROVIDED)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_RUNTIME)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_TEST)));
     }
 
     @Test
-    public void testInclude_Runtime()
-    {
-        ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME );
+    void testInclude_Runtime() {
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME);
 
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_COMPILE ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_SYSTEM ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_PROVIDED ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_RUNTIME ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_TEST ) ) );
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_COMPILE)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_SYSTEM)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_PROVIDED)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_RUNTIME)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_TEST)));
     }
 
     @Test
-    public void testInclude_RuntimePlusSystem()
-    {
-        ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM );
+    void testInclude_RuntimePlusSystem() {
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_RUNTIME_PLUS_SYSTEM);
 
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_COMPILE ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_SYSTEM ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_PROVIDED ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_RUNTIME ) ) );
-        assertFalse( filter.include( newArtifact( Artifact.SCOPE_TEST ) ) );
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_COMPILE)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_SYSTEM)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_PROVIDED)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_RUNTIME)));
+        assertFalse(filter.include(newArtifact(Artifact.SCOPE_TEST)));
     }
 
     @Test
-    public void testInclude_Test()
-    {
-        ScopeArtifactFilter filter = new ScopeArtifactFilter( Artifact.SCOPE_TEST );
+    void testInclude_Test() {
+        ScopeArtifactFilter filter = new ScopeArtifactFilter(Artifact.SCOPE_TEST);
 
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_COMPILE ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_SYSTEM ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_PROVIDED ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_RUNTIME ) ) );
-        assertTrue( filter.include( newArtifact( Artifact.SCOPE_TEST ) ) );
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_COMPILE)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_SYSTEM)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_PROVIDED)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_RUNTIME)));
+        assertTrue(filter.include(newArtifact(Artifact.SCOPE_TEST)));
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java b/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java
index 558b5a5..c44eb74 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/testutils/TestFileManager.java
@@ -1,43 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.artifact.testutils;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -50,10 +30,9 @@
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class TestFileManager
-{
+public class TestFileManager {
 
-    public static final String TEMP_DIR_PATH = System.getProperty( "java.io.tmpdir" );
+    public static final String TEMP_DIR_PATH = System.getProperty("java.io.tmpdir");
 
     private List<File> filesToDelete = new ArrayList<>();
 
@@ -67,83 +46,65 @@
 
     private boolean warnAboutCleanup = false;
 
-    public TestFileManager( String baseFilename, String fileSuffix )
-    {
+    public TestFileManager(String baseFilename, String fileSuffix) {
         this.baseFilename = baseFilename;
         this.fileSuffix = fileSuffix;
 
         initializeCleanupMonitoring();
     }
 
-    private void initializeCleanupMonitoring()
-    {
+    private void initializeCleanupMonitoring() {
         callerInfo = new NullPointerException().getStackTrace()[2];
 
         Runnable warning = this::maybeWarnAboutCleanUp;
 
-        cleanupWarning = new Thread( warning );
+        cleanupWarning = new Thread(warning);
 
-        Runtime.getRuntime().addShutdownHook( cleanupWarning );
+        Runtime.getRuntime().addShutdownHook(cleanupWarning);
     }
 
-    private void maybeWarnAboutCleanUp()
-    {
-        if ( warnAboutCleanup )
-        {
-            System.out.println( "[WARNING] TestFileManager from: " + callerInfo.getClassName() + " not cleaned up!" );
+    private void maybeWarnAboutCleanUp() {
+        if (warnAboutCleanup) {
+            System.out.println("[WARNING] TestFileManager from: " + callerInfo.getClassName() + " not cleaned up!");
         }
     }
 
-    public void markForDeletion( File toDelete )
-    {
-        filesToDelete.add( toDelete );
+    public void markForDeletion(File toDelete) {
+        filesToDelete.add(toDelete);
         warnAboutCleanup = true;
     }
 
-    public synchronized File createTempDir()
-    {
-        try
-        {
-            Thread.sleep( 20 );
-        }
-        catch ( InterruptedException e )
-        {
+    public synchronized File createTempDir() {
+        try {
+            Thread.sleep(20);
+        } catch (InterruptedException e) {
             // ignore
         }
 
-        File dir = new File( TEMP_DIR_PATH, baseFilename + System.currentTimeMillis() );
+        File dir = new File(TEMP_DIR_PATH, baseFilename + System.currentTimeMillis());
 
         dir.mkdirs();
-        markForDeletion( dir );
+        markForDeletion(dir);
 
         return dir;
     }
 
-    public synchronized File createTempFile()
-        throws IOException
-    {
-        File tempFile = File.createTempFile( baseFilename, fileSuffix );
+    public synchronized File createTempFile() throws IOException {
+        File tempFile = File.createTempFile(baseFilename, fileSuffix);
         tempFile.deleteOnExit();
-        markForDeletion( tempFile );
+        markForDeletion(tempFile);
 
         return tempFile;
     }
 
-    public void cleanUp()
-        throws IOException
-    {
-        for ( Iterator it = filesToDelete.iterator(); it.hasNext(); )
-        {
+    public void cleanUp() throws IOException {
+        for (Iterator it = filesToDelete.iterator(); it.hasNext(); ) {
             File file = (File) it.next();
 
-            if ( file.exists() )
-            {
-                if ( file.isDirectory() )
-                {
-                    FileUtils.deleteDirectory( file );
-                }
-                else
-                {
+            if (file.exists()) {
+                if (file.isDirectory()) {
+                    FileUtils.deleteDirectory(file);
+                } else {
                     file.delete();
                 }
             }
@@ -154,65 +115,50 @@
         warnAboutCleanup = false;
     }
 
-    public void assertFileExistence( File dir, String filename, boolean shouldExist )
-    {
-        File file = new File( dir, filename );
+    public void assertFileExistence(File dir, String filename, boolean shouldExist) {
+        File file = new File(dir, filename);
 
-        if ( shouldExist )
-        {
-            assertTrue( file.exists() );
-        }
-        else
-        {
-            assertFalse( file.exists() );
+        if (shouldExist) {
+            assertTrue(file.exists());
+        } else {
+            assertFalse(file.exists());
         }
     }
 
-    public void assertFileContents( File dir, String filename, String contentsTest, String encoding )
-        throws IOException
-    {
-        assertFileExistence( dir, filename, true );
+    public void assertFileContents(File dir, String filename, String contentsTest, String encoding) throws IOException {
+        assertFileExistence(dir, filename, true);
 
-        File file = new File( dir, filename );
+        File file = new File(dir, filename);
 
-        String contents = FileUtils.fileRead( file, encoding );
+        String contents = FileUtils.fileRead(file, encoding);
 
-        assertEquals( contentsTest, contents );
+        assertEquals(contentsTest, contents);
     }
 
-    public File createFile( File dir, String filename, String contents, String encoding )
-        throws IOException
-    {
-        File file = new File( dir, filename );
+    public File createFile(File dir, String filename, String contents, String encoding) throws IOException {
+        File file = new File(dir, filename);
 
         file.getParentFile().mkdirs();
 
-        FileUtils.fileWrite( file.getPath(), encoding, contents );
+        FileUtils.fileWrite(file.getPath(), encoding, contents);
 
-        markForDeletion( file );
+        markForDeletion(file);
 
         return file;
     }
 
-    public String getFileContents( File file, String encoding )
-        throws IOException
-    {
-        return FileUtils.fileRead( file, encoding );
+    public String getFileContents(File file, String encoding) throws IOException {
+        return FileUtils.fileRead(file, encoding);
     }
 
-    protected void finalize()
-        throws Throwable
-    {
+    protected void finalize() throws Throwable {
         maybeWarnAboutCleanUp();
 
         super.finalize();
     }
 
-    public File createFile( String filename, String content, String encoding )
-        throws IOException
-    {
+    public File createFile(String filename, String content, String encoding) throws IOException {
         File dir = createTempDir();
-        return createFile( dir, filename, content, encoding );
+        return createFile(dir, filename, content, encoding);
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/artifact/transform/TransformationManagerTest.java b/maven-compat/src/test/java/org/apache/maven/artifact/transform/TransformationManagerTest.java
index 68a7522..829c4bb 100644
--- a/maven-compat/src/test/java/org/apache/maven/artifact/transform/TransformationManagerTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/artifact/transform/TransformationManagerTest.java
@@ -1,19 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.artifact.transform;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
 
 import java.util.List;
 
@@ -28,27 +33,27 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
-/** @author Jason van Zyl */
 @PlexusTest
-public class TransformationManagerTest
-{
+class TransformationManagerTest {
     @Inject
     ArtifactTransformationManager tm;
 
     @Test
-    public void testTransformationManager()
-    {
+    void testTransformationManager() {
         List<ArtifactTransformation> tms = tm.getArtifactTransformations();
 
-        assertEquals( 3, tms.size() );
+        assertEquals(3, tms.size());
 
-        assertTrue( tms.get(0) instanceof ReleaseArtifactTransformation, "We expected the release transformation and got " + tms.get(0) );
+        assertTrue(
+                tms.get(0) instanceof ReleaseArtifactTransformation,
+                "We expected the release transformation and got " + tms.get(0));
 
-        assertTrue( tms.get(1) instanceof LatestArtifactTransformation, "We expected the latest transformation and got " + tms.get(1) );
+        assertTrue(
+                tms.get(1) instanceof LatestArtifactTransformation,
+                "We expected the latest transformation and got " + tms.get(1));
 
-        assertTrue( tms.get(2) instanceof SnapshotTransformation, "We expected the snapshot transformation and got " + tms.get(2) );
+        assertTrue(
+                tms.get(2) instanceof SnapshotTransformation,
+                "We expected the snapshot transformation and got " + tms.get(2));
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/profiles/manager/DefaultProfileManagerTest.java b/maven-compat/src/test/java/org/apache/maven/profiles/manager/DefaultProfileManagerTest.java
index bcb50a1..22ebf81 100644
--- a/maven-compat/src/test/java/org/apache/maven/profiles/manager/DefaultProfileManagerTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/profiles/manager/DefaultProfileManagerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.profiles.manager;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.profiles.manager;
+
+import javax.inject.Inject;
 
 import java.util.List;
 import java.util.Properties;
 
-import javax.inject.Inject;
-
-import org.codehaus.plexus.testing.PlexusTest;
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.ActivationProperty;
 import org.apache.maven.model.Profile;
 import org.apache.maven.profiles.DefaultProfileManager;
 import org.apache.maven.profiles.ProfileManager;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
@@ -38,8 +37,7 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 @PlexusTest
-public class DefaultProfileManagerTest
-{
+class DefaultProfileManagerTest {
 
     @Inject
     PlexusContainer container;
@@ -49,175 +47,162 @@
     }
 
     @Test
-    public void testShouldActivateDefaultProfile()
-        throws Exception
-    {
+    void testShouldActivateDefaultProfile() throws Exception {
         Profile notActivated = new Profile();
-        notActivated.setId( "notActivated" );
+        notActivated.setId("notActivated");
 
         Activation nonActivation = new Activation();
 
-        nonActivation.setJdk( "19.2" );
+        nonActivation.setJdk("19.2");
 
-        notActivated.setActivation( nonActivation );
+        notActivated.setActivation(nonActivation);
 
         Profile defaultActivated = new Profile();
-        defaultActivated.setId( "defaultActivated" );
+        defaultActivated.setId("defaultActivated");
 
         Activation defaultActivation = new Activation();
 
-        defaultActivation.setActiveByDefault( true );
+        defaultActivation.setActiveByDefault(true);
 
-        defaultActivated.setActivation( defaultActivation );
+        defaultActivated.setActivation(defaultActivation);
 
         Properties props = System.getProperties();
 
-        ProfileManager profileManager = new DefaultProfileManager( getContainer(), props );
+        ProfileManager profileManager = new DefaultProfileManager(getContainer(), props);
 
-        profileManager.addProfile( notActivated );
-        profileManager.addProfile( defaultActivated );
+        profileManager.addProfile(notActivated);
+        profileManager.addProfile(defaultActivated);
 
         List active = profileManager.getActiveProfiles();
 
-        assertNotNull( active );
-        assertEquals( 1, active.size() );
-        assertEquals( "defaultActivated", ( (Profile) active.get( 0 ) ).getId() );
+        assertNotNull(active);
+        assertEquals(1, active.size());
+        assertEquals("defaultActivated", ((Profile) active.get(0)).getId());
     }
 
     @Test
-    public void testShouldNotActivateDefaultProfile()
-        throws Exception
-    {
+    void testShouldNotActivateDefaultProfile() throws Exception {
         Profile syspropActivated = new Profile();
-        syspropActivated.setId( "syspropActivated" );
+        syspropActivated.setId("syspropActivated");
 
         Activation syspropActivation = new Activation();
 
         ActivationProperty syspropProperty = new ActivationProperty();
-        syspropProperty.setName( "java.version" );
+        syspropProperty.setName("java.version");
 
-        syspropActivation.setProperty( syspropProperty );
+        syspropActivation.setProperty(syspropProperty);
 
-        syspropActivated.setActivation( syspropActivation );
+        syspropActivated.setActivation(syspropActivation);
 
         Profile defaultActivated = new Profile();
-        defaultActivated.setId( "defaultActivated" );
+        defaultActivated.setId("defaultActivated");
 
         Activation defaultActivation = new Activation();
 
-        defaultActivation.setActiveByDefault( true );
+        defaultActivation.setActiveByDefault(true);
 
-        defaultActivated.setActivation( defaultActivation );
+        defaultActivated.setActivation(defaultActivation);
 
         Properties props = System.getProperties();
 
-        ProfileManager profileManager = new DefaultProfileManager( getContainer(), props );
+        ProfileManager profileManager = new DefaultProfileManager(getContainer(), props);
 
-        profileManager.addProfile( syspropActivated );
-        profileManager.addProfile( defaultActivated );
+        profileManager.addProfile(syspropActivated);
+        profileManager.addProfile(defaultActivated);
 
         List active = profileManager.getActiveProfiles();
 
-        assertNotNull( active );
-        assertEquals( 1, active.size() );
-        assertEquals( "syspropActivated", ( (Profile) active.get( 0 ) ).getId() );
+        assertNotNull(active);
+        assertEquals(1, active.size());
+        assertEquals("syspropActivated", ((Profile) active.get(0)).getId());
     }
 
-
     @Test
-    public void testShouldNotActivateReversalOfPresentSystemProperty()
-        throws Exception
-    {
+    void testShouldNotActivateReversalOfPresentSystemProperty() throws Exception {
         Profile syspropActivated = new Profile();
-        syspropActivated.setId( "syspropActivated" );
+        syspropActivated.setId("syspropActivated");
 
         Activation syspropActivation = new Activation();
 
         ActivationProperty syspropProperty = new ActivationProperty();
-        syspropProperty.setName( "!java.version" );
+        syspropProperty.setName("!java.version");
 
-        syspropActivation.setProperty( syspropProperty );
+        syspropActivation.setProperty(syspropProperty);
 
-        syspropActivated.setActivation( syspropActivation );
+        syspropActivated.setActivation(syspropActivation);
 
         Properties props = System.getProperties();
 
-        ProfileManager profileManager = new DefaultProfileManager( getContainer(), props );
+        ProfileManager profileManager = new DefaultProfileManager(getContainer(), props);
 
-        profileManager.addProfile( syspropActivated );
+        profileManager.addProfile(syspropActivated);
 
         List active = profileManager.getActiveProfiles();
 
-        assertNotNull( active );
-        assertEquals( 0, active.size() );
+        assertNotNull(active);
+        assertEquals(0, active.size());
     }
 
     @Test
-    public void testShouldOverrideAndActivateInactiveProfile()
-        throws Exception
-    {
+    void testShouldOverrideAndActivateInactiveProfile() throws Exception {
         Profile syspropActivated = new Profile();
-        syspropActivated.setId( "syspropActivated" );
+        syspropActivated.setId("syspropActivated");
 
         Activation syspropActivation = new Activation();
 
         ActivationProperty syspropProperty = new ActivationProperty();
-        syspropProperty.setName( "!java.version" );
+        syspropProperty.setName("!java.version");
 
-        syspropActivation.setProperty( syspropProperty );
+        syspropActivation.setProperty(syspropProperty);
 
-        syspropActivated.setActivation( syspropActivation );
+        syspropActivated.setActivation(syspropActivation);
 
         Properties props = System.getProperties();
 
-        ProfileManager profileManager = new DefaultProfileManager( getContainer(), props );
+        ProfileManager profileManager = new DefaultProfileManager(getContainer(), props);
 
-        profileManager.addProfile( syspropActivated );
+        profileManager.addProfile(syspropActivated);
 
-        profileManager.explicitlyActivate( "syspropActivated" );
+        profileManager.explicitlyActivate("syspropActivated");
 
         List active = profileManager.getActiveProfiles();
 
-        assertNotNull( active );
-        assertEquals( 1, active.size() );
-        assertEquals( "syspropActivated", ( (Profile) active.get( 0 ) ).getId() );
+        assertNotNull(active);
+        assertEquals(1, active.size());
+        assertEquals("syspropActivated", ((Profile) active.get(0)).getId());
     }
 
     @Test
-    public void testShouldOverrideAndDeactivateActiveProfile()
-        throws Exception
-    {
+    void testShouldOverrideAndDeactivateActiveProfile() throws Exception {
         Profile syspropActivated = new Profile();
-        syspropActivated.setId( "syspropActivated" );
+        syspropActivated.setId("syspropActivated");
 
         Activation syspropActivation = new Activation();
 
         ActivationProperty syspropProperty = new ActivationProperty();
-        syspropProperty.setName( "java.version" );
+        syspropProperty.setName("java.version");
 
-        syspropActivation.setProperty( syspropProperty );
+        syspropActivation.setProperty(syspropProperty);
 
-        syspropActivated.setActivation( syspropActivation );
+        syspropActivated.setActivation(syspropActivation);
 
         Properties props = System.getProperties();
 
-        ProfileManager profileManager = new DefaultProfileManager( getContainer(), props );
+        ProfileManager profileManager = new DefaultProfileManager(getContainer(), props);
 
-        profileManager.addProfile( syspropActivated );
+        profileManager.addProfile(syspropActivated);
 
-        profileManager.explicitlyDeactivate( "syspropActivated" );
+        profileManager.explicitlyDeactivate("syspropActivated");
 
         List active = profileManager.getActiveProfiles();
 
-        assertNotNull( active );
-        assertEquals( 0, active.size() );
+        assertNotNull(active);
+        assertEquals(0, active.size());
     }
 
     @Test
     @Disabled
-    public void testOsActivationProfile()
-        throws Exception
-    {
+    void testOsActivationProfile() throws Exception {
         /*
         Profile osActivated = new Profile();
         osActivated.setId( "os-profile" );
@@ -245,5 +230,4 @@
         assertEquals( 1, active.size() );
         */
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
index 482a5b4..e436fbd 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
@@ -1,30 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.project;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.Arrays;
 
-import javax.inject.Inject;
-
-import org.codehaus.plexus.testing.PlexusTest;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
 import org.apache.maven.model.building.ModelBuildingException;
@@ -32,17 +33,16 @@
 import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.junit.jupiter.api.BeforeEach;
 
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
- * @author Jason van Zyl
  */
 @PlexusTest
-public abstract class AbstractMavenProjectTestCase
-{
+public abstract class AbstractMavenProjectTestCase {
     protected ProjectBuilder projectBuilder;
 
     @Inject
@@ -56,22 +56,16 @@
     }
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        if ( getContainer().hasComponent( ProjectBuilder.class, "test" ) )
-        {
-            projectBuilder = getContainer().lookup( ProjectBuilder.class, "test" );
-        }
-        else
-        {
+    public void setUp() throws Exception {
+        if (getContainer().hasComponent(ProjectBuilder.class, "test")) {
+            projectBuilder = getContainer().lookup(ProjectBuilder.class, "test");
+        } else {
             // default over to the main project builder...
-            projectBuilder = getContainer().lookup( ProjectBuilder.class );
+            projectBuilder = getContainer().lookup(ProjectBuilder.class);
         }
     }
 
-    protected ProjectBuilder getProjectBuilder()
-    {
+    protected ProjectBuilder getProjectBuilder() {
         return projectBuilder;
     }
 
@@ -79,35 +73,30 @@
     // Local repository
     // ----------------------------------------------------------------------
 
-    protected File getLocalRepositoryPath()
-        throws FileNotFoundException, URISyntaxException
-    {
-        File markerFile = getFileForClasspathResource( "local-repo/marker.txt" );
+    protected File getLocalRepositoryPath() throws FileNotFoundException, URISyntaxException {
+        File markerFile = getFileForClasspathResource("local-repo/marker.txt");
 
         return markerFile.getAbsoluteFile().getParentFile();
     }
 
-    protected static File getFileForClasspathResource( String resource )
-        throws FileNotFoundException
-    {
+    protected static File getFileForClasspathResource(String resource)
+            throws FileNotFoundException, URISyntaxException {
         ClassLoader cloader = Thread.currentThread().getContextClassLoader();
 
-        URL resourceUrl = cloader.getResource( resource );
+        URL resourceUrl = cloader.getResource(resource);
 
-        if ( resourceUrl == null )
-        {
-            throw new FileNotFoundException( "Unable to find: " + resource );
+        if (resourceUrl == null) {
+            throw new FileNotFoundException("Unable to find: " + resource);
         }
 
-        return new File( URI.create( resourceUrl.toString().replaceAll( " ", "%20" ) ) );
+        return new File(resourceUrl.toURI());
     }
 
-    protected ArtifactRepository getLocalRepository()
-        throws Exception
-    {
-        ArtifactRepositoryLayout repoLayout = getContainer().lookup( ArtifactRepositoryLayout.class );
+    protected ArtifactRepository getLocalRepository() throws Exception {
+        ArtifactRepositoryLayout repoLayout = getContainer().lookup(ArtifactRepositoryLayout.class);
 
-        ArtifactRepository r = repositorySystem.createArtifactRepository( "local", "file://" + getLocalRepositoryPath().getAbsolutePath(), repoLayout, null, null );
+        ArtifactRepository r = repositorySystem.createArtifactRepository(
+                "local", "file://" + getLocalRepositoryPath().getAbsolutePath(), repoLayout, null, null);
 
         return r;
     }
@@ -116,54 +105,43 @@
     // Project building
     // ----------------------------------------------------------------------
 
-    protected MavenProject getProjectWithDependencies( File pom )
-        throws Exception
-    {
+    protected MavenProject getProjectWithDependencies(File pom) throws Exception {
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setLocalRepository( getLocalRepository() );
-        configuration.setRemoteRepositories( Arrays.asList( new ArtifactRepository[] {} ) );
-        configuration.setProcessPlugins( false );
-        configuration.setResolveDependencies( true );
-        initRepoSession( configuration );
+        configuration.setLocalRepository(getLocalRepository());
+        configuration.setRemoteRepositories(Arrays.asList(new ArtifactRepository[] {}));
+        configuration.setProcessPlugins(false);
+        configuration.setResolveDependencies(true);
+        initRepoSession(configuration);
 
-        try
-        {
-            return projectBuilder.build( pom, configuration ).getProject();
-        }
-        catch ( Exception e )
-        {
+        try {
+            return projectBuilder.build(pom, configuration).getProject();
+        } catch (Exception e) {
             Throwable cause = e.getCause();
-            if ( cause instanceof ModelBuildingException )
-            {
+            if (cause instanceof ModelBuildingException) {
                 String message = "In: " + pom + "\n\n";
-                for ( ModelProblem problem : ( (ModelBuildingException) cause ).getProblems() )
-                {
+                for (ModelProblem problem : ((ModelBuildingException) cause).getProblems()) {
                     message += problem + "\n";
                 }
-                System.out.println( message );
-                fail( message );
+                System.out.println(message);
+                fail(message);
             }
 
             throw e;
         }
     }
 
-    protected MavenProject getProject( File pom )
-        throws Exception
-    {
+    protected MavenProject getProject(File pom) throws Exception {
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setLocalRepository( getLocalRepository() );
-        initRepoSession( configuration );
+        configuration.setLocalRepository(getLocalRepository());
+        initRepoSession(configuration);
 
-        return projectBuilder.build( pom, configuration ).getProject();
+        return projectBuilder.build(pom, configuration).getProject();
     }
 
-    protected void initRepoSession( ProjectBuildingRequest request )
-    {
-        File localRepo = new File( request.getLocalRepository().getBasedir() );
+    protected void initRepoSession(ProjectBuildingRequest request) {
+        File localRepo = new File(request.getLocalRepository().getBasedir());
         DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
-        session.setLocalRepositoryManager( new LegacyLocalRepositoryManager( localRepo ) );
-        request.setRepositorySession( session );
+        session.setLocalRepositoryManager(new LegacyLocalRepositoryManager(localRepo));
+        request.setRepositorySession(session);
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java b/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java
index f481359..3eb3d11 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/ClasspathArtifactResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -33,60 +36,43 @@
 import org.eclipse.aether.resolution.ArtifactResult;
 import org.eclipse.aether.transfer.ArtifactNotFoundException;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 /**
- * @author Benjamin Bentmann
  */
-@Named( "classpath" )
+@Named("classpath")
 @Singleton
-public class ClasspathArtifactResolver
-    implements ArtifactResolver
-{
+public class ClasspathArtifactResolver implements ArtifactResolver {
 
-    public List<ArtifactResult> resolveArtifacts( RepositorySystemSession session,
-                                                  Collection<? extends ArtifactRequest> requests )
-        throws ArtifactResolutionException
-    {
+    public List<ArtifactResult> resolveArtifacts(
+            RepositorySystemSession session, Collection<? extends ArtifactRequest> requests)
+            throws ArtifactResolutionException {
         List<ArtifactResult> results = new ArrayList<>();
 
-        for ( ArtifactRequest request : requests )
-        {
-            ArtifactResult result = new ArtifactResult( request );
-            results.add( result );
+        for (ArtifactRequest request : requests) {
+            ArtifactResult result = new ArtifactResult(request);
+            results.add(result);
 
             Artifact artifact = request.getArtifact();
-            if ( "maven-test".equals( artifact.getGroupId() ) )
-            {
-                String scope = artifact.getArtifactId().substring( "scope-".length() );
+            if ("maven-test".equals(artifact.getGroupId())) {
+                String scope = artifact.getArtifactId().substring("scope-".length());
 
-                try
-                {
-                    artifact =
-                        artifact.setFile( ProjectClasspathTest.getFileForClasspathResource( ProjectClasspathTest.dir
-                            + "transitive-" + scope + "-dep.xml" ) );
-                    result.setArtifact( artifact );
+                try {
+                    artifact = artifact.setFile(ProjectClasspathTest.getFileForClasspathResource(
+                            ProjectClasspathTest.dir + "transitive-" + scope + "-dep.xml"));
+                    result.setArtifact(artifact);
+                } catch (FileNotFoundException | URISyntaxException e) {
+                    throw new IllegalStateException("Missing test POM for " + artifact, e);
                 }
-                catch ( FileNotFoundException e )
-                {
-                    throw new IllegalStateException( "Missing test POM for " + artifact );
-                }
-            }
-            else
-            {
-                result.addException( new ArtifactNotFoundException( artifact, null ) );
-                throw new ArtifactResolutionException( results );
+            } else {
+                result.addException(new ArtifactNotFoundException(artifact, null));
+                throw new ArtifactResolutionException(results);
             }
         }
 
         return results;
     }
 
-    public ArtifactResult resolveArtifact( RepositorySystemSession session, ArtifactRequest request )
-        throws ArtifactResolutionException
-    {
-        return resolveArtifacts( session, Collections.singleton( request ) ).get( 0 );
+    public ArtifactResult resolveArtifact(RepositorySystemSession session, ArtifactRequest request)
+            throws ArtifactResolutionException {
+        return resolveArtifacts(session, Collections.singleton(request)).get(0);
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
index 21c7349..f1c138f 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -36,75 +35,58 @@
  * A stub implementation that assumes an empty lifecycle to bypass interaction with the plugin manager and to avoid
  * plugin artifact resolution from repositories.
  *
- * @author Benjamin Bentmann
  */
-public class EmptyLifecycleExecutor
-    implements LifecycleExecutor
-{
+public class EmptyLifecycleExecutor implements LifecycleExecutor {
 
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
-    {
-        return new MavenExecutionPlan( null, new DefaultLifecycles() );
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, String... tasks) {
+        return new MavenExecutionPlan(null, new DefaultLifecycles());
     }
 
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, boolean setup, String... tasks )
-    {
-        return new MavenExecutionPlan( null, new DefaultLifecycles() );
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, boolean setup, String... tasks) {
+        return new MavenExecutionPlan(null, new DefaultLifecycles());
     }
 
-    public void execute( MavenSession session )
-    {
-    }
+    public void execute(MavenSession session) {}
 
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
         Set<Plugin> plugins;
 
         // NOTE: The upper-case packaging name is intentional, that's a special hinting mode used for certain tests
-        if ( "JAR".equals( packaging ) )
-        {
+        if ("JAR".equals(packaging)) {
             plugins = new LinkedHashSet<>();
 
-            plugins.add( newPlugin( "maven-compiler-plugin", "compile", "testCompile" ) );
-            plugins.add( newPlugin( "maven-resources-plugin", "resources", "testResources" ) );
-            plugins.add( newPlugin( "maven-surefire-plugin", "test" ) );
-            plugins.add( newPlugin( "maven-jar-plugin", "jar" ) );
-            plugins.add( newPlugin( "maven-install-plugin", "install" ) );
-            plugins.add( newPlugin( "maven-deploy-plugin", "deploy" ) );
-        }
-        else
-        {
+            plugins.add(newPlugin("maven-compiler-plugin", "compile", "testCompile"));
+            plugins.add(newPlugin("maven-resources-plugin", "resources", "testResources"));
+            plugins.add(newPlugin("maven-surefire-plugin", "test"));
+            plugins.add(newPlugin("maven-jar-plugin", "jar"));
+            plugins.add(newPlugin("maven-install-plugin", "install"));
+            plugins.add(newPlugin("maven-deploy-plugin", "deploy"));
+        } else {
             plugins = Collections.emptySet();
         }
 
         return plugins;
     }
 
-    private Plugin newPlugin( String artifactId, String... goals )
-    {
+    private Plugin newPlugin(String artifactId, String... goals) {
         Plugin plugin = new Plugin();
 
-        plugin.setGroupId( "org.apache.maven.plugins" );
-        plugin.setArtifactId( artifactId );
+        plugin.setGroupId("org.apache.maven.plugins");
+        plugin.setArtifactId(artifactId);
 
-        for ( String goal : goals )
-        {
+        for (String goal : goals) {
             PluginExecution pluginExecution = new PluginExecution();
-            pluginExecution.setId( "default-" + goal );
-            pluginExecution.addGoal( goal );
-            plugin.addExecution( pluginExecution );
+            pluginExecution.setId("default-" + goal);
+            pluginExecution.addGoal(goal);
+            plugin.addExecution(pluginExecution);
         }
 
         return plugin;
     }
 
-    public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-    {
-    }
+    public void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session) {}
 
-    public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-    {
+    public List<MavenProject> executeForkedExecutions(MojoExecution mojoExecution, MavenSession session) {
         return Collections.emptyList();
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java
index 672e07b..1819ef5 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/EmptyLifecyclePluginAnalyzer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -28,51 +27,41 @@
 import org.apache.maven.model.PluginExecution;
 
 /**
- * @author Benjamin Bentmann
  */
-public class EmptyLifecyclePluginAnalyzer
-    implements LifeCyclePluginAnalyzer
-{
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
+public class EmptyLifecyclePluginAnalyzer implements LifeCyclePluginAnalyzer {
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
         Set<Plugin> plugins;
 
         // NOTE: The upper-case packaging name is intentional, that's a special hinting mode used for certain tests
-        if ( "JAR".equals( packaging ) )
-        {
+        if ("JAR".equals(packaging)) {
             plugins = new LinkedHashSet<>();
 
-            plugins.add( newPlugin( "maven-compiler-plugin", "compile", "testCompile" ) );
-            plugins.add( newPlugin( "maven-resources-plugin", "resources", "testResources" ) );
-            plugins.add( newPlugin( "maven-surefire-plugin", "test" ) );
-            plugins.add( newPlugin( "maven-jar-plugin", "jar" ) );
-            plugins.add( newPlugin( "maven-install-plugin", "install" ) );
-            plugins.add( newPlugin( "maven-deploy-plugin", "deploy" ) );
-        }
-        else
-        {
+            plugins.add(newPlugin("maven-compiler-plugin", "compile", "testCompile"));
+            plugins.add(newPlugin("maven-resources-plugin", "resources", "testResources"));
+            plugins.add(newPlugin("maven-surefire-plugin", "test"));
+            plugins.add(newPlugin("maven-jar-plugin", "jar"));
+            plugins.add(newPlugin("maven-install-plugin", "install"));
+            plugins.add(newPlugin("maven-deploy-plugin", "deploy"));
+        } else {
             plugins = Collections.emptySet();
         }
 
         return plugins;
     }
 
-    private Plugin newPlugin( String artifactId, String... goals )
-    {
+    private Plugin newPlugin(String artifactId, String... goals) {
         Plugin plugin = new Plugin();
 
-        plugin.setGroupId( "org.apache.maven.plugins" );
-        plugin.setArtifactId( artifactId );
+        plugin.setGroupId("org.apache.maven.plugins");
+        plugin.setArtifactId(artifactId);
 
-        for ( String goal : goals )
-        {
+        for (String goal : goals) {
             PluginExecution pluginExecution = new PluginExecution();
-            pluginExecution.setId( "default-" + goal );
-            pluginExecution.addGoal( goal );
-            plugin.addExecution( pluginExecution );
+            pluginExecution.setId("default-" + goal);
+            pluginExecution.addGoal(goal);
+            plugin.addExecution(pluginExecution);
         }
 
         return plugin;
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java b/maven-compat/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java
index c919cdf..6631e61 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 
@@ -35,126 +34,103 @@
 import org.eclipse.aether.repository.RemoteRepository;
 
 /**
- * @author Benjamin Bentmann
  */
-public class LegacyLocalRepositoryManager
-    implements LocalRepositoryManager
-{
+public class LegacyLocalRepositoryManager implements LocalRepositoryManager {
 
     private final LocalRepository repository;
 
-    public LegacyLocalRepositoryManager( File basedir )
-    {
-        this.repository = new LocalRepository( basedir.getAbsoluteFile(), "legacy" );
+    public LegacyLocalRepositoryManager(File basedir) {
+        this.repository = new LocalRepository(basedir.getAbsoluteFile(), "legacy");
     }
 
-    public LocalRepository getRepository()
-    {
+    public LocalRepository getRepository() {
         return repository;
     }
 
-    public String getPathForLocalArtifact( Artifact artifact )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    public String getPathForLocalArtifact(Artifact artifact) {
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( artifact.getGroupId() ).append( '/' );
+        path.append(artifact.getGroupId()).append('/');
 
-        path.append( artifact.getExtension() ).append( "s/" );
+        path.append(artifact.getExtension()).append("s/");
 
-        path.append( artifact.getArtifactId() ).append( '-' ).append( artifact.getVersion() );
+        path.append(artifact.getArtifactId()).append('-').append(artifact.getVersion());
 
-        if ( artifact.getClassifier().length() > 0 )
-        {
-            path.append( '-' ).append( artifact.getClassifier() );
+        if (artifact.getClassifier().length() > 0) {
+            path.append('-').append(artifact.getClassifier());
         }
 
-        path.append( '.' ).append( artifact.getExtension() );
+        path.append('.').append(artifact.getExtension());
 
         return path.toString();
     }
 
-    public String getPathForRemoteArtifact( Artifact artifact, RemoteRepository repository, String context )
-    {
-        return getPathForLocalArtifact( artifact );
+    public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) {
+        return getPathForLocalArtifact(artifact);
     }
 
-    public String getPathForLocalMetadata( Metadata metadata )
-    {
-        return getPath( metadata, "local" );
+    public String getPathForLocalMetadata(Metadata metadata) {
+        return getPath(metadata, "local");
     }
 
-    public String getPathForRemoteMetadata( Metadata metadata, RemoteRepository repository, String context )
-    {
-        return getPath( metadata, getRepositoryKey( repository, context ) );
+    public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) {
+        return getPath(metadata, getRepositoryKey(repository, context));
     }
 
-    String getRepositoryKey( RemoteRepository repository, String context )
-    {
+    String getRepositoryKey(RemoteRepository repository, String context) {
         return repository.getId();
     }
 
-    private String getPath( Metadata metadata, String repositoryKey )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    private String getPath(Metadata metadata, String repositoryKey) {
+        StringBuilder path = new StringBuilder(128);
 
-        if ( metadata.getGroupId().length() > 0 )
-        {
-            path.append( metadata.getGroupId().replace( '.', '/' ) ).append( '/' );
+        if (metadata.getGroupId().length() > 0) {
+            path.append(metadata.getGroupId().replace('.', '/')).append('/');
 
-            if ( metadata.getArtifactId().length() > 0 )
-            {
-                path.append( metadata.getArtifactId() ).append( '/' );
+            if (metadata.getArtifactId().length() > 0) {
+                path.append(metadata.getArtifactId()).append('/');
 
-                if ( metadata.getVersion().length() > 0 )
-                {
-                    path.append( metadata.getVersion() ).append( '/' );
+                if (metadata.getVersion().length() > 0) {
+                    path.append(metadata.getVersion()).append('/');
                 }
             }
         }
 
-        path.append( insertRepositoryKey( metadata.getType(), repositoryKey ) );
+        path.append(insertRepositoryKey(metadata.getType(), repositoryKey));
 
         return path.toString();
     }
 
-    private String insertRepositoryKey( String filename, String repositoryKey )
-    {
+    private String insertRepositoryKey(String filename, String repositoryKey) {
         String result;
-        int idx = filename.indexOf( '.' );
-        if ( idx < 0 )
-        {
+        int idx = filename.indexOf('.');
+        if (idx < 0) {
             result = filename + '-' + repositoryKey;
-        }
-        else
-        {
-            result = filename.substring( 0, idx ) + '-' + repositoryKey + filename.substring( idx );
+        } else {
+            result = filename.substring(0, idx) + '-' + repositoryKey + filename.substring(idx);
         }
         return result;
     }
 
-    public LocalArtifactResult find( RepositorySystemSession session, LocalArtifactRequest request )
-    {
-        String path = getPathForLocalArtifact( request.getArtifact() );
-        File file = new File( getRepository().getBasedir(), path );
+    public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) {
+        String path = getPathForLocalArtifact(request.getArtifact());
+        File file = new File(getRepository().getBasedir(), path);
 
-        LocalArtifactResult result = new LocalArtifactResult( request );
-        if ( file.isFile() )
-        {
-            result.setFile( file );
-            result.setAvailable( true );
+        LocalArtifactResult result = new LocalArtifactResult(request);
+        if (file.isFile()) {
+            result.setFile(file);
+            result.setAvailable(true);
         }
 
         return result;
     }
 
-    public void add( RepositorySystemSession session, LocalArtifactRegistration request )
-    {
+    public void add(RepositorySystemSession session, LocalArtifactRegistration request) {
         // noop
     }
 
-    public LocalMetadataResult find( RepositorySystemSession session, LocalMetadataRequest request )
-    {
-        LocalMetadataResult result = new LocalMetadataResult( request );
+    public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) {
+        LocalMetadataResult result = new LocalMetadataResult(request);
 
         String path;
 
@@ -162,31 +138,25 @@
         String context = request.getContext();
         RemoteRepository remote = request.getRepository();
 
-        if ( remote != null )
-        {
-            path = getPathForRemoteMetadata( metadata, remote, context );
-        }
-        else
-        {
-            path = getPathForLocalMetadata( metadata );
+        if (remote != null) {
+            path = getPathForRemoteMetadata(metadata, remote, context);
+        } else {
+            path = getPathForLocalMetadata(metadata);
         }
 
-        File file = new File( getRepository().getBasedir(), path );
-        if ( file.isFile() )
-        {
-            result.setFile( file );
+        File file = new File(getRepository().getBasedir(), path);
+        if (file.isFile()) {
+            result.setFile(file);
         }
 
         return result;
     }
 
-    public void add( RepositorySystemSession session, LocalMetadataRegistration request )
-    {
+    public void add(RepositorySystemSession session, LocalMetadataRegistration request) {
         // noop
     }
 
-    public String toString()
-    {
-        return String.valueOf( getRepository() );
+    public String toString() {
+        return String.valueOf(getRepository());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/ModelUtilsTest.java b/maven-compat/src/test/java/org/apache/maven/project/ModelUtilsTest.java
deleted file mode 100644
index 74178d9..0000000
--- a/maven-compat/src/test/java/org/apache/maven/project/ModelUtilsTest.java
+++ /dev/null
@@ -1,637 +0,0 @@
-package org.apache.maven.project;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.io.StringReader;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.maven.model.Build;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.PluginExecution;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
-
-public class ModelUtilsTest
-{
-
-    @Test
-    public void testShouldUseMainPluginDependencyVersionOverManagedDepVersion()
-    {
-        Plugin mgtPlugin = createPlugin( "group", "artifact", "1", Collections.EMPTY_MAP );
-        Dependency mgtDep = createDependency( "g", "a", "2" );
-        mgtPlugin.addDependency( mgtDep );
-
-        Plugin plugin = createPlugin( "group", "artifact", "1", Collections.EMPTY_MAP );
-        Dependency dep = createDependency( "g", "a", "1" );
-        plugin.addDependency( dep );
-
-        ModelUtils.mergePluginDefinitions( plugin, mgtPlugin, false );
-
-        assertEquals( dep.getVersion(), plugin.getDependencies().get( 0 ).getVersion() );
-    }
-
-    private Dependency createDependency( String gid,
-                                         String aid,
-                                         String ver )
-    {
-        Dependency dep = new Dependency();
-        dep.setGroupId( gid );
-        dep.setArtifactId( aid );
-        dep.setVersion( ver );
-
-        return dep;
-    }
-
-    @Test
-    public void testShouldNotInheritPluginWithInheritanceSetToFalse()
-    {
-        PluginContainer parent = new PluginContainer();
-
-        Plugin parentPlugin = createPlugin( "group", "artifact", "1.0", Collections.EMPTY_MAP );
-        parentPlugin.setInherited( "false" );
-
-        parent.addPlugin( parentPlugin );
-
-        PluginContainer child = new PluginContainer();
-
-        child.addPlugin( createPlugin( "group3", "artifact3", "1.0", Collections.EMPTY_MAP ) );
-
-        ModelUtils.mergePluginLists( child, parent, true );
-
-        List results = child.getPlugins();
-
-        assertEquals( 1, results.size() );
-
-        Plugin result1 = (Plugin) results.get( 0 );
-        assertEquals( "group3", result1.getGroupId() );
-        assertEquals( "artifact3", result1.getArtifactId() );
-    }
-
-    /**
-     * Test that this is the resulting ordering of plugins after merging:
-     * <p>
-     * Given:
-     * </p>
-     * <pre>
-     *   parent: X -&gt; A -&gt; B -&gt; D -&gt; E
-     *   child: Y -&gt; A -&gt; C -&gt; D -&gt; F
-     * </pre>
-     * <p>
-     * Result:
-     * </p>
-     * <pre>
-     *   X -&gt; Y -&gt; A -&gt; B -&gt; C -&gt; D -&gt; E -&gt; F
-     * </pre>
-     */
-    @Test
-    public void testShouldPreserveChildOrderingOfPluginsAfterParentMerge()
-    {
-        PluginContainer parent = new PluginContainer();
-
-        parent.addPlugin( createPlugin( "group", "artifact", "1.0", Collections.EMPTY_MAP ) );
-        parent.addPlugin( createPlugin( "group2", "artifact2", "1.0", Collections.singletonMap( "key", "value" ) ) );
-
-        PluginContainer child = new PluginContainer();
-
-        child.addPlugin( createPlugin( "group3", "artifact3", "1.0", Collections.EMPTY_MAP ) );
-        child.addPlugin( createPlugin( "group2", "artifact2", "1.0", Collections.singletonMap( "key2", "value2" ) ) );
-
-        ModelUtils.mergePluginLists( child, parent, true );
-
-        List results = child.getPlugins();
-
-        assertEquals( 3, results.size() );
-
-        Plugin result1 = (Plugin) results.get( 0 );
-
-        assertEquals( "group", result1.getGroupId() );
-        assertEquals( "artifact", result1.getArtifactId() );
-
-        Plugin result2 = (Plugin) results.get( 1 );
-
-        assertEquals( "group3", result2.getGroupId() );
-        assertEquals( "artifact3", result2.getArtifactId() );
-
-        Plugin result3 = (Plugin) results.get( 2 );
-
-        assertEquals( "group2", result3.getGroupId() );
-        assertEquals( "artifact2", result3.getArtifactId() );
-
-        Xpp3Dom result3Config = (Xpp3Dom) result3.getConfiguration();
-
-        assertNotNull( result3Config );
-
-        assertEquals( "value", result3Config.getChild( "key" ).getValue() );
-        assertEquals( "value2", result3Config.getChild( "key2" ).getValue() );
-    }
-
-    private Plugin createPlugin( String groupId, String artifactId, String version, Map configuration )
-    {
-        Plugin plugin = new Plugin();
-        plugin.setGroupId( groupId );
-        plugin.setArtifactId( artifactId );
-        plugin.setVersion( version );
-
-        Xpp3Dom config = new Xpp3Dom( "configuration" );
-
-        if( configuration != null )
-        {
-            for ( Object o : configuration.entrySet() )
-            {
-                Map.Entry entry = (Map.Entry) o;
-
-                Xpp3Dom param = new Xpp3Dom( String.valueOf( entry.getKey() ) );
-                param.setValue( String.valueOf( entry.getValue() ) );
-
-                config.addChild( param );
-            }
-        }
-
-        plugin.setConfiguration( config );
-
-        return plugin;
-    }
-
-    @Test
-    public void testShouldInheritOnePluginWithExecution()
-    {
-        Plugin parent = new Plugin();
-        parent.setArtifactId( "testArtifact" );
-        parent.setGroupId( "testGroup" );
-        parent.setVersion( "1.0" );
-
-        PluginExecution parentExecution = new PluginExecution();
-        parentExecution.setId( "testExecution" );
-
-        parent.addExecution( parentExecution );
-
-        Plugin child = new Plugin();
-        child.setArtifactId( "testArtifact" );
-        child.setGroupId( "testGroup" );
-        child.setVersion( "1.0" );
-
-        ModelUtils.mergePluginDefinitions( child, parent, false );
-
-        assertEquals( 1, child.getExecutions().size() );
-    }
-
-    @Test
-    public void testShouldMergeInheritedPluginHavingExecutionWithLocalPlugin()
-    {
-        Plugin parent = new Plugin();
-        parent.setArtifactId( "testArtifact" );
-        parent.setGroupId( "testGroup" );
-        parent.setVersion( "1.0" );
-
-        PluginExecution parentExecution = new PluginExecution();
-        parentExecution.setId( "testExecution" );
-
-        parent.addExecution( parentExecution );
-
-        Plugin child = new Plugin();
-        child.setArtifactId( "testArtifact" );
-        child.setGroupId( "testGroup" );
-        child.setVersion( "1.0" );
-
-        PluginExecution childExecution = new PluginExecution();
-        childExecution.setId( "testExecution2" );
-
-        child.addExecution( childExecution );
-
-        ModelUtils.mergePluginDefinitions( child, parent, false );
-
-        assertEquals( 2, child.getExecutions().size() );
-    }
-
-    @Test
-    public void testShouldMergeOnePluginWithInheritExecutionWithoutDuplicatingPluginInList()
-    {
-        Plugin parent = new Plugin();
-        parent.setArtifactId( "testArtifact" );
-        parent.setGroupId( "testGroup" );
-        parent.setVersion( "1.0" );
-
-        PluginExecution parentExecution = new PluginExecution();
-        parentExecution.setId( "testExecution" );
-
-        parent.addExecution( parentExecution );
-
-        Build parentContainer = new Build();
-        parentContainer.addPlugin( parent );
-
-        Plugin child = new Plugin();
-        child.setArtifactId( "testArtifact" );
-        child.setGroupId( "testGroup" );
-        child.setVersion( "1.0" );
-
-        Build childContainer = new Build();
-        childContainer.addPlugin( child );
-
-        ModelUtils.mergePluginLists( childContainer, parentContainer, true );
-
-        List plugins = childContainer.getPlugins();
-
-        assertEquals( 1, plugins.size() );
-
-        Plugin plugin = (Plugin) plugins.get( 0 );
-
-        assertEquals( 1, plugin.getExecutions().size() );
-    }
-
-    @Test
-    public void testShouldMergePluginWithDifferentExecutionFromParentWithoutDuplicatingPluginInList()
-    {
-        Plugin parent = new Plugin();
-        parent.setArtifactId( "testArtifact" );
-        parent.setGroupId( "testGroup" );
-        parent.setVersion( "1.0" );
-
-        PluginExecution parentExecution = new PluginExecution();
-        parentExecution.setId( "testExecution" );
-
-        parent.addExecution( parentExecution );
-
-        Build parentContainer = new Build();
-        parentContainer.addPlugin( parent );
-
-        Plugin child = new Plugin();
-        child.setArtifactId( "testArtifact" );
-        child.setGroupId( "testGroup" );
-        child.setVersion( "1.0" );
-
-        PluginExecution childExecution = new PluginExecution();
-        childExecution.setId( "testExecution2" );
-
-        child.addExecution( childExecution );
-
-
-        Build childContainer = new Build();
-        childContainer.addPlugin( child );
-
-        ModelUtils.mergePluginLists( childContainer, parentContainer, true );
-
-        List plugins = childContainer.getPlugins();
-
-        assertEquals( 1, plugins.size() );
-
-        Plugin plugin = (Plugin) plugins.get( 0 );
-
-        assertEquals( 2, plugin.getExecutions().size() );
-    }
-
-    @Test
-    public void testShouldNOTMergeInheritedPluginHavingInheritEqualFalse()
-    {
-        Plugin parent = new Plugin();
-        parent.setArtifactId( "testArtifact" );
-        parent.setGroupId( "testGroup" );
-        parent.setVersion( "1.0" );
-        parent.setInherited( "false" );
-
-        PluginExecution parentExecution = new PluginExecution();
-        parentExecution.setId( "testExecution" );
-
-        parent.addExecution( parentExecution );
-
-        Plugin child = new Plugin();
-        child.setArtifactId( "testArtifact" );
-        child.setGroupId( "testGroup" );
-        child.setVersion( "1.0" );
-
-        ModelUtils.mergePluginDefinitions( child, parent, true );
-
-        assertEquals( 0, child.getExecutions().size() );
-    }
-
-    /**
-     * Verifies MNG-1499: The order of the merged list should be the plugins specified by the parent followed by the
-     * child list.
-     */
-    @Test
-    public void testShouldKeepOriginalPluginOrdering()
-    {
-        Plugin parentPlugin1 = new Plugin();
-        parentPlugin1.setArtifactId( "testArtifact" );
-        parentPlugin1.setGroupId( "zzz" );  // This will put this plugin last in the sorted map
-        parentPlugin1.setVersion( "1.0" );
-
-        PluginExecution parentExecution1 = new PluginExecution();
-        parentExecution1.setId( "testExecution" );
-
-        parentPlugin1.addExecution( parentExecution1 );
-
-        Plugin parentPlugin2 = new Plugin();
-        parentPlugin2.setArtifactId( "testArtifact" );
-        parentPlugin2.setGroupId( "yyy" );
-        parentPlugin2.setVersion( "1.0" );
-
-        PluginExecution parentExecution2 = new PluginExecution();
-        parentExecution2.setId( "testExecution" );
-
-        parentPlugin2.addExecution( parentExecution2 );
-
-        PluginContainer parentContainer = new PluginContainer();
-        parentContainer.addPlugin(parentPlugin1);
-        parentContainer.addPlugin(parentPlugin2);
-
-
-        Plugin childPlugin1 = new Plugin();
-        childPlugin1.setArtifactId( "testArtifact" );
-        childPlugin1.setGroupId( "bbb" );
-        childPlugin1.setVersion( "1.0" );
-
-        PluginExecution childExecution1 = new PluginExecution();
-        childExecution1.setId( "testExecution" );
-
-        childPlugin1.addExecution( childExecution1 );
-
-        Plugin childPlugin2 = new Plugin();
-        childPlugin2.setArtifactId( "testArtifact" );
-        childPlugin2.setGroupId( "aaa" );
-        childPlugin2.setVersion( "1.0" );
-
-        PluginExecution childExecution2 = new PluginExecution();
-        childExecution2.setId( "testExecution" );
-
-        childPlugin2.addExecution( childExecution2 );
-
-        PluginContainer childContainer = new PluginContainer();
-        childContainer.addPlugin(childPlugin1);
-        childContainer.addPlugin(childPlugin2);
-
-
-        ModelUtils.mergePluginLists(childContainer, parentContainer, true);
-
-        assertEquals( 4, childContainer.getPlugins().size() );
-        assertSame(parentPlugin1, childContainer.getPlugins().get(0));
-        assertSame(parentPlugin2, childContainer.getPlugins().get(1));
-        assertSame(childPlugin1, childContainer.getPlugins().get(2));
-        assertSame(childPlugin2, childContainer.getPlugins().get(3));
-    }
-
-    /**
-     * Verifies MNG-1499: The ordering of plugin executions should also be in the specified order.
-     */
-    @Test
-    public void testShouldKeepOriginalPluginExecutionOrdering()
-    {
-        Plugin parent = new Plugin();
-        parent.setArtifactId( "testArtifact" );
-        parent.setGroupId( "testGroup" );
-        parent.setVersion( "1.0" );
-
-        PluginExecution parentExecution1 = new PluginExecution();
-        parentExecution1.setId( "zzz" );  // Will show up last in the sorted map
-        PluginExecution parentExecution2 = new PluginExecution();
-        parentExecution2.setId( "yyy" );  // Will show up last in the sorted map
-
-        parent.addExecution( parentExecution1 );
-        parent.addExecution( parentExecution2 );
-
-        // this block verifies MNG-1703
-        Dependency dep = new Dependency();
-        dep.setGroupId( "depGroupId" );
-        dep.setArtifactId( "depArtifactId" );
-        dep.setVersion( "depVersion" );
-        parent.setDependencies( Collections.singletonList( dep ) );
-
-        Plugin child = new Plugin();
-        child.setArtifactId( "testArtifact" );
-        child.setGroupId( "testGroup" );
-        child.setVersion( "1.0" );
-
-        PluginExecution childExecution1 = new PluginExecution();
-        childExecution1.setId( "bbb" );
-        PluginExecution childExecution2 = new PluginExecution();
-        childExecution2.setId( "aaa" );
-
-        child.addExecution( childExecution1 );
-        child.addExecution( childExecution2 );
-
-        ModelUtils.mergePluginDefinitions( child, parent, false );
-
-        assertEquals( 4, child.getExecutions().size() );
-        assertSame(parentExecution1, child.getExecutions().get(0));
-        assertSame(parentExecution2, child.getExecutions().get(1));
-        assertSame(childExecution1, child.getExecutions().get(2));
-        assertSame(childExecution2, child.getExecutions().get(3));
-
-        // this block prevents MNG-1703
-        assertEquals( 1, child.getDependencies().size() );
-        Dependency dep2 = child.getDependencies().get( 0 );
-        assertEquals( dep.getManagementKey(), dep2.getManagementKey() );
-    }
-
-    @Test
-    public void testShouldOverwritePluginConfigurationSubItemsByDefault()
-        throws XmlPullParserException, IOException
-    {
-        String parentConfigStr = "<configuration><items><item>one</item><item>two</item></items></configuration>";
-        Xpp3Dom parentConfig = Xpp3DomBuilder.build( new StringReader( parentConfigStr ) );
-
-        Plugin parentPlugin = createPlugin( "group", "artifact", "1", null );
-        parentPlugin.setConfiguration( parentConfig );
-
-        String childConfigStr = "<configuration><items><item>three</item></items></configuration>";
-        Xpp3Dom childConfig = Xpp3DomBuilder.build( new StringReader( childConfigStr ) );
-
-        Plugin childPlugin = createPlugin( "group", "artifact", "1", null );
-        childPlugin.setConfiguration( childConfig );
-
-        ModelUtils.mergePluginDefinitions( childPlugin, parentPlugin, true );
-
-        Xpp3Dom result = (Xpp3Dom) childPlugin.getConfiguration();
-        Xpp3Dom items = result.getChild( "items" );
-
-        assertEquals( 1, items.getChildCount() );
-
-        Xpp3Dom item = items.getChild( 0 );
-        assertEquals( "three", item.getValue() );
-    }
-
-    @Test
-    public void testShouldMergePluginConfigurationSubItemsWithMergeAttributeSet()
-        throws XmlPullParserException, IOException
-    {
-        String parentConfigStr = "<configuration><items><item>one</item><item>two</item></items></configuration>";
-        Xpp3Dom parentConfig = Xpp3DomBuilder.build( new StringReader( parentConfigStr ) );
-
-        Plugin parentPlugin = createPlugin( "group", "artifact", "1", null );
-        parentPlugin.setConfiguration( parentConfig );
-
-        String childConfigStr = "<configuration><items combine.children=\"append\"><item>three</item></items></configuration>";
-        Xpp3Dom childConfig = Xpp3DomBuilder.build( new StringReader( childConfigStr ) );
-
-        Plugin childPlugin = createPlugin( "group", "artifact", "1", null );
-        childPlugin.setConfiguration( childConfig );
-
-        ModelUtils.mergePluginDefinitions( childPlugin, parentPlugin, true );
-
-        Xpp3Dom result = (Xpp3Dom) childPlugin.getConfiguration();
-        Xpp3Dom items = result.getChild( "items" );
-
-        assertEquals( 3, items.getChildCount() );
-
-        Xpp3Dom[] item = items.getChildren();
-
-        List<String> actual = Arrays.asList( item[0].getValue(), item[1].getValue(), item[2].getValue() );
-        List<String> expected = Arrays.asList( "one", "two", "three" );
-        Collections.sort( actual );
-        Collections.sort( expected );
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testShouldNotMergePluginExecutionWhenExecInheritedIsFalseAndTreatAsInheritanceIsTrue()
-    {
-        String gid = "group";
-        String aid = "artifact";
-        String ver = "1";
-
-        PluginContainer parent = new PluginContainer();
-        Plugin pParent = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
-
-        pParent.setInherited( Boolean.toString( true ) );
-
-        PluginExecution eParent = new PluginExecution();
-
-        String testId = "test";
-
-        eParent.setId( testId );
-        eParent.addGoal( "run" );
-        eParent.setPhase( "initialize" );
-        eParent.setInherited( Boolean.toString( false ) );
-
-        pParent.addExecution( eParent );
-        parent.addPlugin( pParent );
-
-        PluginContainer child = new PluginContainer();
-        Plugin pChild = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
-        PluginExecution eChild = new PluginExecution();
-
-        eChild.setId( "child-specified" );
-        eChild.addGoal( "child" );
-        eChild.setPhase( "compile" );
-
-        pChild.addExecution( eChild );
-        child.addPlugin( pChild );
-
-        ModelUtils.mergePluginDefinitions( pChild, pParent, true );
-
-        Map executionMap = pChild.getExecutionsAsMap();
-        assertNull( executionMap.get( testId ), "test execution should not be inherited from parent." );
-    }
-
-    @Test
-    public void testShouldNotMergePluginExecutionWhenPluginInheritedIsFalseAndTreatAsInheritanceIsTrue()
-    {
-        String gid = "group";
-        String aid = "artifact";
-        String ver = "1";
-
-        PluginContainer parent = new PluginContainer();
-        Plugin pParent = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
-
-        pParent.setInherited( Boolean.toString( false ) );
-
-        PluginExecution eParent = new PluginExecution();
-
-        String testId = "test";
-
-        eParent.setId( testId );
-        eParent.addGoal( "run" );
-        eParent.setPhase( "initialize" );
-        eParent.setInherited( Boolean.toString( true ) );
-
-        pParent.addExecution( eParent );
-        parent.addPlugin( pParent );
-
-        PluginContainer child = new PluginContainer();
-        Plugin pChild = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
-        PluginExecution eChild = new PluginExecution();
-
-        eChild.setId( "child-specified" );
-        eChild.addGoal( "child" );
-        eChild.setPhase( "compile" );
-
-        pChild.addExecution( eChild );
-        child.addPlugin( pChild );
-
-        ModelUtils.mergePluginDefinitions( pChild, pParent, true );
-
-        Map executionMap = pChild.getExecutionsAsMap();
-        assertNull( executionMap.get( testId ), "test execution should not be inherited from parent." );
-    }
-
-    @Test
-    public void testShouldMergePluginExecutionWhenExecInheritedIsTrueAndTreatAsInheritanceIsTrue()
-    {
-        String gid = "group";
-        String aid = "artifact";
-        String ver = "1";
-
-        PluginContainer parent = new PluginContainer();
-        Plugin pParent = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
-
-        pParent.setInherited( Boolean.toString( true ) );
-
-        PluginExecution eParent = new PluginExecution();
-
-        String testId = "test";
-
-        eParent.setId( testId );
-        eParent.addGoal( "run" );
-        eParent.setPhase( "initialize" );
-        eParent.setInherited( Boolean.toString( true ) );
-
-        pParent.addExecution( eParent );
-        parent.addPlugin( pParent );
-
-        PluginContainer child = new PluginContainer();
-        Plugin pChild = createPlugin( gid, aid, ver, Collections.EMPTY_MAP );
-        PluginExecution eChild = new PluginExecution();
-
-        eChild.setId( "child-specified" );
-        eChild.addGoal( "child" );
-        eChild.setPhase( "compile" );
-
-        pChild.addExecution( eChild );
-        child.addPlugin( pChild );
-
-        ModelUtils.mergePluginDefinitions( pChild, pParent, true );
-
-        Map executionMap = pChild.getExecutionsAsMap();
-        assertNotNull( executionMap.get( testId ), "test execution should be inherited from parent." );
-    }
-
-}
diff --git a/maven-compat/src/test/java/org/apache/maven/project/ProjectClasspathTest.java b/maven-compat/src/test/java/org/apache/maven/project/ProjectClasspathTest.java
index ad4531c..41fc6ae 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/ProjectClasspathTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/ProjectClasspathTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.lang.reflect.Field;
@@ -33,118 +32,107 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
-public class ProjectClasspathTest
-    extends AbstractMavenProjectTestCase
-{
+class ProjectClasspathTest extends AbstractMavenProjectTestCase {
     static final String dir = "projects/scope/";
 
     @Override
     @BeforeEach
-    public void setUp()
-            throws Exception
-    {
+    public void setUp() throws Exception {
         super.setUp();
 
-        ArtifactResolver resolver = getContainer().lookup( ArtifactResolver.class, "classpath" );
-        DefaultArtifactDescriptorReader pomReader = (DefaultArtifactDescriptorReader) getContainer().lookup(ArtifactDescriptorReader.class);
-        Field field = DefaultArtifactDescriptorReader.class.getDeclaredField( "artifactResolver" );
-        field.setAccessible( true );
-        field.set( pomReader, resolver );
+        ArtifactResolver resolver = getContainer().lookup(ArtifactResolver.class, "classpath");
+        DefaultArtifactDescriptorReader pomReader =
+                (DefaultArtifactDescriptorReader) getContainer().lookup(ArtifactDescriptorReader.class);
+        Field field = DefaultArtifactDescriptorReader.class.getDeclaredField("artifactResolver");
+        field.setAccessible(true);
+        field.set(pomReader, resolver);
 
-        projectBuilder = getContainer().lookup( ProjectBuilder.class, "classpath" );
+        projectBuilder = getContainer().lookup(ProjectBuilder.class, "classpath");
     }
 
     @Test
-    public void testProjectClasspath()
-        throws Exception
-    {
-        File f = getFileForClasspathResource( dir + "project-with-scoped-dependencies.xml" );
+    void testProjectClasspath() throws Exception {
+        File f = getFileForClasspathResource(dir + "project-with-scoped-dependencies.xml");
 
-        MavenProject project = getProjectWithDependencies( f );
+        MavenProject project = getProjectWithDependencies(f);
 
         Artifact artifact;
 
-        assertNotNull( project, "Test project can't be null!" );
+        assertNotNull(project, "Test project can't be null!");
 
-        checkArtifactIdScope( project, "provided", "provided" );
-        checkArtifactIdScope( project, "test", "test" );
-        checkArtifactIdScope( project, "compile", "compile" );
-        checkArtifactIdScope( project, "runtime", "runtime" );
-        checkArtifactIdScope( project, "default", "compile" );
+        checkArtifactIdScope(project, "provided", "provided");
+        checkArtifactIdScope(project, "test", "test");
+        checkArtifactIdScope(project, "compile", "compile");
+        checkArtifactIdScope(project, "runtime", "runtime");
+        checkArtifactIdScope(project, "default", "compile");
 
         // check all transitive deps of a test dependency are test, except test and provided which is skipped
-        artifact = getArtifact( project, "maven-test-test", "scope-provided" );
-        assertNull( artifact, "Check no provided dependencies are transitive" );
-        artifact = getArtifact( project, "maven-test-test", "scope-test" );
-        assertNull( artifact, "Check no test dependencies are transitive" );
+        artifact = getArtifact(project, "maven-test-test", "scope-provided");
+        assertNull(artifact, "Check no provided dependencies are transitive");
+        artifact = getArtifact(project, "maven-test-test", "scope-test");
+        assertNull(artifact, "Check no test dependencies are transitive");
 
-        artifact = getArtifact( project, "maven-test-test", "scope-compile" );
-        assertNotNull( artifact );
+        artifact = getArtifact(project, "maven-test-test", "scope-compile");
+        assertNotNull(artifact);
 
-        System.out.println( "a = " + artifact );
-        System.out.println( "b = " + artifact.getScope() );
-        assertEquals( "test", artifact.getScope(), "Check scope" );
-        artifact = getArtifact( project, "maven-test-test", "scope-default" );
-        assertEquals( "test", artifact.getScope(), "Check scope" );
-        artifact = getArtifact( project, "maven-test-test", "scope-runtime" );
-        assertEquals( "test", artifact.getScope(), "Check scope" );
+        System.out.println("a = " + artifact);
+        System.out.println("b = " + artifact.getScope());
+        assertEquals("test", artifact.getScope(), "Check scope");
+        artifact = getArtifact(project, "maven-test-test", "scope-default");
+        assertEquals("test", artifact.getScope(), "Check scope");
+        artifact = getArtifact(project, "maven-test-test", "scope-runtime");
+        assertEquals("test", artifact.getScope(), "Check scope");
 
         // check all transitive deps of a provided dependency are provided scope, except for test
-        checkGroupIdScope( project, "provided", "maven-test-provided" );
-        artifact = getArtifact( project, "maven-test-provided", "scope-runtime" );
-        assertEquals( "provided", artifact.getScope(), "Check scope" );
+        checkGroupIdScope(project, "provided", "maven-test-provided");
+        artifact = getArtifact(project, "maven-test-provided", "scope-runtime");
+        assertEquals("provided", artifact.getScope(), "Check scope");
 
         // check all transitive deps of a runtime dependency are runtime scope, except for test
-        checkGroupIdScope( project, "runtime", "maven-test-runtime" );
-        artifact = getArtifact( project, "maven-test-runtime", "scope-runtime" );
-        assertEquals( "runtime", artifact.getScope(), "Check scope" );
+        checkGroupIdScope(project, "runtime", "maven-test-runtime");
+        artifact = getArtifact(project, "maven-test-runtime", "scope-runtime");
+        assertEquals("runtime", artifact.getScope(), "Check scope");
 
         // check all transitive deps of a compile dependency are compile scope, except for runtime and test
-        checkGroupIdScope( project, "compile", "maven-test-compile" );
-        artifact = getArtifact( project, "maven-test-compile", "scope-runtime" );
-        assertEquals( "runtime", artifact.getScope(), "Check scope" );
+        checkGroupIdScope(project, "compile", "maven-test-compile");
+        artifact = getArtifact(project, "maven-test-compile", "scope-runtime");
+        assertEquals("runtime", artifact.getScope(), "Check scope");
 
         // check all transitive deps of a default dependency are compile scope, except for runtime and test
-        checkGroupIdScope( project, "compile", "maven-test-default" );
-        artifact = getArtifact( project, "maven-test-default", "scope-runtime" );
-        assertEquals( "runtime", artifact.getScope(), "Check scope" );
+        checkGroupIdScope(project, "compile", "maven-test-default");
+        artifact = getArtifact(project, "maven-test-default", "scope-runtime");
+        assertEquals("runtime", artifact.getScope(), "Check scope");
     }
 
-    private void checkGroupIdScope( MavenProject project, String scopeValue, String groupId )
-    {
+    private void checkGroupIdScope(MavenProject project, String scopeValue, String groupId) {
         Artifact artifact;
-        artifact = getArtifact( project, groupId, "scope-compile" );
-        assertEquals( scopeValue, artifact.getScope(), "Check scope" );
-        artifact = getArtifact( project, groupId, "scope-test" );
-        assertNull( artifact, "Check test dependency is not transitive" );
-        artifact = getArtifact( project, groupId, "scope-provided" );
-        assertNull( artifact, "Check provided dependency is not transitive" );
-        artifact = getArtifact( project, groupId, "scope-default" );
-        assertEquals( scopeValue, artifact.getScope(), "Check scope" );
+        artifact = getArtifact(project, groupId, "scope-compile");
+        assertEquals(scopeValue, artifact.getScope(), "Check scope");
+        artifact = getArtifact(project, groupId, "scope-test");
+        assertNull(artifact, "Check test dependency is not transitive");
+        artifact = getArtifact(project, groupId, "scope-provided");
+        assertNull(artifact, "Check provided dependency is not transitive");
+        artifact = getArtifact(project, groupId, "scope-default");
+        assertEquals(scopeValue, artifact.getScope(), "Check scope");
     }
 
-    private void checkArtifactIdScope( MavenProject project, String scope, String scopeValue )
-    {
+    private void checkArtifactIdScope(MavenProject project, String scope, String scopeValue) {
         String artifactId = "scope-" + scope;
-        Artifact artifact = getArtifact( project, "maven-test", artifactId );
-        assertNotNull( artifact );
-        assertEquals( scopeValue, artifact.getScope(), "Check scope" );
+        Artifact artifact = getArtifact(project, "maven-test", artifactId);
+        assertNotNull(artifact);
+        assertEquals(scopeValue, artifact.getScope(), "Check scope");
     }
 
-    private Artifact getArtifact( MavenProject project, String groupId, String artifactId )
-    {
-        System.out.println( "[ Looking for " + groupId + ":" + artifactId + " ]" );
-        for ( Artifact a : project.getArtifacts() )
-        {
-            System.out.println( a.toString() );
-            if ( artifactId.equals( a.getArtifactId() ) && a.getGroupId().equals( groupId ) )
-            {
-                System.out.println( "RETURN" );
+    private Artifact getArtifact(MavenProject project, String groupId, String artifactId) {
+        System.out.println("[ Looking for " + groupId + ":" + artifactId + " ]");
+        for (Artifact a : project.getArtifacts()) {
+            System.out.println(a.toString());
+            if (artifactId.equals(a.getArtifactId()) && a.getGroupId().equals(groupId)) {
+                System.out.println("RETURN");
                 return a;
             }
         }
-        System.out.println( "Return null" );
+        System.out.println("Return null");
         return null;
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/TestArtifactResolver.java b/maven-compat/src/test/java/org/apache/maven/project/TestArtifactResolver.java
index 94b30db..cd30606 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/TestArtifactResolver.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/TestArtifactResolver.java
@@ -1,36 +1,37 @@
-package org.apache.maven.project;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
-import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
-import org.apache.maven.artifact.resolver.DefaultArtifactResolver;
+package org.apache.maven.project;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-@Named( "classpath" )
+import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
+import org.apache.maven.artifact.resolver.DefaultArtifactResolver;
+
+@Named("classpath")
 @Singleton
-public class TestArtifactResolver
-    extends DefaultArtifactResolver
-{
+public class TestArtifactResolver extends DefaultArtifactResolver {
     private ArtifactMetadataSource source;
 
     @Inject
-    public TestArtifactResolver(final @Named( "classpath" ) ArtifactMetadataSource source) {
+    public TestArtifactResolver(final @Named("classpath") ArtifactMetadataSource source) {
         this.source = source;
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/TestMavenRepositorySystem.java b/maven-compat/src/test/java/org/apache/maven/project/TestMavenRepositorySystem.java
index f3b342d..c79ee86 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/TestMavenRepositorySystem.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/TestMavenRepositorySystem.java
@@ -1,32 +1,33 @@
-package org.apache.maven.project;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
-import org.apache.maven.artifact.resolver.ArtifactResolver;
-import org.apache.maven.repository.legacy.LegacyRepositorySystem;
+package org.apache.maven.project;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-@Named( "classpath" )
+import org.apache.maven.artifact.resolver.ArtifactResolver;
+import org.apache.maven.repository.legacy.LegacyRepositorySystem;
+
+@Named("classpath")
 @Singleton
-public class TestMavenRepositorySystem
-    extends LegacyRepositorySystem
-{
+public class TestMavenRepositorySystem extends LegacyRepositorySystem {
     @Inject
     private ArtifactResolver artifactResolver;
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java b/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java
index a92cd57..612d8e7 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/TestProjectBuilder.java
@@ -1,19 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.project;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.Collections;
@@ -22,39 +29,44 @@
 import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.model.building.ModelBuilder;
 import org.apache.maven.model.building.ModelProcessor;
+import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.repository.internal.ModelCacheFactory;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.impl.RemoteRepositoryManager;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-@Named( "classpath" )
+@Named("classpath")
 @Singleton
-public class TestProjectBuilder
-    extends DefaultProjectBuilder
-{
+public class TestProjectBuilder extends DefaultProjectBuilder {
     @Inject
     public TestProjectBuilder(
-            ModelBuilder modelBuilder, ModelProcessor modelProcessor,
-            ProjectBuildingHelper projectBuildingHelper, MavenRepositorySystem repositorySystem,
-            RepositorySystem repoSystem, RemoteRepositoryManager repositoryManager,
-            ProjectDependenciesResolver dependencyResolver, ModelCacheFactory modelCacheFactory )
-    {
-        super( modelBuilder, modelProcessor, projectBuildingHelper, repositorySystem, repoSystem,
-                repositoryManager, dependencyResolver, modelCacheFactory );
+            ModelBuilder modelBuilder,
+            ModelProcessor modelProcessor,
+            ProjectBuildingHelper projectBuildingHelper,
+            MavenRepositorySystem repositorySystem,
+            RepositorySystem repoSystem,
+            RemoteRepositoryManager repositoryManager,
+            ProjectDependenciesResolver dependencyResolver,
+            ModelCacheFactory modelCacheFactory,
+            RootLocator rootLocator) {
+        super(
+                modelBuilder,
+                modelProcessor,
+                projectBuildingHelper,
+                repositorySystem,
+                repoSystem,
+                repositoryManager,
+                dependencyResolver,
+                modelCacheFactory,
+                rootLocator);
     }
 
     @Override
-    public ProjectBuildingResult build( File pomFile, ProjectBuildingRequest configuration )
-        throws ProjectBuildingException
-    {
-        ProjectBuildingResult result = super.build( pomFile, configuration );
+    public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest configuration)
+            throws ProjectBuildingException {
+        ProjectBuildingResult result = super.build(pomFile, configuration);
 
-        result.getProject().setRemoteArtifactRepositories( Collections.<ArtifactRepository> emptyList() );
+        result.getProject().setRemoteArtifactRepositories(Collections.<ArtifactRepository>emptyList());
 
         return result;
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/project/artifact/DefaultMavenMetadataCacheTest.java b/maven-compat/src/test/java/org/apache/maven/project/artifact/DefaultMavenMetadataCacheTest.java
new file mode 100644
index 0000000..fb40e03
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/project/artifact/DefaultMavenMetadataCacheTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
+import org.apache.maven.project.artifact.DefaultMavenMetadataCache.CacheKey;
+import org.apache.maven.repository.DelegatingLocalArtifactRepository;
+import org.apache.maven.repository.RepositorySystem;
+import org.apache.maven.repository.TestRepositorySystem;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+
+/**
+ */
+class DefaultMavenMetadataCacheTest {
+    private RepositorySystem repositorySystem;
+
+    @BeforeEach
+    void setUp() {
+        repositorySystem = new TestRepositorySystem();
+    }
+
+    @Test
+    void testCacheKey() throws Exception {
+        Artifact a1 = repositorySystem.createArtifact("testGroup", "testArtifact", "1.2.3", "jar");
+        @SuppressWarnings("deprecation")
+        ArtifactRepository lr1 = new DelegatingLocalArtifactRepository(repositorySystem.createDefaultLocalRepository());
+        ArtifactRepository rr1 = repositorySystem.createDefaultRemoteRepository();
+        a1.setDependencyFilter(new ExcludesArtifactFilter(Arrays.asList("foo")));
+
+        Artifact a2 = repositorySystem.createArtifact("testGroup", "testArtifact", "1.2.3", "jar");
+        @SuppressWarnings("deprecation")
+        ArtifactRepository lr2 = new DelegatingLocalArtifactRepository(repositorySystem.createDefaultLocalRepository());
+        ArtifactRepository rr2 = repositorySystem.createDefaultRemoteRepository();
+        a2.setDependencyFilter(new ExcludesArtifactFilter(Arrays.asList("foo")));
+
+        // sanity checks
+        assertNotSame(a1, a2);
+        assertNotSame(lr1, lr2);
+        assertNotSame(rr1, rr2);
+
+        CacheKey k1 = new CacheKey(a1, false, lr1, Collections.singletonList(rr1));
+        CacheKey k2 = new CacheKey(a2, false, lr2, Collections.singletonList(rr2));
+
+        assertEquals(k1.hashCode(), k2.hashCode());
+    }
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/project/artifact/MavenMetadataSourceTest.java b/maven-compat/src/test/java/org/apache/maven/project/artifact/MavenMetadataSourceTest.java
new file mode 100644
index 0000000..d22cb83
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/project/artifact/MavenMetadataSourceTest.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project.artifact;
+
+import javax.inject.Inject;
+
+import org.apache.maven.repository.RepositorySystem;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
+@PlexusTest
+class MavenMetadataSourceTest {
+    @Inject
+    private RepositorySystem repositorySystem;
+
+    @Inject
+    PlexusContainer container;
+
+    @Test
+    @Disabled
+    void testShouldNotCarryExclusionsOverFromDependencyToDependency() throws Exception {
+        /*
+        Dependency dep1 = new Dependency();
+        dep1.setGroupId( "test" );
+        dep1.setArtifactId( "test-artifact" );
+        dep1.setVersion( "1" );
+        dep1.setType( "jar" );
+
+        Exclusion exc = new Exclusion();
+        exc.setGroupId( "test" );
+        exc.setArtifactId( "test-artifact3" );
+
+        dep1.addExclusion( exc );
+
+        Dependency dep2 = new Dependency();
+        dep2.setGroupId( "test" );
+        dep2.setArtifactId( "test-artifact2" );
+        dep2.setVersion( "1" );
+        dep2.setType( "jar" );
+
+        List<Dependency> deps = new ArrayList<>();
+        deps.add( dep1 );
+        deps.add( dep2 );
+
+        ArtifactFactory factory = container.lookup( ArtifactFactory.class );
+
+        ArtifactFilter dependencyFilter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE );
+
+        MavenProject project = new MavenProject( new Model() );
+
+        Set<Artifact> result = project.createArtifacts( dependencyFilter );
+
+        for (Iterator<Artifact> it = result.iterator(); it.hasNext(); )
+        {
+            Artifact artifact = it.next();
+
+            if ( "test-artifact2".equals( artifact.getArtifactId() ) )
+            {
+                ArtifactFilter filter = artifact.getDependencyFilter();
+
+                assertSame( dependencyFilter, filter );
+            }
+        }
+        */
+    }
+
+    @Test
+    @Disabled("TODO restore these if it makes sense")
+    void testShouldUseCompileScopeIfDependencyScopeEmpty() throws Exception {
+        /*
+        String groupId = "org.apache.maven";
+        String artifactId = "maven-model";
+
+        Dependency dep = new Dependency();
+
+        dep.setGroupId( groupId );
+        dep.setArtifactId( artifactId );
+        dep.setVersion( "2.0-alpha-3" );
+
+        Model model = new Model();
+
+        model.addDependency( dep );
+
+        MavenProject project = new MavenProject( model, repositorySystem );
+
+        project.setArtifacts( project.createArtifacts( null ) );
+
+        String key = ArtifactUtils.versionlessKey( groupId, artifactId );
+
+        Map artifactMap = project.getArtifactMap();
+
+        assertNotNull( artifactMap, "artifact-map should not be null." );
+        assertEquals( 1, artifactMap.size(), "artifact-map should contain 1 element." );
+
+        Artifact artifact = (Artifact) artifactMap.get( key );
+
+        assertNotNull( artifact, "dependency artifact not found in map." );
+        assertEquals( Artifact.SCOPE_COMPILE, artifact.getScope(), "dependency artifact has wrong scope." );
+
+        //check for back-propagation of default scope.
+        assertEquals( Artifact.SCOPE_COMPILE, dep.getScope(), "default scope NOT back-propagated to dependency." );
+        */
+    }
+
+    @Test
+    @Disabled
+    void testShouldUseInjectedTestScopeFromDependencyManagement() throws Exception {
+        /*
+        String groupId = "org.apache.maven";
+        String artifactId = "maven-model";
+
+        Dependency dep = new Dependency();
+
+        dep.setGroupId( groupId );
+        dep.setArtifactId( artifactId );
+        dep.setVersion( "2.0-alpha-3" );
+
+        Model model = new Model();
+
+        model.addDependency( dep );
+
+        Dependency mgd = new Dependency();
+        mgd.setGroupId( groupId );
+        mgd.setArtifactId( artifactId );
+        mgd.setScope( Artifact.SCOPE_TEST );
+
+        DependencyManagement depMgmt = new DependencyManagement();
+
+        depMgmt.addDependency( mgd );
+
+        model.setDependencyManagement( depMgmt );
+
+        MavenProject project = new MavenProject( model, repositorySystem );
+
+        TestModelDefaultsInjector injector = new TestModelDefaultsInjector();
+
+        injector.injectDefaults( model );
+
+        project.setArtifacts( project.createArtifacts( null ) );
+
+        String key = ArtifactUtils.versionlessKey( groupId, artifactId );
+
+        Map artifactMap = project.getArtifactMap();
+
+        assertNotNull( artifactMap, "artifact-map should not be null." );
+        assertEquals( 1, artifactMap.size(), "artifact-map should contain 1 element." );
+
+        Artifact artifact = (Artifact) artifactMap.get( key );
+
+        assertNotNull( artifact, "dependency artifact not found in map." );
+        assertEquals( "dependency artifact has wrong scope.", Artifact.SCOPE_TEST, artifact.getScope() );
+
+        //check for back-propagation of default scope.
+        assertEquals( "default scope NOT back-propagated to dependency.", Artifact.SCOPE_TEST, dep.getScope() );
+        */
+    }
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/AbstractProjectInheritanceTestCase.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/AbstractProjectInheritanceTestCase.java
index af3655f..dbdd51e 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/AbstractProjectInheritanceTestCase.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/AbstractProjectInheritanceTestCase.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance;
 
 import java.io.File;
 
@@ -26,34 +25,27 @@
 import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
 
 /**
- * @author Jason van Zyl
  */
-public abstract class AbstractProjectInheritanceTestCase
-    extends AbstractMavenProjectTestCase
-{
-    protected String getTestSeries()
-    {
+public abstract class AbstractProjectInheritanceTestCase extends AbstractMavenProjectTestCase {
+    protected String getTestSeries() {
         String className = getClass().getPackage().getName();
 
-        return className.substring( className.lastIndexOf( '.' ) + 1 );
+        return className.substring(className.lastIndexOf('.') + 1);
     }
 
-    protected File projectFile( String name )
-    {
-        return projectFile( "maven", name );
+    protected File projectFile(String name) {
+        return projectFile("maven", name);
     }
 
-    protected File projectFile( String groupId, String artifactId )
-    {
-        return new File( getLocalRepositoryPath(), "/" + groupId + "/poms/" + artifactId + "-1.0.pom" );
+    protected File projectFile(String groupId, String artifactId) {
+        return new File(getLocalRepositoryPath(), "/" + groupId + "/poms/" + artifactId + "-1.0.pom");
     }
 
     // ----------------------------------------------------------------------
     // The local repository for this category of tests
     // ----------------------------------------------------------------------
 
-    protected File getLocalRepositoryPath()
-    {
-        return getTestFile("src/test/resources/inheritance-repo/" + getTestSeries() );
+    protected File getLocalRepositoryPath() {
+        return getTestFile("src/test/resources/inheritance-repo/" + getTestSeries());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t00/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t00/ProjectInheritanceTest.java
index 0300d56..45043ed 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t00/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t00/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t00;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t00;
 
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.inheritance.AbstractProjectInheritanceTestCase;
@@ -34,11 +33,8 @@
  * anywhere else in the lineage. We are just making sure that values
  * down in the lineage are bubbling up where they should.
  *
- * @author Jason van Zyl
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p4 inherits from p3
@@ -54,43 +50,41 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testProjectInheritance()
-        throws Exception
-    {
-        MavenProject p4 = getProject( projectFile( "p4" ) );
+    void testProjectInheritance() throws Exception {
+        MavenProject p4 = getProject(projectFile("p4"));
 
-        assertEquals( "p4", p4.getName() );
+        assertEquals("p4", p4.getName());
 
         // ----------------------------------------------------------------------
         // Value inherited from p3
         // ----------------------------------------------------------------------
 
-        assertEquals( "2000", p4.getInceptionYear() );
+        assertEquals("2000", p4.getInceptionYear());
 
         // ----------------------------------------------------------------------
         // Value taken from p2
         // ----------------------------------------------------------------------
 
-        assertEquals( "mailing-list", p4.getMailingLists().get( 0 ).getName() );
+        assertEquals("mailing-list", p4.getMailingLists().get(0).getName());
 
         // ----------------------------------------------------------------------
         // Value taken from p1
         // ----------------------------------------------------------------------
 
-        assertEquals( "scm-url/p2/p3/p4", p4.getScm().getUrl() );
+        assertEquals("scm-url/p2/p3/p4", p4.getScm().getUrl());
 
         // ----------------------------------------------------------------------
         // Value taken from p4
         // ----------------------------------------------------------------------
 
-        assertEquals( "Codehaus", p4.getOrganization().getName() );
+        assertEquals("Codehaus", p4.getOrganization().getName());
 
         // ----------------------------------------------------------------------
         // Value taken from super model
         // ----------------------------------------------------------------------
 
-        assertEquals( "4.0.0", p4.getModelVersion() );
+        assertEquals("4.0.0", p4.getModelVersion());
 
-        assertEquals( "4.0.0", p4.getModelVersion() );
+        assertEquals("4.0.0", p4.getModelVersion());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t01/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t01/ProjectInheritanceTest.java
index 8f8199e..e1baae2 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t01/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t01/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t01;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t01;
 
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.inheritance.AbstractProjectInheritanceTestCase;
@@ -30,11 +29,8 @@
  * we are testing to make sure that elements stated in a model are
  * not clobbered by the same elements elsewhere in the lineage.
  *
- * @author Jason van Zyl
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p4 inherits from p3
@@ -50,47 +46,45 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testProjectInheritance()
-        throws Exception
-    {
+    void testProjectInheritance() throws Exception {
         // ----------------------------------------------------------------------
         // Check p0 value for org name
         // ----------------------------------------------------------------------
 
-        MavenProject p0 = getProject( projectFile( "maven.t01", "p0" ) );
+        MavenProject p0 = getProject(projectFile("maven.t01", "p0"));
 
-        assertEquals( "p0-org", p0.getOrganization().getName() );
+        assertEquals("p0-org", p0.getOrganization().getName());
 
         // ----------------------------------------------------------------------
         // Check p1 value for org name
         // ----------------------------------------------------------------------
 
-        MavenProject p1 = getProject( projectFile( "maven.t01", "p1" ) );
+        MavenProject p1 = getProject(projectFile("maven.t01", "p1"));
 
-        assertEquals( "p1-org", p1.getOrganization().getName() );
+        assertEquals("p1-org", p1.getOrganization().getName());
 
         // ----------------------------------------------------------------------
         // Check p2 value for org name
         // ----------------------------------------------------------------------
 
-        MavenProject p2 = getProject( projectFile( "maven.t01", "p2" ) );
+        MavenProject p2 = getProject(projectFile("maven.t01", "p2"));
 
-        assertEquals( "p2-org", p2.getOrganization().getName() );
+        assertEquals("p2-org", p2.getOrganization().getName());
 
         // ----------------------------------------------------------------------
         // Check p2 value for org name
         // ----------------------------------------------------------------------
 
-        MavenProject p3 = getProject( projectFile( "maven.t01", "p3" ) );
+        MavenProject p3 = getProject(projectFile("maven.t01", "p3"));
 
-        assertEquals( "p3-org", p3.getOrganization().getName() );
+        assertEquals("p3-org", p3.getOrganization().getName());
 
         // ----------------------------------------------------------------------
         // Check p4 value for org name
         // ----------------------------------------------------------------------
 
-        MavenProject p4 = getProject( projectFile( "maven.t01", "p4" ) );
+        MavenProject p4 = getProject(projectFile("maven.t01", "p4"));
 
-        assertEquals( "p4-org", p4.getOrganization().getName() );
+        assertEquals("p4-org", p4.getOrganization().getName());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t02/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t02/ProjectInheritanceTest.java
index adacaf8..1031785 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t02/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t02/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t02;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t02;
 
 import java.io.File;
 import java.util.HashMap;
@@ -44,11 +43,8 @@
  * anywhere else in the lineage. We are just making sure that values
  * down in the lineage are bubbling up where they should.
  *
- * @author Jason van Zyl
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p4 inherits from p3
@@ -64,61 +60,59 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testProjectInheritance()
-        throws Exception
-    {
+    void testProjectInheritance() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        System.out.println( "Local repository is at: " + localRepo.getAbsolutePath() );
+        System.out.println("Local repository is at: " + localRepo.getAbsolutePath());
 
-        File pom0 = new File( localRepo, "p0/pom.xml" );
-        File pom1 = new File( pom0.getParentFile(), "p1/pom.xml" );
-        File pom2 = new File( pom1.getParentFile(), "p2/pom.xml" );
-        File pom3 = new File( pom2.getParentFile(), "p3/pom.xml" );
-        File pom4 = new File( pom3.getParentFile(), "p4/pom.xml" );
-        File pom5 = new File( pom4.getParentFile(), "p5/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
+        File pom1 = new File(pom0.getParentFile(), "p1/pom.xml");
+        File pom2 = new File(pom1.getParentFile(), "p2/pom.xml");
+        File pom3 = new File(pom2.getParentFile(), "p3/pom.xml");
+        File pom4 = new File(pom3.getParentFile(), "p4/pom.xml");
+        File pom5 = new File(pom4.getParentFile(), "p5/pom.xml");
 
-        System.out.println( "Location of project-4's POM: " + pom4.getPath() );
+        System.out.println("Location of project-4's POM: " + pom4.getPath());
 
         // load everything...
-        MavenProject project0 = getProject( pom0 );
-        MavenProject project1 = getProject( pom1 );
-        MavenProject project2 = getProject( pom2 );
-        MavenProject project3 = getProject( pom3 );
-        MavenProject project4 = getProject( pom4 );
-        MavenProject project5 = getProject( pom5 );
+        MavenProject project0 = getProject(pom0);
+        MavenProject project1 = getProject(pom1);
+        MavenProject project2 = getProject(pom2);
+        MavenProject project3 = getProject(pom3);
+        MavenProject project4 = getProject(pom4);
+        MavenProject project5 = getProject(pom5);
 
-        assertEquals( "p4", project4.getName() );
+        assertEquals("p4", project4.getName());
 
         // ----------------------------------------------------------------------
         // Value inherited from p3
         // ----------------------------------------------------------------------
 
-        assertEquals( "2000", project4.getInceptionYear() );
+        assertEquals("2000", project4.getInceptionYear());
 
         // ----------------------------------------------------------------------
         // Value taken from p2
         // ----------------------------------------------------------------------
 
-        assertEquals( "mailing-list", project4.getMailingLists().get( 0 ).getName() );
+        assertEquals("mailing-list", project4.getMailingLists().get(0).getName());
 
         // ----------------------------------------------------------------------
         // Value taken from p1
         // ----------------------------------------------------------------------
 
-        assertEquals( "scm-url/p2/p3/p4", project4.getScm().getUrl() );
+        assertEquals("scm-url/p2/p3/p4", project4.getScm().getUrl());
 
         // ----------------------------------------------------------------------
         // Value taken from p4
         // ----------------------------------------------------------------------
 
-        assertEquals( "Codehaus", project4.getOrganization().getName() );
+        assertEquals("Codehaus", project4.getOrganization().getName());
 
         // ----------------------------------------------------------------------
         // Value taken from super model
         // ----------------------------------------------------------------------
 
-        assertEquals( "4.0.0", project4.getModelVersion() );
+        assertEquals("4.0.0", project4.getModelVersion());
 
         Build build = project4.getBuild();
         List<Plugin> plugins = build.getPlugins();
@@ -128,39 +122,37 @@
         String testPluginArtifactId = "maven-compiler-plugin";
 
         // this is the plugin we're looking for.
-        validPluginCounts.put( testPluginArtifactId, 0 );
+        validPluginCounts.put(testPluginArtifactId, 0);
 
         // these are injected if -DperformRelease=true
-        validPluginCounts.put( "maven-deploy-plugin", 0 );
-        validPluginCounts.put( "maven-javadoc-plugin", 0 );
-        validPluginCounts.put( "maven-source-plugin", 0 );
+        validPluginCounts.put("maven-deploy-plugin", 0);
+        validPluginCounts.put("maven-javadoc-plugin", 0);
+        validPluginCounts.put("maven-source-plugin", 0);
 
         Plugin testPlugin = null;
 
-        for ( Plugin plugin : plugins )
-        {
+        for (Plugin plugin : plugins) {
             String pluginArtifactId = plugin.getArtifactId();
 
-            assertTrue( validPluginCounts.containsKey( pluginArtifactId ), "Illegal plugin found: " + pluginArtifactId );
+            assertTrue(validPluginCounts.containsKey(pluginArtifactId), "Illegal plugin found: " + pluginArtifactId);
 
-            if ( pluginArtifactId.equals( testPluginArtifactId ) )
-            {
+            if (pluginArtifactId.equals(testPluginArtifactId)) {
                 testPlugin = plugin;
             }
 
-            Integer count = validPluginCounts.get( pluginArtifactId );
+            Integer count = validPluginCounts.get(pluginArtifactId);
 
-            assertEquals( 0, (int) count, "Multiple copies of plugin: " + pluginArtifactId + " found in POM." );
+            assertEquals(0, (int) count, "Multiple copies of plugin: " + pluginArtifactId + " found in POM.");
 
             count = count + 1;
 
-            validPluginCounts.put( pluginArtifactId, count );
+            validPluginCounts.put(pluginArtifactId, count);
         }
 
-        assertNotNull( testPlugin );
+        assertNotNull(testPlugin);
 
         List<PluginExecution> executions = testPlugin.getExecutions();
 
-        assertEquals( 1, executions.size() );
+        assertEquals(1, executions.size());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t03/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t03/ProjectInheritanceTest.java
index ca8565a..c899fff 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t03/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t03/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t03;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t03;
 
 import java.io.File;
 
@@ -36,11 +35,8 @@
  * anywhere else in the lineage. We are just making sure that values
  * down in the lineage are bubbling up where they should.
  *
- * @author Jason van Zyl
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -53,20 +49,18 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testProjectInheritance()
-        throws Exception
-    {
+    void testProjectInheritance() throws Exception {
         File localRepo = getLocalRepositoryPath();
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
 
         File pom0Basedir = pom0.getParentFile();
 
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load everything...
-        MavenProject project0 = getProject( pom0 );
-        MavenProject project1 = getProject( pom1 );
+        MavenProject project0 = getProject(pom0);
+        MavenProject project1 = getProject(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t04/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t04/ProjectInheritanceTest.java
index 34a31d5..8f653dc 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t04/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t04/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t04;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t04;
 
 import java.io.File;
 import java.util.Set;
@@ -36,11 +35,8 @@
  * dependencyManagement section is chosen over another version of the same
  * dependency, listed transitively.
  *
- * @author <a href="mailto:pschneider@gmail.com">Patrick Schneider</a>
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -57,35 +53,28 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testDependencyManagementOverridesTransitiveDependencyVersion()
-        throws Exception
-    {
+    void testDependencyManagementOverridesTransitiveDependencyVersion() throws Exception {
         File localRepo = getLocalRepositoryPath();
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
         File pom0Basedir = pom0.getParentFile();
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load the child project, which inherits from p0...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
         Set set = project1.getArtifacts();
-        assertNotNull( set, "No artifacts" );
-        assertTrue( set.size() > 0, "No Artifacts" );
-        assertTrue( set.size() == 3, "Set size should be 3, is " + set.size() );
+        assertNotNull(set, "No artifacts");
+        assertTrue(set.size() > 0, "No Artifacts");
+        assertTrue(set.size() == 3, "Set size should be 3, is " + set.size());
 
-        for ( Object aSet : set )
-        {
+        for (Object aSet : set) {
             Artifact artifact = (Artifact) aSet;
-            System.out.println(
-                "Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion() + " Optional=" + (
-                    artifact.isOptional()
-                        ? "true"
-                        : "false" ) );
-            assertTrue( artifact.getVersion().equals( "1.0" ),
-                        "Incorrect version for " + artifact.getDependencyConflictId() );
+            System.out.println("Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion()
+                    + " Optional=" + (artifact.isOptional() ? "true" : "false"));
+            assertTrue(
+                    artifact.getVersion().equals("1.0"), "Incorrect version for " + artifact.getDependencyConflictId());
         }
-
     }
-}
\ No newline at end of file
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t05/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t05/ProjectInheritanceTest.java
index 8af4a2f..063c8102 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t05/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t05/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t05;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t05;
 
 import java.io.File;
 import java.util.Set;
@@ -34,11 +33,8 @@
 /**
  * A test which demonstrates maven's dependency management
  *
- * @author <a href="rgoers@apache.org">Ralph Goers</a>
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -51,34 +47,29 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testDependencyManagement()
-        throws Exception
-    {
+    void testDependencyManagement() throws Exception {
         File localRepo = getLocalRepositoryPath();
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
 
         File pom0Basedir = pom0.getParentFile();
 
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load everything...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
         Set set = project1.getArtifacts();
-        assertNotNull( set, "No artifacts" );
-        assertTrue( set.size() > 0, "No Artifacts" );
+        assertNotNull(set, "No artifacts");
+        assertTrue(set.size() > 0, "No Artifacts");
 
-        for ( Object aSet : set )
-        {
+        for (Object aSet : set) {
             Artifact artifact = (Artifact) aSet;
-            System.out.println(
-                "Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion() + " Scope: "
-                    + artifact.getScope() );
-            assertTrue( artifact.getVersion().equals( "1.0" ),
-                        "Incorrect version for " + artifact.getDependencyConflictId() );
+            System.out.println("Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion()
+                    + " Scope: " + artifact.getScope());
+            assertTrue(
+                    artifact.getVersion().equals("1.0"), "Incorrect version for " + artifact.getDependencyConflictId());
         }
-
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t06/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t06/ProjectInheritanceTest.java
index bc37066..8cf7585 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t06/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t06/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t06;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t06;
 
 import java.io.File;
 import java.util.Iterator;
@@ -35,11 +34,8 @@
 /**
  * A test which demonstrates maven's dependency management
  *
- * @author <a href="rgoers@apache.org">Ralph Goers</a>
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -52,35 +48,31 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testDependencyManagement()
-        throws Exception
-    {
+    void testDependencyManagement() throws Exception {
         File localRepo = getLocalRepositoryPath();
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
 
         File pom0Basedir = pom0.getParentFile();
 
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load everything...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
         Set set = project1.getArtifacts();
-        assertNotNull( set, "No artifacts" );
-        assertTrue( set.size() > 0, "No Artifacts" );
+        assertNotNull(set, "No artifacts");
+        assertTrue(set.size() > 0, "No Artifacts");
         Iterator iter = set.iterator();
-        assertTrue( set.size() == 4, "Set size should be 4, is " + set.size() );
+        assertTrue(set.size() == 4, "Set size should be 4, is " + set.size());
 
-        while ( iter.hasNext() )
-        {
+        while (iter.hasNext()) {
             Artifact artifact = (Artifact) iter.next();
-            System.out.println( "Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion()
-              + " Optional=" + ( artifact.isOptional() ? "true" : "false" ) );
-            assertTrue( artifact.getVersion().equals( "1.0" ),
-                        "Incorrect version for " + artifact.getDependencyConflictId() );
+            System.out.println("Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion()
+                    + " Optional=" + (artifact.isOptional() ? "true" : "false"));
+            assertTrue(
+                    artifact.getVersion().equals("1.0"), "Incorrect version for " + artifact.getDependencyConflictId());
         }
-
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t07/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t07/ProjectInheritanceTest.java
index 87b07d3..c6ef086 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t07/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t07/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t07;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t07;
 
 import java.io.File;
 import java.util.Set;
@@ -35,11 +34,8 @@
 /**
  * A test which demonstrates maven's dependency management
  *
- * @author Jason van Zyl
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -52,37 +48,31 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testDependencyManagement()
-        throws Exception
-    {
+    void testDependencyManagement() throws Exception {
         File localRepo = getLocalRepositoryPath();
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
 
         File pom0Basedir = pom0.getParentFile();
 
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load everything...
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
         System.out.println("Project " + project1.getId() + " " + project1);
         Set set = project1.getArtifacts();
-        assertNotNull( set, "No artifacts" );
-        assertTrue( set.size() > 0, "No Artifacts" );
-        assertTrue( set.size() == 3, "Set size should be 3, is " + set.size() );
+        assertNotNull(set, "No artifacts");
+        assertTrue(set.size() > 0, "No Artifacts");
+        assertTrue(set.size() == 3, "Set size should be 3, is " + set.size());
 
-        for ( Object aSet : set )
-        {
+        for (Object aSet : set) {
             Artifact artifact = (Artifact) aSet;
-            assertFalse( artifact.getArtifactId().equals( "t07-d" ) );
-            System.out.println(
-                "Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion() + " Optional=" + (
-                    artifact.isOptional()
-                        ? "true"
-                        : "false" ) );
-            assertTrue( artifact.getVersion().equals( "1.0" ),
-                        "Incorrect version for " + artifact.getDependencyConflictId() );
+            assertFalse(artifact.getArtifactId().equals("t07-d"));
+            System.out.println("Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion()
+                    + " Optional=" + (artifact.isOptional() ? "true" : "false"));
+            assertTrue(
+                    artifact.getVersion().equals("1.0"), "Incorrect version for " + artifact.getDependencyConflictId());
         }
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t08/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t08/ProjectInheritanceTest.java
index c4562dc..edea47d 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t08/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t08/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t08;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t08;
 
 import java.io.File;
 import java.util.Iterator;
@@ -35,11 +34,8 @@
 /**
  * A test which demonstrates maven's dependency management
  *
- * @author <a href="rgoers@apache.org">Ralph Goers</a>
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -52,35 +48,32 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testDependencyManagement()
-        throws Exception
-    {
+    void testDependencyManagement() throws Exception {
         File localRepo = getLocalRepositoryPath();
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
 
         File pom0Basedir = pom0.getParentFile();
 
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load everything...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
-        System.out.println( "Project " + project1.getId() + " " + project1 );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
+        System.out.println("Project " + project1.getId() + " " + project1);
         Set set = project1.getArtifacts();
-        assertNotNull( set, "No artifacts" );
-        assertTrue( set.size() > 0, "No Artifacts" );
+        assertNotNull(set, "No artifacts");
+        assertTrue(set.size() > 0, "No Artifacts");
         Iterator iter = set.iterator();
-        assertTrue( set.size() == 4, "Set size should be 4, is " + set.size() );
+        assertTrue(set.size() == 4, "Set size should be 4, is " + set.size());
 
-        while ( iter.hasNext() )
-        {
+        while (iter.hasNext()) {
             Artifact artifact = (Artifact) iter.next();
-            System.out.println( "Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion()
-              + " Optional=" + ( artifact.isOptional() ? "true" : "false" ) );
-            assertTrue( artifact.getVersion().equals( "1.0" ), "Incorrect version for " + artifact.getDependencyConflictId() );
+            System.out.println("Artifact: " + artifact.getDependencyConflictId() + " " + artifact.getVersion()
+                    + " Optional=" + (artifact.isOptional() ? "true" : "false"));
+            assertTrue(
+                    artifact.getVersion().equals("1.0"), "Incorrect version for " + artifact.getDependencyConflictId());
         }
-
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t09/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t09/ProjectInheritanceTest.java
index dcc4e8b..867052e 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t09/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t09/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t09;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t09;
+
 import java.io.File;
 import java.util.Map;
 
@@ -34,11 +34,8 @@
  * Verifies exclusions listed in dependencyManagement are valid for
  * transitive dependencies.
  *
- * @author <a href="mailto:pschneider@gmail.com">Patrick Schneider</a>
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -63,30 +60,28 @@
      * a &amp; b only.
      */
     @Test
-    public void testDependencyManagementExclusionsExcludeTransitively()
-        throws Exception
-    {
+    void testDependencyManagementExclusionsExcludeTransitively() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
         File pom0Basedir = pom0.getParentFile();
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load the child project, which inherits from p0...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertNotNull( project1.getParent(), "Parent is null" );
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
+        assertNotNull(project1.getParent(), "Parent is null");
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
         Map map = project1.getArtifactMap();
 
-        assertNotNull( map, "No artifacts" );
-        assertTrue( map.size() > 0, "No Artifacts" );
-        assertTrue( map.size() == 2, "Set size should be 2, is " + map.size() );
+        assertNotNull(map, "No artifacts");
+        assertTrue(map.size() > 0, "No Artifacts");
+        assertTrue(map.size() == 2, "Set size should be 2, is " + map.size());
 
-        assertTrue( map.containsKey( "maven-test:t09-a" ), "maven-test:t09-a is not in the project" );
-        assertTrue( map.containsKey( "maven-test:t09-b" ), "maven-test:t09-b is not in the project" );
-        assertFalse( map.containsKey( "maven-test:t09-c" ), "maven-test:t09-c is in the project" );
+        assertTrue(map.containsKey("maven-test:t09-a"), "maven-test:t09-a is not in the project");
+        assertTrue(map.containsKey("maven-test:t09-b"), "maven-test:t09-b is not in the project");
+        assertFalse(map.containsKey("maven-test:t09-c"), "maven-test:t09-c is in the project");
     }
 
     /**
@@ -100,28 +95,26 @@
      * @throws Exception
      */
     @Test
-    public void testDependencyManagementExclusionDoesNotOverrideGloballyForTransitives()
-        throws Exception
-    {
+    void testDependencyManagementExclusionDoesNotOverrideGloballyForTransitives() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
         File pom0Basedir = pom0.getParentFile();
-        File pom2 = new File( pom0Basedir, "p2/pom.xml" );
+        File pom2 = new File(pom0Basedir, "p2/pom.xml");
 
         // load the child project, which inherits from p0...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project2 = getProjectWithDependencies( pom2 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project2 = getProjectWithDependencies(pom2);
 
-        assertEquals( pom0Basedir, project2.getParent().getBasedir() );
+        assertEquals(pom0Basedir, project2.getParent().getBasedir());
         Map map = project2.getArtifactMap();
-        assertNotNull( map, "No artifacts" );
-        assertTrue( map.size() > 0, "No Artifacts" );
-        assertTrue( map.size() == 4, "Set size should be 4, is " + map.size() );
+        assertNotNull(map, "No artifacts");
+        assertTrue(map.size() > 0, "No Artifacts");
+        assertTrue(map.size() == 4, "Set size should be 4, is " + map.size());
 
-        assertTrue( map.containsKey( "maven-test:t09-a" ), "maven-test:t09-a is not in the project" );
-        assertTrue( map.containsKey( "maven-test:t09-b" ), "maven-test:t09-b is not in the project" );
-        assertTrue( map.containsKey( "maven-test:t09-c" ), "maven-test:t09-c is not in the project" );
-        assertTrue( map.containsKey( "maven-test:t09-d" ), "maven-test:t09-d is not in the project" );
+        assertTrue(map.containsKey("maven-test:t09-a"), "maven-test:t09-a is not in the project");
+        assertTrue(map.containsKey("maven-test:t09-b"), "maven-test:t09-b is not in the project");
+        assertTrue(map.containsKey("maven-test:t09-c"), "maven-test:t09-c is not in the project");
+        assertTrue(map.containsKey("maven-test:t09-d"), "maven-test:t09-d is not in the project");
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java
index b1e7408..9e8b1b4 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t10/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t10;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t10;
 
 import java.io.File;
 import java.util.Map;
@@ -41,11 +40,8 @@
  * 3. Direct dependencies should inherit scope from dependencyManagement when
  *    they do not explicitly state a scope.
  *
- * @author <a href="mailto:pschneider@gmail.com">Patrick Schneider</a>
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -58,43 +54,40 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testDependencyManagementOverridesTransitiveDependencyVersion()
-        throws Exception
-    {
+    void testDependencyManagementOverridesTransitiveDependencyVersion() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
         File pom0Basedir = pom0.getParentFile();
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load the child project, which inherits from p0...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
         System.out.println("Project " + project1.getId() + " " + project1);
         Map map = project1.getArtifactMap();
-        assertNotNull( map, "No artifacts" );
-        assertTrue( map.size() > 0, "No Artifacts" );
-        assertTrue( map.size() == 3, "Set size should be 3, is " + map.size() );
+        assertNotNull(map, "No artifacts");
+        assertTrue(map.size() > 0, "No Artifacts");
+        assertTrue(map.size() == 3, "Set size should be 3, is " + map.size());
 
         Artifact a = (Artifact) map.get("maven-test:t10-a");
         Artifact b = (Artifact) map.get("maven-test:t10-b");
         Artifact c = (Artifact) map.get("maven-test:t10-c");
 
-        assertNotNull( a );
-        assertNotNull( b );
-        assertNotNull( c );
+        assertNotNull(a);
+        assertNotNull(b);
+        assertNotNull(c);
 
         // inherited from depMgmt
         System.out.println(a.getScope());
-        assertTrue( a.getScope().equals("test"), "Incorrect scope for " + a.getDependencyConflictId() );
+        assertTrue(a.getScope().equals("test"), "Incorrect scope for " + a.getDependencyConflictId());
 
         // transitive dep, overridden b depMgmt
-        assertTrue( b.getScope().equals("runtime"), "Incorrect scope for " + b.getDependencyConflictId() );
+        assertTrue(b.getScope().equals("runtime"), "Incorrect scope for " + b.getDependencyConflictId());
 
         // direct dep, overrides depMgmt
-        assertTrue( c.getScope().equals("runtime"), "Incorrect scope for " + c.getDependencyConflictId() );
-
+        assertTrue(c.getScope().equals("runtime"), "Incorrect scope for " + c.getDependencyConflictId());
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t11/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t11/ProjectInheritanceTest.java
index 3f21d5e..b129b07 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t11/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t11/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t11;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t11;
 
 import java.io.File;
 
@@ -31,12 +30,9 @@
 /**
  * Verifies scope of root project is preserved regardless of parent dependency management.
  *
- * @author <a href="mailto:pschneider@gmail.com">Patrick Schneider</a>
  * @see <a href="https://issues.apache.org/jira/browse/MNG-2919">MNG-2919</a>
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -49,21 +45,20 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testDependencyManagementDoesNotOverrideScopeOfCurrentArtifact()
-        throws Exception
-    {
+    void testDependencyManagementDoesNotOverrideScopeOfCurrentArtifact() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
         File pom0Basedir = pom0.getParentFile();
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
         // load the child project, which inherits from p0...
-        MavenProject project0 = getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        MavenProject project0 = getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
-        assertEquals( pom0Basedir, project1.getParent().getBasedir() );
-        assertNull( project1.getArtifact().getScope(),
-                    "dependencyManagement has overwritten the scope of the currently building child project" );
+        assertEquals(pom0Basedir, project1.getParent().getBasedir());
+        assertNull(
+                project1.getArtifact().getScope(),
+                "dependencyManagement has overwritten the scope of the currently building child project");
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12/ProjectInheritanceTest.java
index 50f5f08..b5607de 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t12;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t12;
 
 import java.io.File;
 import java.util.Map;
@@ -34,8 +33,7 @@
  * Verifies that plugin execution sections in the parent POM that have
  * inherit == false are not inherited to the child POM.
  */
-public class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -48,24 +46,24 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testFalsePluginExecutionInheritValue() throws Exception
-    {
+    void testFalsePluginExecutionInheritValue() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
         File pom0Basedir = pom0.getParentFile();
-        File pom1 = new File( pom0Basedir, "p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "p1/pom.xml");
 
-        getProjectWithDependencies( pom0 );
-        MavenProject project1 = getProjectWithDependencies( pom1 );
+        getProjectWithDependencies(pom0);
+        MavenProject project1 = getProjectWithDependencies(pom1);
 
         Map pluginMap = project1.getBuild().getPluginsAsMap();
-        Plugin compilerPlugin = (Plugin) pluginMap.get( "org.apache.maven.plugins:maven-compiler-plugin" );
+        Plugin compilerPlugin = (Plugin) pluginMap.get("org.apache.maven.plugins:maven-compiler-plugin");
 
-        assertNotNull( compilerPlugin );
+        assertNotNull(compilerPlugin);
 
         Map executionMap = compilerPlugin.getExecutionsAsMap();
-        assertNull( executionMap.get( "test" ),
-                "Plugin execution: 'test' should NOT exist in the compiler plugin specification for the child project!" );
+        assertNull(
+                executionMap.get("test"),
+                "Plugin execution: 'test' should NOT exist in the compiler plugin specification for the child project!");
     }
-}
\ No newline at end of file
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12scm/ProjectInheritanceTest.java b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12scm/ProjectInheritanceTest.java
index 82aee6c..8f2b2b1 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12scm/ProjectInheritanceTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/inheritance/t12scm/ProjectInheritanceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.inheritance.t12scm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.inheritance.t12scm;
 
 import java.io.File;
 
@@ -30,11 +29,8 @@
 /**
  * Verifies SCM inheritance uses modules statement from parent.
  *
- * @author jdcasey
  */
-public class ProjectInheritanceTest
-    extends AbstractProjectInheritanceTestCase
-{
+class ProjectInheritanceTest extends AbstractProjectInheritanceTestCase {
     // ----------------------------------------------------------------------
     //
     // p1 inherits from p0
@@ -47,84 +43,80 @@
     // ----------------------------------------------------------------------
 
     @Test
-    public void testScmInfoCalculatedCorrectlyOnParentAndChildRead()
-        throws Exception
-    {
+    void testScmInfoCalculatedCorrectlyOnParentAndChildRead() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        File pom0 = new File( localRepo, "p0/pom.xml" );
+        File pom0 = new File(localRepo, "p0/pom.xml");
         File pom0Basedir = pom0.getParentFile();
-        File pom1 = new File( pom0Basedir, "modules/p1/pom.xml" );
+        File pom1 = new File(pom0Basedir, "modules/p1/pom.xml");
 
         // load the child project, which inherits from p0...
-        MavenProject project0 = getProject( pom0 );
-        MavenProject project1 = getProject( pom1 );
+        MavenProject project0 = getProject(pom0);
+        MavenProject project1 = getProject(pom1);
 
-        System.out.println( "\n\n" );
-        System.out.println( "Parent SCM URL is: " + project0.getScm().getUrl() );
-        System.out.println( "Child SCM URL is: " + project1.getScm().getUrl() );
+        System.out.println("\n\n");
+        System.out.println("Parent SCM URL is: " + project0.getScm().getUrl());
+        System.out.println("Child SCM URL is: " + project1.getScm().getUrl());
         System.out.println();
-        System.out.println( "Parent SCM connection is: " + project0.getScm().getConnection() );
-        System.out.println( "Child SCM connection is: " + project1.getScm().getConnection() );
+        System.out.println("Parent SCM connection is: " + project0.getScm().getConnection());
+        System.out.println("Child SCM connection is: " + project1.getScm().getConnection());
         System.out.println();
-        System.out.println( "Parent SCM developer connection is: "
-                            + project0.getScm().getDeveloperConnection() );
-        System.out.println( "Child SCM developer connection is: "
-                            + project1.getScm().getDeveloperConnection() );
+        System.out.println(
+                "Parent SCM developer connection is: " + project0.getScm().getDeveloperConnection());
+        System.out.println(
+                "Child SCM developer connection is: " + project1.getScm().getDeveloperConnection());
 
-        assertEquals( project1.getScm().getUrl(), project0.getScm().getUrl() + "/modules/p1" );
-        assertEquals( project1.getScm().getConnection(), project0.getScm().getConnection()
-                                                         + "/modules/p1" );
-        assertEquals( project1.getScm().getDeveloperConnection(), project0.getScm()
-                                                                          .getDeveloperConnection()
-                                                                  + "/modules/p1" );
+        assertEquals(project1.getScm().getUrl(), project0.getScm().getUrl() + "/modules/p1");
+        assertEquals(project1.getScm().getConnection(), project0.getScm().getConnection() + "/modules/p1");
+        assertEquals(
+                project1.getScm().getDeveloperConnection(), project0.getScm().getDeveloperConnection() + "/modules/p1");
     }
 
     @Test
-    public void testScmInfoCalculatedCorrectlyOnChildOnlyRead()
-        throws Exception
-    {
+    void testScmInfoCalculatedCorrectlyOnChildOnlyRead() throws Exception {
         File localRepo = getLocalRepositoryPath();
 
-        File pom1 = new File( localRepo, "p0/modules/p1/pom.xml" );
+        File pom1 = new File(localRepo, "p0/modules/p1/pom.xml");
 
         // load the child project, which inherits from p0...
-        MavenProject project1 = getProject( pom1 );
+        MavenProject project1 = getProject(pom1);
 
-        System.out.println( "\n\n" );
-        System.out.println( "Child SCM URL is: " + project1.getScm().getUrl() );
-        System.out.println( "Child SCM connection is: " + project1.getScm().getConnection() );
-        System.out.println( "Child SCM developer connection is: "
-                            + project1.getScm().getDeveloperConnection() );
+        System.out.println("\n\n");
+        System.out.println("Child SCM URL is: " + project1.getScm().getUrl());
+        System.out.println("Child SCM connection is: " + project1.getScm().getConnection());
+        System.out.println(
+                "Child SCM developer connection is: " + project1.getScm().getDeveloperConnection());
 
-        assertEquals( "http://host/viewer?path=/p0/modules/p1", project1.getScm().getUrl() );
-        assertEquals( "scm:svn:http://host/p0/modules/p1", project1.getScm().getConnection() );
-        assertEquals( "scm:svn:https://host/p0/modules/p1", project1.getScm().getDeveloperConnection() );
+        assertEquals("http://host/viewer?path=/p0/modules/p1", project1.getScm().getUrl());
+        assertEquals("scm:svn:http://host/p0/modules/p1", project1.getScm().getConnection());
+        assertEquals("scm:svn:https://host/p0/modules/p1", project1.getScm().getDeveloperConnection());
     }
 
-//    public void testScmInfoCalculatedCorrectlyOnChildReadFromLocalRepository()
-//        throws Exception
-//    {
-//        File localRepo = getLocalRepositoryPath();
-//
-//        ArtifactFactory factory = (ArtifactFactory) lookup( ArtifactFactory.class );
-//        Artifact artifact = factory.createProjectArtifact( "maven", "p1", "1.0" );
-//
-//        ArtifactRepositoryFactory repoFactory = (ArtifactRepositoryFactory) lookup( ArtifactRepositoryFactory.class );
-//        ArtifactRepository localArtifactRepo = repoFactory.createLocalRepository( localRepo );
-//
-//        MavenProject project1 = getProjectBuilder().buildFromRepository( artifact, Collections.EMPTY_LIST, localArtifactRepo );
-//
-//        System.out.println( "\n\n" );
-//        System.out.println( "Child SCM URL is: " + project1.getScm().getUrl() );
-//        System.out.println( "Child SCM connection is: " + project1.getScm().getConnection() );
-//        System.out.println( "Child SCM developer connection is: "
-//                            + project1.getScm().getDeveloperConnection() );
-//
-//        assertEquals( project1.getScm().getUrl(), "http://host/viewer?path=/p0/modules/p1" );
-//        assertEquals( project1.getScm().getConnection(), "scm:svn:http://host/p0/modules/p1" );
-//        assertEquals( project1.getScm().getDeveloperConnection(),
-//                      "scm:svn:https://host/p0/modules/p1" );
-//    }
+    //    public void testScmInfoCalculatedCorrectlyOnChildReadFromLocalRepository()
+    //        throws Exception
+    //    {
+    //        File localRepo = getLocalRepositoryPath();
+    //
+    //        ArtifactFactory factory = (ArtifactFactory) lookup( ArtifactFactory.class );
+    //        Artifact artifact = factory.createProjectArtifact( "maven", "p1", "1.0" );
+    //
+    //        ArtifactRepositoryFactory repoFactory = (ArtifactRepositoryFactory) lookup(
+    // ArtifactRepositoryFactory.class );
+    //        ArtifactRepository localArtifactRepo = repoFactory.createLocalRepository( localRepo );
+    //
+    //        MavenProject project1 = getProjectBuilder().buildFromRepository( artifact, Collections.EMPTY_LIST,
+    // localArtifactRepo );
+    //
+    //        System.out.println( "\n\n" );
+    //        System.out.println( "Child SCM URL is: " + project1.getScm().getUrl() );
+    //        System.out.println( "Child SCM connection is: " + project1.getScm().getConnection() );
+    //        System.out.println( "Child SCM developer connection is: "
+    //                            + project1.getScm().getDeveloperConnection() );
+    //
+    //        assertEquals( project1.getScm().getUrl(), "http://host/viewer?path=/p0/modules/p1" );
+    //        assertEquals( project1.getScm().getConnection(), "scm:svn:http://host/p0/modules/p1" );
+    //        assertEquals( project1.getScm().getDeveloperConnection(),
+    //                      "scm:svn:https://host/p0/modules/p1" );
+    //    }
 
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/project/path/DefaultPathTranslatorTest.java b/maven-compat/src/test/java/org/apache/maven/project/path/DefaultPathTranslatorTest.java
index 022ccd5..4e4e822 100644
--- a/maven-compat/src/test/java/org/apache/maven/project/path/DefaultPathTranslatorTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/project/path/DefaultPathTranslatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,44 +16,41 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.path;
 
 import java.io.File;
 
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-@SuppressWarnings( "deprecation" )
-public class DefaultPathTranslatorTest
-{
+
+@SuppressWarnings("deprecation")
+class DefaultPathTranslatorTest {
 
     @Test
-    public void testAlignToBasedirWhereBasedirExpressionIsTheCompleteValue()
-    {
-        File basedir = new File( System.getProperty( "java.io.tmpdir" ), "test" ).getAbsoluteFile();
+    void testAlignToBasedirWhereBasedirExpressionIsTheCompleteValue() {
+        File basedir = new File(System.getProperty("java.io.tmpdir"), "test").getAbsoluteFile();
 
-        String aligned = new DefaultPathTranslator().alignToBaseDirectory( "${basedir}", basedir );
+        String aligned = new DefaultPathTranslator().alignToBaseDirectory("${basedir}", basedir);
 
-        assertEquals( basedir.getAbsolutePath(), aligned );
+        assertEquals(basedir.getAbsolutePath(), aligned);
     }
 
     @Test
-    public void testAlignToBasedirWhereBasedirExpressionIsTheValuePrefix()
-    {
-        File basedir = new File( System.getProperty( "java.io.tmpdir" ), "test" ).getAbsoluteFile();
+    void testAlignToBasedirWhereBasedirExpressionIsTheValuePrefix() {
+        File basedir = new File(System.getProperty("java.io.tmpdir"), "test").getAbsoluteFile();
 
-        String aligned = new DefaultPathTranslator().alignToBaseDirectory( "${basedir}/dir", basedir );
+        String aligned = new DefaultPathTranslator().alignToBaseDirectory("${basedir}/dir", basedir);
 
-        assertEquals( new File( basedir, "dir" ).getAbsolutePath(), aligned );
+        assertEquals(new File(basedir, "dir").getAbsolutePath(), aligned);
     }
 
     @Test
-    public void testUnalignToBasedirWherePathEqualsBasedir()
-    {
-        File basedir = new File( System.getProperty( "java.io.tmpdir" ), "test" ).getAbsoluteFile();
+    void testUnalignToBasedirWherePathEqualsBasedir() {
+        File basedir = new File(System.getProperty("java.io.tmpdir"), "test").getAbsoluteFile();
 
-        String unaligned = new DefaultPathTranslator().unalignFromBaseDirectory( basedir.getAbsolutePath(), basedir );
+        String unaligned = new DefaultPathTranslator().unalignFromBaseDirectory(basedir.getAbsolutePath(), basedir);
 
-        assertEquals( ".", unaligned );
+        assertEquals(".", unaligned);
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/DefaultMirrorSelectorTest.java b/maven-compat/src/test/java/org/apache/maven/repository/DefaultMirrorSelectorTest.java
index 97687e3..5efa70c 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/DefaultMirrorSelectorTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/DefaultMirrorSelectorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.DefaultArtifactRepository;
@@ -25,13 +24,11 @@
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
 
-public class DefaultMirrorSelectorTest
-{
+class DefaultMirrorSelectorTest {
     @Test
-    public void testMirrorWithMirrorOfPatternContainingANegationIsNotSelected()
-    {
-        ArtifactRepository repository = new DefaultArtifactRepository( "snapshots.repo", "http://whatever", null );
+    void testMirrorWithMirrorOfPatternContainingANegationIsNotSelected() {
+        ArtifactRepository repository = new DefaultArtifactRepository("snapshots.repo", "http://whatever", null);
         String pattern = "external:*, !snapshots.repo";
-        assertFalse( DefaultMirrorSelector.matchPattern( repository, pattern ) );
+        assertFalse(DefaultMirrorSelector.matchPattern(repository, pattern));
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/LegacyRepositorySystemTest.java b/maven-compat/src/test/java/org/apache/maven/repository/LegacyRepositorySystemTest.java
index f68a996..035b80f 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/LegacyRepositorySystemTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/LegacyRepositorySystemTest.java
@@ -1,25 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.repository;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
 
 import java.io.File;
 import java.util.Arrays;
 import java.util.List;
 
 import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.metadata.SwitchableMetadataSource;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
 import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
@@ -31,12 +37,15 @@
 import org.apache.maven.model.Repository;
 import org.apache.maven.model.RepositoryPolicy;
 import org.apache.maven.plugin.LegacySupport;
+import org.apache.maven.project.artifact.DefaultMetadataSource;
 import org.apache.maven.repository.legacy.LegacyRepositorySystem;
-import org.codehaus.plexus.testing.PlexusTest;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
 import org.eclipse.aether.repository.LocalRepository;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
@@ -44,149 +53,149 @@
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
 /**
  * Tests {@link LegacyRepositorySystem}.
  *
- * @author Benjamin Bentmann
  */
 @PlexusTest
-public class LegacyRepositorySystemTest
-{
+class LegacyRepositorySystemTest {
     @Inject
-    private RepositorySystem repositorySystem;
+    private LegacyRepositorySystem repositorySystem;
+
     @Inject
     private ResolutionErrorHandler resolutionErrorHandler;
+
     @Inject
     private PlexusContainer container;
 
-    protected List<ArtifactRepository> getRemoteRepositories()
-        throws Exception
-    {
-        File repoDir = new File( getBasedir(), "src/test/remote-repo" ).getAbsoluteFile();
+    protected List<ArtifactRepository> getRemoteRepositories() throws Exception {
+        File repoDir = new File(getBasedir(), "src/test/remote-repo").getAbsoluteFile();
 
         RepositoryPolicy policy = new RepositoryPolicy();
-        policy.setEnabled( true );
-        policy.setChecksumPolicy( "ignore" );
-        policy.setUpdatePolicy( "always" );
+        policy.setEnabled(true);
+        policy.setChecksumPolicy("ignore");
+        policy.setUpdatePolicy("always");
 
         Repository repository = new Repository();
-        repository.setId( RepositorySystem.DEFAULT_REMOTE_REPO_ID );
-        repository.setUrl( "file://" + repoDir.toURI().getPath() );
-        repository.setReleases( policy );
-        repository.setSnapshots( policy );
+        repository.setId(RepositorySystem.DEFAULT_REMOTE_REPO_ID);
+        repository.setUrl("file://" + repoDir.toURI().getPath());
+        repository.setReleases(policy);
+        repository.setSnapshots(policy);
 
-        return Arrays.asList( repositorySystem.buildArtifactRepository( repository ) );
+        return Arrays.asList(repositorySystem.buildArtifactRepository(repository));
     }
 
-    protected ArtifactRepository getLocalRepository()
-        throws Exception
-    {
-        File repoDir = new File( getBasedir(), "target/local-repo" ).getAbsoluteFile();
+    protected ArtifactRepository getLocalRepository() throws Exception {
+        File repoDir = new File(getBasedir(), "target/local-repo").getAbsoluteFile();
 
-        return repositorySystem.createLocalRepository( repoDir );
+        return repositorySystem.createLocalRepository(repoDir);
     }
 
     @Test
-    public void testThatASystemScopedDependencyIsNotResolvedFromRepositories()
-        throws Exception
-    {
+    void testThatASystemScopedDependencyIsNotResolvedFromRepositories() throws Exception {
         //
         // We should get a whole slew of dependencies resolving this artifact transitively
         //
         Dependency d = new Dependency();
-        d.setGroupId( "org.apache.maven.its" );
-        d.setArtifactId( "b" );
-        d.setVersion( "0.1" );
-        d.setScope( Artifact.SCOPE_COMPILE );
-        Artifact artifact = repositorySystem.createDependencyArtifact( d );
+        d.setGroupId("org.apache.maven.its");
+        d.setArtifactId("b");
+        d.setVersion("0.1");
+        d.setScope(Artifact.SCOPE_COMPILE);
+        Artifact artifact = repositorySystem.createDependencyArtifact(d);
 
         ArtifactResolutionRequest request = new ArtifactResolutionRequest()
-            .setArtifact( artifact )
-            .setResolveRoot( true )
-            .setResolveTransitively( true )
-            .setRemoteRepositories( getRemoteRepositories() )
-            .setLocalRepository( getLocalRepository() );
+                .setArtifact(artifact)
+                .setResolveRoot(true)
+                .setResolveTransitively(true)
+                .setRemoteRepositories(getRemoteRepositories())
+                .setLocalRepository(getLocalRepository());
 
         DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
-        LocalRepository localRepo = new LocalRepository( request.getLocalRepository().getBasedir() );
-        session.setLocalRepositoryManager( new SimpleLocalRepositoryManagerFactory().newInstance( session, localRepo ) );
-        LegacySupport legacySupport = container.lookup( LegacySupport.class );
-        legacySupport.setSession( new MavenSession( container, session, new DefaultMavenExecutionRequest(),
-                                                    new DefaultMavenExecutionResult() ) );
+        LocalRepository localRepo =
+                new LocalRepository(request.getLocalRepository().getBasedir());
+        session.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory().newInstance(session, localRepo));
+        LegacySupport legacySupport = container.lookup(LegacySupport.class);
+        legacySupport.setSession(new MavenSession(
+                container, session, new DefaultMavenExecutionRequest(), new DefaultMavenExecutionResult()));
 
-        ArtifactResolutionResult result = repositorySystem.resolve( request );
-        resolutionErrorHandler.throwErrors( request, result );
-        assertEquals( 2, result.getArtifacts().size() );
+        ArtifactResolutionResult result = repositorySystem.resolve(request);
+        resolutionErrorHandler.throwErrors(request, result);
+        assertEquals(2, result.getArtifacts().size());
 
         //
         // System scoped version which should
         //
-        d.setScope( Artifact.SCOPE_SYSTEM );
-        File file = new File( getBasedir(), "src/test/repository-system/maven-core-2.1.0.jar" );
-        assertTrue( file.exists() );
-        d.setSystemPath( file.getCanonicalPath() );
+        d.setScope(Artifact.SCOPE_SYSTEM);
+        File file = new File(getBasedir(), "src/test/repository-system/maven-core-2.1.0.jar");
+        assertTrue(file.exists());
+        d.setSystemPath(file.getCanonicalPath());
 
-        artifact = repositorySystem.createDependencyArtifact( d );
+        artifact = repositorySystem.createDependencyArtifact(d);
 
         //
-        // The request has not set any local or remote repositories as the system scoped dependency being resolved should only
+        // The request has not set any local or remote repositories as the system scoped dependency being resolved
+        // should only
         // give us the dependency off the disk and nothing more.
         //
         request = new ArtifactResolutionRequest()
-            .setArtifact( artifact )
-            .setResolveRoot( true )
-            .setResolveTransitively( true );
+                .setArtifact(artifact)
+                .setResolveRoot(true)
+                .setResolveTransitively(true);
 
-        result = repositorySystem.resolve( request );
-        resolutionErrorHandler.throwErrors( request, result );
-        assertEquals( 1, result.getArtifacts().size() );
+        result = repositorySystem.resolve(request);
+        resolutionErrorHandler.throwErrors(request, result);
+        assertEquals(1, result.getArtifacts().size());
 
         //
         // Put in a bogus file to make sure missing files cause the resolution to fail.
         //
-        file = new File( getBasedir(), "src/test/repository-system/maven-monkey-2.1.0.jar" );
-        assertFalse( file.exists() );
-        d.setSystemPath( file.getCanonicalPath() );
-        artifact = repositorySystem.createDependencyArtifact( d );
+        file = new File(getBasedir(), "src/test/repository-system/maven-monkey-2.1.0.jar");
+        assertFalse(file.exists());
+        d.setSystemPath(file.getCanonicalPath());
+        artifact = repositorySystem.createDependencyArtifact(d);
 
         //
-        // The request has not set any local or remote repositories as the system scoped dependency being resolved should only
+        // The request has not set any local or remote repositories as the system scoped dependency being resolved
+        // should only
         // give us the dependency off the disk and nothing more.
         //
         request = new ArtifactResolutionRequest()
-            .setArtifact( artifact )
-            .setResolveRoot( true )
-            .setResolveTransitively( true );
+                .setArtifact(artifact)
+                .setResolveRoot(true)
+                .setResolveTransitively(true);
 
-        try
-        {
-            result = repositorySystem.resolve( request );
-            resolutionErrorHandler.throwErrors( request, result );
-        }
-        catch( Exception e )
-        {
-            assertTrue( result.hasMissingArtifacts() );
+        try {
+            result = repositorySystem.resolve(request);
+            resolutionErrorHandler.throwErrors(request, result);
+        } catch (Exception e) {
+            assertTrue(result.hasMissingArtifacts());
         }
     }
 
     @Test
-    public void testLocalRepositoryBasedir()
-        throws Exception
-    {
-        File localRepoDir = new File( "" ).getAbsoluteFile();
+    void testLocalRepositoryBasedir() throws Exception {
+        File localRepoDir = new File("").getAbsoluteFile();
 
-        ArtifactRepository localRepo = repositorySystem.createLocalRepository( localRepoDir );
+        ArtifactRepository localRepo = repositorySystem.createLocalRepository(localRepoDir);
 
         String basedir = localRepo.getBasedir();
 
-        assertFalse( basedir.endsWith( "/" ) );
-        assertFalse( basedir.endsWith( "\\" ) );
+        assertFalse(basedir.endsWith("/"));
+        assertFalse(basedir.endsWith("\\"));
 
-        assertEquals( localRepoDir, new File( basedir ) );
+        assertEquals(localRepoDir, new File(basedir));
 
-        assertEquals( localRepoDir.getPath(), basedir );
+        assertEquals(localRepoDir.getPath(), basedir);
     }
 
+    @Inject
+    DefaultMetadataSource defaultMetadataSource;
+
+    @Inject
+    SwitchableMetadataSource switchableMetadataSource;
+
+    @BeforeEach
+    void setup() throws CycleDetectedInComponentGraphException {
+        switchableMetadataSource.setDelegate(defaultMetadataSource);
+    }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/MirrorProcessorTest.java b/maven-compat/src/test/java/org/apache/maven/repository/MirrorProcessorTest.java
index 9e8ab4e..9b6c999 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/MirrorProcessorTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/MirrorProcessorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
+
+import javax.inject.Inject;
 
 import java.util.Arrays;
 import java.util.List;
 
-import org.codehaus.plexus.testing.PlexusTest;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
 import org.apache.maven.repository.legacy.repository.ArtifactRepositoryFactory;
 import org.apache.maven.settings.Mirror;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -34,11 +35,8 @@
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
 @PlexusTest
-public class MirrorProcessorTest
-{
+class MirrorProcessorTest {
     @Inject
     private DefaultMirrorSelector mirrorSelector;
 
@@ -46,176 +44,168 @@
     private ArtifactRepositoryFactory repositorySystem;
 
     @Test
-    public void testExternalURL()
-    {
-        assertTrue( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://somehost" ) ) );
-        assertTrue( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://somehost:9090/somepath" ) ) );
-        assertTrue( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "ftp://somehost" ) ) );
-        assertTrue( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://192.168.101.1" ) ) );
-        assertTrue( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://" ) ) );
+    void testExternalURL() {
+        assertTrue(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://somehost")));
+        assertTrue(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://somehost:9090/somepath")));
+        assertTrue(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "ftp://somehost")));
+        assertTrue(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://192.168.101.1")));
+        assertTrue(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://")));
         // these are local
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://localhost:8080" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://127.0.0.1:9090" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "file://localhost/somepath" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "file://localhost/D:/somepath" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://localhost" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "http://127.0.0.1" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "file:///somepath" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "file://D:/somepath" ) ) );
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://localhost:8080")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://127.0.0.1:9090")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "file://localhost/somepath")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "file://localhost/D:/somepath")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://localhost")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "http://127.0.0.1")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "file:///somepath")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "file://D:/somepath")));
 
         // not a proper url so returns false;
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "192.168.101.1" ) ) );
-        assertFalse( DefaultMirrorSelector.isExternalRepo( getRepo( "foo", "" ) ) );
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "192.168.101.1")));
+        assertFalse(DefaultMirrorSelector.isExternalRepo(getRepo("foo", "")));
     }
 
     @Test
-    public void testMirrorLookup()
-    {
-        Mirror mirrorA = newMirror( "a", "a", "http://a" );
-        Mirror mirrorB = newMirror( "b", "b", "http://b" );
+    void testMirrorLookup() {
+        Mirror mirrorA = newMirror("a", "a", "http://a");
+        Mirror mirrorB = newMirror("b", "b", "http://b");
 
-        List<Mirror> mirrors = Arrays.asList( mirrorA, mirrorB );
+        List<Mirror> mirrors = Arrays.asList(mirrorA, mirrorB);
 
-        assertSame( mirrorA, mirrorSelector.getMirror( getRepo( "a", "http://a.a" ), mirrors ) );
+        assertSame(mirrorA, mirrorSelector.getMirror(getRepo("a", "http://a.a"), mirrors));
 
-        assertSame( mirrorB, mirrorSelector.getMirror( getRepo( "b", "http://a.a" ), mirrors ) );
+        assertSame(mirrorB, mirrorSelector.getMirror(getRepo("b", "http://a.a"), mirrors));
 
-        assertNull( mirrorSelector.getMirror( getRepo( "c", "http://c.c" ), mirrors ) );
+        assertNull(mirrorSelector.getMirror(getRepo("c", "http://c.c"), mirrors));
     }
 
     @Test
-    public void testMirrorWildcardLookup()
-    {
-        Mirror mirrorA = newMirror( "a", "a", "http://a" );
-        Mirror mirrorB = newMirror( "b", "b", "http://b" );
-        Mirror mirrorC = newMirror( "c", "*", "http://wildcard" );
+    void testMirrorWildcardLookup() {
+        Mirror mirrorA = newMirror("a", "a", "http://a");
+        Mirror mirrorB = newMirror("b", "b", "http://b");
+        Mirror mirrorC = newMirror("c", "*", "http://wildcard");
 
-        List<Mirror> mirrors = Arrays.asList( mirrorA, mirrorB, mirrorC );
+        List<Mirror> mirrors = Arrays.asList(mirrorA, mirrorB, mirrorC);
 
-        assertSame( mirrorA, mirrorSelector.getMirror( getRepo( "a", "http://a.a" ), mirrors ) );
+        assertSame(mirrorA, mirrorSelector.getMirror(getRepo("a", "http://a.a"), mirrors));
 
-        assertSame( mirrorB, mirrorSelector.getMirror( getRepo( "b", "http://a.a" ), mirrors ) );
+        assertSame(mirrorB, mirrorSelector.getMirror(getRepo("b", "http://a.a"), mirrors));
 
-        assertSame( mirrorC, mirrorSelector.getMirror( getRepo( "c", "http://c.c" ), mirrors ) );
+        assertSame(mirrorC, mirrorSelector.getMirror(getRepo("c", "http://c.c"), mirrors));
     }
 
     @Test
-    public void testMirrorStopOnFirstMatch()
-    {
+    void testMirrorStopOnFirstMatch() {
         // exact matches win first
-        Mirror mirrorA2 = newMirror( "a2", "a,b", "http://a2" );
-        Mirror mirrorA = newMirror( "a", "a", "http://a" );
+        Mirror mirrorA2 = newMirror("a2", "a,b", "http://a2");
+        Mirror mirrorA = newMirror("a", "a", "http://a");
         // make sure repeated entries are skipped
-        Mirror mirrorA3 = newMirror( "a", "a", "http://a3" );
+        Mirror mirrorA3 = newMirror("a", "a", "http://a3");
 
-        Mirror mirrorB = newMirror( "b", "b", "http://b" );
-        Mirror mirrorC = newMirror( "c", "d,e", "http://de" );
-        Mirror mirrorC2 = newMirror( "c", "*", "http://wildcard" );
-        Mirror mirrorC3 = newMirror( "c", "e,f", "http://ef" );
+        Mirror mirrorB = newMirror("b", "b", "http://b");
+        Mirror mirrorC = newMirror("c", "d,e", "http://de");
+        Mirror mirrorC2 = newMirror("c", "*", "http://wildcard");
+        Mirror mirrorC3 = newMirror("c", "e,f", "http://ef");
 
-        List<Mirror> mirrors = Arrays.asList( mirrorA2, mirrorA, mirrorA3, mirrorB, mirrorC, mirrorC2, mirrorC3 );
+        List<Mirror> mirrors = Arrays.asList(mirrorA2, mirrorA, mirrorA3, mirrorB, mirrorC, mirrorC2, mirrorC3);
 
-        assertSame( mirrorA, mirrorSelector.getMirror( getRepo( "a", "http://a.a" ), mirrors ) );
+        assertSame(mirrorA, mirrorSelector.getMirror(getRepo("a", "http://a.a"), mirrors));
 
-        assertSame( mirrorB, mirrorSelector.getMirror( getRepo( "b", "http://a.a" ), mirrors ) );
+        assertSame(mirrorB, mirrorSelector.getMirror(getRepo("b", "http://a.a"), mirrors));
 
-        assertSame( mirrorC2, mirrorSelector.getMirror( getRepo( "c", "http://c.c" ), mirrors ) );
+        assertSame(mirrorC2, mirrorSelector.getMirror(getRepo("c", "http://c.c"), mirrors));
 
-        assertSame( mirrorC, mirrorSelector.getMirror( getRepo( "d", "http://d" ), mirrors ) );
+        assertSame(mirrorC, mirrorSelector.getMirror(getRepo("d", "http://d"), mirrors));
 
-        assertSame( mirrorC, mirrorSelector.getMirror( getRepo( "e", "http://e" ), mirrors ) );
+        assertSame(mirrorC, mirrorSelector.getMirror(getRepo("e", "http://e"), mirrors));
 
-        assertSame( mirrorC2, mirrorSelector.getMirror( getRepo( "f", "http://f" ), mirrors ) );
+        assertSame(mirrorC2, mirrorSelector.getMirror(getRepo("f", "http://f"), mirrors));
     }
 
     @Test
-    public void testPatterns()
-    {
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "*" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "*," ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), ",*," ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "*," ) );
+    void testPatterns() {
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "*"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "*,"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), ",*,"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "*,"));
 
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "a" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "a," ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), ",a," ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "a," ) );
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "a"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "a,"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), ",a,"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "a,"));
 
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "b" ), "a" ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "b" ), "a," ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "b" ), ",a" ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "b" ), ",a," ) );
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("b"), "a"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("b"), "a,"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("b"), ",a"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("b"), ",a,"));
 
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "a,b" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "b" ), "a,b" ) );
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "a,b"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("b"), "a,b"));
 
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "c" ), "a,b" ) );
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("c"), "a,b"));
 
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "*" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "*,b" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "*,!b" ) );
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "*"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "*,b"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a"), "*,!b"));
 
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "*,!a" ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "a" ), "!a,*" ) );
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("a"), "*,!a"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("a"), "!a,*"));
 
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "c" ), "*,!a" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "c" ), "!a,*" ) );
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("c"), "*,!a"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("c"), "!a,*"));
 
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "c" ), "!a,!c" ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "d" ), "!a,!c*" ) );
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("c"), "!a,!c"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("d"), "!a,!c*"));
     }
 
     @Test
-    public void testPatternsWithExternal()
-    {
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a", "http://localhost" ), "*" ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "a", "http://localhost" ), "external:*" ) );
+    void testPatternsWithExternal() {
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a", "http://localhost"), "*"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("a", "http://localhost"), "external:*"));
 
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a", "http://localhost" ), "external:*,a" ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "a", "http://localhost" ), "external:*,!a" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "a", "http://localhost" ), "a,external:*" ) );
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "a", "http://localhost" ), "!a,external:*" ) );
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a", "http://localhost"), "external:*,a"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("a", "http://localhost"), "external:*,!a"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("a", "http://localhost"), "a,external:*"));
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("a", "http://localhost"), "!a,external:*"));
 
-        assertFalse( DefaultMirrorSelector.matchPattern( getRepo( "c", "http://localhost" ), "!a,external:*" ) );
-        assertTrue( DefaultMirrorSelector.matchPattern( getRepo( "c", "http://somehost" ), "!a,external:*" ) );
+        assertFalse(DefaultMirrorSelector.matchPattern(getRepo("c", "http://localhost"), "!a,external:*"));
+        assertTrue(DefaultMirrorSelector.matchPattern(getRepo("c", "http://somehost"), "!a,external:*"));
     }
 
     @Test
-    public void testLayoutPattern()
-    {
-        assertTrue( DefaultMirrorSelector.matchesLayout( "default", null ) );
-        assertTrue( DefaultMirrorSelector.matchesLayout( "default", "" ) );
-        assertTrue( DefaultMirrorSelector.matchesLayout( "default", "*" ) );
+    void testLayoutPattern() {
+        assertTrue(DefaultMirrorSelector.matchesLayout("default", null));
+        assertTrue(DefaultMirrorSelector.matchesLayout("default", ""));
+        assertTrue(DefaultMirrorSelector.matchesLayout("default", "*"));
 
-        assertTrue( DefaultMirrorSelector.matchesLayout( "default", "default" ) );
-        assertFalse( DefaultMirrorSelector.matchesLayout( "default", "legacy" ) );
+        assertTrue(DefaultMirrorSelector.matchesLayout("default", "default"));
+        assertFalse(DefaultMirrorSelector.matchesLayout("default", "legacy"));
 
-        assertTrue( DefaultMirrorSelector.matchesLayout( "default", "legacy,default" ) );
-        assertTrue( DefaultMirrorSelector.matchesLayout( "default", "default,legacy" ) );
+        assertTrue(DefaultMirrorSelector.matchesLayout("default", "legacy,default"));
+        assertTrue(DefaultMirrorSelector.matchesLayout("default", "default,legacy"));
 
-        assertFalse( DefaultMirrorSelector.matchesLayout( "default", "legacy,!default" ) );
-        assertFalse( DefaultMirrorSelector.matchesLayout( "default", "!default,legacy" ) );
+        assertFalse(DefaultMirrorSelector.matchesLayout("default", "legacy,!default"));
+        assertFalse(DefaultMirrorSelector.matchesLayout("default", "!default,legacy"));
 
-        assertFalse( DefaultMirrorSelector.matchesLayout( "default", "*,!default" ) );
-        assertFalse( DefaultMirrorSelector.matchesLayout( "default", "!default,*" ) );
+        assertFalse(DefaultMirrorSelector.matchesLayout("default", "*,!default"));
+        assertFalse(DefaultMirrorSelector.matchesLayout("default", "!default,*"));
     }
 
     @Test
-    public void testMirrorLayoutConsideredForMatching()
-    {
-        ArtifactRepository repo = getRepo( "a" );
+    void testMirrorLayoutConsideredForMatching() {
+        ArtifactRepository repo = getRepo("a");
 
-        Mirror mirrorA = newMirror( "a", "a", null, "http://a" );
-        Mirror mirrorB = newMirror( "b", "a", "p2", "http://b" );
+        Mirror mirrorA = newMirror("a", "a", null, "http://a");
+        Mirror mirrorB = newMirror("b", "a", "p2", "http://b");
 
-        Mirror mirrorC = newMirror( "c", "*", null, "http://c" );
-        Mirror mirrorD = newMirror( "d", "*", "p2", "http://d" );
+        Mirror mirrorC = newMirror("c", "*", null, "http://c");
+        Mirror mirrorD = newMirror("d", "*", "p2", "http://d");
 
-        assertSame( mirrorA, mirrorSelector.getMirror( repo, Arrays.asList( mirrorA ) ) );
-        assertNull( mirrorSelector.getMirror( repo, Arrays.asList( mirrorB ) ) );
+        assertSame(mirrorA, mirrorSelector.getMirror(repo, Arrays.asList(mirrorA)));
+        assertNull(mirrorSelector.getMirror(repo, Arrays.asList(mirrorB)));
 
-        assertSame( mirrorC, mirrorSelector.getMirror( repo, Arrays.asList( mirrorC ) ) );
-        assertNull( mirrorSelector.getMirror( repo, Arrays.asList( mirrorD ) ) );
+        assertSame(mirrorC, mirrorSelector.getMirror(repo, Arrays.asList(mirrorC)));
+        assertNull(mirrorSelector.getMirror(repo, Arrays.asList(mirrorD)));
     }
 
     /**
@@ -225,9 +215,8 @@
      * @param url
      * @return
      */
-    private ArtifactRepository getRepo( String id, String url )
-    {
-        return repositorySystem.createArtifactRepository( id, url, new DefaultRepositoryLayout(), null, null );
+    private ArtifactRepository getRepo(String id, String url) {
+        return repositorySystem.createArtifactRepository(id, url, new DefaultRepositoryLayout(), null, null);
     }
 
     /**
@@ -236,26 +225,22 @@
      * @param id
      * @return
      */
-    private ArtifactRepository getRepo( String id )
-    {
-        return getRepo( id, "http://something" );
+    private ArtifactRepository getRepo(String id) {
+        return getRepo(id, "http://something");
     }
 
-    private Mirror newMirror( String id, String mirrorOf, String url )
-    {
-        return newMirror( id, mirrorOf, null, url );
+    private Mirror newMirror(String id, String mirrorOf, String url) {
+        return newMirror(id, mirrorOf, null, url);
     }
 
-    private Mirror newMirror( String id, String mirrorOf, String layouts, String url )
-    {
+    private Mirror newMirror(String id, String mirrorOf, String layouts, String url) {
         Mirror mirror = new Mirror();
 
-        mirror.setId( id );
-        mirror.setMirrorOf( mirrorOf );
-        mirror.setMirrorOfLayouts( layouts );
-        mirror.setUrl( url );
+        mirror.setId(id);
+        mirror.setMirrorOf(mirrorOf);
+        mirror.setMirrorOfLayouts(layouts);
+        mirror.setUrl(url);
 
         return mirror;
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java
new file mode 100644
index 0000000..860fbe3
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/repository/TestArtifactHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import org.apache.maven.artifact.handler.ArtifactHandler;
+
+/**
+ * Assists unit testing.
+ *
+ */
+class TestArtifactHandler implements ArtifactHandler {
+
+    private String type;
+
+    private String extension;
+
+    public TestArtifactHandler(String type) {
+        this(type, type);
+    }
+
+    public TestArtifactHandler(String type, String extension) {
+        this.type = type;
+        this.extension = extension;
+    }
+
+    public String getClassifier() {
+        return null;
+    }
+
+    public String getDirectory() {
+        return getPackaging() + "s";
+    }
+
+    public String getExtension() {
+        return extension;
+    }
+
+    public String getLanguage() {
+        return "java";
+    }
+
+    public String getPackaging() {
+        return type;
+    }
+
+    public boolean isAddedToClasspath() {
+        return true;
+    }
+
+    public boolean isIncludesDependencies() {
+        return false;
+    }
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/TestRepositorySystem.java b/maven-compat/src/test/java/org/apache/maven/repository/TestRepositorySystem.java
new file mode 100644
index 0000000..a4b1663
--- /dev/null
+++ b/maven-compat/src/test/java/org/apache/maven/repository/TestRepositorySystem.java
@@ -0,0 +1,300 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.InvalidRepositoryException;
+import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
+import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.Repository;
+import org.apache.maven.model.io.ModelReader;
+import org.apache.maven.project.artifact.ArtifactWithDependencies;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ */
+@Named
+@Singleton
+@Priority(10)
+public class TestRepositorySystem implements RepositorySystem {
+
+    private final ModelReader modelReader;
+
+    private final ArtifactFactory artifactFactory;
+
+    public TestRepositorySystem() {
+        this(null, null);
+    }
+
+    @Inject
+    public TestRepositorySystem(ModelReader modelReader, ArtifactFactory artifactFactory) {
+        this.modelReader = modelReader;
+        this.artifactFactory = artifactFactory;
+    }
+
+    public ArtifactRepository buildArtifactRepository(Repository repository) throws InvalidRepositoryException {
+        return new MavenArtifactRepository(
+                repository.getId(),
+                repository.getUrl(),
+                new DefaultRepositoryLayout(),
+                new ArtifactRepositoryPolicy(),
+                new ArtifactRepositoryPolicy());
+    }
+
+    public Artifact createArtifact(String groupId, String artifactId, String version, String packaging) {
+        return createArtifact(groupId, artifactId, version, null, packaging);
+    }
+
+    public Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type) {
+        return new DefaultArtifact(groupId, artifactId, version, scope, type, null, new TestArtifactHandler(type));
+    }
+
+    public ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases) {
+        return new MavenArtifactRepository(id, url, repositoryLayout, snapshots, releases);
+    }
+
+    public Artifact createArtifactWithClassifier(
+            String groupId, String artifactId, String version, String type, String classifier) {
+        return new DefaultArtifact(groupId, artifactId, version, null, type, classifier, new TestArtifactHandler(type));
+    }
+
+    public ArtifactRepository createDefaultLocalRepository() throws InvalidRepositoryException {
+        return createLocalRepository(
+                new File(System.getProperty("basedir", "."), "target/local-repo").getAbsoluteFile());
+    }
+
+    public ArtifactRepository createDefaultRemoteRepository() throws InvalidRepositoryException {
+        return new MavenArtifactRepository(
+                DEFAULT_REMOTE_REPO_ID,
+                "file://"
+                        + new File(System.getProperty("basedir", "."), "src/test/remote-repo")
+                                .getAbsoluteFile()
+                                .toURI()
+                                .getPath(),
+                new DefaultRepositoryLayout(),
+                new ArtifactRepositoryPolicy(),
+                new ArtifactRepositoryPolicy());
+    }
+
+    public Artifact createDependencyArtifact(Dependency dependency) {
+        Artifact artifact = new DefaultArtifact(
+                dependency.getGroupId(),
+                dependency.getArtifactId(),
+                dependency.getVersion(),
+                dependency.getScope(),
+                dependency.getType(),
+                dependency.getClassifier(),
+                new TestArtifactHandler(dependency.getType()));
+
+        if (Artifact.SCOPE_SYSTEM.equals(dependency.getScope())) {
+            artifact.setFile(new File(dependency.getSystemPath()));
+            artifact.setResolved(true);
+        }
+
+        return artifact;
+    }
+
+    public ArtifactRepository createLocalRepository(File localRepository) throws InvalidRepositoryException {
+        return new MavenArtifactRepository(
+                MavenRepositorySystem.DEFAULT_LOCAL_REPO_ID,
+                "file://" + localRepository.toURI().getPath(),
+                new DefaultRepositoryLayout(),
+                new ArtifactRepositoryPolicy(),
+                new ArtifactRepositoryPolicy());
+    }
+
+    public Artifact createPluginArtifact(Plugin plugin) {
+        VersionRange versionRange;
+        try {
+            String version = plugin.getVersion();
+            if (version == null || version.isEmpty()) {
+                version = "RELEASE";
+            }
+            versionRange = VersionRange.createFromVersionSpec(version);
+        } catch (InvalidVersionSpecificationException e) {
+            return null;
+        }
+
+        return artifactFactory.createPluginArtifact(plugin.getGroupId(), plugin.getArtifactId(), versionRange);
+    }
+
+    public Artifact createProjectArtifact(String groupId, String artifactId, String version) {
+        return createArtifact(groupId, artifactId, version, "pom");
+    }
+
+    public List<ArtifactRepository> getEffectiveRepositories(List<ArtifactRepository> repositories) {
+        return repositories;
+    }
+
+    public Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors) {
+        return null;
+    }
+
+    public void injectAuthentication(List<ArtifactRepository> repositories, List<Server> servers) {}
+
+    public void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {}
+
+    public void injectProxy(List<ArtifactRepository> repositories, List<Proxy> proxies) {}
+
+    public void publish(
+            ArtifactRepository repository, File source, String remotePath, ArtifactTransferListener transferListener)
+            throws ArtifactTransferFailedException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public ArtifactResolutionResult resolve(ArtifactResolutionRequest request) {
+        ArtifactResolutionResult result = new ArtifactResolutionResult();
+
+        if (request.isResolveRoot()) {
+            try {
+                resolve(request.getArtifact(), request);
+                result.addArtifact(request.getArtifact());
+            } catch (IOException e) {
+                result.addMissingArtifact(request.getArtifact());
+            }
+        }
+
+        if (request.isResolveTransitively()) {
+            Map<String, Artifact> artifacts = new LinkedHashMap<>();
+
+            if (request.getArtifactDependencies() != null) {
+                for (Artifact artifact : request.getArtifactDependencies()) {
+                    artifacts.put(artifact.getDependencyConflictId(), artifact);
+                }
+            }
+
+            List<Dependency> dependencies = new ArrayList<>();
+            if (request.getArtifact() instanceof ArtifactWithDependencies) {
+                dependencies = ((ArtifactWithDependencies) request.getArtifact()).getDependencies();
+            } else {
+                Artifact pomArtifact = createProjectArtifact(
+                        request.getArtifact().getGroupId(),
+                        request.getArtifact().getArtifactId(),
+                        request.getArtifact().getVersion());
+                File pomFile = new File(
+                        request.getLocalRepository().getBasedir(),
+                        request.getLocalRepository().pathOf(pomArtifact));
+
+                try {
+                    Model model = modelReader.read(pomFile, null).getDelegate();
+
+                    dependencies = Dependency.dependencyToApiV3(model.getDependencies());
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+
+            for (Dependency dependency : dependencies) {
+                Artifact artifact = createDependencyArtifact(dependency);
+                if (!artifacts.containsKey(artifact.getDependencyConflictId())) {
+                    artifacts.put(artifact.getDependencyConflictId(), artifact);
+                }
+            }
+
+            for (Artifact artifact : artifacts.values()) {
+                try {
+                    resolve(artifact, request);
+                    result.addArtifact(artifact);
+                } catch (IOException e) {
+                    result.addMissingArtifact(artifact);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    private void resolve(Artifact artifact, ArtifactResolutionRequest request) throws IOException {
+        if (Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
+            return;
+        }
+
+        ArtifactRepository localRepo = request.getLocalRepository();
+
+        File localFile = new File(localRepo.getBasedir(), localRepo.pathOf(artifact));
+
+        artifact.setFile(localFile);
+
+        if (!localFile.exists()) {
+            if (request.getRemoteRepositories().isEmpty()) {
+                throw new IOException(localFile + " does not exist and no remote repositories are configured");
+            }
+
+            ArtifactRepository remoteRepo = request.getRemoteRepositories().get(0);
+
+            File remoteFile = new File(remoteRepo.getBasedir(), remoteRepo.pathOf(artifact));
+
+            Files.createDirectories(localFile.toPath().getParent());
+            Files.copy(remoteFile.toPath(), localFile.toPath());
+        }
+
+        artifact.setResolved(true);
+    }
+
+    public void retrieve(
+            ArtifactRepository repository,
+            File destination,
+            String remotePath,
+            ArtifactTransferListener transferListener)
+            throws ArtifactTransferFailedException, ArtifactDoesNotExistException {
+        // TODO Auto-generated method stub
+
+    }
+
+    public void injectMirror(RepositorySystemSession session, List<ArtifactRepository> repositories) {}
+
+    public void injectProxy(RepositorySystemSession session, List<ArtifactRepository> repositories) {}
+
+    public void injectAuthentication(RepositorySystemSession session, List<ArtifactRepository> repositories) {}
+}
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManagerTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManagerTest.java
index 85041ee..78bc281 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManagerTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultUpdateCheckManagerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
+package org.apache.maven.repository.legacy;
 
 import javax.inject.Inject;
 
+import java.io.File;
+
 import org.apache.maven.artifact.AbstractArtifactComponentTestCase;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.factory.ArtifactFactory;
@@ -40,9 +39,7 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class DefaultUpdateCheckManagerTest
-    extends AbstractArtifactComponentTestCase
-{
+class DefaultUpdateCheckManagerTest extends AbstractArtifactComponentTestCase {
 
     @Inject
     private ArtifactFactory artifactFactory;
@@ -50,209 +47,196 @@
     DefaultUpdateCheckManager updateCheckManager;
 
     @Override
-    protected String component()
-    {
+    protected String component() {
         return "updateCheckManager";
     }
 
     @BeforeEach
     @Override
-    public void setUp()
-        throws Exception
-    {
+    public void setUp() throws Exception {
         super.setUp();
 
-        updateCheckManager = new DefaultUpdateCheckManager( new ConsoleLogger( Logger.LEVEL_DEBUG, "test" ) );
+        updateCheckManager = new DefaultUpdateCheckManager(new ConsoleLogger(Logger.LEVEL_DEBUG, "test"));
     }
 
     @Test
-    public void testArtifact() throws Exception
-    {
+    void testArtifact() throws Exception {
         ArtifactRepository remoteRepository = remoteRepository();
 
         ArtifactRepository localRepository = localRepository();
 
-        Artifact a = createArtifact( "a", "0.0.1-SNAPSHOT" );
-        File file = new File( localRepository.getBasedir(),
-                              localRepository.pathOf( a ) );
+        Artifact a = createArtifact("a", "0.0.1-SNAPSHOT");
+        File file = new File(localRepository.getBasedir(), localRepository.pathOf(a));
         file.delete();
-        a.setFile( file );
+        a.setFile(file);
 
-        File touchFile = updateCheckManager.getTouchfile( a );
+        File touchFile = updateCheckManager.getTouchfile(a);
         touchFile.delete();
 
-        assertTrue( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertTrue(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
         file.getParentFile().mkdirs();
         file.createNewFile();
-        updateCheckManager.touch( a, remoteRepository, null );
+        updateCheckManager.touch(a, remoteRepository, null);
 
-        assertFalse( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertFalse(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
-        assertNull( updateCheckManager.readLastUpdated( touchFile,
-                                                        updateCheckManager.getRepositoryKey( remoteRepository ) ) );
+        assertNull(
+                updateCheckManager.readLastUpdated(touchFile, updateCheckManager.getRepositoryKey(remoteRepository)));
 
-        assertFalse( updateCheckManager.getTouchfile( a ).exists() );
+        assertFalse(updateCheckManager.getTouchfile(a).exists());
     }
 
     @Test
-    public void testMissingArtifact()
-        throws Exception
-    {
+    void testMissingArtifact() throws Exception {
         ArtifactRepository remoteRepository = remoteRepository();
 
         ArtifactRepository localRepository = localRepository();
 
-        Artifact a = createArtifact( "a", "0.0.1-SNAPSHOT" );
-        File file = new File( localRepository.getBasedir(),
-                              localRepository.pathOf( a ) );
+        Artifact a = createArtifact("a", "0.0.1-SNAPSHOT");
+        File file = new File(localRepository.getBasedir(), localRepository.pathOf(a));
         file.delete();
-        a.setFile( file );
+        a.setFile(file);
 
-        File touchFile = updateCheckManager.getTouchfile( a );
+        File touchFile = updateCheckManager.getTouchfile(a);
         touchFile.delete();
 
-        assertTrue( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertTrue(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
-        updateCheckManager.touch( a, remoteRepository, null );
+        updateCheckManager.touch(a, remoteRepository, null);
 
-        assertFalse( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertFalse(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
-        assertFalse( file.exists() );
-        assertNotNull( updateCheckManager.readLastUpdated( touchFile,
-                                                           updateCheckManager.getRepositoryKey( remoteRepository ) ) );
+        assertFalse(file.exists());
+        assertNotNull(
+                updateCheckManager.readLastUpdated(touchFile, updateCheckManager.getRepositoryKey(remoteRepository)));
     }
 
     @Test
-    public void testPom() throws Exception
-    {
+    void testPom() throws Exception {
         ArtifactRepository remoteRepository = remoteRepository();
 
         ArtifactRepository localRepository = localRepository();
 
-        Artifact a = createArtifact( "a", "0.0.1", "pom" );
-        File file = new File( localRepository.getBasedir(),
-                              localRepository.pathOf( a ) );
+        Artifact a = createArtifact("a", "0.0.1", "pom");
+        File file = new File(localRepository.getBasedir(), localRepository.pathOf(a));
         file.delete();
-        a.setFile( file );
+        a.setFile(file);
 
-        File touchFile = updateCheckManager.getTouchfile( a );
+        File touchFile = updateCheckManager.getTouchfile(a);
         touchFile.delete();
 
-        assertTrue( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertTrue(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
         file.getParentFile().mkdirs();
         file.createNewFile();
-        updateCheckManager.touch( a, remoteRepository, null );
+        updateCheckManager.touch(a, remoteRepository, null);
 
-        assertFalse( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertFalse(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
-        assertNull( updateCheckManager.readLastUpdated( touchFile,
-                                                        updateCheckManager.getRepositoryKey( remoteRepository ) ) );
+        assertNull(
+                updateCheckManager.readLastUpdated(touchFile, updateCheckManager.getRepositoryKey(remoteRepository)));
 
-        assertFalse( updateCheckManager.getTouchfile( a ).exists() );
+        assertFalse(updateCheckManager.getTouchfile(a).exists());
     }
 
     @Test
-    public void testMissingPom()
-        throws Exception
-    {
+    void testMissingPom() throws Exception {
         ArtifactRepository remoteRepository = remoteRepository();
 
         ArtifactRepository localRepository = localRepository();
 
-        Artifact a = createArtifact( "a", "0.0.1", "pom" );
-        File file = new File( localRepository.getBasedir(),
-                              localRepository.pathOf( a ) );
+        Artifact a = createArtifact("a", "0.0.1", "pom");
+        File file = new File(localRepository.getBasedir(), localRepository.pathOf(a));
         file.delete();
-        a.setFile( file );
+        a.setFile(file);
 
-        File touchFile = updateCheckManager.getTouchfile( a );
+        File touchFile = updateCheckManager.getTouchfile(a);
         touchFile.delete();
 
-        assertTrue( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertTrue(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
-        updateCheckManager.touch( a, remoteRepository, null );
+        updateCheckManager.touch(a, remoteRepository, null);
 
-        assertFalse( updateCheckManager.isUpdateRequired( a, remoteRepository ) );
+        assertFalse(updateCheckManager.isUpdateRequired(a, remoteRepository));
 
-        assertFalse( file.exists() );
-        assertNotNull( updateCheckManager.readLastUpdated( touchFile,
-                                                           updateCheckManager.getRepositoryKey( remoteRepository ) ) );
+        assertFalse(file.exists());
+        assertNotNull(
+                updateCheckManager.readLastUpdated(touchFile, updateCheckManager.getRepositoryKey(remoteRepository)));
     }
 
     @Test
-    public void testMetadata() throws Exception
-    {
+    void testMetadata() throws Exception {
         ArtifactRepository remoteRepository = remoteRepository();
 
         ArtifactRepository localRepository = localRepository();
 
-        Artifact a = createRemoteArtifact( "a", "0.0.1-SNAPSHOT" );
-        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( a );
+        Artifact a = createRemoteArtifact("a", "0.0.1-SNAPSHOT");
+        RepositoryMetadata metadata = new ArtifactRepositoryMetadata(a);
 
-        File file = new File( localRepository.getBasedir(),
-                              localRepository.pathOfLocalRepositoryMetadata( metadata, localRepository ) );
+        File file = new File(
+                localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata(metadata, localRepository));
         file.delete();
 
-        File touchFile = updateCheckManager.getTouchfile( metadata, file );
+        File touchFile = updateCheckManager.getTouchfile(metadata, file);
         touchFile.delete();
 
-        assertTrue( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+        assertTrue(updateCheckManager.isUpdateRequired(metadata, remoteRepository, file));
 
         file.getParentFile().mkdirs();
         file.createNewFile();
-        updateCheckManager.touch( metadata, remoteRepository, file );
+        updateCheckManager.touch(metadata, remoteRepository, file);
 
-        assertFalse( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+        assertFalse(updateCheckManager.isUpdateRequired(metadata, remoteRepository, file));
 
-        assertNotNull( updateCheckManager.readLastUpdated( touchFile, updateCheckManager.getMetadataKey( remoteRepository, file ) ) );
+        assertNotNull(updateCheckManager.readLastUpdated(
+                touchFile, updateCheckManager.getMetadataKey(remoteRepository, file)));
     }
 
     @Test
-    public void testMissingMetadata() throws Exception
-    {
+    void testMissingMetadata() throws Exception {
         ArtifactRepository remoteRepository = remoteRepository();
 
         ArtifactRepository localRepository = localRepository();
 
-        Artifact a = createRemoteArtifact( "a", "0.0.1-SNAPSHOT" );
-        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( a );
+        Artifact a = createRemoteArtifact("a", "0.0.1-SNAPSHOT");
+        RepositoryMetadata metadata = new ArtifactRepositoryMetadata(a);
 
-        File file = new File( localRepository.getBasedir(),
-                              localRepository.pathOfLocalRepositoryMetadata( metadata, localRepository ) );
+        File file = new File(
+                localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata(metadata, localRepository));
         file.delete();
 
-        File touchFile = updateCheckManager.getTouchfile( metadata, file );
+        File touchFile = updateCheckManager.getTouchfile(metadata, file);
         touchFile.delete();
 
-        assertTrue( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+        assertTrue(updateCheckManager.isUpdateRequired(metadata, remoteRepository, file));
 
-        updateCheckManager.touch( metadata, remoteRepository, file );
+        updateCheckManager.touch(metadata, remoteRepository, file);
 
-        assertFalse( updateCheckManager.isUpdateRequired( metadata, remoteRepository, file ) );
+        assertFalse(updateCheckManager.isUpdateRequired(metadata, remoteRepository, file));
 
-        assertNotNull( updateCheckManager.readLastUpdated( touchFile, updateCheckManager.getMetadataKey( remoteRepository, file ) ) );
+        assertNotNull(updateCheckManager.readLastUpdated(
+                touchFile, updateCheckManager.getMetadataKey(remoteRepository, file)));
     }
 
     @Test
-    public void testArtifactTouchFileName() throws Exception
-    {
+    void testArtifactTouchFileName() throws Exception {
         ArtifactRepository localRepository = localRepository();
 
-        Artifact a = artifactFactory.createArtifactWithClassifier( "groupId", "a", "0.0.1-SNAPSHOT", "jar", null );
-        File file = new File( localRepository.getBasedir(),
-                              localRepository.pathOf( a ) );
-        a.setFile( file );
+        Artifact a = artifactFactory.createArtifactWithClassifier("groupId", "a", "0.0.1-SNAPSHOT", "jar", null);
+        File file = new File(localRepository.getBasedir(), localRepository.pathOf(a));
+        a.setFile(file);
 
-        assertEquals( "a-0.0.1-SNAPSHOT.jar.lastUpdated", updateCheckManager.getTouchfile( a ).getName() );
+        assertEquals(
+                "a-0.0.1-SNAPSHOT.jar.lastUpdated",
+                updateCheckManager.getTouchfile(a).getName());
 
-        a = artifactFactory.createArtifactWithClassifier( "groupId", "a", "0.0.1-SNAPSHOT", "jar", "classifier" );
-        file = new File( localRepository.getBasedir(),
-                              localRepository.pathOf( a ) );
-        a.setFile( file );
+        a = artifactFactory.createArtifactWithClassifier("groupId", "a", "0.0.1-SNAPSHOT", "jar", "classifier");
+        file = new File(localRepository.getBasedir(), localRepository.pathOf(a));
+        a.setFile(file);
 
-        assertEquals( "a-0.0.1-SNAPSHOT-classifier.jar.lastUpdated", updateCheckManager.getTouchfile( a ).getName() );
+        assertEquals(
+                "a-0.0.1-SNAPSHOT-classifier.jar.lastUpdated",
+                updateCheckManager.getTouchfile(a).getName());
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultWagonManagerTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultWagonManagerTest.java
index 14961c1..5abe032 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultWagonManagerTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/DefaultWagonManagerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
+
+import javax.inject.Inject;
 
 import java.io.File;
 import java.io.IOException;
@@ -34,7 +35,6 @@
 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
 import org.apache.maven.artifact.versioning.VersionRange;
 import org.apache.maven.repository.legacy.repository.ArtifactRepositoryFactory;
-import org.codehaus.plexus.testing.PlexusTest;
 import org.apache.maven.wagon.ResourceDoesNotExistException;
 import org.apache.maven.wagon.TransferFailedException;
 import org.apache.maven.wagon.UnsupportedProtocolException;
@@ -43,6 +43,7 @@
 import org.apache.maven.wagon.events.TransferListener;
 import org.apache.maven.wagon.observers.AbstractTransferListener;
 import org.apache.maven.wagon.observers.Debug;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.codehaus.plexus.util.FileUtils;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
@@ -55,14 +56,10 @@
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
 /**
- * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
  */
 @PlexusTest
-public class DefaultWagonManagerTest
-{
+class DefaultWagonManagerTest {
     @Inject
     private WagonManager wagonManager;
 
@@ -75,120 +72,107 @@
     private ArtifactRepositoryFactory artifactRepositoryFactory;
 
     @Test
-    public void testUnnecessaryRepositoryLookup()
-        throws Exception
-    {
-        Artifact artifact = createTestPomArtifact( "target/test-data/get-missing-pom" );
+    void testUnnecessaryRepositoryLookup() throws Exception {
+        Artifact artifact = createTestPomArtifact("target/test-data/get-missing-pom");
 
         List<ArtifactRepository> repos = new ArrayList<>();
-        repos.add( artifactRepositoryFactory.createArtifactRepository( "repo1", "string://url1",
-                                                                       new ArtifactRepositoryLayoutStub(), null, null ) );
-        repos.add( artifactRepositoryFactory.createArtifactRepository( "repo2", "string://url2",
-                                                                       new ArtifactRepositoryLayoutStub(), null, null ) );
+        repos.add(artifactRepositoryFactory.createArtifactRepository(
+                "repo1", "string://url1", new ArtifactRepositoryLayoutStub(), null, null));
+        repos.add(artifactRepositoryFactory.createArtifactRepository(
+                "repo2", "string://url2", new ArtifactRepositoryLayoutStub(), null, null));
 
-        StringWagon wagon = (StringWagon) wagonManager.getWagon( "string" );
-        wagon.addExpectedContent( repos.get( 0 ).getLayout().pathOf( artifact ), "expected" );
-        wagon.addExpectedContent( repos.get( 0 ).getLayout().pathOf( artifact ) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac" );
-        wagon.addExpectedContent( repos.get( 1 ).getLayout().pathOf( artifact ), "expected" );
-        wagon.addExpectedContent( repos.get( 1 ).getLayout().pathOf( artifact ) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac" );
+        StringWagon wagon = (StringWagon) wagonManager.getWagon("string");
+        wagon.addExpectedContent(repos.get(0).getLayout().pathOf(artifact), "expected");
+        wagon.addExpectedContent(
+                repos.get(0).getLayout().pathOf(artifact) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac");
+        wagon.addExpectedContent(repos.get(1).getLayout().pathOf(artifact), "expected");
+        wagon.addExpectedContent(
+                repos.get(1).getLayout().pathOf(artifact) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac");
 
-
-        class TransferListener
-            extends AbstractTransferListener
-        {
+        class TransferListener extends AbstractTransferListener {
             public List<TransferEvent> events = new ArrayList<>();
 
             @Override
-            public void transferInitiated( TransferEvent transferEvent )
-            {
-                events.add( transferEvent );
+            public void transferInitiated(TransferEvent transferEvent) {
+                events.add(transferEvent);
             }
         }
 
         TransferListener listener = new TransferListener();
-        wagonManager.getArtifact( artifact, repos, listener, false );
-        assertEquals( 1, listener.events.size() );
+        wagonManager.getArtifact(artifact, repos, listener, false);
+        assertEquals(1, listener.events.size());
     }
 
     @Test
-    public void testGetMissingJar() throws TransferFailedException, UnsupportedProtocolException, IOException
-    {
-        Artifact artifact = createTestArtifact( "target/test-data/get-missing-jar", "jar" );
+    void testGetMissingJar() throws TransferFailedException, UnsupportedProtocolException, IOException {
+        Artifact artifact = createTestArtifact("target/test-data/get-missing-jar", "jar");
 
         ArtifactRepository repo = createStringRepo();
 
-        assertThrows( ResourceDoesNotExistException.class,
-                () -> wagonManager.getArtifact( artifact, repo, null, false ) );
+        assertThrows(ResourceDoesNotExistException.class, () -> wagonManager.getArtifact(artifact, repo, null, false));
 
-        assertFalse( artifact.getFile().exists() );
+        assertFalse(artifact.getFile().exists());
     }
 
     @Test
-    public void testGetMissingJarForced() throws TransferFailedException, UnsupportedProtocolException, IOException
-    {
-        Artifact artifact = createTestArtifact( "target/test-data/get-missing-jar", "jar" );
+    void testGetMissingJarForced() throws TransferFailedException, UnsupportedProtocolException, IOException {
+        Artifact artifact = createTestArtifact("target/test-data/get-missing-jar", "jar");
 
         ArtifactRepository repo = createStringRepo();
 
-        assertThrows( ResourceDoesNotExistException.class,
-                () -> wagonManager.getArtifact( artifact, repo, null, true ) );
+        assertThrows(ResourceDoesNotExistException.class, () -> wagonManager.getArtifact(artifact, repo, null, true));
 
-        assertFalse( artifact.getFile().exists() );
+        assertFalse(artifact.getFile().exists());
     }
 
     @Test
-    public void testGetRemoteJar()
-        throws TransferFailedException, ResourceDoesNotExistException, UnsupportedProtocolException, IOException
-    {
-        Artifact artifact = createTestArtifact( "target/test-data/get-remote-jar", "jar" );
+    void testGetRemoteJar()
+            throws TransferFailedException, ResourceDoesNotExistException, UnsupportedProtocolException, IOException {
+        Artifact artifact = createTestArtifact("target/test-data/get-remote-jar", "jar");
 
         ArtifactRepository repo = createStringRepo();
 
-        StringWagon wagon = (StringWagon) wagonManager.getWagon( "string" );
-        wagon.addExpectedContent( repo.getLayout().pathOf( artifact ), "expected" );
-        wagon.addExpectedContent( repo.getLayout().pathOf( artifact ) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac" );
+        StringWagon wagon = (StringWagon) wagonManager.getWagon("string");
+        wagon.addExpectedContent(repo.getLayout().pathOf(artifact), "expected");
+        wagon.addExpectedContent(repo.getLayout().pathOf(artifact) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac");
 
-        wagonManager.getArtifact( artifact, repo, null, false );
+        wagonManager.getArtifact(artifact, repo, null, false);
 
-        assertTrue( artifact.getFile().exists() );
-        assertEquals( "expected", FileUtils.fileRead( artifact.getFile(), "UTF-8" ) );
+        assertTrue(artifact.getFile().exists());
+        assertEquals("expected", FileUtils.fileRead(artifact.getFile(), "UTF-8"));
     }
 
-    private Artifact createTestPomArtifact( String directory )
-        throws IOException
-    {
-        File testData = getTestFile( directory );
-        FileUtils.deleteDirectory( testData );
+    private Artifact createTestPomArtifact(String directory) throws IOException {
+        File testData = getTestFile(directory);
+        FileUtils.deleteDirectory(testData);
         testData.mkdirs();
 
-        Artifact artifact = artifactFactory.createProjectArtifact( "test", "test", "1.0" );
-        artifact.setFile( new File( testData, "test-1.0.pom" ) );
-        assertFalse( artifact.getFile().exists() );
+        Artifact artifact = artifactFactory.createProjectArtifact("test", "test", "1.0");
+        artifact.setFile(new File(testData, "test-1.0.pom"));
+        assertFalse(artifact.getFile().exists());
         return artifact;
     }
 
-    private Artifact createTestArtifact( String directory, String type )
-        throws IOException
-    {
-        return createTestArtifact( directory, "1.0", type );
+    private Artifact createTestArtifact(String directory, String type) throws IOException {
+        return createTestArtifact(directory, "1.0", type);
     }
 
-    private Artifact createTestArtifact( String directory, String version, String type )
-        throws IOException
-    {
-        File testData = getTestFile( directory );
-        FileUtils.deleteDirectory( testData );
+    private Artifact createTestArtifact(String directory, String version, String type) throws IOException {
+        File testData = getTestFile(directory);
+        FileUtils.deleteDirectory(testData);
         testData.mkdirs();
 
-        Artifact artifact = artifactFactory.createBuildArtifact( "test", "test", version, type );
-        artifact.setFile( new File( testData, "test-" + version + "." + artifact.getArtifactHandler().getExtension() ) );
-        assertFalse( artifact.getFile().exists() );
+        Artifact artifact = artifactFactory.createBuildArtifact("test", "test", version, type);
+        artifact.setFile(new File(
+                testData,
+                "test-" + version + "." + artifact.getArtifactHandler().getExtension()));
+        assertFalse(artifact.getFile().exists());
         return artifact;
     }
 
-    private ArtifactRepository createStringRepo()
-    {
-        return artifactRepositoryFactory.createArtifactRepository( "id", "string://url", new ArtifactRepositoryLayoutStub(), null, null );
+    private ArtifactRepository createStringRepo() {
+        return artifactRepositoryFactory.createArtifactRepository(
+                "id", "string://url", new ArtifactRepositoryLayoutStub(), null, null);
     }
 
     /**
@@ -198,9 +182,8 @@
      * @param url
      * @return
      */
-    private ArtifactRepository getRepo( String id, String url )
-    {
-        return artifactRepositoryFactory.createArtifactRepository( id, url, new DefaultRepositoryLayout(), null, null );
+    private ArtifactRepository getRepo(String id, String url) {
+        return artifactRepositoryFactory.createArtifactRepository(id, url, new DefaultRepositoryLayout(), null, null);
     }
 
     /**
@@ -209,55 +192,54 @@
      * @param id
      * @return
      */
-    private ArtifactRepository getRepo( String id )
-    {
-        return getRepo( id, "http://something" );
+    private ArtifactRepository getRepo(String id) {
+        return getRepo(id, "http://something");
     }
 
     @Test
-    public void testDefaultWagonManager()
-        throws Exception
-    {
-        assertWagon( "a" );
+    void testDefaultWagonManager() throws Exception {
+        assertWagon("a");
 
-        assertWagon( "b" );
+        assertWagon("b");
 
-        assertWagon( "c" );
+        assertWagon("c");
 
-        assertWagon( "string" );
+        assertWagon("string");
 
-        assertThrows( UnsupportedProtocolException.class, () -> assertWagon( "d" ) );
+        assertThrows(UnsupportedProtocolException.class, () -> assertWagon("d"));
     }
 
     /**
      * Check that transfer listeners are properly removed after getArtifact and putArtifact
      */
     @Test
-    public void testWagonTransferListenerRemovedAfterGetArtifactAndPutArtifact()
-        throws Exception
-    {
-        Artifact artifact = createTestArtifact( "target/test-data/transfer-listener", "jar" );
+    void testWagonTransferListenerRemovedAfterGetArtifactAndPutArtifact() throws Exception {
+        Artifact artifact = createTestArtifact("target/test-data/transfer-listener", "jar");
         ArtifactRepository repo = createStringRepo();
-        StringWagon wagon = (StringWagon) wagonManager.getWagon( "string" );
-        wagon.addExpectedContent( repo.getLayout().pathOf( artifact ), "expected" );
-        wagon.addExpectedContent( repo.getLayout().pathOf( artifact ) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac" );
+        StringWagon wagon = (StringWagon) wagonManager.getWagon("string");
+        wagon.addExpectedContent(repo.getLayout().pathOf(artifact), "expected");
+        wagon.addExpectedContent(repo.getLayout().pathOf(artifact) + ".md5", "cd26d9e10ce691cc69aa2b90dcebbdac");
 
         /* getArtifact */
-        assertFalse( wagon.getTransferEventSupport().hasTransferListener( transferListener ),
-                    "Transfer listener is registered before test" );
-        wagonManager.getArtifact( artifact, repo, transferListener, false );
-        assertFalse( wagon.getTransferEventSupport().hasTransferListener( transferListener ),
-                    "Transfer listener still registered after getArtifact" );
+        assertFalse(
+                wagon.getTransferEventSupport().hasTransferListener(transferListener),
+                "Transfer listener is registered before test");
+        wagonManager.getArtifact(artifact, repo, transferListener, false);
+        assertFalse(
+                wagon.getTransferEventSupport().hasTransferListener(transferListener),
+                "Transfer listener still registered after getArtifact");
 
         /* putArtifact */
-        File sampleFile = getTestFile( "target/test-file" );
-        FileUtils.fileWrite( sampleFile.getAbsolutePath(), "sample file" );
+        File sampleFile = getTestFile("target/test-file");
+        FileUtils.fileWrite(sampleFile.getAbsolutePath(), "sample file");
 
-        assertFalse( wagon.getTransferEventSupport().hasTransferListener( transferListener ),
-                    "Transfer listener is registered before test" );
-        wagonManager.putArtifact( sampleFile, artifact, repo, transferListener );
-        assertFalse( wagon.getTransferEventSupport().hasTransferListener( transferListener ),
-                    "Transfer listener still registered after putArtifact" );
+        assertFalse(
+                wagon.getTransferEventSupport().hasTransferListener(transferListener),
+                "Transfer listener is registered before test");
+        wagonManager.putArtifact(sampleFile, artifact, repo, transferListener);
+        assertFalse(
+                wagon.getTransferEventSupport().hasTransferListener(transferListener),
+                "Transfer listener still registered after putArtifact");
     }
 
     /**
@@ -265,99 +247,93 @@
      */
     @Disabled
     @Test
-    public void testChecksumVerification()
-        throws Exception
-    {
-        ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy( true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL );
+    void testChecksumVerification() throws Exception {
+        ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy(
+                true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL);
 
-        ArtifactRepository repo = artifactRepositoryFactory.createArtifactRepository( "id", "string://url", new ArtifactRepositoryLayoutStub(), policy, policy );
+        ArtifactRepository repo = artifactRepositoryFactory.createArtifactRepository(
+                "id", "string://url", new ArtifactRepositoryLayoutStub(), policy, policy);
 
-        Artifact artifact =
-            new DefaultArtifact( "sample.group", "sample-art", VersionRange.createFromVersion( "1.0" ), "scope",
-                                 "jar", "classifier", null );
-        artifact.setFile( getTestFile( "target/sample-art" ) );
+        Artifact artifact = new DefaultArtifact(
+                "sample.group",
+                "sample-art",
+                VersionRange.createFromVersion("1.0"),
+                "scope",
+                "jar",
+                "classifier",
+                null);
+        artifact.setFile(getTestFile("target/sample-art"));
 
-        StringWagon wagon = (StringWagon) wagonManager.getWagon( "string" );
+        StringWagon wagon = (StringWagon) wagonManager.getWagon("string");
 
         wagon.clearExpectedContent();
-        wagon.addExpectedContent( "path", "lower-case-checksum" );
-        wagon.addExpectedContent( "path.sha1", "2a25dc564a3b34f68237fc849066cbc7bb7a36a1" );
-        wagonManager.getArtifact( artifact, repo, null, false );
+        wagon.addExpectedContent("path", "lower-case-checksum");
+        wagon.addExpectedContent("path.sha1", "2a25dc564a3b34f68237fc849066cbc7bb7a36a1");
+        wagonManager.getArtifact(artifact, repo, null, false);
 
         wagon.clearExpectedContent();
-        wagon.addExpectedContent( "path", "upper-case-checksum" );
-        wagon.addExpectedContent( "path.sha1", "B7BB97D7D0B9244398D9B47296907F73313663E6" );
-        wagonManager.getArtifact( artifact, repo, null, false );
+        wagon.addExpectedContent("path", "upper-case-checksum");
+        wagon.addExpectedContent("path.sha1", "B7BB97D7D0B9244398D9B47296907F73313663E6");
+        wagonManager.getArtifact(artifact, repo, null, false);
 
         wagon.clearExpectedContent();
-        wagon.addExpectedContent( "path", "expected-failure" );
-        wagon.addExpectedContent( "path.sha1", "b7bb97d7d0b9244398d9b47296907f73313663e6" );
-        assertThrows(
-                ChecksumFailedException.class, () ->
-                wagonManager.getArtifact( artifact, repo, null, false ),
-                "Checksum verification did not fail" );
-
-        wagon.clearExpectedContent();
-        wagon.addExpectedContent( "path", "lower-case-checksum" );
-        wagon.addExpectedContent( "path.md5", "50b2cf50a103a965efac62b983035cac" );
-        wagonManager.getArtifact( artifact, repo, null, false );
-
-        wagon.clearExpectedContent();
-        wagon.addExpectedContent( "path", "upper-case-checksum" );
-        wagon.addExpectedContent( "path.md5", "842F568FCCFEB7E534DC72133D42FFDC" );
-        wagonManager.getArtifact( artifact, repo, null, false );
-
-        wagon.clearExpectedContent();
-        wagon.addExpectedContent( "path", "expected-failure" );
-        wagon.addExpectedContent( "path.md5", "b7bb97d7d0b9244398d9b47296907f73313663e6" );
+        wagon.addExpectedContent("path", "expected-failure");
+        wagon.addExpectedContent("path.sha1", "b7bb97d7d0b9244398d9b47296907f73313663e6");
         assertThrows(
                 ChecksumFailedException.class,
-                () -> wagonManager.getArtifact( artifact, repo, null, false ),
-                "Checksum verification did not fail" );
+                () -> wagonManager.getArtifact(artifact, repo, null, false),
+                "Checksum verification did not fail");
+
+        wagon.clearExpectedContent();
+        wagon.addExpectedContent("path", "lower-case-checksum");
+        wagon.addExpectedContent("path.md5", "50b2cf50a103a965efac62b983035cac");
+        wagonManager.getArtifact(artifact, repo, null, false);
+
+        wagon.clearExpectedContent();
+        wagon.addExpectedContent("path", "upper-case-checksum");
+        wagon.addExpectedContent("path.md5", "842F568FCCFEB7E534DC72133D42FFDC");
+        wagonManager.getArtifact(artifact, repo, null, false);
+
+        wagon.clearExpectedContent();
+        wagon.addExpectedContent("path", "expected-failure");
+        wagon.addExpectedContent("path.md5", "b7bb97d7d0b9244398d9b47296907f73313663e6");
+        assertThrows(
+                ChecksumFailedException.class,
+                () -> wagonManager.getArtifact(artifact, repo, null, false),
+                "Checksum verification did not fail");
     }
 
     @Test
-    public void testPerLookupInstantiation()
-        throws Exception
-    {
+    void testPerLookupInstantiation() throws Exception {
         String protocol = "perlookup";
 
-        Wagon one = wagonManager.getWagon( protocol );
-        Wagon two = wagonManager.getWagon( protocol );
+        Wagon one = wagonManager.getWagon(protocol);
+        Wagon two = wagonManager.getWagon(protocol);
 
-        assertNotSame( one, two );
+        assertNotSame(one, two);
     }
 
-    private void assertWagon( String protocol )
-        throws Exception
-    {
-        Wagon wagon = wagonManager.getWagon( protocol );
+    private void assertWagon(String protocol) throws Exception {
+        Wagon wagon = wagonManager.getWagon(protocol);
 
-        assertNotNull( wagon, "Check wagon, protocol=" + protocol );
+        assertNotNull(wagon, "Check wagon, protocol=" + protocol);
     }
 
-    private final class ArtifactRepositoryLayoutStub
-        implements ArtifactRepositoryLayout
-    {
-        public String getId()
-        {
+    private final class ArtifactRepositoryLayoutStub implements ArtifactRepositoryLayout {
+        public String getId() {
             return "test";
         }
 
-        public String pathOfRemoteRepositoryMetadata( ArtifactMetadata metadata )
-        {
+        public String pathOfRemoteRepositoryMetadata(ArtifactMetadata metadata) {
             return "path";
         }
 
-        public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-        {
+        public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
             return "path";
         }
 
-        public String pathOf( Artifact artifact )
-        {
+        public String pathOf(Artifact artifact) {
             return "path";
         }
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/LegacyRepositorySystemTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/LegacyRepositorySystemTest.java
index ab93995..1728a55 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/LegacyRepositorySystemTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/LegacyRepositorySystemTest.java
@@ -1,26 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.repository.legacy;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
 
 import java.io.File;
 import java.util.Arrays;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.Authentication;
-import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.settings.Server;
 import org.codehaus.plexus.testing.PlexusTest;
 import org.junit.jupiter.api.Test;
@@ -28,43 +32,35 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-import javax.inject.Inject;
-
 /**
  * Tests {@link LegacyRepositorySystem}.
  *
- * @author Benjamin Bentmann
  */
 @PlexusTest
-public class LegacyRepositorySystemTest
-{
+class LegacyRepositorySystemTest {
     @Inject
-    private RepositorySystem repositorySystem;
+    private LegacyRepositorySystem repositorySystem;
 
     @Test
-    public void testThatLocalRepositoryWithSpacesIsProperlyHandled()
-        throws Exception
-    {
-        File basedir = new File( "target/spacy path" ).getAbsoluteFile();
-        ArtifactRepository repo = repositorySystem.createLocalRepository( basedir );
-        assertEquals( basedir, new File( repo.getBasedir() ) );
+    void testThatLocalRepositoryWithSpacesIsProperlyHandled() throws Exception {
+        File basedir = new File("target/spacy path").getAbsoluteFile();
+        ArtifactRepository repo = repositorySystem.createLocalRepository(basedir);
+        assertEquals(basedir, new File(repo.getBasedir()));
     }
 
     @Test
-    public void testAuthenticationHandling()
-    {
+    void testAuthenticationHandling() {
         Server server = new Server();
-        server.setId( "repository" );
-        server.setUsername( "jason" );
-        server.setPassword( "abc123" );
+        server.setId("repository");
+        server.setUsername("jason");
+        server.setPassword("abc123");
 
         ArtifactRepository repository =
-            repositorySystem.createArtifactRepository( "repository", "http://foo", null, null, null );
-        repositorySystem.injectAuthentication( Arrays.asList( repository ), Arrays.asList( server ) );
+                repositorySystem.createArtifactRepository("repository", "http://foo", null, null, null);
+        repositorySystem.injectAuthentication(Arrays.asList(repository), Arrays.asList(server));
         Authentication authentication = repository.getAuthentication();
-        assertNotNull( authentication );
-        assertEquals( "jason", authentication.getUsername() );
-        assertEquals( "abc123", authentication.getPassword() );
+        assertNotNull(authentication);
+        assertEquals("jason", authentication.getUsername());
+        assertEquals("abc123", authentication.getPassword());
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/PerLookupWagon.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/PerLookupWagon.java
index 26a68b4..9d4b5d3 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/PerLookupWagon.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/PerLookupWagon.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,20 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import javax.inject.Named;
 
 /**
  * Wagon with per-lookup instantiation strategy.
  */
-@Named( "perlookup" )
-public class PerLookupWagon
-    extends WagonMock
-{
+@Named("perlookup")
+public class PerLookupWagon extends WagonMock {
 
-    public String[] getSupportedProtocols()
-    {
-        return new String[] { "perlookup" };
+    public String[] getSupportedProtocols() {
+        return new String[] {"perlookup"};
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java
index 00be162..6e32a11 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/StringWagon.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -35,68 +37,48 @@
 import org.apache.maven.wagon.authorization.AuthorizationException;
 import org.apache.maven.wagon.resource.Resource;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-@Named( "string" )
+@Named("string")
 @Singleton
-public class StringWagon
-    extends StreamWagon
-{
+public class StringWagon extends StreamWagon {
     private Map<String, String> expectedContent = new HashMap<>();
 
-    public void addExpectedContent( String resourceName, String expectedContent )
-    {
-        this.expectedContent.put( resourceName, expectedContent );
+    public void addExpectedContent(String resourceName, String expectedContent) {
+        this.expectedContent.put(resourceName, expectedContent);
     }
 
-    public String[] getSupportedProtocols()
-    {
-        return new String[] { "string" };
+    public String[] getSupportedProtocols() {
+        return new String[] {"string"};
     }
 
     @Override
-    public void closeConnection()
-        throws ConnectionException
-    {
-    }
+    public void closeConnection() throws ConnectionException {}
 
     @Override
-    public void fillInputData( InputData inputData )
-        throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
-    {
+    public void fillInputData(InputData inputData)
+            throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException {
         Resource resource = inputData.getResource();
 
-        String content = expectedContent.get( resource.getName() );
+        String content = expectedContent.get(resource.getName());
 
-        if ( content != null )
-        {
-            resource.setContentLength( content.length() );
-            resource.setLastModified( System.currentTimeMillis() );
+        if (content != null) {
+            resource.setContentLength(content.length());
+            resource.setLastModified(System.currentTimeMillis());
 
-            inputData.setInputStream( new ByteArrayInputStream( content.getBytes( StandardCharsets.UTF_8 ) ) );
-        }
-        else
-        {
-            throw new ResourceDoesNotExistException( "No content provided for " + resource.getName() );
+            inputData.setInputStream(new ByteArrayInputStream(content.getBytes(StandardCharsets.UTF_8)));
+        } else {
+            throw new ResourceDoesNotExistException("No content provided for " + resource.getName());
         }
     }
 
     @Override
-    public void fillOutputData( OutputData outputData )
-        throws TransferFailedException
-    {
-        outputData.setOutputStream( new ByteArrayOutputStream() );
+    public void fillOutputData(OutputData outputData) throws TransferFailedException {
+        outputData.setOutputStream(new ByteArrayOutputStream());
     }
 
     @Override
-    protected void openConnectionInternal()
-        throws ConnectionException, AuthenticationException
-    {
-    }
+    protected void openConnectionInternal() throws ConnectionException, AuthenticationException {}
 
-    public void clearExpectedContent()
-    {
+    public void clearExpectedContent() {
         expectedContent.clear();
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonA.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonA.java
index dbab864..f84fd32 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonA.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonA.java
@@ -1,4 +1,3 @@
-package org.apache.maven.repository.legacy;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -8,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -17,22 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
+
 import javax.inject.Named;
 import javax.inject.Singleton;
 
 /**
  * Wagon for testing, for protocol <code>a</code>
  *
- * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-@Named( "a" )
+@Named("a")
 @Singleton
-public class WagonA
-    extends WagonMock
-{
-    public String[] getSupportedProtocols()
-    {
-        return new String[]{ "a" };
+public class WagonA extends WagonMock {
+    public String[] getSupportedProtocols() {
+        return new String[] {"a"};
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonB.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonB.java
index c083811..5c8772a 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonB.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonB.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -25,16 +24,11 @@
 /**
  * Wagon for testing, for protocols <code>b1</code> and <code>b2</code>
  *
- * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-@Named( "b" )
+@Named("b")
 @Singleton
-public class WagonB
-    extends WagonMock
-{
-    public String[] getSupportedProtocols()
-    {
-        return new String[]{ "b1", "b2" };
+public class WagonB extends WagonMock {
+    public String[] getSupportedProtocols() {
+        return new String[] {"b1", "b2"};
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonC.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonC.java
index 29aa1de..2af580f 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonC.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonC.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -25,16 +24,11 @@
 /**
  * Wagon for testing, for protocol <code>c</code>
  *
- * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-@Named( "c" )
+@Named("c")
 @Singleton
-public class WagonC
-    extends WagonMock
-{
-    public String[] getSupportedProtocols()
-    {
-        return new String[]{ "c" };
+public class WagonC extends WagonMock {
+    public String[] getSupportedProtocols() {
+        return new String[] {"c"};
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonMock.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonMock.java
index c516360..c0abd11 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonMock.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/WagonMock.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy;
 
 import org.apache.maven.wagon.providers.file.FileWagon;
 
 /**
  * Mock of a Wagon for testing
  *
- * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
  */
-public class WagonMock
-    extends FileWagon
-{
+public class WagonMock extends FileWagon {
 
     /**
      * A field that can be configured in the Wagon
@@ -37,14 +33,11 @@
      */
     private String configurableField = null;
 
-    public void setConfigurableField( String configurableField )
-    {
+    public void setConfigurableField(String configurableField) {
         this.configurableField = configurableField;
     }
 
-    public String getConfigurableField()
-    {
+    public String getConfigurableField() {
         return configurableField;
     }
-
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/DefaultArtifactCollectorTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/DefaultArtifactCollectorTest.java
index 56018d3..ff3ac75 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/DefaultArtifactCollectorTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/DefaultArtifactCollectorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver;
+
+import javax.inject.Inject;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -29,8 +30,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import javax.inject.Inject;
-
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
@@ -62,11 +61,9 @@
 /**
  * Test the default artifact collector.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
 @PlexusTest
-public class DefaultArtifactCollectorTest
-{
+class DefaultArtifactCollectorTest {
     @Inject
     private LegacyArtifactCollector artifactCollector;
 
@@ -80,628 +77,593 @@
     private static final String GROUP_ID = "test";
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
+    void setUp() throws Exception {
         source = new Source();
 
-        projectArtifact = createArtifactSpec( "project", "1.0", null );
+        projectArtifact = createArtifactSpec("project", "1.0", null);
     }
 
     @Test
     @Disabled("works, but we don't fail on cycles presently")
-    public void testCircularDependencyNotIncludingCurrentProject()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        b.addDependency( "a", "1.0" );
+    void testCircularDependencyNotIncludingCurrentProject()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        b.addDependency("a", "1.0");
         assertThrows(
                 CyclicDependencyException.class,
-                () -> collect( a ),
-                "Should have failed on cyclic dependency not involving project" );
+                () -> collect(a),
+                "Should have failed on cyclic dependency not involving project");
     }
 
     @Test
     @Disabled("works, but we don't fail on cycles presently")
-    public void testCircularDependencyIncludingCurrentProject()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        b.addDependency( "project", "1.0" );
+    void testCircularDependencyIncludingCurrentProject()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        b.addDependency("project", "1.0");
         assertThrows(
                 CyclicDependencyException.class,
-                () -> collect( a ),
-                "Should have failed on cyclic dependency not involving project" );
+                () -> collect(a),
+                "Should have failed on cyclic dependency not involving project");
     }
 
     @Test
-    public void testResolveWithFilter()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        ArtifactSpec c = a.addDependency( "c", "3.0" );
+    void testResolveWithFilter() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        ArtifactSpec c = a.addDependency("c", "3.0");
 
-        b.addDependency( "c", "2.0" );
-        ArtifactSpec d = b.addDependency( "d", "4.0" );
+        b.addDependency("c", "2.0");
+        ArtifactSpec d = b.addDependency("d", "4.0");
 
-        ArtifactResolutionResult res = collect( a );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact, d.artifact } ), res.getArtifacts(),
-                    "Check artifact list" );
+        ArtifactResolutionResult res = collect(a);
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, c.artifact, d.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
 
-        ArtifactFilter filter = new ExclusionSetFilter( new String[] { "b" } );
-        res = collect( a, filter );
-        assertEquals( createSet( new Object[] { a.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
+        ArtifactFilter filter = new ExclusionSetFilter(new String[] {"b"});
+        res = collect(a, filter);
+        assertEquals(createSet(new Object[] {a.artifact, c.artifact}), res.getArtifacts(), "Check artifact list");
     }
 
     @Test
-    public void testResolveCorrectDependenciesWhenDifferentDependenciesOnNearest()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        ArtifactSpec c2 = b.addDependency( "c", "2.0" );
-        c2.addDependency( "d", "1.0" );
+    void testResolveCorrectDependenciesWhenDifferentDependenciesOnNearest()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        ArtifactSpec c2 = b.addDependency("c", "2.0");
+        c2.addDependency("d", "1.0");
 
-        ArtifactSpec e = createArtifactSpec( "e", "1.0" );
-        ArtifactSpec c1 = e.addDependency( "c", "1.0" );
-        ArtifactSpec f = c1.addDependency( "f", "1.0" );
+        ArtifactSpec e = createArtifactSpec("e", "1.0");
+        ArtifactSpec c1 = e.addDependency("c", "1.0");
+        ArtifactSpec f = c1.addDependency("f", "1.0");
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, e.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, e.artifact, c1.artifact, f.artifact } ),
-                      res.getArtifacts(), "Check artifact list" );
-        assertEquals( "1.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, e.artifact}));
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, e.artifact, c1.artifact, f.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
+        assertEquals("1.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
     @Disabled
-    public void testResolveCorrectDependenciesWhenDifferentDependenciesOnNewest()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
+    void testResolveCorrectDependenciesWhenDifferentDependenciesOnNewest()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
         // TODO use newest conflict resolver
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        ArtifactSpec c2 = b.addDependency( "c", "2.0" );
-        ArtifactSpec d = c2.addDependency( "d", "1.0" );
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        ArtifactSpec c2 = b.addDependency("c", "2.0");
+        ArtifactSpec d = c2.addDependency("d", "1.0");
 
-        ArtifactSpec e = createArtifactSpec( "e", "1.0" );
-        ArtifactSpec c1 = e.addDependency( "c", "1.0" );
-        c1.addDependency( "f", "1.0" );
+        ArtifactSpec e = createArtifactSpec("e", "1.0");
+        ArtifactSpec c1 = e.addDependency("c", "1.0");
+        c1.addDependency("f", "1.0");
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, e.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, e.artifact, c2.artifact, d.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, e.artifact}));
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, e.artifact, c2.artifact, d.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
+        assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
     @Disabled
-    public void testResolveCorrectDependenciesWhenDifferentDependenciesOnNewestVersionReplaced()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
+    void testResolveCorrectDependenciesWhenDifferentDependenciesOnNewestVersionReplaced()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
         // TODO use newest conflict resolver
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b1 = a.addDependency( "b", "1.0" );
-        ArtifactSpec c = a.addDependency( "c", "1.0" );
-        ArtifactSpec d2 = b1.addDependency( "d", "2.0" );
-        d2.addDependency( "h", "1.0" );
-        ArtifactSpec d1 = c.addDependency( "d", "1.0" );
-        ArtifactSpec b2 = c.addDependency( "b", "2.0" );
-        ArtifactSpec e = b2.addDependency( "e", "1.0" );
-        ArtifactSpec g = d1.addDependency( "g", "1.0" );
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b1 = a.addDependency("b", "1.0");
+        ArtifactSpec c = a.addDependency("c", "1.0");
+        ArtifactSpec d2 = b1.addDependency("d", "2.0");
+        d2.addDependency("h", "1.0");
+        ArtifactSpec d1 = c.addDependency("d", "1.0");
+        ArtifactSpec b2 = c.addDependency("b", "2.0");
+        ArtifactSpec e = b2.addDependency("e", "1.0");
+        ArtifactSpec g = d1.addDependency("g", "1.0");
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact } ) );
-        Object[] artifacts = new Object[] { a.artifact, c.artifact, d1.artifact, b2.artifact, e.artifact, g.artifact };
-        assertEquals( createSet( artifacts ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "1.0", getArtifact( "d", res.getArtifacts() ).getVersion(), "Check version" );
-        assertEquals( "2.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact}));
+        Object[] artifacts = new Object[] {a.artifact, c.artifact, d1.artifact, b2.artifact, e.artifact, g.artifact};
+        assertEquals(createSet(artifacts), res.getArtifacts(), "Check artifact list");
+        assertEquals("1.0", getArtifact("d", res.getArtifacts()).getVersion(), "Check version");
+        assertEquals("2.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testResolveNearestNewestIsNearest()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        ArtifactSpec c = a.addDependency( "c", "3.0" );
+    void testResolveNearestNewestIsNearest() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        ArtifactSpec c = a.addDependency("c", "3.0");
 
-        b.addDependency( "c", "2.0" );
+        b.addDependency("c", "2.0");
 
-        ArtifactResolutionResult res = collect( a );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "3.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(a);
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
+        assertEquals("3.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testResolveNearestOldestIsNearest()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        ArtifactSpec c = a.addDependency( "c", "2.0" );
+    void testResolveNearestOldestIsNearest() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        ArtifactSpec c = a.addDependency("c", "2.0");
 
-        b.addDependency( "c", "3.0" );
+        b.addDependency("c", "3.0");
 
-        ArtifactResolutionResult res = collect( a );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(a);
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
+        assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testResolveLocalNewestIsLocal()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        a.addDependency( "b", "2.0" );
-        ArtifactSpec b = createArtifactSpec( "b", "3.0" );
+    void testResolveLocalNewestIsLocal() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        a.addDependency("b", "2.0");
+        ArtifactSpec b = createArtifactSpec("b", "3.0");
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "3.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
+        assertEquals("3.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testResolveLocalOldestIsLocal()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        a.addDependency( "b", "3.0" );
-        ArtifactSpec b = createArtifactSpec( "b", "2.0" );
+    void testResolveLocalOldestIsLocal() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        a.addDependency("b", "3.0");
+        ArtifactSpec b = createArtifactSpec("b", "2.0");
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "2.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
+        assertEquals("2.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testResolveLocalWithNewerVersionButLesserScope()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "commons-logging", "1.0" );
-        a.addDependency( "junit", "3.7" );
-        ArtifactSpec b = createArtifactSpec( "junit", "3.8.1", Artifact.SCOPE_TEST );
+    void testResolveLocalWithNewerVersionButLesserScope()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("commons-logging", "1.0");
+        a.addDependency("junit", "3.7");
+        ArtifactSpec b = createArtifactSpec("junit", "3.8.1", Artifact.SCOPE_TEST);
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "3.8.1", getArtifact( "junit", res.getArtifacts() ).getVersion(), "Check version" );
-        assertEquals( Artifact.SCOPE_TEST, getArtifact( "junit", res.getArtifacts() ).getScope(), "Check artifactScope" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
+        assertEquals("3.8.1", getArtifact("junit", res.getArtifacts()).getVersion(), "Check version");
+        assertEquals(
+                Artifact.SCOPE_TEST, getArtifact("junit", res.getArtifacts()).getScope(), "Check artifactScope");
     }
 
     @Test
-    public void testResolveLocalWithNewerVersionButLesserScopeResolvedFirst()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec b = createArtifactSpec( "junit", "3.8.1", Artifact.SCOPE_TEST );
-        ArtifactSpec a = createArtifactSpec( "commons-logging", "1.0" );
-        a.addDependency( "junit", "3.7" );
+    void testResolveLocalWithNewerVersionButLesserScopeResolvedFirst()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec b = createArtifactSpec("junit", "3.8.1", Artifact.SCOPE_TEST);
+        ArtifactSpec a = createArtifactSpec("commons-logging", "1.0");
+        a.addDependency("junit", "3.7");
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "3.8.1", getArtifact( "junit", res.getArtifacts() ).getVersion(), "Check version" );
-        assertEquals( Artifact.SCOPE_TEST, getArtifact( "junit", res.getArtifacts() ).getScope(), "Check artifactScope" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
+        assertEquals("3.8.1", getArtifact("junit", res.getArtifacts()).getVersion(), "Check version");
+        assertEquals(
+                Artifact.SCOPE_TEST, getArtifact("junit", res.getArtifacts()).getScope(), "Check artifactScope");
     }
 
     @Test
-    public void testResolveNearestWithRanges()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        ArtifactSpec c = a.addDependency( "c", "2.0" );
+    void testResolveNearestWithRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        ArtifactSpec c = a.addDependency("c", "2.0");
 
-        b.addDependency( "c", "[1.0,3.0]" );
+        b.addDependency("c", "[1.0,3.0]");
 
-        ArtifactResolutionResult res = collect( a );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(a);
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
+        assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testResolveRangeWithManagedVersion()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "[1.0,3.0]" );
+    void testResolveRangeWithManagedVersion() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "[1.0,3.0]");
 
-        ArtifactSpec managedB = createArtifactSpec( "b", "5.0" );
+        ArtifactSpec managedB = createArtifactSpec("b", "5.0");
 
-        ArtifactResolutionResult res = collect( a, managedB.artifact );
-        assertEquals( createSet( new Object[] { a.artifact, managedB.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "5.0", getArtifact( "b", res.getArtifacts() ).getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(a, managedB.artifact);
+        assertEquals(
+                createSet(new Object[] {a.artifact, managedB.artifact}), res.getArtifacts(), "Check artifact list");
+        assertEquals("5.0", getArtifact("b", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testCompatibleRanges()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        a.addDependency( "c", "[2.0,2.5]" );
-        b.addDependency( "c", "[1.0,3.0]" );
-        ArtifactSpec c = createArtifactSpec( "c", "2.5" );
+    void testCompatibleRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        a.addDependency("c", "[2.0,2.5]");
+        b.addDependency("c", "[1.0,3.0]");
+        ArtifactSpec c = createArtifactSpec("c", "2.5");
 
-        ArtifactResolutionResult res = collect( a );
+        ArtifactResolutionResult res = collect(a);
 
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "2.5", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, c.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
+        assertEquals("2.5", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testIncompatibleRanges()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        a.addDependency( "c", "[2.4,3.0]" );
+    void testIncompatibleRanges() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        a.addDependency("c", "[2.4,3.0]");
 
-        b.addDependency( "c", "[1.0,2.0]" );
+        b.addDependency("c", "[1.0,2.0]");
 
-        ArtifactResolutionResult res = collect( a );
+        ArtifactResolutionResult res = collect(a);
 
-        assertTrue( res.hasVersionRangeViolations() );
+        assertTrue(res.hasVersionRangeViolations());
     }
 
     @Test
-    public void testUnboundedRangeWhenVersionUnavailable()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = a.addDependency( "b", "1.0" );
-        a.addDependency( "c", "[2.0,]" );
-        b.addDependency( "c", "[1.0,]" );
+    void testUnboundedRangeWhenVersionUnavailable()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = a.addDependency("b", "1.0");
+        a.addDependency("c", "[2.0,]");
+        b.addDependency("c", "[1.0,]");
 
-        ArtifactResolutionResult res = collect( a );
+        ArtifactResolutionResult res = collect(a);
 
-        assertTrue( res.hasVersionRangeViolations() );
+        assertTrue(res.hasVersionRangeViolations());
     }
 
     @Test
-    public void testUnboundedRangeBelowLastRelease()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        createArtifactSpec( "c", "1.5" );
-        ArtifactSpec c = createArtifactSpec( "c", "2.0" );
-        createArtifactSpec( "c", "1.1" );
-        a.addDependency( "c", "[1.0,)" );
+    void testUnboundedRangeBelowLastRelease() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        createArtifactSpec("c", "1.5");
+        ArtifactSpec c = createArtifactSpec("c", "2.0");
+        createArtifactSpec("c", "1.1");
+        a.addDependency("c", "[1.0,)");
 
-        ArtifactResolutionResult res = collect( a );
+        ArtifactResolutionResult res = collect(a);
 
-        assertEquals( createSet( new Object[] { a.artifact, c.artifact } ), res.getArtifacts(), "Check artifact list" );
-        assertEquals( "2.0", getArtifact( "c", res.getArtifacts() ).getVersion(), "Check version" );
+        assertEquals(createSet(new Object[] {a.artifact, c.artifact}), res.getArtifacts(), "Check artifact list");
+        assertEquals("2.0", getArtifact("c", res.getArtifacts()).getVersion(), "Check version");
     }
 
     @Test
-    public void testUnboundedRangeAboveLastRelease()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        createArtifactSpec( "c", "2.0" );
-        a.addDependency( "c", "[10.0,)" );
+    void testUnboundedRangeAboveLastRelease() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        createArtifactSpec("c", "2.0");
+        a.addDependency("c", "[10.0,)");
 
-        ArtifactResolutionResult res = collect( a );
+        ArtifactResolutionResult res = collect(a);
 
-        assertTrue( res.hasVersionRangeViolations() );
+        assertTrue(res.hasVersionRangeViolations());
     }
 
     @Test
-    public void testResolveManagedVersion()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        a.addDependency( "b", "3.0", Artifact.SCOPE_RUNTIME );
+    void testResolveManagedVersion() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        a.addDependency("b", "3.0", Artifact.SCOPE_RUNTIME);
 
-        Artifact managedVersion = createArtifactSpec( "b", "5.0" ).artifact;
-        Artifact modifiedB = createArtifactSpec( "b", "5.0", Artifact.SCOPE_RUNTIME ).artifact;
+        Artifact managedVersion = createArtifactSpec("b", "5.0").artifact;
+        Artifact modifiedB = createArtifactSpec("b", "5.0", Artifact.SCOPE_RUNTIME).artifact;
 
-        ArtifactResolutionResult res = collect( a, managedVersion );
-        assertEquals( createSet( new Object[] { a.artifact, modifiedB } ), res.getArtifacts(), "Check artifact list" );
+        ArtifactResolutionResult res = collect(a, managedVersion);
+        assertEquals(createSet(new Object[] {a.artifact, modifiedB}), res.getArtifacts(), "Check artifact list");
     }
 
     @Test
-    public void testCollectChangesVersionOfOriginatingArtifactIfInDependencyManagementHasDifferentVersion()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
+    void testCollectChangesVersionOfOriginatingArtifactIfInDependencyManagementHasDifferentVersion()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
 
         Artifact artifact = projectArtifact.artifact;
-        Artifact managedVersion = createArtifactSpec( artifact.getArtifactId(), "2.0" ).artifact;
+        Artifact managedVersion = createArtifactSpec(artifact.getArtifactId(), "2.0").artifact;
 
-        ArtifactResolutionResult result = collect( a, managedVersion );
+        ArtifactResolutionResult result = collect(a, managedVersion);
 
-        assertEquals( "1.0", artifact.getVersion(), "collect has modified version in originating artifact" );
+        assertEquals("1.0", artifact.getVersion(), "collect has modified version in originating artifact");
 
         Artifact resolvedArtifact = result.getArtifacts().iterator().next();
 
-        assertEquals( "1.0", resolvedArtifact.getVersion(), "Resolved version don't match original artifact version" );
+        assertEquals("1.0", resolvedArtifact.getVersion(), "Resolved version don't match original artifact version");
     }
 
     @Test
-    public void testResolveCompileScopeOverTestScope()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_TEST );
+    void testResolveCompileScopeOverTestScope()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_TEST);
 
-        a.addDependency( "c", "2.0", Artifact.SCOPE_COMPILE );
+        a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
 
-        Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_COMPILE ).artifact;
+        Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
-        Artifact artifact = getArtifact( "c", res.getArtifacts() );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
+        Artifact artifact = getArtifact("c", res.getArtifacts());
         // local wins now, and irrelevant if not local as test/provided aren't transitive
         // assertEquals( Artifact.SCOPE_COMPILE, artifact.getArtifactScope(), "Check artifactScope" );
-        assertEquals( Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope" );
+        assertEquals(Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope");
     }
 
     @Test
-    public void testResolveRuntimeScopeOverTestScope()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_TEST );
+    void testResolveRuntimeScopeOverTestScope()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_TEST);
 
-        a.addDependency( "c", "2.0", Artifact.SCOPE_RUNTIME );
+        a.addDependency("c", "2.0", Artifact.SCOPE_RUNTIME);
 
-        Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_RUNTIME ).artifact;
+        Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_RUNTIME).artifact;
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
-        Artifact artifact = getArtifact( "c", res.getArtifacts() );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
+        Artifact artifact = getArtifact("c", res.getArtifacts());
         // local wins now, and irrelevant if not local as test/provided aren't transitive
         // assertEquals( Artifact.SCOPE_RUNTIME, artifact.getArtifactScope(), "Check artifactScope" );
-        assertEquals( Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope" );
+        assertEquals(Artifact.SCOPE_TEST, artifact.getScope(), "Check artifactScope");
     }
 
     @Test
-    public void testResolveCompileScopeOverRuntimeScope()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec root = createArtifactSpec( "root", "1.0" );
-        ArtifactSpec a = root.addDependency( "a", "1.0" );
-        root.addDependency( "c", "3.0", Artifact.SCOPE_RUNTIME );
+    void testResolveCompileScopeOverRuntimeScope()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec root = createArtifactSpec("root", "1.0");
+        ArtifactSpec a = root.addDependency("a", "1.0");
+        root.addDependency("c", "3.0", Artifact.SCOPE_RUNTIME);
 
-        a.addDependency( "c", "2.0", Artifact.SCOPE_COMPILE );
+        a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
 
-        Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_COMPILE ).artifact;
+        Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { root.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, root.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
-        Artifact artifact = getArtifact( "c", res.getArtifacts() );
-        assertEquals( Artifact.SCOPE_COMPILE, artifact.getScope(), "Check artifactScope" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {root.artifact}));
+        assertEquals(
+                createSet(new Object[] {a.artifact, root.artifact, modifiedC}),
+                res.getArtifacts(),
+                "Check artifact list");
+        Artifact artifact = getArtifact("c", res.getArtifacts());
+        assertEquals(Artifact.SCOPE_COMPILE, artifact.getScope(), "Check artifactScope");
     }
 
     @Test
-    public void testResolveCompileScopeOverProvidedScope()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_PROVIDED );
+    void testResolveCompileScopeOverProvidedScope()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_PROVIDED);
 
-        a.addDependency( "c", "2.0", Artifact.SCOPE_COMPILE );
+        a.addDependency("c", "2.0", Artifact.SCOPE_COMPILE);
 
-        Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_COMPILE ).artifact;
+        Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_COMPILE).artifact;
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
-        Artifact artifact = getArtifact( "c", res.getArtifacts() );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
+        Artifact artifact = getArtifact("c", res.getArtifacts());
         // local wins now, and irrelevant if not local as test/provided aren't transitive
         // assertEquals( Artifact.SCOPE_COMPILE, artifact.getArtifactScope(), "Check artifactScope" );
-        assertEquals( Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope" );
+        assertEquals(Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope");
     }
 
     @Test
-    public void testResolveRuntimeScopeOverProvidedScope()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec c = createArtifactSpec( "c", "3.0", Artifact.SCOPE_PROVIDED );
+    void testResolveRuntimeScopeOverProvidedScope()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec c = createArtifactSpec("c", "3.0", Artifact.SCOPE_PROVIDED);
 
-        a.addDependency( "c", "2.0", Artifact.SCOPE_RUNTIME );
+        a.addDependency("c", "2.0", Artifact.SCOPE_RUNTIME);
 
-        Artifact modifiedC = createArtifactSpec( "c", "3.0", Artifact.SCOPE_RUNTIME ).artifact;
+        Artifact modifiedC = createArtifactSpec("c", "3.0", Artifact.SCOPE_RUNTIME).artifact;
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, c.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, modifiedC } ), res.getArtifacts(), "Check artifact list" );
-        Artifact artifact = getArtifact( "c", res.getArtifacts() );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, c.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, modifiedC}), res.getArtifacts(), "Check artifact list");
+        Artifact artifact = getArtifact("c", res.getArtifacts());
         // local wins now, and irrelevant if not local as test/provided aren't transitive
         // assertEquals( Artifact.SCOPE_RUNTIME, artifact.getArtifactScope(), "Check artifactScope" );
-        assertEquals( Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope" );
+        assertEquals(Artifact.SCOPE_PROVIDED, artifact.getScope(), "Check artifactScope");
     }
 
     @Test
-    public void testProvidedScopeNotTransitive()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0", Artifact.SCOPE_PROVIDED );
-        ArtifactSpec b = createArtifactSpec( "b", "1.0" );
-        b.addDependency( "c", "3.0", Artifact.SCOPE_PROVIDED );
+    void testProvidedScopeNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0", Artifact.SCOPE_PROVIDED);
+        ArtifactSpec b = createArtifactSpec("b", "1.0");
+        b.addDependency("c", "3.0", Artifact.SCOPE_PROVIDED);
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
     }
 
     @Test
-    public void testOptionalNotTransitive()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = createArtifactSpec( "b", "1.0" );
-        b.addDependency( "c", "3.0", true );
+    void testOptionalNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = createArtifactSpec("b", "1.0");
+        b.addDependency("c", "3.0", true);
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
     }
 
     @Test
-    public void testOptionalIncludedAtRoot()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
+    void testOptionalIncludedAtRoot() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
 
-        ArtifactSpec b = createArtifactSpec( "b", "1.0", true );
+        ArtifactSpec b = createArtifactSpec("b", "1.0", true);
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
     }
 
     @Test
-    public void testScopeUpdate()
-        throws InvalidVersionSpecificationException, ArtifactResolutionException
-    {
+    void testScopeUpdate() throws InvalidVersionSpecificationException, ArtifactResolutionException {
         /* farthest = compile */
-        checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE );
+        checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_COMPILE, Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE);
 
         /* farthest = provided */
-        checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED );
-        checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
-        checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
-        checkScopeUpdate( Artifact.SCOPE_PROVIDED, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST );
+        checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
+        checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
+        checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
+        checkScopeUpdate(Artifact.SCOPE_PROVIDED, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
 
         /* farthest = runtime */
-        checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME );
-        checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
-        checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
-        checkScopeUpdate( Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME );
+        checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME);
+        checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
+        checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
+        checkScopeUpdate(Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME);
 
         /* farthest = system */
-        checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED );
-        checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
-        checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
-        checkScopeUpdate( Artifact.SCOPE_SYSTEM, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST );
+        checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
+        checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
+        checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
+        checkScopeUpdate(Artifact.SCOPE_SYSTEM, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
 
         /* farthest = test */
-        checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE );
-        checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED );
-        checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME );
-        checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM );
-        checkScopeUpdate( Artifact.SCOPE_TEST, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST );
+        checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_COMPILE, Artifact.SCOPE_COMPILE);
+        checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_PROVIDED);
+        checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_RUNTIME, Artifact.SCOPE_RUNTIME);
+        checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_SYSTEM);
+        checkScopeUpdate(Artifact.SCOPE_TEST, Artifact.SCOPE_TEST, Artifact.SCOPE_TEST);
     }
 
-    private void checkScopeUpdate( String farthestScope, String nearestScope, String expectedScope )
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        checkScopeUpdateDirect( farthestScope, nearestScope, expectedScope );
-        checkScopeUpdateTransitively( farthestScope, nearestScope, expectedScope );
+    private void checkScopeUpdate(String farthestScope, String nearestScope, String expectedScope)
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        checkScopeUpdateDirect(farthestScope, nearestScope, expectedScope);
+        checkScopeUpdateTransitively(farthestScope, nearestScope, expectedScope);
     }
 
-    private void checkScopeUpdateTransitively( String farthestScope, String nearestScope, String expectedScope )
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = createArtifactSpec( "b", "1.0", nearestScope );
-        ArtifactSpec c = createArtifactSpec( "c", "1.0" );
-        a.addDependency( c );
-        ArtifactSpec dNearest = createArtifactSpec( "d", "2.0" );
-        b.addDependency( dNearest );
-        ArtifactSpec dFarthest = createArtifactSpec( "d", "3.0", farthestScope );
-        c.addDependency( dFarthest );
+    private void checkScopeUpdateTransitively(String farthestScope, String nearestScope, String expectedScope)
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = createArtifactSpec("b", "1.0", nearestScope);
+        ArtifactSpec c = createArtifactSpec("c", "1.0");
+        a.addDependency(c);
+        ArtifactSpec dNearest = createArtifactSpec("d", "2.0");
+        b.addDependency(dNearest);
+        ArtifactSpec dFarthest = createArtifactSpec("d", "3.0", farthestScope);
+        c.addDependency(dFarthest);
 
         /* system and provided dependencies are not transitive */
-        if ( !Artifact.SCOPE_SYSTEM.equals( nearestScope ) && !Artifact.SCOPE_PROVIDED.equals( nearestScope ) )
-        {
-            checkScopeUpdate( a, b, expectedScope, "2.0" );
+        if (!Artifact.SCOPE_SYSTEM.equals(nearestScope) && !Artifact.SCOPE_PROVIDED.equals(nearestScope)) {
+            checkScopeUpdate(a, b, expectedScope, "2.0");
         }
     }
 
-    private void checkScopeUpdateDirect( String farthestScope, String nearestScope, String expectedScope )
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = createArtifactSpec( "b", "1.0" );
-        ArtifactSpec c = createArtifactSpec( "c", "1.0" );
-        a.addDependency( c );
-        ArtifactSpec dNearest = createArtifactSpec( "d", "2.0", nearestScope );
-        b.addDependency( dNearest );
-        ArtifactSpec dFarthest = createArtifactSpec( "d", "3.0", farthestScope );
-        c.addDependency( dFarthest );
+    private void checkScopeUpdateDirect(String farthestScope, String nearestScope, String expectedScope)
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = createArtifactSpec("b", "1.0");
+        ArtifactSpec c = createArtifactSpec("c", "1.0");
+        a.addDependency(c);
+        ArtifactSpec dNearest = createArtifactSpec("d", "2.0", nearestScope);
+        b.addDependency(dNearest);
+        ArtifactSpec dFarthest = createArtifactSpec("d", "3.0", farthestScope);
+        c.addDependency(dFarthest);
 
-        checkScopeUpdate( a, b, expectedScope, "2.0" );
+        checkScopeUpdate(a, b, expectedScope, "2.0");
     }
 
-    private void checkScopeUpdate( ArtifactSpec a, ArtifactSpec b, String expectedScope, String expectedVersion )
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
+    private void checkScopeUpdate(ArtifactSpec a, ArtifactSpec b, String expectedScope, String expectedVersion)
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
         ScopeArtifactFilter filter;
-        if ( Artifact.SCOPE_PROVIDED.equals( expectedScope ) )
-        {
-            filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE );
-        }
-        else if ( Artifact.SCOPE_SYSTEM.equals( expectedScope ) )
-        {
-            filter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE );
-        }
-        else
-        {
-            filter = new ScopeArtifactFilter( expectedScope );
+        if (Artifact.SCOPE_PROVIDED.equals(expectedScope)) {
+            filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE);
+        } else if (Artifact.SCOPE_SYSTEM.equals(expectedScope)) {
+            filter = new ScopeArtifactFilter(Artifact.SCOPE_COMPILE);
+        } else {
+            filter = new ScopeArtifactFilter(expectedScope);
         }
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ), filter );
-        Artifact artifact = getArtifact( "d", res.getArtifacts() );
-        assertNotNull( artifact, "MNG-1895 Dependency was not added to resolution" );
-        assertEquals( expectedScope, artifact.getScope(), "Check artifactScope" );
-        assertEquals( expectedVersion, artifact.getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}), filter);
+        Artifact artifact = getArtifact("d", res.getArtifacts());
+        assertNotNull(artifact, "MNG-1895 Dependency was not added to resolution");
+        assertEquals(expectedScope, artifact.getScope(), "Check artifactScope");
+        assertEquals(expectedVersion, artifact.getVersion(), "Check version");
 
-        ArtifactSpec d = createArtifactSpec( "d", "1.0" );
-        res = collect( createSet( new Object[] { a.artifact, b.artifact, d.artifact } ), filter );
-        artifact = getArtifact( "d", res.getArtifacts() );
-        assertNotNull( artifact, "MNG-1895 Dependency was not added to resolution" );
-        assertEquals( d.artifact.getScope(), artifact.getScope(), "Check artifactScope" );
-        assertEquals( "1.0", artifact.getVersion(), "Check version" );
+        ArtifactSpec d = createArtifactSpec("d", "1.0");
+        res = collect(createSet(new Object[] {a.artifact, b.artifact, d.artifact}), filter);
+        artifact = getArtifact("d", res.getArtifacts());
+        assertNotNull(artifact, "MNG-1895 Dependency was not added to resolution");
+        assertEquals(d.artifact.getScope(), artifact.getScope(), "Check artifactScope");
+        assertEquals("1.0", artifact.getVersion(), "Check version");
     }
 
     @Test
     @Disabled
-    public void testOptionalNotTransitiveButVersionIsInfluential()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        ArtifactSpec b = createArtifactSpec( "b", "1.0" );
-        b.addDependency( "c", "3.0", true );
-        ArtifactSpec d = a.addDependency( "d", "1.0" );
-        ArtifactSpec e = d.addDependency( "e", "1.0" );
-        e.addDependency( "c", "2.0" );
+    void testOptionalNotTransitiveButVersionIsInfluential()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        ArtifactSpec b = createArtifactSpec("b", "1.0");
+        b.addDependency("c", "3.0", true);
+        ArtifactSpec d = a.addDependency("d", "1.0");
+        ArtifactSpec e = d.addDependency("e", "1.0");
+        e.addDependency("c", "2.0");
 
-        ArtifactSpec c = createArtifactSpec( "c", "3.0" );
+        ArtifactSpec c = createArtifactSpec("c", "3.0");
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact, c.artifact, d.artifact, e.artifact } ), res.getArtifacts(), "Check artifact list" );
-        Artifact artifact = getArtifact( "c", res.getArtifacts() );
-        assertEquals( "3.0", artifact.getVersion(), "Check version" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(
+                createSet(new Object[] {a.artifact, b.artifact, c.artifact, d.artifact, e.artifact}),
+                res.getArtifacts(),
+                "Check artifact list");
+        Artifact artifact = getArtifact("c", res.getArtifacts());
+        assertEquals("3.0", artifact.getVersion(), "Check version");
     }
 
     @Test
-    public void testTestScopeNotTransitive()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0", Artifact.SCOPE_TEST );
-        ArtifactSpec b = createArtifactSpec( "b", "1.0" );
-        b.addDependency( "c", "3.0", Artifact.SCOPE_TEST );
+    void testTestScopeNotTransitive() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0", Artifact.SCOPE_TEST);
+        ArtifactSpec b = createArtifactSpec("b", "1.0");
+        b.addDependency("c", "3.0", Artifact.SCOPE_TEST);
 
-        ArtifactResolutionResult res = collect( createSet( new Object[] { a.artifact, b.artifact } ) );
-        assertEquals( createSet( new Object[] { a.artifact, b.artifact } ), res.getArtifacts(), "Check artifact list" );
+        ArtifactResolutionResult res = collect(createSet(new Object[] {a.artifact, b.artifact}));
+        assertEquals(createSet(new Object[] {a.artifact, b.artifact}), res.getArtifacts(), "Check artifact list");
     }
 
     @Test
-    public void testSnapshotNotIncluded()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        a.addDependency( "b", "[1.0,)" );
-        createArtifactSpec( "b", "1.0-SNAPSHOT" );
+    void testSnapshotNotIncluded() throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        a.addDependency("b", "[1.0,)");
+        createArtifactSpec("b", "1.0-SNAPSHOT");
 
-        ArtifactResolutionResult res = collect( a );
+        ArtifactResolutionResult res = collect(a);
 
-        assertTrue( res.hasVersionRangeViolations() );
+        assertTrue(res.hasVersionRangeViolations());
 
         /*
          * try { ArtifactResolutionResult res = collect( a ); fail( "Expected b not to resolve: " + res ); } catch (
@@ -712,281 +674,258 @@
 
     @Test
     @Disabled("that one does not work")
-    public void testOverConstrainedVersionException()
-        throws ArtifactResolutionException, InvalidVersionSpecificationException
-    {
-        ArtifactSpec a = createArtifactSpec( "a", "1.0" );
-        a.addDependency( "b", "[1.0, 2.0)" );
-        a.addDependency( "c", "[3.3.0,4.0.0)" );
+    void testOverConstrainedVersionException()
+            throws ArtifactResolutionException, InvalidVersionSpecificationException {
+        ArtifactSpec a = createArtifactSpec("a", "1.0");
+        a.addDependency("b", "[1.0, 2.0)");
+        a.addDependency("c", "[3.3.0,4.0.0)");
 
-        ArtifactSpec b = createArtifactSpec( "b", "1.0.0" );
-        b.addDependency( "c", "3.3.0-v3346" );
+        ArtifactSpec b = createArtifactSpec("b", "1.0.0");
+        b.addDependency("c", "3.3.0-v3346");
 
-        ArtifactSpec c = createArtifactSpec( "c", "3.2.1-v3235e" );
+        ArtifactSpec c = createArtifactSpec("c", "3.2.1-v3235e");
 
         OverConstrainedVersionException e = assertThrows(
-                OverConstrainedVersionException.class,
-                () -> collect( createSet( new Object[] { a.artifact } ) ) );
-        assertTrue( e.getMessage().contains( "[3.2.1-v3235e, 3.3.0-v3346]" ), "Versions unordered" );
-        assertTrue( e.getMessage().contains( "Path to dependency:" ), "DependencyTrail unresolved" );
+                OverConstrainedVersionException.class, () -> collect(createSet(new Object[] {a.artifact})));
+        assertTrue(e.getMessage().contains("[3.2.1-v3235e, 3.3.0-v3346]"), "Versions unordered");
+        assertTrue(e.getMessage().contains("Path to dependency:"), "DependencyTrail unresolved");
     }
 
-    private Artifact getArtifact( String id, Set artifacts )
-    {
-        for ( Object artifact : artifacts )
-        {
+    private Artifact getArtifact(String id, Set artifacts) {
+        for (Object artifact : artifacts) {
             Artifact a = (Artifact) artifact;
-            if ( a.getArtifactId().equals( id ) && a.getGroupId().equals( GROUP_ID ) )
-            {
+            if (a.getArtifactId().equals(id) && a.getGroupId().equals(GROUP_ID)) {
                 return a;
             }
         }
         return null;
     }
 
-    private ArtifactResolutionResult collect( Set<Artifact> artifacts )
-        throws ArtifactResolutionException
-    {
-        return collect( artifacts, null );
+    private ArtifactResolutionResult collect(Set<Artifact> artifacts) throws ArtifactResolutionException {
+        return collect(artifacts, null);
     }
 
-    private ArtifactResolutionResult collect( Set<Artifact> artifacts, ArtifactFilter filter )
-        throws ArtifactResolutionException
-    {
-        return artifactCollector.collect( artifacts, projectArtifact.artifact, null, null, null, source, filter,
-                                          Collections.emptyList(), null );
+    private ArtifactResolutionResult collect(Set<Artifact> artifacts, ArtifactFilter filter)
+            throws ArtifactResolutionException {
+        return artifactCollector.collect(
+                artifacts, projectArtifact.artifact, null, null, null, source, filter, Collections.emptyList(), null);
     }
 
-    private ArtifactResolutionResult collect( ArtifactSpec a )
-        throws ArtifactResolutionException
-    {
-        return artifactCollector.collect( Collections.singleton( a.artifact ), projectArtifact.artifact, null, null,
-                                          null, source, null, Collections.emptyList(), null );
+    private ArtifactResolutionResult collect(ArtifactSpec a) throws ArtifactResolutionException {
+        return artifactCollector.collect(
+                Collections.singleton(a.artifact),
+                projectArtifact.artifact,
+                null,
+                null,
+                null,
+                source,
+                null,
+                Collections.emptyList(),
+                null);
     }
 
-    private ArtifactResolutionResult collect( ArtifactSpec a, ArtifactFilter filter )
-        throws ArtifactResolutionException
-    {
-        return artifactCollector.collect( Collections.singleton( a.artifact ), projectArtifact.artifact, null, null,
-                                          null, source, filter, Collections.emptyList(), null );
+    private ArtifactResolutionResult collect(ArtifactSpec a, ArtifactFilter filter) throws ArtifactResolutionException {
+        return artifactCollector.collect(
+                Collections.singleton(a.artifact),
+                projectArtifact.artifact,
+                null,
+                null,
+                null,
+                source,
+                filter,
+                Collections.emptyList(),
+                null);
     }
 
-    private ArtifactResolutionResult collect( ArtifactSpec a, Artifact managedVersion )
-        throws ArtifactResolutionException
-    {
-        Map<String, Artifact> managedVersions = Collections.singletonMap( managedVersion.getDependencyConflictId(), managedVersion );
-        return artifactCollector.collect( Collections.singleton( a.artifact ), projectArtifact.artifact,
-                                          managedVersions, null, null, source, null, Collections.emptyList(), null );
+    private ArtifactResolutionResult collect(ArtifactSpec a, Artifact managedVersion)
+            throws ArtifactResolutionException {
+        Map<String, Artifact> managedVersions =
+                Collections.singletonMap(managedVersion.getDependencyConflictId(), managedVersion);
+        return artifactCollector.collect(
+                Collections.singleton(a.artifact),
+                projectArtifact.artifact,
+                managedVersions,
+                null,
+                null,
+                source,
+                null,
+                Collections.emptyList(),
+                null);
     }
 
-    private ArtifactSpec createArtifactSpec( String id, String version )
-        throws InvalidVersionSpecificationException
-    {
-        return createArtifactSpec( id, version, Artifact.SCOPE_COMPILE );
+    private ArtifactSpec createArtifactSpec(String id, String version) throws InvalidVersionSpecificationException {
+        return createArtifactSpec(id, version, Artifact.SCOPE_COMPILE);
     }
 
-    private ArtifactSpec createArtifactSpec( String id, String version, boolean optional )
-        throws InvalidVersionSpecificationException
-    {
-        return createArtifactSpec( id, version, Artifact.SCOPE_COMPILE, null, optional );
+    private ArtifactSpec createArtifactSpec(String id, String version, boolean optional)
+            throws InvalidVersionSpecificationException {
+        return createArtifactSpec(id, version, Artifact.SCOPE_COMPILE, null, optional);
     }
 
-    private ArtifactSpec createArtifactSpec( String id, String version, String scope )
-        throws InvalidVersionSpecificationException
-    {
-        return createArtifactSpec( id, version, scope, null, false );
+    private ArtifactSpec createArtifactSpec(String id, String version, String scope)
+            throws InvalidVersionSpecificationException {
+        return createArtifactSpec(id, version, scope, null, false);
     }
 
-    private ArtifactSpec createArtifactSpec( String id, String version, String scope, String inheritedScope,
-                                             boolean optional )
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange versionRange = VersionRange.createFromVersionSpec( version );
-        Artifact artifact =
-            artifactFactory.createDependencyArtifact( GROUP_ID, id, versionRange, "jar", null, scope, inheritedScope,
-                                                      optional );
+    private ArtifactSpec createArtifactSpec(
+            String id, String version, String scope, String inheritedScope, boolean optional)
+            throws InvalidVersionSpecificationException {
+        VersionRange versionRange = VersionRange.createFromVersionSpec(version);
+        Artifact artifact = artifactFactory.createDependencyArtifact(
+                GROUP_ID, id, versionRange, "jar", null, scope, inheritedScope, optional);
         ArtifactSpec spec = null;
-        if ( artifact != null )
-        {
+        if (artifact != null) {
             spec = new ArtifactSpec();
             spec.artifact = artifact;
-            source.addArtifact( spec );
+            source.addArtifact(spec);
         }
         return spec;
     }
 
-    @SuppressWarnings( "unchecked" )
-    private static Set<Artifact> createSet( Object[] x )
-    {
-        return new LinkedHashSet( Arrays.asList( x ) );
+    @SuppressWarnings("unchecked")
+    private static Set<Artifact> createSet(Object[] x) {
+        return new LinkedHashSet(Arrays.asList(x));
     }
 
-    private class ArtifactSpec
-    {
+    private class ArtifactSpec {
         private Artifact artifact;
 
         private Set<Artifact> dependencies = new HashSet<>();
 
-        public ArtifactSpec addDependency( String id, String version )
-            throws InvalidVersionSpecificationException
-        {
-            return addDependency( id, version, Artifact.SCOPE_COMPILE );
+        public ArtifactSpec addDependency(String id, String version) throws InvalidVersionSpecificationException {
+            return addDependency(id, version, Artifact.SCOPE_COMPILE);
         }
 
-        public ArtifactSpec addDependency( String id, String version, String scope )
-            throws InvalidVersionSpecificationException
-        {
-            return addDependency( id, version, scope, false );
+        public ArtifactSpec addDependency(String id, String version, String scope)
+                throws InvalidVersionSpecificationException {
+            return addDependency(id, version, scope, false);
         }
 
-        private ArtifactSpec addDependency( ArtifactSpec dep )
-            throws InvalidVersionSpecificationException
-        {
-            if ( dep != null )
-            {
-                dependencies.add( dep.artifact );
+        private ArtifactSpec addDependency(ArtifactSpec dep) throws InvalidVersionSpecificationException {
+            if (dep != null) {
+                dependencies.add(dep.artifact);
             }
             return dep;
         }
 
-        private ArtifactSpec addDependency( String id, String version, String scope, boolean optional )
-            throws InvalidVersionSpecificationException
-        {
-            ArtifactSpec dep = createArtifactSpec( id, version, scope, artifact.getScope(), optional );
-            return addDependency( dep );
+        private ArtifactSpec addDependency(String id, String version, String scope, boolean optional)
+                throws InvalidVersionSpecificationException {
+            ArtifactSpec dep = createArtifactSpec(id, version, scope, artifact.getScope(), optional);
+            return addDependency(dep);
         }
 
-        public ArtifactSpec addDependency( String id, String version, boolean optional )
-            throws InvalidVersionSpecificationException
-        {
-            return addDependency( id, version, Artifact.SCOPE_COMPILE, optional );
+        public ArtifactSpec addDependency(String id, String version, boolean optional)
+                throws InvalidVersionSpecificationException {
+            return addDependency(id, version, Artifact.SCOPE_COMPILE, optional);
         }
     }
 
-    private class Source
-        implements ArtifactMetadataSource
-    {
+    private class Source implements ArtifactMetadataSource {
         private Map<String, ArtifactSpec> artifacts = new HashMap<>();
 
         private Map<String, List<ArtifactVersion>> versions = new HashMap<>();
 
-        public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                                         List<ArtifactRepository> remoteRepositories )
-            throws ArtifactMetadataRetrievalException
-        {
-            String key = getKey( artifact );
+        public ResolutionGroup retrieve(
+                Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+                throws ArtifactMetadataRetrievalException {
+            String key = getKey(artifact);
 
-            ArtifactSpec a = (ArtifactSpec) artifacts.get( key );
-            try
-            {
-                return new ResolutionGroup( artifact, createArtifacts( artifactFactory, a.dependencies,
-                                                                       artifact.getScope(),
-                                                                       artifact.getDependencyFilter() ),
-                                            Collections.emptyList() );
-            }
-            catch ( InvalidVersionSpecificationException e )
-            {
-                throw new ArtifactMetadataRetrievalException( "Invalid version creating artifacts", e, artifact );
+            ArtifactSpec a = (ArtifactSpec) artifacts.get(key);
+            try {
+                return new ResolutionGroup(
+                        artifact,
+                        createArtifacts(
+                                artifactFactory, a.dependencies, artifact.getScope(), artifact.getDependencyFilter()),
+                        Collections.emptyList());
+            } catch (InvalidVersionSpecificationException e) {
+                throw new ArtifactMetadataRetrievalException("Invalid version creating artifacts", e, artifact);
             }
         }
 
-        private String getKey( Artifact artifact )
-        {
+        private String getKey(Artifact artifact) {
             return artifact.getDependencyConflictId();
         }
 
-        private Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, Set<Artifact> dependencies, String inheritedScope,
-                                     ArtifactFilter dependencyFilter )
-            throws InvalidVersionSpecificationException
-        {
+        private Set<Artifact> createArtifacts(
+                ArtifactFactory artifactFactory,
+                Set<Artifact> dependencies,
+                String inheritedScope,
+                ArtifactFilter dependencyFilter)
+                throws InvalidVersionSpecificationException {
             Set<Artifact> projectArtifacts = new HashSet<>();
 
-            for ( Artifact d : dependencies )
-            {
+            for (Artifact d : dependencies) {
                 VersionRange versionRange;
-                if ( d.getVersionRange() != null )
-                {
+                if (d.getVersionRange() != null) {
                     versionRange = d.getVersionRange();
-                }
-                else
-                {
-                    versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
+                } else {
+                    versionRange = VersionRange.createFromVersionSpec(d.getVersion());
                 }
                 Artifact artifact;
-                if ( d.getScope().equals( Artifact.SCOPE_TEST ) || d.getScope().equals( Artifact.SCOPE_PROVIDED ) )
-                {
+                if (d.getScope().equals(Artifact.SCOPE_TEST) || d.getScope().equals(Artifact.SCOPE_PROVIDED)) {
                     /* don't call createDependencyArtifact as it'll ignore test and provided scopes */
-                    artifact =
-                        artifactFactory.createArtifact( d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getScope(),
-                                                        d.getType() );
-                }
-                else
-                {
-                    artifact =
-                        artifactFactory.createDependencyArtifact( d.getGroupId(), d.getArtifactId(), versionRange,
-                                                                  d.getType(), d.getClassifier(), d.getScope(),
-                                                                  inheritedScope, d.isOptional() );
+                    artifact = artifactFactory.createArtifact(
+                            d.getGroupId(), d.getArtifactId(), d.getVersion(), d.getScope(), d.getType());
+                } else {
+                    artifact = artifactFactory.createDependencyArtifact(
+                            d.getGroupId(),
+                            d.getArtifactId(),
+                            versionRange,
+                            d.getType(),
+                            d.getClassifier(),
+                            d.getScope(),
+                            inheritedScope,
+                            d.isOptional());
                 }
 
-                if ( artifact != null && ( dependencyFilter == null || dependencyFilter.include( artifact ) ) )
-                {
-                    artifact.setDependencyFilter( dependencyFilter );
+                if (artifact != null && (dependencyFilter == null || dependencyFilter.include(artifact))) {
+                    artifact.setDependencyFilter(dependencyFilter);
 
-                    projectArtifacts.add( artifact );
+                    projectArtifacts.add(artifact);
                 }
             }
 
             return projectArtifacts;
         }
 
-        public void addArtifact( ArtifactSpec spec )
-        {
-            artifacts.put( getKey( spec.artifact ), spec );
+        public void addArtifact(ArtifactSpec spec) {
+            artifacts.put(getKey(spec.artifact), spec);
 
             String key = spec.artifact.getDependencyConflictId();
-            List<ArtifactVersion> artifactVersions = versions.computeIfAbsent( key, k -> new ArrayList<>() );
-            if ( spec.artifact.getVersion() != null )
-            {
-                artifactVersions.add( new DefaultArtifactVersion( spec.artifact.getVersion() ) );
+            List<ArtifactVersion> artifactVersions = versions.computeIfAbsent(key, k -> new ArrayList<>());
+            if (spec.artifact.getVersion() != null) {
+                artifactVersions.add(new DefaultArtifactVersion(spec.artifact.getVersion()));
             }
         }
 
-        public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
-                                                                List<ArtifactRepository> remoteRepositories )
-            throws ArtifactMetadataRetrievalException
-        {
-            return retrieveAvailableVersions( artifact );
+        public List<ArtifactVersion> retrieveAvailableVersions(
+                Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+                throws ArtifactMetadataRetrievalException {
+            return retrieveAvailableVersions(artifact);
         }
 
         public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
-                                                                                        Artifact artifact,
-                                                                                        ArtifactRepository localRepository,
-                                                                                        ArtifactRepository remoteRepository )
-            throws ArtifactMetadataRetrievalException
-        {
-            return retrieveAvailableVersions( artifact );
+                Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+                throws ArtifactMetadataRetrievalException {
+            return retrieveAvailableVersions(artifact);
         }
 
-        private List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact )
-        {
-            List<ArtifactVersion> artifactVersions = versions.get( artifact.getDependencyConflictId() );
-            if ( artifactVersions == null )
-            {
+        private List<ArtifactVersion> retrieveAvailableVersions(Artifact artifact) {
+            List<ArtifactVersion> artifactVersions = versions.get(artifact.getDependencyConflictId());
+            if (artifactVersions == null) {
                 artifactVersions = Collections.emptyList();
             }
             return artifactVersions;
         }
 
-        public ResolutionGroup retrieve( MetadataResolutionRequest request )
-            throws ArtifactMetadataRetrievalException
-        {
-            return retrieve( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+        public ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException {
+            return retrieve(request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
         }
 
-        public List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
-            throws ArtifactMetadataRetrievalException
-        {
-            return retrieveAvailableVersions( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+        public List<ArtifactVersion> retrieveAvailableVersions(MetadataResolutionRequest request)
+                throws ArtifactMetadataRetrievalException {
+            return retrieveAvailableVersions(
+                    request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
         }
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/AbstractConflictResolverTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/AbstractConflictResolverTest.java
index 1789339..50f2e36 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/AbstractConflictResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/AbstractConflictResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
+
+import javax.inject.Inject;
 
 import java.util.Collections;
 
@@ -27,23 +28,19 @@
 import org.apache.maven.artifact.resolver.ResolutionNode;
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 import org.apache.maven.artifact.versioning.VersionRange;
-import org.codehaus.plexus.testing.PlexusTest;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.junit.jupiter.api.BeforeEach;
 
-import javax.inject.Inject;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
  * Provides a basis for testing conflict resolvers.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  */
 @PlexusTest
-public abstract class AbstractConflictResolverTest
-{
+public abstract class AbstractConflictResolverTest {
     // constants --------------------------------------------------------------
 
     private static final String GROUP_ID = "test";
@@ -68,9 +65,7 @@
 
     // constructors -----------------------------------------------------------
 
-    public AbstractConflictResolverTest( String roleHint )
-        throws Exception
-    {
+    public AbstractConflictResolverTest(String roleHint) throws Exception {
         this.roleHint = roleHint;
     }
 
@@ -80,58 +75,50 @@
      * @see junit.framework.TestCase#setUp()
      */
     @BeforeEach
-    public void setUp()
-            throws Exception
-    {
-        conflictResolver = (ConflictResolver) container.lookup( ConflictResolver.ROLE, roleHint );
+    public void setUp() throws Exception {
+        conflictResolver = (ConflictResolver) container.lookup(ConflictResolver.ROLE, roleHint);
 
-        a1 = createArtifact( "a", "1.0" );
-        a2 = createArtifact( "a", "2.0" );
-        b1 = createArtifact( "b", "1.0" );
+        a1 = createArtifact("a", "1.0");
+        a2 = createArtifact("a", "2.0");
+        b1 = createArtifact("b", "1.0");
     }
 
     // protected methods ------------------------------------------------------
 
-    protected ConflictResolver getConflictResolver()
-    {
+    protected ConflictResolver getConflictResolver() {
         return conflictResolver;
     }
 
-    protected void assertResolveConflict( ResolutionNode expectedNode, ResolutionNode actualNode1, ResolutionNode actualNode2 )
-    {
-        ResolutionNode resolvedNode = getConflictResolver().resolveConflict( actualNode1, actualNode2 );
+    protected void assertResolveConflict(
+            ResolutionNode expectedNode, ResolutionNode actualNode1, ResolutionNode actualNode2) {
+        ResolutionNode resolvedNode = getConflictResolver().resolveConflict(actualNode1, actualNode2);
 
-        assertNotNull( resolvedNode, "Expected resolvable" );
-        assertEquals( expectedNode, resolvedNode, "Resolution node" );
+        assertNotNull(resolvedNode, "Expected resolvable");
+        assertEquals(expectedNode, resolvedNode, "Resolution node");
     }
 
-    protected Artifact createArtifact( String id, String version ) throws InvalidVersionSpecificationException
-    {
-        return createArtifact( id, version, Artifact.SCOPE_COMPILE );
+    protected Artifact createArtifact(String id, String version) throws InvalidVersionSpecificationException {
+        return createArtifact(id, version, Artifact.SCOPE_COMPILE);
     }
 
-    protected Artifact createArtifact( String id, String version, String scope )
-        throws InvalidVersionSpecificationException
-    {
-        return createArtifact( id, version, scope, null, false );
+    protected Artifact createArtifact(String id, String version, String scope)
+            throws InvalidVersionSpecificationException {
+        return createArtifact(id, version, scope, null, false);
     }
 
-    protected Artifact createArtifact( String id, String version, String scope, String inheritedScope, boolean optional )
-        throws InvalidVersionSpecificationException
-    {
-        VersionRange versionRange = VersionRange.createFromVersionSpec( version );
+    protected Artifact createArtifact(String id, String version, String scope, String inheritedScope, boolean optional)
+            throws InvalidVersionSpecificationException {
+        VersionRange versionRange = VersionRange.createFromVersionSpec(version);
 
-        return artifactFactory.createDependencyArtifact( GROUP_ID, id, versionRange, "jar", null, scope,
-                                                         inheritedScope, optional );
+        return artifactFactory.createDependencyArtifact(
+                GROUP_ID, id, versionRange, "jar", null, scope, inheritedScope, optional);
     }
 
-    protected ResolutionNode createResolutionNode( Artifact Artifact )
-    {
-        return new ResolutionNode( Artifact, Collections.<ArtifactRepository>emptyList() );
-    }
-    protected ResolutionNode createResolutionNode( Artifact Artifact, ResolutionNode parent )
-    {
-        return new ResolutionNode( Artifact, Collections.<ArtifactRepository>emptyList(), parent );
+    protected ResolutionNode createResolutionNode(Artifact Artifact) {
+        return new ResolutionNode(Artifact, Collections.<ArtifactRepository>emptyList());
     }
 
+    protected ResolutionNode createResolutionNode(Artifact Artifact, ResolutionNode parent) {
+        return new ResolutionNode(Artifact, Collections.<ArtifactRepository>emptyList(), parent);
+    }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolverTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolverTest.java
index 7b46ee3..9bba456 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/FarthestConflictResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
 import org.junit.jupiter.api.Test;
@@ -25,17 +24,12 @@
 /**
  * Tests <code>FarthestConflictResolver</code>.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @see FarthestConflictResolver
  */
-public class FarthestConflictResolverTest
-    extends AbstractConflictResolverTest
-{
+class FarthestConflictResolverTest extends AbstractConflictResolverTest {
     // constructors -----------------------------------------------------------
 
-    public FarthestConflictResolverTest()
-        throws Exception
-    {
+    public FarthestConflictResolverTest() throws Exception {
         super("farthest");
     }
 
@@ -49,13 +43,12 @@
      * </pre>
      */
     @Test
-    public void testDepth()
-    {
-        ResolutionNode a1n = createResolutionNode( a1);
-        ResolutionNode b1n = createResolutionNode( b1);
-        ResolutionNode a2n = createResolutionNode( a2,  b1n );
+    void testDepth() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
 
-        assertResolveConflict( a2n, a1n, a2n );
+        assertResolveConflict(a2n, a1n, a2n);
     }
 
     /**
@@ -66,13 +59,12 @@
      * </pre>
      */
     @Test
-    public void testDepthReversed()
-    {
-        ResolutionNode b1n = createResolutionNode( b1  );
-        ResolutionNode a2n = createResolutionNode( a2, b1n );
-        ResolutionNode a1n = createResolutionNode( a1 );
+    void testDepthReversed() {
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a2n, a2n, a1n );
+        assertResolveConflict(a2n, a2n, a1n);
     }
 
     /**
@@ -83,12 +75,11 @@
      * </pre>
      */
     @Test
-    public void testEqual()
-    {
-        ResolutionNode a1n = createResolutionNode( a1 );
-        ResolutionNode a2n = createResolutionNode( a2 );
+    void testEqual() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode a2n = createResolutionNode(a2);
 
-        assertResolveConflict( a1n, a1n, a2n );
+        assertResolveConflict(a1n, a1n, a2n);
     }
 
     /**
@@ -99,11 +90,10 @@
      * </pre>
      */
     @Test
-    public void testEqualReversed()
-    {
-        ResolutionNode a2n = createResolutionNode( a2);
-        ResolutionNode a1n = createResolutionNode( a1);
+    void testEqualReversed() {
+        ResolutionNode a2n = createResolutionNode(a2);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a2n, a2n, a1n );
+        assertResolveConflict(a2n, a2n, a1n);
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolverTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolverTest.java
index 34026bc..8157065 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NearestConflictResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
 import org.junit.jupiter.api.Test;
@@ -25,17 +24,12 @@
 /**
  * Tests <code>NearestConflictResolver</code>.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @see NearestConflictResolver
  */
-public class NearestConflictResolverTest
-    extends AbstractConflictResolverTest
-{
+class NearestConflictResolverTest extends AbstractConflictResolverTest {
     // constructors -----------------------------------------------------------
 
-    public NearestConflictResolverTest()
-        throws Exception
-    {
+    public NearestConflictResolverTest() throws Exception {
         super("nearest");
     }
 
@@ -49,13 +43,12 @@
      * </pre>
      */
     @Test
-    public void testDepth()
-    {
-        ResolutionNode a1n = createResolutionNode( a1);
-        ResolutionNode b1n = createResolutionNode( b1);
-        ResolutionNode a2n = createResolutionNode( a2, b1n );
+    void testDepth() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
 
-        assertResolveConflict( a1n, a1n, a2n );
+        assertResolveConflict(a1n, a1n, a2n);
     }
 
     /**
@@ -66,13 +59,12 @@
      * </pre>
      */
     @Test
-    public void testDepthReversed()
-    {
-        ResolutionNode b1n = createResolutionNode( b1 );
-        ResolutionNode a2n = createResolutionNode( a2, b1n );
-        ResolutionNode a1n = createResolutionNode( a1 );
+    void testDepthReversed() {
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a1n, a2n, a1n );
+        assertResolveConflict(a1n, a2n, a1n);
     }
 
     /**
@@ -83,12 +75,11 @@
      * </pre>
      */
     @Test
-    public void testEqual()
-    {
-        ResolutionNode a1n = createResolutionNode( a1 );
-        ResolutionNode a2n = createResolutionNode( a2 );
+    void testEqual() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode a2n = createResolutionNode(a2);
 
-        assertResolveConflict( a1n, a1n, a2n );
+        assertResolveConflict(a1n, a1n, a2n);
     }
 
     /**
@@ -99,11 +90,10 @@
      * </pre>
      */
     @Test
-    public void testEqualReversed()
-    {
-        ResolutionNode a2n = createResolutionNode( a2);
-        ResolutionNode a1n = createResolutionNode( a1 );
+    void testEqualReversed() {
+        ResolutionNode a2n = createResolutionNode(a2);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a2n, a2n, a1n );
+        assertResolveConflict(a2n, a2n, a1n);
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolverTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolverTest.java
index 874644a..de969d3 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
 import org.junit.jupiter.api.Test;
@@ -25,17 +24,12 @@
 /**
  * Tests <code>NewestConflictResolver</code>.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @see NewestConflictResolver
  */
-public class NewestConflictResolverTest
-    extends AbstractConflictResolverTest
-{
+class NewestConflictResolverTest extends AbstractConflictResolverTest {
     // constructors -----------------------------------------------------------
 
-    public NewestConflictResolverTest()
-        throws Exception
-    {
+    public NewestConflictResolverTest() throws Exception {
         super("newest");
     }
 
@@ -49,13 +43,12 @@
      * </pre>
      */
     @Test
-    public void testDepth()
-    {
-        ResolutionNode a1n = createResolutionNode( a1 );
-        ResolutionNode b1n = createResolutionNode( b1 );
-        ResolutionNode a2n = createResolutionNode( a2, b1n );
+    void testDepth() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
 
-        assertResolveConflict( a2n, a1n, a2n );
+        assertResolveConflict(a2n, a1n, a2n);
     }
 
     /**
@@ -66,13 +59,12 @@
      * </pre>
      */
     @Test
-    public void testDepthReversed()
-    {
-        ResolutionNode b1n = createResolutionNode( b1 );
-        ResolutionNode a2n = createResolutionNode( a2, b1n );
-        ResolutionNode a1n = createResolutionNode( a1 );
+    void testDepthReversed() {
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a2n, a2n, a1n );
+        assertResolveConflict(a2n, a2n, a1n);
     }
 
     /**
@@ -83,12 +75,11 @@
      * </pre>
      */
     @Test
-    public void testEqual()
-    {
-        ResolutionNode a1n = createResolutionNode( a1 );
-        ResolutionNode a2n = createResolutionNode( a2 );
+    void testEqual() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode a2n = createResolutionNode(a2);
 
-        assertResolveConflict( a2n, a1n, a2n );
+        assertResolveConflict(a2n, a1n, a2n);
     }
 
     /**
@@ -99,11 +90,10 @@
      * </pre>
      */
     @Test
-    public void testEqualReversed()
-    {
-        ResolutionNode a2n = createResolutionNode( a2 );
-        ResolutionNode a1n = createResolutionNode( a1 );
+    void testEqualReversed() {
+        ResolutionNode a2n = createResolutionNode(a2);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a2n, a2n, a1n );
+        assertResolveConflict(a2n, a2n, a1n);
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolverTest.java b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolverTest.java
index 76335f2..2a91b6d 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/legacy/resolver/conflict/OldestConflictResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.legacy.resolver.conflict;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.legacy.resolver.conflict;
 
 import org.apache.maven.artifact.resolver.ResolutionNode;
 import org.junit.jupiter.api.Test;
@@ -25,17 +24,12 @@
 /**
  * Tests <code>OldestConflictResolver</code>.
  *
- * @author <a href="mailto:markhobson@gmail.com">Mark Hobson</a>
  * @see OldestConflictResolver
  */
-public class OldestConflictResolverTest
-    extends AbstractConflictResolverTest
-{
+class OldestConflictResolverTest extends AbstractConflictResolverTest {
     // constructors -----------------------------------------------------------
 
-    public OldestConflictResolverTest()
-        throws Exception
-    {
+    public OldestConflictResolverTest() throws Exception {
         super("oldest");
     }
 
@@ -49,16 +43,14 @@
      * </pre>
      */
     @Test
-    public void testDepth()
-    {
-        ResolutionNode a1n = createResolutionNode( a1 );
-        ResolutionNode b1n = createResolutionNode( b1);
-        ResolutionNode a2n = createResolutionNode( a2,  b1n );
+    void testDepth() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
 
-        assertResolveConflict( a1n, a1n, a2n );
+        assertResolveConflict(a1n, a1n, a2n);
     }
 
-
     /**
      * Tests that <code>a:1.0</code> wins in the scenario:
      * <pre>
@@ -67,13 +59,12 @@
      * </pre>
      */
     @Test
-    public void testDepthReversed()
-    {
-        ResolutionNode b1n = createResolutionNode( b1 );
-        ResolutionNode a2n = createResolutionNode( a2, b1n );
-        ResolutionNode a1n = createResolutionNode( a1 );
+    void testDepthReversed() {
+        ResolutionNode b1n = createResolutionNode(b1);
+        ResolutionNode a2n = createResolutionNode(a2, b1n);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a1n, a2n, a1n );
+        assertResolveConflict(a1n, a2n, a1n);
     }
 
     /**
@@ -84,12 +75,11 @@
      * </pre>
      */
     @Test
-    public void testEqual()
-    {
-        ResolutionNode a1n = createResolutionNode( a1 );
-        ResolutionNode a2n = createResolutionNode( a2 );
+    void testEqual() {
+        ResolutionNode a1n = createResolutionNode(a1);
+        ResolutionNode a2n = createResolutionNode(a2);
 
-        assertResolveConflict( a1n, a1n, a2n );
+        assertResolveConflict(a1n, a1n, a2n);
     }
 
     /**
@@ -100,11 +90,10 @@
      * </pre>
      */
     @Test
-    public void testEqualReversed()
-    {
-        ResolutionNode a2n = createResolutionNode( a2);
-        ResolutionNode a1n = createResolutionNode( a1 );
+    void testEqualReversed() {
+        ResolutionNode a2n = createResolutionNode(a2);
+        ResolutionNode a1n = createResolutionNode(a1);
 
-        assertResolveConflict( a1n, a2n, a1n );
+        assertResolveConflict(a1n, a2n, a1n);
     }
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultClasspathTransformationTest.java b/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultClasspathTransformationTest.java
index 348dd97..f228f7b 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultClasspathTransformationTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultClasspathTransformationTest.java
@@ -1,38 +1,39 @@
-package org.apache.maven.repository.metadata;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import javax.inject.Inject;
 
 import org.apache.maven.artifact.ArtifactScopeEnum;
 import org.codehaus.plexus.testing.PlexusTest;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
  *
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
 @PlexusTest
-public class DefaultClasspathTransformationTest
-{
+class DefaultClasspathTransformationTest {
     @Inject
     ClasspathTransformation transform;
 
@@ -42,80 +43,77 @@
     MetadataGraphVertex v2;
     MetadataGraphVertex v3;
     MetadataGraphVertex v4;
-    //------------------------------------------------------------------------------------------
-	@BeforeEach
-    public void setUp() throws Exception
-    {
-        graph = new MetadataGraph( 4, 3 );
+
+    // ------------------------------------------------------------------------------------------
+    @BeforeEach
+    void setUp() throws Exception {
+        graph = new MetadataGraph(4, 3);
         /*
          *       v2
          *   v1<
          *       v3-v4
          *
          */
-        v1 = graph.addVertex(new ArtifactMetadata("g","a1","1.0"));
+        v1 = graph.addVertex(new ArtifactMetadata("g", "a1", "1.0"));
         graph.setEntry(v1);
-        v2 = graph.addVertex(new ArtifactMetadata("g","a2","1.0"));
-        v3 = graph.addVertex(new ArtifactMetadata("g","a3","1.0"));
-        v4 = graph.addVertex(new ArtifactMetadata("g","a4","1.0"));
+        v2 = graph.addVertex(new ArtifactMetadata("g", "a2", "1.0"));
+        v3 = graph.addVertex(new ArtifactMetadata("g", "a3", "1.0"));
+        v4 = graph.addVertex(new ArtifactMetadata("g", "a4", "1.0"));
 
         // v1-->v2
-        graph.addEdge(v1, v2, new MetadataGraphEdge( "1.1", true, null, null, 2, 1 ) );
-        graph.addEdge(v1, v2, new MetadataGraphEdge( "1.2", true, null, null, 2, 2 ) );
+        graph.addEdge(v1, v2, new MetadataGraphEdge("1.1", true, null, null, 2, 1));
+        graph.addEdge(v1, v2, new MetadataGraphEdge("1.2", true, null, null, 2, 2));
 
         // v1-->v3
-        graph.addEdge(v1, v3, new MetadataGraphEdge( "1.1", true, null, null, 2, 1 ) );
-        graph.addEdge(v1, v3, new MetadataGraphEdge( "1.2", true, null, null, 4, 2 ) );
+        graph.addEdge(v1, v3, new MetadataGraphEdge("1.1", true, null, null, 2, 1));
+        graph.addEdge(v1, v3, new MetadataGraphEdge("1.2", true, null, null, 4, 2));
 
         // v3-->v4
-        graph.addEdge(v3, v4, new MetadataGraphEdge( "1.1", true, ArtifactScopeEnum.runtime, null, 2, 2 ) );
-        graph.addEdge(v3, v4, new MetadataGraphEdge( "1.2", true, ArtifactScopeEnum.test, null, 2, 2 ) );
+        graph.addEdge(v3, v4, new MetadataGraphEdge("1.1", true, ArtifactScopeEnum.runtime, null, 2, 2));
+        graph.addEdge(v3, v4, new MetadataGraphEdge("1.2", true, ArtifactScopeEnum.test, null, 2, 2));
     }
-    //------------------------------------------------------------------------------------------
-	@Test
-    public void testCompileClasspathTransform()
-    throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @Test
+    void testCompileClasspathTransform() throws Exception {
         ClasspathContainer res;
 
-        res = transform.transform( graph, ArtifactScopeEnum.compile, false );
+        res = transform.transform(graph, ArtifactScopeEnum.compile, false);
 
-        assertNotNull( res, "null classpath container after compile transform" );
-        assertNotNull( res.getClasspath(), "null classpath after compile transform" );
-        assertEquals( 3, res.getClasspath().size(), "compile classpath should have 3 entries" );
+        assertNotNull(res, "null classpath container after compile transform");
+        assertNotNull(res.getClasspath(), "null classpath after compile transform");
+        assertEquals(3, res.getClasspath().size(), "compile classpath should have 3 entries");
     }
-    //------------------------------------------------------------------------------------------
-	@Test
-    public void testRuntimeClasspathTransform()
-    throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @Test
+    void testRuntimeClasspathTransform() throws Exception {
         ClasspathContainer res;
 
-        res = transform.transform( graph, ArtifactScopeEnum.runtime, false );
+        res = transform.transform(graph, ArtifactScopeEnum.runtime, false);
 
-        assertNotNull( res, "null classpath container after runtime transform" );
-        assertNotNull( res.getClasspath(), "null classpath after runtime transform" );
-        assertEquals( 4, res.getClasspath().size(), "runtime classpath should have 4 entries" );
+        assertNotNull(res, "null classpath container after runtime transform");
+        assertNotNull(res.getClasspath(), "null classpath after runtime transform");
+        assertEquals(4, res.getClasspath().size(), "runtime classpath should have 4 entries");
 
         ArtifactMetadata md = res.getClasspath().get(3);
-        assertEquals("1.1", md.getVersion(), "runtime artifact version should be 1.1" );
+        assertEquals("1.1", md.getVersion(), "runtime artifact version should be 1.1");
     }
-    //------------------------------------------------------------------------------------------
-	@Test
-    public void testTestClasspathTransform()
-    throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @Test
+    void testTestClasspathTransform() throws Exception {
         ClasspathContainer res;
 
-        res = transform.transform( graph, ArtifactScopeEnum.test, false );
+        res = transform.transform(graph, ArtifactScopeEnum.test, false);
 
-        assertNotNull( res, "null classpath container after test transform" );
-        assertNotNull( res.getClasspath(), "null classpath after test transform" );
-        assertEquals( 4, res.getClasspath().size(), "test classpath should have 4 entries" );
+        assertNotNull(res, "null classpath container after test transform");
+        assertNotNull(res.getClasspath(), "null classpath after test transform");
+        assertEquals(4, res.getClasspath().size(), "test classpath should have 4 entries");
 
         ArtifactMetadata md = res.getClasspath().get(3);
-        assertEquals("1.2", md.getVersion(), "test artifact version should be 1.2" );
+        assertEquals("1.2", md.getVersion(), "test artifact version should be 1.2");
     }
-    //------------------------------------------------------------------------------------------
-    //------------------------------------------------------------------------------------------
+    // ------------------------------------------------------------------------------------------
+    // ------------------------------------------------------------------------------------------
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicyTest.java b/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicyTest.java
index ea4352e..ce3caf8 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicyTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolutionPolicyTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.repository.metadata;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -22,38 +25,34 @@
 
 /**
  *
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
-
-public class DefaultGraphConflictResolutionPolicyTest
-{
+class DefaultGraphConflictResolutionPolicyTest {
     GraphConflictResolutionPolicy policy;
     MetadataGraphEdge e1;
     MetadataGraphEdge e2;
     MetadataGraphEdge e3;
-    //------------------------------------------------------------------------------------------
-	@BeforeEach
-    public void setUp() throws Exception
-	{
-		policy = new DefaultGraphConflictResolutionPolicy();
-    	e1 = new MetadataGraphEdge( "1.1", true, null, null, 2, 1 );
-    	e2 = new MetadataGraphEdge( "1.2", true, null, null, 3, 2 );
-    	e3 = new MetadataGraphEdge( "1.2", true, null, null, 2, 3 );
-	}
-    //------------------------------------------------------------------------------------------
-	@Test
-    public void testDefaultPolicy()
-        throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @BeforeEach
+    void setUp() throws Exception {
+        policy = new DefaultGraphConflictResolutionPolicy();
+        e1 = new MetadataGraphEdge("1.1", true, null, null, 2, 1);
+        e2 = new MetadataGraphEdge("1.2", true, null, null, 3, 2);
+        e3 = new MetadataGraphEdge("1.2", true, null, null, 2, 3);
+    }
+
+    // ------------------------------------------------------------------------------------------
+    @Test
+    void testDefaultPolicy() throws Exception {
         MetadataGraphEdge res;
 
-        res = policy.apply( e1, e2 );
-        assertEquals( "1.1", res.getVersion(), "Wrong depth edge selected" );
+        res = policy.apply(e1, e2);
+        assertEquals("1.1", res.getVersion(), "Wrong depth edge selected");
 
-        res = policy.apply( e1, e3 );
-        assertEquals( "1.2", res.getVersion(), "Wrong version edge selected" );
+        res = policy.apply(e1, e3);
+        assertEquals("1.2", res.getVersion(), "Wrong version edge selected");
     }
-    //------------------------------------------------------------------------------------------
-    //------------------------------------------------------------------------------------------
+    // ------------------------------------------------------------------------------------------
+    // ------------------------------------------------------------------------------------------
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolverTest.java b/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolverTest.java
index 67a003a..659b044 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolverTest.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/metadata/DefaultGraphConflictResolverTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.repository.metadata;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.repository.metadata;
 
 import javax.inject.Inject;
 
@@ -27,12 +30,10 @@
 
 /**
  *
- * @author <a href="mailto:oleg@codehaus.org">Oleg Gusakov</a>
  *
  */
 @PlexusTest
-public class DefaultGraphConflictResolverTest
-{
+class DefaultGraphConflictResolverTest {
     @Inject
     GraphConflictResolver resolver;
 
@@ -42,111 +43,159 @@
     MetadataGraphVertex v2;
     MetadataGraphVertex v3;
     MetadataGraphVertex v4;
-    //------------------------------------------------------------------------------------------
-	@BeforeEach
-    public void setUp() throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @BeforeEach
+    void setUp() throws Exception {
         /*
          *       v2
          *   v1<
          *      v3-v4
          *
          */
-        graph = new MetadataGraph( 4, 3 );
-        v1 = graph.addVertex(new ArtifactMetadata("g","a1","1.0"));
+        graph = new MetadataGraph(4, 3);
+        v1 = graph.addVertex(new ArtifactMetadata("g", "a1", "1.0"));
         graph.setEntry(v1);
-        v2 = graph.addVertex(new ArtifactMetadata("g","a2","1.0"));
-        v3 = graph.addVertex(new ArtifactMetadata("g","a3","1.0"));
-        v4 = graph.addVertex(new ArtifactMetadata("g","a4","1.0"));
+        v2 = graph.addVertex(new ArtifactMetadata("g", "a2", "1.0"));
+        v3 = graph.addVertex(new ArtifactMetadata("g", "a3", "1.0"));
+        v4 = graph.addVertex(new ArtifactMetadata("g", "a4", "1.0"));
 
         // v1-->v2
-        graph.addEdge(v1, v2, new MetadataGraphEdge( "1.1", true, null, null, 2, 1 ) );
-        graph.addEdge(v1, v2, new MetadataGraphEdge( "1.2", true, null, null, 2, 2 ) );
+        graph.addEdge(v1, v2, new MetadataGraphEdge("1.1", true, null, null, 2, 1));
+        graph.addEdge(v1, v2, new MetadataGraphEdge("1.2", true, null, null, 2, 2));
 
         // v1-->v3
-        graph.addEdge(v1, v3, new MetadataGraphEdge( "1.1", true, null, null, 2, 1 ) );
-        graph.addEdge(v1, v3, new MetadataGraphEdge( "1.2", true, null, null, 4, 2 ) );
+        graph.addEdge(v1, v3, new MetadataGraphEdge("1.1", true, null, null, 2, 1));
+        graph.addEdge(v1, v3, new MetadataGraphEdge("1.2", true, null, null, 4, 2));
 
         // v3-->v4
-        graph.addEdge(v3, v4, new MetadataGraphEdge( "1.1", true, ArtifactScopeEnum.runtime, null, 2, 1 ) );
-        graph.addEdge(v3, v4, new MetadataGraphEdge( "1.2", true, ArtifactScopeEnum.provided, null, 2, 2 ) );
+        graph.addEdge(v3, v4, new MetadataGraphEdge("1.1", true, ArtifactScopeEnum.runtime, null, 2, 1));
+        graph.addEdge(v3, v4, new MetadataGraphEdge("1.2", true, ArtifactScopeEnum.provided, null, 2, 2));
     }
-    //------------------------------------------------------------------------------------------
-	@Test
-    public void testCompileResolution()
-    throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @Test
+    void testCompileResolution() throws Exception {
         MetadataGraph res;
 
-        res = resolver.resolveConflicts( graph, ArtifactScopeEnum.compile );
+        res = resolver.resolveConflicts(graph, ArtifactScopeEnum.compile);
 
-        assertNotNull( res, "null graph after resolver" );
-        assertNotNull( res.getVertices(), "no vertices in the resulting graph after resolver" );
+        assertNotNull(res, "null graph after resolver");
+        assertNotNull(res.getVertices(), "no vertices in the resulting graph after resolver");
 
-        assertNotNull( res.getExcidentEdges(v1), "no edges in the resulting graph after resolver" );
+        assertNotNull(res.getExcidentEdges(v1), "no edges in the resulting graph after resolver");
 
-        assertEquals( 4, res.getVertices().size(), "wrong # of vertices in the resulting graph after resolver" );
-        assertEquals( 2, res.getExcidentEdges(v1).size(), "wrong # of excident edges in the resulting graph entry after resolver" );
+        assertEquals(4, res.getVertices().size(), "wrong # of vertices in the resulting graph after resolver");
+        assertEquals(
+                2,
+                res.getExcidentEdges(v1).size(),
+                "wrong # of excident edges in the resulting graph entry after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v2).size(), "wrong # of v2 incident edges in the resulting graph after resolver" );
-        assertEquals( "1.2", res.getIncidentEdges(v2).get(0).getVersion(), "wrong edge v1-v2 in the resulting graph after resolver" );
+        assertEquals(
+                1,
+                res.getIncidentEdges(v2).size(),
+                "wrong # of v2 incident edges in the resulting graph after resolver");
+        assertEquals(
+                "1.2",
+                res.getIncidentEdges(v2).get(0).getVersion(),
+                "wrong edge v1-v2 in the resulting graph after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v3).size(), "wrong # of edges v1-v3 in the resulting graph after resolver" );
-        assertEquals( "1.1", res.getIncidentEdges(v3).get(0).getVersion(), "wrong edge v1-v3 in the resulting graph after resolver" );
+        assertEquals(
+                1, res.getIncidentEdges(v3).size(), "wrong # of edges v1-v3 in the resulting graph after resolver");
+        assertEquals(
+                "1.1",
+                res.getIncidentEdges(v3).get(0).getVersion(),
+                "wrong edge v1-v3 in the resulting graph after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v4).size(), "wrong # of edges v3-v4 in the resulting graph after resolver" );
-        assertEquals( "1.2", res.getIncidentEdges(v4).get(0).getVersion(), "wrong edge v3-v4 in the resulting graph after resolver" );
+        assertEquals(
+                1, res.getIncidentEdges(v4).size(), "wrong # of edges v3-v4 in the resulting graph after resolver");
+        assertEquals(
+                "1.2",
+                res.getIncidentEdges(v4).get(0).getVersion(),
+                "wrong edge v3-v4 in the resulting graph after resolver");
     }
-    //------------------------------------------------------------------------------------------
-	@Test
-    public void testRuntimeResolution()
-    throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @Test
+    void testRuntimeResolution() throws Exception {
         MetadataGraph res;
 
-        res = resolver.resolveConflicts( graph, ArtifactScopeEnum.runtime );
+        res = resolver.resolveConflicts(graph, ArtifactScopeEnum.runtime);
 
-        assertNotNull( res, "null graph after resolver" );
-        assertNotNull( res.getVertices(), "no vertices in the resulting graph after resolver" );
-        assertNotNull( res.getExcidentEdges(v1), "no edges in the resulting graph after resolver" );
+        assertNotNull(res, "null graph after resolver");
+        assertNotNull(res.getVertices(), "no vertices in the resulting graph after resolver");
+        assertNotNull(res.getExcidentEdges(v1), "no edges in the resulting graph after resolver");
 
-        assertEquals( 4, res.getVertices().size(), "wrong # of vertices in the resulting graph after resolver" );
-        assertEquals( 2, res.getExcidentEdges(v1).size(), "wrong # of excident edges in the resulting graph entry after resolver" );
+        assertEquals(4, res.getVertices().size(), "wrong # of vertices in the resulting graph after resolver");
+        assertEquals(
+                2,
+                res.getExcidentEdges(v1).size(),
+                "wrong # of excident edges in the resulting graph entry after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v2).size(), "wrong # of v2 incident edges in the resulting graph after resolver" );
-        assertEquals( "1.2", res.getIncidentEdges(v2).get(0).getVersion(), "wrong edge v1-v2 in the resulting graph after resolver" );
+        assertEquals(
+                1,
+                res.getIncidentEdges(v2).size(),
+                "wrong # of v2 incident edges in the resulting graph after resolver");
+        assertEquals(
+                "1.2",
+                res.getIncidentEdges(v2).get(0).getVersion(),
+                "wrong edge v1-v2 in the resulting graph after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v3).size(), "wrong # of edges v1-v3 in the resulting graph after resolver" );
-        assertEquals( "1.1", res.getIncidentEdges(v3).get(0).getVersion(), "wrong edge v1-v3 in the resulting graph after resolver" );
+        assertEquals(
+                1, res.getIncidentEdges(v3).size(), "wrong # of edges v1-v3 in the resulting graph after resolver");
+        assertEquals(
+                "1.1",
+                res.getIncidentEdges(v3).get(0).getVersion(),
+                "wrong edge v1-v3 in the resulting graph after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v4).size(), "wrong # of edges v3-v4 in the resulting graph after resolver" );
-        assertEquals( "1.1", res.getIncidentEdges(v4).get(0).getVersion(), "wrong edge v3-v4 in the resulting graph after resolver" );
+        assertEquals(
+                1, res.getIncidentEdges(v4).size(), "wrong # of edges v3-v4 in the resulting graph after resolver");
+        assertEquals(
+                "1.1",
+                res.getIncidentEdges(v4).get(0).getVersion(),
+                "wrong edge v3-v4 in the resulting graph after resolver");
     }
-    //------------------------------------------------------------------------------------------
-	@Test
-    public void testTestResolution()
-    throws Exception
-    {
+
+    // ------------------------------------------------------------------------------------------
+    @Test
+    void testTestResolution() throws Exception {
         MetadataGraph res;
 
-        res = resolver.resolveConflicts( graph, ArtifactScopeEnum.test );
+        res = resolver.resolveConflicts(graph, ArtifactScopeEnum.test);
 
-        assertNotNull( res, "null graph after resolver" );
-        assertNotNull( res.getVertices(), "no vertices in the resulting graph after resolver" );
-        assertNotNull( res.getExcidentEdges(v1), "no edges in the resulting graph after resolver" );
+        assertNotNull(res, "null graph after resolver");
+        assertNotNull(res.getVertices(), "no vertices in the resulting graph after resolver");
+        assertNotNull(res.getExcidentEdges(v1), "no edges in the resulting graph after resolver");
 
-        assertEquals( 4, res.getVertices().size(), "wrong # of vertices in the resulting graph after resolver" );
-        assertEquals( 2, res.getExcidentEdges(v1).size(), "wrong # of excident edges in the resulting graph entry after resolver" );
+        assertEquals(4, res.getVertices().size(), "wrong # of vertices in the resulting graph after resolver");
+        assertEquals(
+                2,
+                res.getExcidentEdges(v1).size(),
+                "wrong # of excident edges in the resulting graph entry after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v2).size(), "wrong # of v2 incident edges in the resulting graph after resolver" );
-        assertEquals( "1.2", res.getIncidentEdges(v2).get(0).getVersion(), "wrong edge v1-v2 in the resulting graph after resolver" );
+        assertEquals(
+                1,
+                res.getIncidentEdges(v2).size(),
+                "wrong # of v2 incident edges in the resulting graph after resolver");
+        assertEquals(
+                "1.2",
+                res.getIncidentEdges(v2).get(0).getVersion(),
+                "wrong edge v1-v2 in the resulting graph after resolver");
 
-        assertEquals(  1, res.getIncidentEdges(v3).size(), "wrong # of edges v1-v3 in the resulting graph after resolver" );
-        assertEquals( "1.1", res.getIncidentEdges(v3).get(0).getVersion(), "wrong edge v1-v3 in the resulting graph after resolver" );
+        assertEquals(
+                1, res.getIncidentEdges(v3).size(), "wrong # of edges v1-v3 in the resulting graph after resolver");
+        assertEquals(
+                "1.1",
+                res.getIncidentEdges(v3).get(0).getVersion(),
+                "wrong edge v1-v3 in the resulting graph after resolver");
 
-        assertEquals( 1, res.getIncidentEdges(v4).size(), "wrong # of edges v3-v4 in the resulting graph after resolver" );
-        assertEquals( "1.2", res.getIncidentEdges(v4).get(0).getVersion(), "wrong edge v3-v4 in the resulting graph after resolver" );
+        assertEquals(
+                1, res.getIncidentEdges(v4).size(), "wrong # of edges v3-v4 in the resulting graph after resolver");
+        assertEquals(
+                "1.2",
+                res.getIncidentEdges(v4).get(0).getVersion(),
+                "wrong edge v3-v4 in the resulting graph after resolver");
     }
-    //------------------------------------------------------------------------------------------
-    //------------------------------------------------------------------------------------------
+    // ------------------------------------------------------------------------------------------
+    // ------------------------------------------------------------------------------------------
 }
diff --git a/maven-compat/src/test/java/org/apache/maven/repository/metadata/TestMetadataSource.java b/maven-compat/src/test/java/org/apache/maven/repository/metadata/TestMetadataSource.java
index efec2e6..0fc6db4 100644
--- a/maven-compat/src/test/java/org/apache/maven/repository/metadata/TestMetadataSource.java
+++ b/maven-compat/src/test/java/org/apache/maven/repository/metadata/TestMetadataSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.metadata;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.HashSet;
 import java.util.List;
@@ -32,71 +35,53 @@
 import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
 import org.apache.maven.repository.legacy.metadata.ResolutionGroup;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 @Named
 @Singleton
-public class TestMetadataSource
-    implements ArtifactMetadataSource
-{
+public class TestMetadataSource implements ArtifactMetadataSource {
     @Inject
     private ArtifactFactory factory;
 
-    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException
-    {
+    public ResolutionGroup retrieve(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
         Set<Artifact> dependencies = new HashSet<>();
 
-        if ( "g".equals( artifact.getArtifactId() ) )
-        {
+        if ("g".equals(artifact.getArtifactId())) {
             Artifact a = null;
-            try
-            {
-                a = factory.createBuildArtifact( "org.apache.maven", "h", "1.0", "jar" );
-                dependencies.add( a );
-            }
-            catch ( Exception e )
-            {
-                throw new ArtifactMetadataRetrievalException( "Error retrieving metadata", e, a );
+            try {
+                a = factory.createBuildArtifact("org.apache.maven", "h", "1.0", "jar");
+                dependencies.add(a);
+            } catch (Exception e) {
+                throw new ArtifactMetadataRetrievalException("Error retrieving metadata", e, a);
             }
         }
 
-        if ( "i".equals( artifact.getArtifactId() ) )
-        {
+        if ("i".equals(artifact.getArtifactId())) {
             Artifact a = null;
-            try
-            {
-                a = factory.createBuildArtifact( "org.apache.maven", "j", "1.0-SNAPSHOT", "jar" );
-                dependencies.add( a );
-            }
-            catch ( Exception e )
-            {
-                throw new ArtifactMetadataRetrievalException( "Error retrieving metadata", e, a );
+            try {
+                a = factory.createBuildArtifact("org.apache.maven", "j", "1.0-SNAPSHOT", "jar");
+                dependencies.add(a);
+            } catch (Exception e) {
+                throw new ArtifactMetadataRetrievalException("Error retrieving metadata", e, a);
             }
         }
 
-
-        return new ResolutionGroup( artifact, dependencies, remoteRepositories );
+        return new ResolutionGroup(artifact, dependencies, remoteRepositories);
     }
 
-    public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException
-    {
-        throw new UnsupportedOperationException( "Cannot get available versions in this test case" );
+    public List<ArtifactVersion> retrieveAvailableVersions(
+            Artifact artifact, ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories)
+            throws ArtifactMetadataRetrievalException {
+        throw new UnsupportedOperationException("Cannot get available versions in this test case");
     }
 
-    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository )
-        throws ArtifactMetadataRetrievalException
-    {
-        throw new UnsupportedOperationException( "Cannot get available versions in this test case" );
+    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository(
+            Artifact artifact, ArtifactRepository localRepository, ArtifactRepository remoteRepository)
+            throws ArtifactMetadataRetrievalException {
+        throw new UnsupportedOperationException("Cannot get available versions in this test case");
     }
 
-    public ResolutionGroup retrieve( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException
-    {
-        return retrieve( request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories() );
+    public ResolutionGroup retrieve(MetadataResolutionRequest request) throws ArtifactMetadataRetrievalException {
+        return retrieve(request.getArtifact(), request.getLocalRepository(), request.getRemoteRepositories());
     }
-
 }
diff --git a/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt b/maven-compat/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt
similarity index 100%
rename from maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt
rename to maven-compat/src/test/projects/project-dependencies-resolver/it0063/jdk/jre/placeholder.txt
diff --git a/maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/lib/tools.jar b/maven-compat/src/test/projects/project-dependencies-resolver/it0063/jdk/lib/tools.jar
similarity index 100%
rename from maven-core/src/test/projects/project-dependencies-resolver/it0063/jdk/lib/tools.jar
rename to maven-compat/src/test/projects/project-dependencies-resolver/it0063/jdk/lib/tools.jar
Binary files differ
diff --git a/maven-core/src/test/projects/project-dependencies-resolver/it0063/pom.xml b/maven-compat/src/test/projects/project-dependencies-resolver/it0063/pom.xml
similarity index 100%
rename from maven-core/src/test/projects/project-dependencies-resolver/it0063/pom.xml
rename to maven-compat/src/test/projects/project-dependencies-resolver/it0063/pom.xml
diff --git a/maven-core/src/test/projects/project-dependencies-resolver/project-with-exclusions/pom.xml b/maven-compat/src/test/projects/project-dependencies-resolver/project-with-exclusions/pom.xml
similarity index 100%
rename from maven-core/src/test/projects/project-dependencies-resolver/project-with-exclusions/pom.xml
rename to maven-compat/src/test/projects/project-dependencies-resolver/project-with-exclusions/pom.xml
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index 62c33d2..6a08adb 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-core</artifactId>
@@ -75,11 +73,15 @@
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
-      <artifactId>maven-model-transform</artifactId>
+      <artifactId>maven-resolver-provider</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
-      <artifactId>maven-resolver-provider</artifactId>
+      <artifactId>maven-api-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-spi</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.maven.resolver</groupId>
@@ -98,21 +100,23 @@
       <artifactId>maven-resolver-util</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.maven.shared</groupId>
-      <artifactId>maven-shared-utils</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.eclipse.sisu</groupId>
       <artifactId>org.eclipse.sisu.plexus</artifactId>
     </dependency>
     <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.eclipse.sisu</groupId>
       <artifactId>org.eclipse.sisu.inject</artifactId>
+      <classifier>no_asm</classifier>
     </dependency>
     <dependency>
       <groupId>com.google.inject</groupId>
       <artifactId>guice</artifactId>
-      <classifier>no_aop</classifier>
+      <classifier>classes</classifier>
     </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
@@ -129,20 +133,14 @@
     <!-- Plexus -->
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-classworlds</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-lang3</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
+
+    <!-- Test dependencies -->
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
@@ -154,16 +152,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>commons-io</groupId>
-      <artifactId>commons-io</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>org.hamcrest</groupId>
       <artifactId>hamcrest-library</artifactId>
       <scope>test</scope>
@@ -175,11 +163,6 @@
     </dependency>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-api</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
       <artifactId>junit-jupiter-params</artifactId>
       <scope>test</scope>
     </dependency>
@@ -188,13 +171,19 @@
       <artifactId>plexus-testing</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-junit-jupiter</artifactId>
+      <version>${mockitoVersion}</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
     <resources>
       <resource>
-        <directory>src/main/resources</directory>
         <filtering>true</filtering>
+        <directory>src/main/resources</directory>
       </resource>
     </resources>
     <pluginManagement>
@@ -224,16 +213,16 @@
         <configuration>
           <version>1.1.0</version>
           <!-- This is a required attribute and is intentionally left empty -->
-          <models></models>
+          <models />
         </configuration>
         <executions>
           <execution>
             <!-- This step is required to generate xdoc, and does not generate java code -->
             <id>modello-site-doc</id>
-            <phase>pre-site</phase>
             <goals>
               <goal>xdoc</goal>
             </goals>
+            <phase>pre-site</phase>
             <configuration>
               <version>1.0.0</version>
               <models>
@@ -273,6 +262,86 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <parameter>
+            <includes>
+              <include>org.apache.maven.artifact</include>
+              <include>org.apache.maven.classrealm</include>
+              <include>org.apache.maven.cli</include>
+              <include>org.apache.maven.configuration</include>
+              <include>org.apache.maven.exception</include>
+              <include>org.apache.maven.execution</include>
+              <include>org.apache.maven.execution.scope</include>
+              <include>org.apache.maven.feature</include>
+              <include>org.apache.maven.graph</include>
+              <include>org.apache.maven.lifecycle</include>
+              <include>org.apache.maven.model</include>
+              <include>org.apache.maven.monitor</include>
+              <include>org.apache.maven.plugin</include>
+              <include>org.apache.maven.profiles</include>
+              <include>org.apache.maven.project</include>
+              <include>org.apache.maven.reporting</include>
+              <include>org.apache.maven.repository</include>
+              <include>org.apache.maven.rtinfo</include>
+              <include>org.apache.maven.rtinfo.internal</include>
+              <include>org.apache.maven.settings</include>
+              <include>org.apache.maven.toolchain</include>
+              <include>org.apache.maven.usability</include>
+            </includes>
+            <!-- allowed non-binary backwards compatible changes -->
+            <excludes>
+              <!-- START default constructor on Plexus/JSR 330 components -->
+              <exclude>org.apache.maven.lifecycle.DefaultLifecycleExecutor#DefaultLifecycleExecutor()</exclude>
+              <exclude>org.apache.maven.plugin.DefaultBuildPluginManager#DefaultBuildPluginManager()</exclude>
+              <exclude>org.apache.maven.project.DefaultMavenProjectHelper#DefaultMavenProjectHelper()</exclude>
+              <exclude>org.apache.maven.project.DefaultProjectBuilder#DefaultProjectBuilder()</exclude>
+              <exclude>org.apache.maven.project.DefaultProjectBuildingHelper#DefaultProjectBuildingHelper()</exclude>
+              <exclude>org.apache.maven.project.DefaultProjectDependenciesResolver#DefaultProjectDependenciesResolver()</exclude>
+              <exclude>org.apache.maven.rtinfo.internal.DefaultRuntimeInformation#DefaultRuntimeInformation()</exclude>
+              <exclude>org.apache.maven.settings.DefaultMavenSettingsBuilder#DefaultMavenSettingsBuilder()</exclude>
+              <exclude>org.apache.maven.toolchain.DefaultToolchainManager#DefaultToolchainManager():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.toolchain.DefaultToolchainManagerPrivate#DefaultToolchainManagerPrivate()</exclude>
+              <!-- END default constructor on Plexus/JSR 330 components -->
+              <!-- system property with that name no longer evaluated -->
+              <exclude>org.apache.maven.project.DefaultProjectBuilder#DISABLE_GLOBAL_MODEL_CACHE_SYSTEM_PROPERTY</exclude>
+              <!-- was only a workaround for Plexus Container, hopefully never used by anyone else -->
+              <exclude>org.apache.maven.plugin.DefaultBuildPluginManager#setMojoExecutionListeners(java.util.List)</exclude>
+              <!-- could have never been used due to usage of non-export class (CoreExportsProvider) -->
+              <exclude>org.apache.maven.classrealm.DefaultClassRealmManager#DefaultClassRealmManager(org.codehaus.plexus.logging.Logger,org.codehaus.plexus.PlexusContainer,java.util.List,org.apache.maven.extension.internal.CoreExportsProvider)</exclude>
+              <!-- internal field removed -->
+              <exclude>org.apache.maven.graph.DefaultGraphBuilder#projectBuilder</exclude>
+              <!-- MavenPluginValidator has been transformed into an interface -->
+              <exclude>org.apache.maven.plugin.MavenPluginValidator</exclude>
+              <!-- Remove plexus logger -->
+              <exclude>org.apache.maven.plugin.PluginParameterExpressionEvaluator#PluginParameterExpressionEvaluator(org.apache.maven.execution.MavenSession,org.apache.maven.plugin.MojoExecution,org.apache.maven.project.path.PathTranslator,org.codehaus.plexus.logging.Logger,org.apache.maven.project.MavenProject,java.util.Properties):CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.toolchain.DefaultToolchain#getLog():METHOD_RETURN_TYPE_CHANGED</exclude>
+              <exclude>org.apache.maven.toolchain.DefaultToolchain#DefaultToolchain(org.apache.maven.toolchain.model.ToolchainModel,org.codehaus.plexus.logging.Logger):CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.toolchain.DefaultToolchain#DefaultToolchain(org.apache.maven.toolchain.model.ToolchainModel,java.lang.String,org.codehaus.plexus.logging.Logger):CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.toolchain.DefaultToolchainManager#logger</exclude>
+              <!-- Remove plexus utils -->
+              <exclude>org.apache.maven.project.ProjectSorter#getDAG():METHOD_REMOVED</exclude>
+              <!-- classes moved to maven-compat -->
+              <exclude>org.apache.maven.plugin.PluginManager</exclude>
+              <exclude>org.apache.maven.repository.ArtifactDoesNotExistException</exclude>
+              <exclude>org.apache.maven.repository.ArtifactTransferEvent</exclude>
+              <exclude>org.apache.maven.repository.ArtifactTransferFailedException</exclude>
+              <exclude>org.apache.maven.repository.ArtifactTransferListener</exclude>
+              <exclude>org.apache.maven.repository.ArtifactTransferResource</exclude>
+              <exclude>org.apache.maven.repository.DelegatingLocalArtifactRepository</exclude>
+              <exclude>org.apache.maven.repository.LocalArtifactRepository</exclude>
+              <exclude>org.apache.maven.repository.LocalRepositoryNotAccessibleException</exclude>
+              <exclude>org.apache.maven.repository.RepositorySystem</exclude>
+              <exclude>org.apache.maven.settings.DefaultMavenSettingsBuilder</exclude>
+              <exclude>org.apache.maven.settings.MavenSettingsBuilder</exclude>
+              <exclude>org.apache.maven.toolchain.DefaultToolchainsBuilder</exclude>
+              <exclude>org.apache.maven.toolchain.ToolchainsBuilder</exclude>
+            </excludes>
+          </parameter>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/maven-core/src/main/java/org/apache/maven/AbstractMavenLifecycleParticipant.java b/maven-core/src/main/java/org/apache/maven/AbstractMavenLifecycleParticipant.java
index 09f23d3..c3384a3 100644
--- a/maven-core/src/main/java/org/apache/maven/AbstractMavenLifecycleParticipant.java
+++ b/maven-core/src/main/java/org/apache/maven/AbstractMavenLifecycleParticipant.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 import org.apache.maven.execution.MavenSession;
 
@@ -31,8 +30,7 @@
  * @see <a href="https://issues.apache.org/jira/browse/MNG-4224">MNG-4224</a>
  * @since 3.0-alpha-3
  */
-public abstract class AbstractMavenLifecycleParticipant
-{
+public abstract class AbstractMavenLifecycleParticipant {
 
     /**
      * Invoked after all MavenProject instances have been created.
@@ -43,9 +41,7 @@
      * @param session the Maven session
      * @throws MavenExecutionException in case of issue
      */
-    public void afterProjectsRead( MavenSession session )
-        throws MavenExecutionException
-    {
+    public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
         // do nothing
     }
 
@@ -60,9 +56,7 @@
      * @throws MavenExecutionException in case of issue
      */
     // TODO This is too early for build extensions, so maybe just remove it?
-    public void afterSessionStart( MavenSession session )
-        throws MavenExecutionException
-    {
+    public void afterSessionStart(MavenSession session) throws MavenExecutionException {
         // do nothing
     }
 
@@ -78,9 +72,7 @@
      * @throws MavenExecutionException in case of issue
      * @since 3.2.1, MNG-5389
      */
-    public void afterSessionEnd( MavenSession session )
-        throws MavenExecutionException
-    {
+    public void afterSessionEnd(MavenSession session) throws MavenExecutionException {
         // do nothing
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/ArtifactFilterManager.java b/maven-core/src/main/java/org/apache/maven/ArtifactFilterManager.java
deleted file mode 100644
index 0db1c59..0000000
--- a/maven-core/src/main/java/org/apache/maven/ArtifactFilterManager.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package org.apache.maven;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Set;
-
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-
-/**
- * ArtifactFilterManager
- */
-public interface ArtifactFilterManager
-{
-    /**
-     * Returns a filter for core + extension artifacts.
-     *
-     * @return the artifact filter
-     * @deprecated use {@code META-INF/maven/extension.xml} to define artifacts exported by Maven core and plugin
-     *             extensions.
-     */
-    ArtifactFilter getArtifactFilter();
-
-    /**
-     * Returns a filter for only the core artifacts.
-     *
-     * @return the artifact filter
-     */
-    ArtifactFilter getCoreArtifactFilter();
-
-    /**
-     * Exclude an extension artifact (doesn't affect getArtifactFilter's result, only getExtensionArtifactFilter).
-     *
-     * @param artifactId an artifact id
-     * @deprecated use {@code META-INF/maven/extension.xml} to define artifacts exported by Maven core and plugin
-     *             extensions.
-     */
-    void excludeArtifact( String artifactId );
-
-    Set<String> getCoreArtifactExcludes();
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/ArtifactFilterManagerDelegate.java b/maven-core/src/main/java/org/apache/maven/ArtifactFilterManagerDelegate.java
deleted file mode 100644
index 1389325..0000000
--- a/maven-core/src/main/java/org/apache/maven/ArtifactFilterManagerDelegate.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package org.apache.maven;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Set;
-
-/**
- * @deprecated use {@code META-INF/maven/extension.xml} to define artifacts exported by Maven core extensions.
- */
-public interface ArtifactFilterManagerDelegate
-{
-
-    void addExcludes( Set<String> excludes );
-
-    void addCoreExcludes( Set<String> excludes );
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/BuildAbort.java b/maven-core/src/main/java/org/apache/maven/BuildAbort.java
index 3255e32..6585f9e 100644
--- a/maven-core/src/main/java/org/apache/maven/BuildAbort.java
+++ b/maven-core/src/main/java/org/apache/maven/BuildAbort.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,22 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 /**
  * A special throwable used to signal a graceful abort of the build.
  */
-public class BuildAbort
-    extends Error
-{
+public class BuildAbort extends Error {
 
-    public BuildAbort( String message )
-    {
-        super( message );
+    public BuildAbort(String message) {
+        super(message);
     }
 
-    public BuildAbort( String message, Throwable cause )
-    {
-        super( message, cause );
+    public BuildAbort(String message, Throwable cause) {
+        super(message, cause);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/BuildFailureException.java b/maven-core/src/main/java/org/apache/maven/BuildFailureException.java
index d35b0d2..2edb65f 100644
--- a/maven-core/src/main/java/org/apache/maven/BuildFailureException.java
+++ b/maven-core/src/main/java/org/apache/maven/BuildFailureException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 /**
  * One or more builds failed.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class BuildFailureException
-    extends Exception
-{
-    public BuildFailureException( String message )
-    {
-        super( message );
+public class BuildFailureException extends Exception {
+    public BuildFailureException(String message) {
+        super(message);
     }
 
-    public BuildFailureException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public BuildFailureException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java b/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
deleted file mode 100644
index 810baae..0000000
--- a/maven-core/src/main/java/org/apache/maven/DefaultArtifactFilterManager.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package org.apache.maven;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-import org.apache.maven.artifact.resolver.filter.ExclusionSetFilter;
-import org.apache.maven.extension.internal.CoreExports;
-
-/**
- * @author Jason van Zyl
- */
-@Named
-@Singleton
-@SuppressWarnings( "deprecation" )
-public class DefaultArtifactFilterManager
-    implements ArtifactFilterManager
-{
-
-    // this is a live injected collection
-    protected final List<ArtifactFilterManagerDelegate> delegates;
-
-    protected Set<String> excludedArtifacts;
-
-    private final Set<String> coreArtifacts;
-
-    @Inject
-    public DefaultArtifactFilterManager( List<ArtifactFilterManagerDelegate> delegates,
-                                         CoreExports coreExports )
-    {
-        this.delegates = delegates;
-        this.coreArtifacts = coreExports.getExportedArtifacts();
-    }
-
-    private synchronized Set<String> getExcludedArtifacts()
-    {
-        if ( excludedArtifacts == null )
-        {
-            excludedArtifacts = new LinkedHashSet<>( coreArtifacts );
-        }
-        return excludedArtifacts;
-    }
-
-    /**
-     * Returns the artifact filter for the core + extension artifacts.
-     *
-     * @see org.apache.maven.ArtifactFilterManager#getArtifactFilter()
-     */
-    public ArtifactFilter getArtifactFilter()
-    {
-        Set<String> excludes = new LinkedHashSet<>( getExcludedArtifacts() );
-
-        for ( ArtifactFilterManagerDelegate delegate : delegates )
-        {
-            delegate.addExcludes( excludes );
-        }
-
-        return new ExclusionSetFilter( excludes );
-    }
-
-    /**
-     * Returns the artifact filter for the standard core artifacts.
-     *
-     * @see org.apache.maven.ArtifactFilterManager#getCoreArtifactFilter()
-     */
-    public ArtifactFilter getCoreArtifactFilter()
-    {
-        return new ExclusionSetFilter( getCoreArtifactExcludes() );
-    }
-
-    public void excludeArtifact( String artifactId )
-    {
-        getExcludedArtifacts().add( artifactId );
-    }
-
-    public Set<String> getCoreArtifactExcludes()
-    {
-        Set<String> excludes = new LinkedHashSet<>( coreArtifacts );
-
-        for ( ArtifactFilterManagerDelegate delegate : delegates )
-        {
-            delegate.addCoreExcludes( excludes );
-        }
-
-        return excludes;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
index 9792c21..10d28bc 100644
--- a/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
+++ b/maven-core/src/main/java/org/apache/maven/DefaultMaven.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,7 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Stream;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Prerequisites;
+import org.apache.maven.api.model.Profile;
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.execution.BuildResumptionAnalyzer;
 import org.apache.maven.execution.BuildResumptionDataRepository;
@@ -34,59 +58,36 @@
 import org.apache.maven.graph.GraphBuilder;
 import org.apache.maven.graph.ProjectSelector;
 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
-import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.internal.aether.MavenChainedWorkspaceReader;
+import org.apache.maven.internal.impl.DefaultSessionFactory;
+import org.apache.maven.internal.impl.InternalSession;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
 import org.apache.maven.lifecycle.internal.LifecycleStarter;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Prerequisites;
-import org.apache.maven.model.Profile;
 import org.apache.maven.model.building.ModelProblem;
 import org.apache.maven.model.building.Result;
 import org.apache.maven.model.superpom.SuperPomProvider;
 import org.apache.maven.plugin.LegacySupport;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuilder;
-import org.apache.maven.repository.LocalRepositoryNotAccessibleException;
 import org.apache.maven.session.scope.internal.SessionScope;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
-import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.CloseableSession;
 import org.eclipse.aether.repository.WorkspaceReader;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.helpers.MessageFormatter;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.Function;
-import java.util.stream.Stream;
-
 import static java.util.stream.Collectors.toSet;
 
 /**
- * @author Jason van Zyl
  */
 @Named
 @Singleton
-public class DefaultMaven
-    implements Maven
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class DefaultMaven implements Maven {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     protected ProjectBuilder projectBuilder;
 
@@ -110,9 +111,12 @@
 
     private final SuperPomProvider superPomProvider;
 
+    private final DefaultSessionFactory defaultSessionFactory;
+
     private final ProjectSelector projectSelector;
 
     @Inject
+    @SuppressWarnings("checkstyle:ParameterNumber")
     public DefaultMaven(
             ProjectBuilder projectBuilder,
             LifecycleStarter lifecycleStarter,
@@ -121,11 +125,11 @@
             LegacySupport legacySupport,
             SessionScope sessionScope,
             DefaultRepositorySystemSessionFactory repositorySessionFactory,
-            @Named( GraphBuilder.HINT ) GraphBuilder graphBuilder,
+            @Named(GraphBuilder.HINT) GraphBuilder graphBuilder,
             BuildResumptionAnalyzer buildResumptionAnalyzer,
             BuildResumptionDataRepository buildResumptionDataRepository,
-            SuperPomProvider superPomProvider )
-    {
+            SuperPomProvider superPomProvider,
+            DefaultSessionFactory defaultSessionFactory) {
         this.projectBuilder = projectBuilder;
         this.lifecycleStarter = lifecycleStarter;
         this.container = container;
@@ -137,38 +141,28 @@
         this.buildResumptionAnalyzer = buildResumptionAnalyzer;
         this.buildResumptionDataRepository = buildResumptionDataRepository;
         this.superPomProvider = superPomProvider;
+        this.defaultSessionFactory = defaultSessionFactory;
         this.projectSelector = new ProjectSelector(); // if necessary switch to DI
     }
 
     @Override
-    public MavenExecutionResult execute( MavenExecutionRequest request )
-    {
+    public MavenExecutionResult execute(MavenExecutionRequest request) {
         MavenExecutionResult result;
 
-        try
-        {
-            result = doExecute( request );
-        }
-        catch ( OutOfMemoryError e )
-        {
-            result = addExceptionToResult( new DefaultMavenExecutionResult(), e );
-        }
-        catch ( RuntimeException e )
-        {
+        try {
+            result = doExecute(request);
+        } catch (OutOfMemoryError e) {
+            result = addExceptionToResult(new DefaultMavenExecutionResult(), e);
+        } catch (RuntimeException e) {
             // TODO Hack to make the cycle detection the same for the new graph builder
-            if ( e.getCause() instanceof ProjectCycleException )
-            {
-                result = addExceptionToResult( new DefaultMavenExecutionResult(), e.getCause() );
+            if (e.getCause() instanceof ProjectCycleException) {
+                result = addExceptionToResult(new DefaultMavenExecutionResult(), e.getCause());
+            } else {
+                result = addExceptionToResult(
+                        new DefaultMavenExecutionResult(), new InternalErrorException("Internal error: " + e, e));
             }
-            else
-            {
-                result = addExceptionToResult( new DefaultMavenExecutionResult(),
-                                               new InternalErrorException( "Internal error: " + e, e ) );
-            }
-        }
-        finally
-        {
-            legacySupport.setSession( null );
+        } finally {
+            legacySupport.setSession(null);
         }
 
         return result;
@@ -202,20 +196,16 @@
     //
     // 11) Execute LifecycleStarter.start()
     //
-    @SuppressWarnings( "checkstyle:methodlength" )
-    private MavenExecutionResult doExecute( MavenExecutionRequest request )
-    {
-        request.setStartTime( new Date() );
+    @SuppressWarnings("checkstyle:methodlength")
+    private MavenExecutionResult doExecute(MavenExecutionRequest request) {
+        request.setStartTime(new Date());
 
         MavenExecutionResult result = new DefaultMavenExecutionResult();
 
-        try
-        {
-            validateLocalRepository( request );
-        }
-        catch ( LocalRepositoryNotAccessibleException e )
-        {
-            return addExceptionToResult( result, e );
+        try {
+            validateLocalRepository(request);
+        } catch (IOException e) {
+            return addExceptionToResult(result, e);
         }
 
         //
@@ -224,70 +214,65 @@
         // so that @SessionScoped components can be @Injected into AbstractLifecycleParticipants.
         //
         sessionScope.enter();
-        try
-        {
-            DefaultRepositorySystemSession repoSession =
-                (DefaultRepositorySystemSession) newRepositorySession( request );
-            MavenSession session = new MavenSession( container, repoSession, request, result );
+        MavenChainedWorkspaceReader chainedWorkspaceReader = new MavenChainedWorkspaceReader();
+        try (CloseableSession closeableSession = newCloseableSession(request, chainedWorkspaceReader)) {
+            MavenSession session = new MavenSession(closeableSession, request, result);
+            session.setSession(defaultSessionFactory.getSession(session));
 
-            sessionScope.seed( MavenSession.class, session );
+            sessionScope.seed(MavenSession.class, session);
+            sessionScope.seed(Session.class, session.getSession());
+            sessionScope.seed(InternalSession.class, InternalSession.from(session.getSession()));
 
-            legacySupport.setSession( session );
+            legacySupport.setSession(session);
 
-            return doExecute( request, session, result, repoSession );
-        }
-        finally
-        {
+            return doExecute(request, session, result, chainedWorkspaceReader);
+        } finally {
             sessionScope.exit();
         }
     }
 
-    private MavenExecutionResult doExecute( MavenExecutionRequest request, MavenSession session,
-                                            MavenExecutionResult result, DefaultRepositorySystemSession repoSession )
-    {
-        try
-        {
-            afterSessionStart( session );
-        }
-        catch ( MavenExecutionException e )
-        {
-            return addExceptionToResult( result, e );
+    private MavenExecutionResult doExecute(
+            MavenExecutionRequest request,
+            MavenSession session,
+            MavenExecutionResult result,
+            MavenChainedWorkspaceReader chainedWorkspaceReader) {
+        try {
+            afterSessionStart(session);
+        } catch (MavenExecutionException e) {
+            return addExceptionToResult(result, e);
         }
 
-        eventCatapult.fire( ExecutionEvent.Type.ProjectDiscoveryStarted, session, null );
-
-        Result<? extends ProjectDependencyGraph> graphResult = buildGraph( session );
-
-        if ( graphResult.hasErrors() )
-        {
-            return addExceptionToResult( result, graphResult.getProblems().iterator().next().getException() );
+        try {
+            WorkspaceReader reactorReader = container.lookup(WorkspaceReader.class, ReactorReader.HINT);
+            chainedWorkspaceReader.setReaders(Collections.singletonList(reactorReader));
+        } catch (ComponentLookupException e) {
+            return addExceptionToResult(result, e);
         }
 
-        try
-        {
-            session.setProjectMap( getProjectMap( session.getProjects() ) );
-        }
-        catch ( DuplicateProjectException e )
-        {
-            return addExceptionToResult( result, e );
+        eventCatapult.fire(ExecutionEvent.Type.ProjectDiscoveryStarted, session, null);
+
+        Result<? extends ProjectDependencyGraph> graphResult = buildGraph(session);
+
+        if (graphResult.hasErrors()) {
+            return addExceptionToResult(
+                    result, graphResult.getProblems().iterator().next().getException());
         }
 
-        try
-        {
-            setupWorkspaceReader( session, repoSession );
+        try {
+            session.setProjectMap(getProjectMap(session.getProjects()));
+        } catch (DuplicateProjectException e) {
+            return addExceptionToResult(result, e);
         }
-        catch ( ComponentLookupException e )
-        {
-            return addExceptionToResult( result, e );
+
+        try {
+            setupWorkspaceReader(session, chainedWorkspaceReader);
+        } catch (ComponentLookupException e) {
+            return addExceptionToResult(result, e);
         }
-        repoSession.setReadOnly();
-        try
-        {
-            afterProjectsRead( session );
-        }
-        catch ( MavenExecutionException e )
-        {
-            return addExceptionToResult( result, e );
+        try {
+            afterProjectsRead(session);
+        } catch (MavenExecutionException e) {
+            return addExceptionToResult(result, e);
         }
 
         //
@@ -299,277 +284,222 @@
         // not expected that a participant will add or remove projects from the session.
         //
 
-        graphResult = buildGraph( session );
+        graphResult = buildGraph(session);
 
-        if ( graphResult.hasErrors() )
-        {
-            return addExceptionToResult( result, graphResult.getProblems().iterator().next().getException() );
+        if (graphResult.hasErrors()) {
+            return addExceptionToResult(
+                    result, graphResult.getProblems().iterator().next().getException());
         }
 
-        try
-        {
-            if ( result.hasExceptions() )
-            {
+        try {
+            if (result.hasExceptions()) {
                 return result;
             }
 
-            result.setTopologicallySortedProjects( session.getProjects() );
+            result.setTopologicallySortedProjects(session.getProjects());
 
-            result.setProject( session.getTopLevelProject() );
+            result.setProject(session.getTopLevelProject());
 
-            validatePrerequisitesForNonMavenPluginProjects( session.getProjects() );
+            validatePrerequisitesForNonMavenPluginProjects(session.getProjects());
 
-            validateRequiredProfiles( session, request.getProfileActivation() );
-            if ( session.getResult().hasExceptions() )
-            {
+            validateRequiredProfiles(session, request.getProfileActivation());
+            if (session.getResult().hasExceptions()) {
                 return result;
             }
 
-            validateOptionalProfiles( session, request.getProfileActivation() );
+            validateOptionalProfiles(session, request.getProfileActivation());
 
-            lifecycleStarter.execute( session );
+            lifecycleStarter.execute(session);
 
-            validateOptionalProjects( request, session );
-            validateOptionalProfiles( session, request.getProfileActivation() );
+            validateOptionalProjects(request, session);
+            validateOptionalProfiles(session, request.getProfileActivation());
 
-            if ( session.getResult().hasExceptions() )
-            {
-                addExceptionToResult( result, session.getResult().getExceptions().get( 0 ) );
-                persistResumptionData( result, session );
+            if (session.getResult().hasExceptions()) {
+                addExceptionToResult(result, session.getResult().getExceptions().get(0));
+                persistResumptionData(result, session);
                 return result;
-            }
-            else
-            {
+            } else {
                 session.getAllProjects().stream()
-                        .filter( MavenProject::isExecutionRoot )
+                        .filter(MavenProject::isExecutionRoot)
                         .findFirst()
-                        .ifPresent( buildResumptionDataRepository::removeResumptionData );
+                        .ifPresent(buildResumptionDataRepository::removeResumptionData);
             }
-        }
-        finally
-        {
-            try
-            {
-                afterSessionEnd( session.getProjects(), session );
-            }
-            catch ( MavenExecutionException e )
-            {
-                return addExceptionToResult( result, e );
+        } finally {
+            try {
+                afterSessionEnd(session);
+            } catch (MavenExecutionException e) {
+                return addExceptionToResult(result, e);
             }
         }
 
         return result;
     }
 
-    private void setupWorkspaceReader( MavenSession session, DefaultRepositorySystemSession repoSession )
-        throws ComponentLookupException
-    {
+    private void setupWorkspaceReader(MavenSession session, MavenChainedWorkspaceReader chainedWorkspaceReader)
+            throws ComponentLookupException {
         // Desired order of precedence for workspace readers before querying the local artifact repositories
-        List<WorkspaceReader> workspaceReaders = new ArrayList<WorkspaceReader>();
+        Set<WorkspaceReader> workspaceReaders = new LinkedHashSet<>();
         // 1) Reactor workspace reader
-        workspaceReaders.add( container.lookup( WorkspaceReader.class, ReactorReader.HINT ) );
+        WorkspaceReader reactorReader = container.lookup(WorkspaceReader.class, ReactorReader.HINT);
+        workspaceReaders.add(reactorReader);
         // 2) Repository system session-scoped workspace reader
-        WorkspaceReader repoWorkspaceReader = repoSession.getWorkspaceReader();
-        if ( repoWorkspaceReader != null )
-        {
-            workspaceReaders.add( repoWorkspaceReader );
+        for (WorkspaceReader repoWorkspaceReader : chainedWorkspaceReader.getReaders()) {
+            if (repoWorkspaceReader != null && repoWorkspaceReader != reactorReader) {
+                workspaceReaders.add(repoWorkspaceReader);
+            }
         }
         // 3) .. n) Project-scoped workspace readers
-        for ( WorkspaceReader workspaceReader : getProjectScopedExtensionComponents( session.getProjects(),
-                                                                                     WorkspaceReader.class ) )
-        {
-            if ( workspaceReaders.contains( workspaceReader ) )
-            {
-                continue;
-            }
-            workspaceReaders.add( workspaceReader );
-        }
-        repoSession.setWorkspaceReader( MavenChainedWorkspaceReader.of( workspaceReaders ) );
+        workspaceReaders.addAll(getProjectScopedExtensionComponents(session.getProjects(), WorkspaceReader.class));
+        chainedWorkspaceReader.setReaders(workspaceReaders);
     }
 
-    private void afterSessionStart( MavenSession session )
-        throws MavenExecutionException
-    {
-        // CHECKSTYLE_OFF: LineLength
-        for ( AbstractMavenLifecycleParticipant listener : getExtensionComponents( Collections.emptyList(),
-                                                                                   AbstractMavenLifecycleParticipant.class ) )
-        // CHECKSTYLE_ON: LineLength
-        {
-            listener.afterSessionStart( session );
-        }
+    private void afterSessionStart(MavenSession session) throws MavenExecutionException {
+        callListeners(session, AbstractMavenLifecycleParticipant::afterSessionStart);
     }
 
-    private void afterProjectsRead( MavenSession session )
-        throws MavenExecutionException
-    {
+    private void afterProjectsRead(MavenSession session) throws MavenExecutionException {
+        callListeners(session, AbstractMavenLifecycleParticipant::afterProjectsRead);
+    }
+
+    private void afterSessionEnd(MavenSession session) throws MavenExecutionException {
+        callListeners(session, AbstractMavenLifecycleParticipant::afterSessionEnd);
+    }
+
+    @FunctionalInterface
+    interface ListenerMethod {
+        void run(AbstractMavenLifecycleParticipant listener, MavenSession session) throws MavenExecutionException;
+    }
+
+    private void callListeners(MavenSession session, ListenerMethod method) throws MavenExecutionException {
         ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try
-        {
-            // CHECKSTYLE_OFF: LineLength
-            for ( AbstractMavenLifecycleParticipant listener : getExtensionComponents( session.getProjects(),
-                                                                                       AbstractMavenLifecycleParticipant.class ) )
-            // CHECKSTYLE_ON: LineLength
-            {
-                Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
-
-                listener.afterProjectsRead( session );
+        try {
+            for (AbstractMavenLifecycleParticipant listener :
+                    getExtensionComponents(session.getProjects(), AbstractMavenLifecycleParticipant.class)) {
+                Thread.currentThread().setContextClassLoader(listener.getClass().getClassLoader());
+                method.run(listener, session);
             }
-        }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( originalClassLoader );
+        } finally {
+            Thread.currentThread().setContextClassLoader(originalClassLoader);
         }
     }
 
-    private void afterSessionEnd( Collection<MavenProject> projects, MavenSession session )
-        throws MavenExecutionException
-    {
-        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
-        try
-        {
-            // CHECKSTYLE_OFF: LineLength
-            for ( AbstractMavenLifecycleParticipant listener : getExtensionComponents( projects,
-                                                                                       AbstractMavenLifecycleParticipant.class ) )
-            // CHECKSTYLE_ON: LineLength
-            {
-                Thread.currentThread().setContextClassLoader( listener.getClass().getClassLoader() );
+    private void persistResumptionData(MavenExecutionResult result, MavenSession session) {
+        boolean hasLifecycleExecutionExceptions =
+                result.getExceptions().stream().anyMatch(LifecycleExecutionException.class::isInstance);
 
-                listener.afterSessionEnd( session );
-            }
-        }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( originalClassLoader );
-        }
-    }
-
-    private void persistResumptionData( MavenExecutionResult result, MavenSession session )
-    {
-        boolean hasLifecycleExecutionExceptions = result.getExceptions().stream()
-                .anyMatch( LifecycleExecutionException.class::isInstance );
-
-        if ( hasLifecycleExecutionExceptions )
-        {
+        if (hasLifecycleExecutionExceptions) {
             MavenProject rootProject = session.getAllProjects().stream()
-                    .filter( MavenProject::isExecutionRoot )
+                    .filter(MavenProject::isExecutionRoot)
                     .findFirst()
-                    .orElseThrow( () -> new IllegalStateException( "No project in the session is execution root" ) );
+                    .orElseThrow(() -> new IllegalStateException("No project in the session is execution root"));
 
-            buildResumptionAnalyzer.determineBuildResumptionData( result ).ifPresent( resumption ->
-            {
-                try
-                {
-                    buildResumptionDataRepository.persistResumptionData( rootProject, resumption );
-                    result.setCanResume( true );
+            buildResumptionAnalyzer.determineBuildResumptionData(result).ifPresent(resumption -> {
+                try {
+                    buildResumptionDataRepository.persistResumptionData(rootProject, resumption);
+                    result.setCanResume(true);
+                } catch (BuildResumptionPersistenceException e) {
+                    logger.warn("Could not persist build resumption data", e);
                 }
-                catch ( BuildResumptionPersistenceException e )
-                {
-                    logger.warn( "Could not persist build resumption data", e );
-                }
-            } );
+            });
         }
     }
 
-    public RepositorySystemSession newRepositorySession( MavenExecutionRequest request )
-    {
-        return repositorySessionFactory.newRepositorySession( request );
+    /**
+     * Nobody should ever use this method.
+     *
+     * @deprecated If you use this method and your code is not in Maven Core, stop doing this.
+     */
+    @Deprecated
+    public RepositorySystemSession newRepositorySession(MavenExecutionRequest request) {
+        return newCloseableSession(request, new MavenChainedWorkspaceReader());
     }
 
-    private void validateLocalRepository( MavenExecutionRequest request )
-        throws LocalRepositoryNotAccessibleException
-    {
+    private CloseableSession newCloseableSession(MavenExecutionRequest request, WorkspaceReader workspaceReader) {
+        return repositorySessionFactory
+                .newRepositorySessionBuilder(request)
+                .setWorkspaceReader(workspaceReader)
+                .build();
+    }
+
+    private void validateLocalRepository(MavenExecutionRequest request) throws IOException {
         File localRepoDir = request.getLocalRepositoryPath();
 
-        logger.debug( "Using local repository at " + localRepoDir );
+        logger.debug("Using local repository at {}", localRepoDir);
 
         localRepoDir.mkdirs();
 
-        if ( !localRepoDir.isDirectory() )
-        {
-            throw new LocalRepositoryNotAccessibleException( "Could not create local repository at " + localRepoDir );
+        if (!localRepoDir.isDirectory()) {
+            throw new IOException("Could not create local repository at " + localRepoDir);
         }
     }
 
-    private <T> Collection<T> getExtensionComponents( Collection<MavenProject> projects, Class<T> role )
-    {
+    private <T> Collection<T> getExtensionComponents(Collection<MavenProject> projects, Class<T> role) {
         Collection<T> foundComponents = new LinkedHashSet<>();
 
-        try
-        {
-            foundComponents.addAll( container.lookupList( role ) );
-        }
-        catch ( ComponentLookupException e )
-        {
+        try {
+            foundComponents.addAll(container.lookupList(role));
+        } catch (ComponentLookupException e) {
             // this is just silly, lookupList should return an empty list!
-            logger.warn( "Failed to lookup " + role + ": " + e.getMessage() );
+            logger.warn("Failed to lookup {}: {}", role, e.getMessage());
         }
 
-        foundComponents.addAll( getProjectScopedExtensionComponents( projects, role ) );
+        foundComponents.addAll(getProjectScopedExtensionComponents(projects, role));
 
         return foundComponents;
     }
 
-    protected <T> Collection<T> getProjectScopedExtensionComponents( Collection<MavenProject> projects, Class<T> role )
-    {
+    protected <T> Collection<T> getProjectScopedExtensionComponents(Collection<MavenProject> projects, Class<T> role) {
+        if (projects == null) {
+            return Collections.emptyList();
+        }
 
         Collection<T> foundComponents = new LinkedHashSet<>();
         Collection<ClassLoader> scannedRealms = new HashSet<>();
 
         Thread currentThread = Thread.currentThread();
         ClassLoader originalContextClassLoader = currentThread.getContextClassLoader();
-        try
-        {
-            for ( MavenProject project : projects )
-            {
+        try {
+            for (MavenProject project : projects) {
                 ClassLoader projectRealm = project.getClassRealm();
 
-                if ( projectRealm != null && scannedRealms.add( projectRealm ) )
-                {
-                    currentThread.setContextClassLoader( projectRealm );
+                if (projectRealm != null && scannedRealms.add(projectRealm)) {
+                    currentThread.setContextClassLoader(projectRealm);
 
-                    try
-                    {
-                        foundComponents.addAll( container.lookupList( role ) );
-                    }
-                    catch ( ComponentLookupException e )
-                    {
+                    try {
+                        foundComponents.addAll(container.lookupList(role));
+                    } catch (ComponentLookupException e) {
                         // this is just silly, lookupList should return an empty list!
-                        logger.warn( "Failed to lookup " + role + ": " + e.getMessage() );
+                        logger.warn("Failed to lookup {}: {}", role, e.getMessage());
                     }
                 }
             }
             return foundComponents;
-        }
-        finally
-        {
-            currentThread.setContextClassLoader( originalContextClassLoader );
+        } finally {
+            currentThread.setContextClassLoader(originalContextClassLoader);
         }
     }
 
-    private MavenExecutionResult addExceptionToResult( MavenExecutionResult result, Throwable e )
-    {
-        if ( !result.getExceptions().contains( e ) )
-        {
-            result.addException( e );
+    private MavenExecutionResult addExceptionToResult(MavenExecutionResult result, Throwable e) {
+        if (!result.getExceptions().contains(e)) {
+            result.addException(e);
         }
 
         return result;
     }
 
-    private void validatePrerequisitesForNonMavenPluginProjects( List<MavenProject> projects )
-    {
-        for ( MavenProject mavenProject : projects )
-        {
-            if ( !"maven-plugin".equals( mavenProject.getPackaging() ) )
-            {
-                Prerequisites prerequisites = mavenProject.getPrerequisites();
-                if ( prerequisites != null && prerequisites.getMaven() != null )
-                {
-                    logger.warn( "The project " + mavenProject.getId() + " uses prerequisites"
-                        + " which is only intended for maven-plugin projects "
-                        + "but not for non maven-plugin projects. "
-                        + "For such purposes you should use the maven-enforcer-plugin. "
-                        + "See https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html" );
+    private void validatePrerequisitesForNonMavenPluginProjects(List<MavenProject> projects) {
+        for (MavenProject mavenProject : projects) {
+            if (!"maven-plugin".equals(mavenProject.getPackaging())) {
+                Prerequisites prerequisites =
+                        mavenProject.getModel().getDelegate().getPrerequisites();
+                if (prerequisites != null && prerequisites.getMaven() != null) {
+                    logger.warn(
+                            "The project {} uses prerequisites"
+                                    + " which is only intended for maven-plugin projects "
+                                    + "but not for non maven-plugin projects. "
+                                    + "For such purposes you should use the maven-enforcer-plugin. "
+                                    + "See https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html",
+                            mavenProject.getId());
                 }
             }
         }
@@ -580,34 +510,33 @@
      * @param session The Maven session
      * @return A {@link Set} of profile identifiers, never {@code null}.
      */
-    private Set<String> getAllProfiles( MavenSession session )
-    {
-        final Model superPomModel = superPomProvider.getSuperModel( "4.0.0" );
+    private Set<String> getAllProfiles(MavenSession session) {
+        final Map<String, Model> superPomModels = new HashMap<>();
         final Set<MavenProject> projectsIncludingParents = new HashSet<>();
-        for ( MavenProject project : session.getProjects() )
-        {
-            boolean isAdded = projectsIncludingParents.add( project );
+        for (MavenProject project : session.getProjects()) {
+            superPomModels.computeIfAbsent(
+                    project.getModelVersion(),
+                    v -> superPomProvider.getSuperModel(v).getDelegate());
+            boolean isAdded = projectsIncludingParents.add(project);
             MavenProject parent = project.getParent();
-            while ( isAdded && parent != null )
-            {
-                isAdded = projectsIncludingParents.add( parent );
+            while (isAdded && parent != null) {
+                isAdded = projectsIncludingParents.add(parent);
                 parent = parent.getParent();
             }
         }
 
         final Stream<String> projectProfiles = projectsIncludingParents.stream()
-                .map( MavenProject::getModel )
-                .map( Model::getProfiles )
-                .flatMap( Collection::stream )
-                .map( Profile::getId );
-        final Stream<String> settingsProfiles = session.getSettings().getProfiles().stream()
-                .map( org.apache.maven.settings.Profile::getId );
-        final Stream<String> superPomProfiles = superPomModel.getProfiles().stream()
-                .map( Profile::getId );
+                .flatMap(p -> p.getModel().getDelegate().getProfiles().stream())
+                .map(Profile::getId);
+        final Stream<String> settingsProfiles =
+                session.getSettings().getProfiles().stream().map(org.apache.maven.settings.Profile::getId);
+        final Stream<String> superPomProfiles = superPomModels.values().stream()
+                .flatMap(p -> p.getProfiles().stream())
+                .map(Profile::getId);
 
-        return Stream.of( projectProfiles, settingsProfiles, superPomProfiles )
-                .flatMap( Function.identity() )
-                .collect( toSet() );
+        return Stream.of(projectProfiles, settingsProfiles, superPomProfiles)
+                .flatMap(Function.identity())
+                .collect(toSet());
     }
 
     /**
@@ -615,26 +544,26 @@
      * @param session the Maven session.
      * @param profileActivation the requested optional and required profiles.
      */
-    private void validateRequiredProfiles( MavenSession session, ProfileActivation profileActivation )
-    {
-        final Set<String> allAvailableProfiles = getAllProfiles( session );
+    private void validateRequiredProfiles(MavenSession session, ProfileActivation profileActivation) {
+        final Set<String> allAvailableProfiles = getAllProfiles(session);
 
-        final Set<String> requiredProfiles = new HashSet<>( );
-        requiredProfiles.addAll( profileActivation.getRequiredActiveProfileIds() );
-        requiredProfiles.addAll( profileActivation.getRequiredInactiveProfileIds() );
+        final Set<String> requiredProfiles = new HashSet<>();
+        requiredProfiles.addAll(profileActivation.getRequiredActiveProfileIds());
+        requiredProfiles.addAll(profileActivation.getRequiredInactiveProfileIds());
 
         // Check whether the required profiles were found in any of the projects we're building.
         final Set<String> notFoundRequiredProfiles = requiredProfiles.stream()
-                .filter( rap -> !allAvailableProfiles.contains( rap ) )
-                .collect( toSet() );
+                .filter(rap -> !allAvailableProfiles.contains(rap))
+                .collect(toSet());
 
-        if ( !notFoundRequiredProfiles.isEmpty() )
-        {
+        if (!notFoundRequiredProfiles.isEmpty()) {
             // Use SLF4J formatter for consistency with warnings reported by logger
             final String message = MessageFormatter.format(
-                    "The requested profiles {} could not be activated or deactivated because they do not"
-                            + " exist.", notFoundRequiredProfiles ).getMessage();
-            addExceptionToResult( session.getResult(), new MissingProfilesException( message ) );
+                            "The requested profiles {} could not be activated or deactivated because they do not"
+                                    + " exist.",
+                            notFoundRequiredProfiles)
+                    .getMessage();
+            addExceptionToResult(session.getResult(), new MissingProfilesException(message));
         }
     }
 
@@ -643,15 +572,14 @@
      * @param request the {@link MavenExecutionRequest}.
      * @param session the {@link MavenSession}.
      */
-    private void validateOptionalProjects( MavenExecutionRequest request, MavenSession session )
-    {
+    private void validateOptionalProjects(MavenExecutionRequest request, MavenSession session) {
         final ProjectActivation projectActivation = request.getProjectActivation();
         final Set<String> allOptionalSelectors = new HashSet<>();
-        allOptionalSelectors.addAll( projectActivation.getOptionalActiveProjectSelectors() );
-        allOptionalSelectors.addAll( projectActivation.getRequiredActiveProjectSelectors() );
+        allOptionalSelectors.addAll(projectActivation.getOptionalActiveProjectSelectors());
+        allOptionalSelectors.addAll(projectActivation.getRequiredActiveProjectSelectors());
         // We intentionally ignore the results of this method.
         // As a side effect it will log the optional projects that could not be resolved.
-        projectSelector.getOptionalProjectsBySelectors( request, session.getAllProjects(), allOptionalSelectors );
+        projectSelector.getOptionalProjectsBySelectors(request, session.getAllProjects(), allOptionalSelectors);
     }
 
     /**
@@ -659,88 +587,75 @@
      * @param session the Maven session.
      * @param profileActivation the requested optional and required profiles.
      */
-    private void validateOptionalProfiles( MavenSession session, ProfileActivation profileActivation )
-    {
-        final Set<String> allAvailableProfiles = getAllProfiles( session );
+    private void validateOptionalProfiles(MavenSession session, ProfileActivation profileActivation) {
+        final Set<String> allAvailableProfiles = getAllProfiles(session);
 
-        final Set<String> optionalProfiles = new HashSet<>( );
-        optionalProfiles.addAll( profileActivation.getOptionalActiveProfileIds() );
-        optionalProfiles.addAll( profileActivation.getOptionalInactiveProfileIds() );
+        final Set<String> optionalProfiles = new HashSet<>();
+        optionalProfiles.addAll(profileActivation.getOptionalActiveProfileIds());
+        optionalProfiles.addAll(profileActivation.getOptionalInactiveProfileIds());
 
         final Set<String> notFoundOptionalProfiles = optionalProfiles.stream()
-                .filter( rap -> !allAvailableProfiles.contains( rap ) )
-                .collect( toSet() );
+                .filter(rap -> !allAvailableProfiles.contains(rap))
+                .collect(toSet());
 
-        if ( !notFoundOptionalProfiles.isEmpty() )
-        {
-            logger.info( "The requested optional profiles {} could not be activated or deactivated because they do not"
-                            + " exist.", notFoundOptionalProfiles );
+        if (!notFoundOptionalProfiles.isEmpty()) {
+            logger.info(
+                    "The requested optional profiles {} could not be activated or deactivated because they do not"
+                            + " exist.",
+                    notFoundOptionalProfiles);
         }
     }
 
-    private Map<String, MavenProject> getProjectMap( Collection<MavenProject> projects )
-        throws DuplicateProjectException
-    {
+    private Map<String, MavenProject> getProjectMap(Collection<MavenProject> projects)
+            throws DuplicateProjectException {
         Map<String, MavenProject> index = new LinkedHashMap<>();
         Map<String, List<File>> collisions = new LinkedHashMap<>();
 
-        for ( MavenProject project : projects )
-        {
-            String projectId = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
+        for (MavenProject project : projects) {
+            String projectId = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion());
 
-            MavenProject collision = index.get( projectId );
+            MavenProject collision = index.get(projectId);
 
-            if ( collision == null )
-            {
-                index.put( projectId, project );
-            }
-            else
-            {
-                List<File> pomFiles = collisions.get( projectId );
+            if (collision == null) {
+                index.put(projectId, project);
+            } else {
+                List<File> pomFiles = collisions.get(projectId);
 
-                if ( pomFiles == null )
-                {
-                    pomFiles = new ArrayList<>( Arrays.asList( collision.getFile(), project.getFile() ) );
-                    collisions.put( projectId, pomFiles );
-                }
-                else
-                {
-                    pomFiles.add( project.getFile() );
+                if (pomFiles == null) {
+                    pomFiles = new ArrayList<>(Arrays.asList(collision.getFile(), project.getFile()));
+                    collisions.put(projectId, pomFiles);
+                } else {
+                    pomFiles.add(project.getFile());
                 }
             }
         }
 
-        if ( !collisions.isEmpty() )
-        {
-            throw new DuplicateProjectException( "Two or more projects in the reactor"
-                + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
-                + " is unique for each project: " + collisions, collisions );
+        if (!collisions.isEmpty()) {
+            throw new DuplicateProjectException(
+                    "Two or more projects in the reactor"
+                            + " have the same identifier, please make sure that <groupId>:<artifactId>:<version>"
+                            + " is unique for each project: " + collisions,
+                    collisions);
         }
 
         return index;
     }
 
-    private Result<? extends ProjectDependencyGraph> buildGraph( MavenSession session )
-    {
-        Result<? extends ProjectDependencyGraph> graphResult = graphBuilder.build( session );
-        for ( ModelProblem problem : graphResult.getProblems() )
-        {
-            if ( problem.getSeverity() == ModelProblem.Severity.WARNING )
-            {
-                logger.warn( problem.getMessage() );
-            }
-            else
-            {
-                logger.error( problem.getMessage() );
+    private Result<? extends ProjectDependencyGraph> buildGraph(MavenSession session) {
+        Result<? extends ProjectDependencyGraph> graphResult = graphBuilder.build(session);
+        for (ModelProblem problem : graphResult.getProblems()) {
+            if (problem.getSeverity() == ModelProblem.Severity.WARNING) {
+                logger.warn(problem.getMessage());
+            } else {
+                logger.error(problem.getMessage());
             }
         }
 
-        if ( !graphResult.hasErrors() )
-        {
+        if (!graphResult.hasErrors()) {
             ProjectDependencyGraph projectDependencyGraph = graphResult.get();
-            session.setProjects( projectDependencyGraph.getSortedProjects() );
-            session.setAllProjects( projectDependencyGraph.getAllProjects() );
-            session.setProjectDependencyGraph( projectDependencyGraph );
+            session.setProjects(projectDependencyGraph.getSortedProjects());
+            session.setAllProjects(projectDependencyGraph.getAllProjects());
+            session.setProjectDependencyGraph(projectDependencyGraph);
         }
 
         return graphResult;
@@ -748,8 +663,7 @@
 
     @Deprecated
     // 5 January 2014
-    protected Logger getLogger()
-    {
+    protected Logger getLogger() {
         return logger;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/DefaultProjectDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/DefaultProjectDependenciesResolver.java
deleted file mode 100644
index 41255e7..0000000
--- a/maven-core/src/main/java/org/apache/maven/DefaultProjectDependenciesResolver.java
+++ /dev/null
@@ -1,232 +0,0 @@
-package org.apache.maven;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Set;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
-import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
-import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
-import org.apache.maven.artifact.resolver.ResolutionErrorHandler;
-import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.artifact.ProjectArtifact;
-import org.apache.maven.repository.RepositorySystem;
-
-/**
- * @deprecated As of 3.2.2, and there is no direct replacement. This is an internal class which was not marked as such,
- *             but should have been.
- *
- */
-@Deprecated
-@Named
-@Singleton
-public class DefaultProjectDependenciesResolver
-    implements ProjectDependenciesResolver
-{
-
-    private final RepositorySystem repositorySystem;
-
-    private final ResolutionErrorHandler resolutionErrorHandler;
-
-    @Inject
-    public DefaultProjectDependenciesResolver(
-            RepositorySystem repositorySystem,
-            ResolutionErrorHandler resolutionErrorHandler )
-    {
-        this.repositorySystem = repositorySystem;
-        this.resolutionErrorHandler = resolutionErrorHandler;
-    }
-
-    public Set<Artifact> resolve( MavenProject project, Collection<String> scopesToResolve, MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return resolve( Collections.singleton( project ), scopesToResolve, session );
-    }
-
-    public Set<Artifact> resolve( MavenProject project, Collection<String> scopesToCollect,
-                                  Collection<String> scopesToResolve, MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        Set<MavenProject> mavenProjects = Collections.singleton( project );
-        return resolveImpl( mavenProjects, scopesToCollect, scopesToResolve, session,
-                            getIgnorableArtifacts( mavenProjects ) );
-    }
-
-    public Set<Artifact> resolve( Collection<? extends MavenProject> projects, Collection<String> scopesToResolve,
-                                  MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return resolveImpl( projects, null, scopesToResolve, session, getIgnorableArtifacts( projects ) );
-    }
-
-    public Set<Artifact> resolve( MavenProject project, Collection<String> scopesToCollect,
-                                  Collection<String> scopesToResolve, MavenSession session,
-                                  Set<Artifact> ignorableArtifacts )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return resolveImpl( Collections.singleton( project ), scopesToCollect, scopesToResolve, session,
-                            getIgnorableArtifacts( ignorableArtifacts ) );
-    }
-
-
-    private Set<Artifact> resolveImpl( Collection<? extends MavenProject> projects, Collection<String> scopesToCollect,
-                                       Collection<String> scopesToResolve, MavenSession session,
-                                       Set<String> projectIds )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        Set<Artifact> resolved = new LinkedHashSet<>();
-
-        if ( projects == null || projects.isEmpty() )
-        {
-            return resolved;
-        }
-
-        if ( ( scopesToCollect == null || scopesToCollect.isEmpty() )
-            && ( scopesToResolve == null || scopesToResolve.isEmpty() ) )
-        {
-            return resolved;
-        }
-
-        /*
-
-        Logic for transitive global exclusions
-
-        List<String> exclusions = new ArrayList<String>();
-
-        for ( Dependency d : project.getDependencies() )
-        {
-            if ( d.getExclusions() != null )
-            {
-                for ( Exclusion e : d.getExclusions() )
-                {
-                    exclusions.add(  e.getGroupId() + ":" + e.getArtifactId() );
-                }
-            }
-        }
-
-        ArtifactFilter scopeFilter = new ScopeArtifactFilter( scope );
-
-        ArtifactFilter filter;
-
-        if ( ! exclusions.isEmpty() )
-        {
-            filter = new AndArtifactFilter( Arrays.asList( new ArtifactFilter[]{
-                new ExcludesArtifactFilter( exclusions ), scopeFilter } ) );
-        }
-        else
-        {
-            filter = scopeFilter;
-        }
-        */
-
-        CumulativeScopeArtifactFilter resolutionScopeFilter = new CumulativeScopeArtifactFilter( scopesToResolve );
-
-        CumulativeScopeArtifactFilter collectionScopeFilter = new CumulativeScopeArtifactFilter( scopesToCollect );
-        collectionScopeFilter = new CumulativeScopeArtifactFilter( collectionScopeFilter, resolutionScopeFilter );
-
-        ArtifactResolutionRequest request =
-            new ArtifactResolutionRequest().setResolveRoot( false ).setResolveTransitively( true ).setCollectionFilter(
-                collectionScopeFilter ).setResolutionFilter( resolutionScopeFilter ).setLocalRepository(
-                session.getLocalRepository() ).setOffline( session.isOffline() ).setForceUpdate(
-                session.getRequest().isUpdateSnapshots() );
-        request.setServers( session.getRequest().getServers() );
-        request.setMirrors( session.getRequest().getMirrors() );
-        request.setProxies( session.getRequest().getProxies() );
-
-        for ( MavenProject project : projects )
-        {
-            request.setArtifact( new ProjectArtifact( project ) );
-            request.setArtifactDependencies( project.getDependencyArtifacts() );
-            request.setManagedVersionMap( project.getManagedVersionMap() );
-            request.setRemoteRepositories( project.getRemoteArtifactRepositories() );
-
-            ArtifactResolutionResult result = repositorySystem.resolve( request );
-
-            try
-            {
-                resolutionErrorHandler.throwErrors( request, result );
-            }
-            catch ( MultipleArtifactsNotFoundException e )
-            {
-
-                Collection<Artifact> missing = new HashSet<>( e.getMissingArtifacts() );
-
-                for ( Iterator<Artifact> it = missing.iterator(); it.hasNext(); )
-                {
-                    String key = ArtifactUtils.key( it.next() );
-                    if ( projectIds.contains( key ) )
-                    {
-                        it.remove();
-                    }
-                }
-
-                if ( !missing.isEmpty() )
-                {
-                    throw e;
-                }
-            }
-
-            resolved.addAll( result.getArtifacts() );
-        }
-
-        return resolved;
-    }
-
-
-    private Set<String> getIgnorableArtifacts( Collection<? extends MavenProject> projects )
-    {
-        Set<String> projectIds = new HashSet<>( projects.size() * 2 );
-
-        for ( MavenProject p : projects )
-        {
-            String key = ArtifactUtils.key( p.getGroupId(), p.getArtifactId(), p.getVersion() );
-            projectIds.add( key );
-        }
-        return projectIds;
-    }
-
-    private Set<String> getIgnorableArtifacts( Iterable<Artifact> artifactIterable )
-    {
-        Set<String> projectIds = new HashSet<>();
-
-        for ( Artifact artifact : artifactIterable )
-        {
-            String key = ArtifactUtils.key( artifact );
-            projectIds.add( key );
-        }
-        return projectIds;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/DuplicateProjectException.java b/maven-core/src/main/java/org/apache/maven/DuplicateProjectException.java
index 5d7cec1..637d6c5 100644
--- a/maven-core/src/main/java/org/apache/maven/DuplicateProjectException.java
+++ b/maven-core/src/main/java/org/apache/maven/DuplicateProjectException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 import java.io.File;
 import java.util.LinkedHashMap;
@@ -27,11 +26,8 @@
 /**
  * Signals a collision of two or more projects with the same g:a:v during a reactor build.
  *
- * @author Benjamin Bentmann
  */
-public class DuplicateProjectException
-    extends MavenExecutionException
-{
+public class DuplicateProjectException extends MavenExecutionException {
 
     private Map<String, List<File>> collisions;
 
@@ -41,11 +37,10 @@
      * @param message The message text, may be {@code null}.
      * @param collisions The POM files of the projects that collided, indexed by their g:a:v, may be {@code null}.
      */
-    public DuplicateProjectException( String message, Map<String, List<File>> collisions )
-    {
-        super( message, (File) null );
+    public DuplicateProjectException(String message, Map<String, List<File>> collisions) {
+        super(message, (File) null);
 
-        this.collisions = ( collisions != null ) ? collisions : new LinkedHashMap<>();
+        this.collisions = (collisions != null) ? collisions : new LinkedHashMap<>();
     }
 
     /**
@@ -53,9 +48,7 @@
      *
      * @return The POM files of the projects that collided, indexed by their g:a:v, never {@code null}.
      */
-    public Map<String, List<File>> getCollisions()
-    {
+    public Map<String, List<File>> getCollisions() {
         return collisions;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/InternalErrorException.java b/maven-core/src/main/java/org/apache/maven/InternalErrorException.java
index afe92c1..dbd655e 100644
--- a/maven-core/src/main/java/org/apache/maven/InternalErrorException.java
+++ b/maven-core/src/main/java/org/apache/maven/InternalErrorException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,19 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 /**
  * Signals an internal error in Maven itself, e.g. a programming bug.
  *
- * @author Benjamin Bentmann
  */
-public class InternalErrorException
-    extends MavenExecutionException
-{
+public class InternalErrorException extends MavenExecutionException {
 
-    public InternalErrorException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public InternalErrorException(String message, Throwable cause) {
+        super(message, cause);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/Maven.java b/maven-core/src/main/java/org/apache/maven/Maven.java
index 665da6c..95d97c3 100644
--- a/maven-core/src/main/java/org/apache/maven/Maven.java
+++ b/maven-core/src/main/java/org/apache/maven/Maven.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionResult;
@@ -25,14 +24,12 @@
 /**
  * The main Maven execution entry point, which will execute a full Maven execution session.
  *
- * @author Jason van Zyl
  * @see org.apache.maven.execution.MavenSession
  */
-public interface Maven
-{
+public interface Maven {
     @Deprecated
-    @SuppressWarnings( "checkstyle:constantname" )
+    @SuppressWarnings("checkstyle:constantname")
     String POMv4 = "pom.xml";
 
-    MavenExecutionResult execute( MavenExecutionRequest request );
-}
\ No newline at end of file
+    MavenExecutionResult execute(MavenExecutionRequest request);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/MavenExecutionException.java b/maven-core/src/main/java/org/apache/maven/MavenExecutionException.java
index 5708e52..223469d 100644
--- a/maven-core/src/main/java/org/apache/maven/MavenExecutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/MavenExecutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,38 +16,32 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 import java.io.File;
 
 import org.apache.maven.project.ProjectBuildingException;
 
 /**
- * @author Jason van Zyl
  */
-public class MavenExecutionException
-    extends Exception
-{
+public class MavenExecutionException extends Exception {
     private File pomFile;
 
-    public MavenExecutionException( String message, File pomFile )
-    {
-        super( message );
+    public MavenExecutionException(String message, File pomFile) {
+        super(message);
         this.pomFile = pomFile;
     }
 
-    public MavenExecutionException( String message, File pomFile, ProjectBuildingException cause )
-    {
-        super( message, cause );
+    public MavenExecutionException(String message, File pomFile, ProjectBuildingException cause) {
+        super(message, cause);
         this.pomFile = pomFile;
     }
 
-    public MavenExecutionException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public MavenExecutionException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public File getPomFile()
-    {
+    public File getPomFile() {
         return pomFile;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/MissingModuleException.java b/maven-core/src/main/java/org/apache/maven/MissingModuleException.java
index 1bdf87a..d16c9d5 100644
--- a/maven-core/src/main/java/org/apache/maven/MissingModuleException.java
+++ b/maven-core/src/main/java/org/apache/maven/MissingModuleException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,34 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 import java.io.File;
 
 /**
  * MissingModuleException
  */
-public class MissingModuleException
-    extends MavenExecutionException
-{
+public class MissingModuleException extends MavenExecutionException {
 
     private File moduleFile;
     private final String moduleName;
 
-    public MissingModuleException( String moduleName, File moduleFile, File pomFile )
-    {
-        super( "The module: " + moduleName + " cannot be found in file: " + moduleFile, pomFile );
+    public MissingModuleException(String moduleName, File moduleFile, File pomFile) {
+        super("The module: " + moduleName + " cannot be found in file: " + moduleFile, pomFile);
         this.moduleName = moduleName;
         this.moduleFile = moduleFile;
     }
 
-    public File getModuleFile()
-    {
+    public File getModuleFile() {
         return moduleFile;
     }
 
-    public String getModuleName()
-    {
+    public String getModuleName() {
         return moduleName;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/MissingProfilesException.java b/maven-core/src/main/java/org/apache/maven/MissingProfilesException.java
index 6e9ee76..467dd13 100644
--- a/maven-core/src/main/java/org/apache/maven/MissingProfilesException.java
+++ b/maven-core/src/main/java/org/apache/maven/MissingProfilesException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 /**
  * Signals that the user referenced one or more Maven profiles that could not be located in either the project or the
  * settings.
  */
-public class MissingProfilesException
-        extends Exception
-{
-    public MissingProfilesException( String message )
-    {
-        super( message );
+public class MissingProfilesException extends Exception {
+    public MissingProfilesException(String message) {
+        super(message);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/ProjectBuildFailureException.java b/maven-core/src/main/java/org/apache/maven/ProjectBuildFailureException.java
index 66ed3a0..8504b6f 100644
--- a/maven-core/src/main/java/org/apache/maven/ProjectBuildFailureException.java
+++ b/maven-core/src/main/java/org/apache/maven/ProjectBuildFailureException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
 import org.apache.maven.plugin.MojoFailureException;
 
@@ -27,29 +26,23 @@
  * project instance, so we can wrap the {@link MojoFailureException} with context
  * information including projectId that caused the failure.
  *
- * @author jdcasey
  *
  */
-public class ProjectBuildFailureException
-    extends BuildFailureException
-{
+public class ProjectBuildFailureException extends BuildFailureException {
 
     private final String projectId;
 
-    public ProjectBuildFailureException( String projectId, MojoFailureException cause )
-    {
-        super( "Build for project: " + projectId + " failed during execution of mojo.", cause );
+    public ProjectBuildFailureException(String projectId, MojoFailureException cause) {
+        super("Build for project: " + projectId + " failed during execution of mojo.", cause);
 
         this.projectId = projectId;
     }
 
-    public MojoFailureException getMojoFailureException()
-    {
+    public MojoFailureException getMojoFailureException() {
         return (MojoFailureException) getCause();
     }
 
-    public String getProjectId()
-    {
+    public String getProjectId() {
         return projectId;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java b/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
index b4a6fd0..ad004a7 100644
--- a/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
+++ b/maven-core/src/main/java/org/apache/maven/ProjectCycleException.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
-import org.codehaus.plexus.util.dag.CycleDetectedException;
+import org.apache.maven.project.CycleDetectedException;
 
 /**
- * @author jdcasey
  */
-public class ProjectCycleException
-    extends BuildFailureException
-{
-    public ProjectCycleException( String message )
-    {
-        super( message );
+public class ProjectCycleException extends BuildFailureException {
+    public ProjectCycleException(String message) {
+        super(message);
     }
 
-    public ProjectCycleException( String message, CycleDetectedException cause )
-    {
-        super( message, cause );
+    public ProjectCycleException(String message, CycleDetectedException cause) {
+        super(message, cause);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/ProjectDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/ProjectDependenciesResolver.java
deleted file mode 100644
index 1537aa7..0000000
--- a/maven-core/src/main/java/org/apache/maven/ProjectDependenciesResolver.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package org.apache.maven;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Collection;
-import java.util.Set;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.project.MavenProject;
-
-/**
- * @deprecated As of 3.2.2, and there is no direct replacement. This is an internal class which was not marked as such,
- *             but should have been.
- * @author jvanzyl
- *
- */
-@Deprecated
-public interface ProjectDependenciesResolver
-{
-
-    /**
-     * Resolves the transitive dependencies of the specified project.
-     *
-     * @param project         The project whose dependencies should be resolved, must not be {@code null}.
-     * @param scopesToResolve The dependency scopes that should be resolved, may be {@code null}.
-     * @param session         The current build session, must not be {@code null}.
-     * @return The transitive dependencies of the specified project that match the requested scopes, never {@code null}.
-     * @throws ArtifactResolutionException in case of resolution issue
-     * @throws ArtifactNotFoundException if an artifact is not found
-     */
-    Set<Artifact> resolve( MavenProject project, Collection<String> scopesToResolve, MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
-
-    /**
-     * Resolves the transitive dependencies of the specified project.
-     *
-     * @param project         The project whose dependencies should be resolved, must not be {@code null}.
-     * @param scopesToCollect The dependency scopes that should be collected, may be {@code null}.
-     * @param scopesToResolve The dependency scopes that should be collected and also resolved, may be {@code null}.
-     * @param session         The current build session, must not be {@code null}.
-     * @return The transitive dependencies of the specified project that match the requested scopes, never {@code null}.
-     * @throws ArtifactResolutionException in case of resolution issue
-     * @throws ArtifactNotFoundException if an artifact is not found
-     */
-    Set<Artifact> resolve( MavenProject project, Collection<String> scopesToCollect,
-                           Collection<String> scopesToResolve, MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
-
-    /**
-     * Resolves the transitive dependencies of the specified project.
-     *
-     * @param project            The project whose dependencies should be resolved, must not be {@code null}.
-     * @param scopesToCollect    The dependency scopes that should be collected, may be {@code null}.
-     * @param scopesToResolve    The dependency scopes that should be collected and also resolved, may be {@code null}.
-     * @param session            The current build session, must not be {@code null}.
-     * @param ignorableArtifacts Artifacts that need not be resolved
-     * @return The transitive dependencies of the specified project that match the requested scopes, never {@code null}.
-     * @throws ArtifactResolutionException in case of resolution issue
-     * @throws ArtifactNotFoundException if an artifact is not found
-     */
-    Set<Artifact> resolve( MavenProject project, Collection<String> scopesToCollect,
-                           Collection<String> scopesToResolve, MavenSession session, Set<Artifact> ignorableArtifacts )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
-
-    /**
-     * Resolves the transitive dependencies of the specified projects. Note that dependencies which can't be resolved
-     * from any repository but are present among the set of specified projects will not cause an exception. Instead,
-     * those unresolved artifacts will be returned in the result set, allowing the caller to take special care of
-     * artifacts that haven't been build yet.
-     *
-     * @param projects The projects whose dependencies should be resolved, may be {@code null}.
-     * @param scopes   The dependency scopes that should be resolved, may be {@code null}.
-     * @param session  The current build session, must not be {@code null}.
-     * @return The transitive dependencies of the specified projects that match the requested scopes, never
-     *         {@code null}.
-     * @throws ArtifactResolutionException in case of resolution issue
-     * @throws ArtifactNotFoundException if an artifact is not found
-     */
-    Set<Artifact> resolve( Collection<? extends MavenProject> projects, Collection<String> scopes,
-                           MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException;
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/ReactorReader.java b/maven-core/src/main/java/org/apache/maven/ReactorReader.java
index e50eabb..f22fd06 100644
--- a/maven-core/src/main/java/org/apache/maven/ReactorReader.java
+++ b/maven-core/src/main/java/org/apache/maven/ReactorReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,131 +16,120 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.DirectoryNotEmptyException;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.function.Predicate;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.eventspy.EventSpy;
+import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.Model;
 import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.ProjectArtifact;
 import org.apache.maven.repository.internal.MavenWorkspaceReader;
+import org.codehaus.plexus.PlexusContainer;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.repository.WorkspaceRepository;
 import org.eclipse.aether.util.artifact.ArtifactIdUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import static java.util.function.Function.identity;
-import static java.util.stream.Collectors.groupingBy;
-import static java.util.stream.Collectors.toMap;
-
 /**
  * An implementation of a workspace reader that knows how to search the Maven reactor for artifacts, either as packaged
  * jar if it has been built, or only compile output directory if packaging hasn't happened yet.
  *
- * @author Jason van Zyl
  */
-@Named( ReactorReader.HINT )
+@Named(ReactorReader.HINT)
 @SessionScoped
-class ReactorReader
-    implements MavenWorkspaceReader
-{
+class ReactorReader implements MavenWorkspaceReader {
     public static final String HINT = "reactor";
 
-    private static final Collection<String> COMPILE_PHASE_TYPES =
-        Arrays.asList( "jar", "ejb-client", "war", "rar", "ejb3", "par", "sar", "wsr", "har", "app-client" );
+    public static final String PROJECT_LOCAL_REPO = "project-local-repo";
 
-    private static final Logger LOGGER = LoggerFactory.getLogger( ReactorReader.class );
+    private static final Collection<String> COMPILE_PHASE_TYPES = new HashSet<>(
+            Arrays.asList("jar", "ejb-client", "war", "rar", "ejb3", "par", "sar", "wsr", "har", "app-client"));
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ReactorReader.class);
 
     private final MavenSession session;
-    private final Map<String, MavenProject> projectsByGAV;
-    private final Map<String, List<MavenProject>> projectsByGA;
     private final WorkspaceRepository repository;
-
-    private Function<MavenProject, String> projectIntoKey =
-            s -> ArtifactUtils.key( s.getGroupId(), s.getArtifactId(), s.getVersion() );
-
-    private Function<MavenProject, String> projectIntoVersionlessKey =
-            s -> ArtifactUtils.versionlessKey( s.getGroupId(), s.getArtifactId() );
+    // groupId -> (artifactId -> (version -> project)))
+    private Map<String, Map<String, Map<String, MavenProject>>> projects;
+    private Path projectLocalRepository;
+    // projectId -> Deque<lifecycle>
+    private final Map<String, Deque<String>> lifecycles = new ConcurrentHashMap<>();
 
     @Inject
-    ReactorReader( MavenSession session )
-    {
+    ReactorReader(MavenSession session) {
         this.session = session;
-        this.projectsByGAV =
-                session.getAllProjects().stream()
-                        .collect( toMap( projectIntoKey, identity() ) );
-
-        this.projectsByGA = projectsByGAV.values().stream()
-                .collect( groupingBy( projectIntoVersionlessKey ) );
-
-        repository = new WorkspaceRepository( "reactor", new HashSet<>( projectsByGAV.keySet() ) );
+        this.repository = new WorkspaceRepository("reactor", null);
     }
 
     //
     // Public API
     //
 
-    public WorkspaceRepository getRepository()
-    {
+    public WorkspaceRepository getRepository() {
         return repository;
     }
 
-    public File findArtifact( Artifact artifact )
-    {
-        String projectKey = ArtifactUtils.key( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
+    public File findArtifact(Artifact artifact) {
+        MavenProject project = getProject(artifact);
 
-        MavenProject project = projectsByGAV.get( projectKey );
-
-        if ( project != null )
-        {
-            File file = find( project, artifact );
-            if ( file == null && project != project.getExecutionProject() )
-            {
-                file = find( project.getExecutionProject(), artifact );
+        if (project != null) {
+            File file = findArtifact(project, artifact);
+            if (file == null && project != project.getExecutionProject()) {
+                file = findArtifact(project.getExecutionProject(), artifact);
             }
             return file;
         }
 
+        // No project, but most certainly a dependency which has been built previously
+        File packagedArtifactFile = findInProjectLocalRepository(artifact);
+        if (packagedArtifactFile != null && packagedArtifactFile.exists()) {
+            return packagedArtifactFile;
+        }
+
         return null;
     }
 
-    public List<String> findVersions( Artifact artifact )
-    {
-        String key = ArtifactUtils.versionlessKey( artifact.getGroupId(), artifact.getArtifactId() );
-
-        return Optional.ofNullable( projectsByGA.get( key ) )
-                .orElse( Collections.emptyList() ).stream()
-                .filter( s -> Objects.nonNull( find( s, artifact ) ) )
-                .map( MavenProject::getVersion )
-                .collect( Collectors.collectingAndThen( Collectors.toList(), Collections::unmodifiableList ) );
+    public List<String> findVersions(Artifact artifact) {
+        return getProjects()
+                .getOrDefault(artifact.getGroupId(), Collections.emptyMap())
+                .getOrDefault(artifact.getArtifactId(), Collections.emptyMap())
+                .values()
+                .stream()
+                .filter(p -> Objects.nonNull(findArtifact(p, artifact)))
+                .map(MavenProject::getVersion)
+                .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
     }
 
     @Override
-    public Model findModel( Artifact artifact )
-    {
-        String projectKey = ArtifactUtils.key( artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion() );
-        MavenProject project = projectsByGAV.get( projectKey );
+    public Model findModel(Artifact artifact) {
+        MavenProject project = getProject(artifact);
         return project == null ? null : project.getModel();
     }
 
@@ -150,31 +137,34 @@
     // Implementation
     //
 
-    private File find( MavenProject project, Artifact artifact )
-    {
-        if ( "pom".equals( artifact.getExtension() ) )
-        {
+    private File findArtifact(MavenProject project, Artifact artifact) {
+        // POMs are always returned from the file system
+        if ("pom".equals(artifact.getExtension())) {
             return project.getFile();
         }
 
-        Artifact projectArtifact = findMatchingArtifact( project, artifact );
-        File packagedArtifactFile = determinePreviouslyPackagedArtifactFile( project, projectArtifact );
-
-        if ( hasArtifactFileFromPackagePhase( projectArtifact ) )
-        {
-            return projectArtifact.getFile();
-        }
-        // Check whether an earlier Maven run might have produced an artifact that is still on disk.
-        else if ( packagedArtifactFile != null && packagedArtifactFile.exists()
-                && isPackagedArtifactUpToDate( project, packagedArtifactFile, artifact ) )
-        {
+        // First check in the project local repository
+        File packagedArtifactFile = findInProjectLocalRepository(artifact);
+        if (packagedArtifactFile != null
+                && packagedArtifactFile.exists()
+                && isPackagedArtifactUpToDate(project, packagedArtifactFile)) {
             return packagedArtifactFile;
         }
-        else if ( !hasBeenPackagedDuringThisSession( project ) )
-        {
+
+        // Get the matching artifact from the project
+        Artifact projectArtifact = findMatchingArtifact(project, artifact);
+        if (projectArtifact != null) {
+            // If the artifact has been associated to a file, use it
+            packagedArtifactFile = projectArtifact.getFile();
+            if (packagedArtifactFile != null && packagedArtifactFile.exists()) {
+                return packagedArtifactFile;
+            }
+        }
+
+        if (!hasBeenPackagedDuringThisSession(project)) {
             // fallback to loose class files only if artifacts haven't been packaged yet
             // and only for plain old jars. Not war files, not ear files, not anything else.
-            return determineBuildOutputDirectoryForArtifact( project, artifact );
+            return determineBuildOutputDirectoryForArtifact(project, artifact);
         }
 
         // The fall-through indicates that the artifact cannot be found;
@@ -182,32 +172,26 @@
         return null;
     }
 
-    private File determineBuildOutputDirectoryForArtifact( final MavenProject project, final Artifact artifact )
-    {
-        if ( isTestArtifact( artifact ) )
-        {
-            if ( project.hasLifecyclePhase( "test-compile" ) )
-            {
-                return new File( project.getBuild().getTestOutputDirectory() );
+    private File determineBuildOutputDirectoryForArtifact(final MavenProject project, final Artifact artifact) {
+        if (isTestArtifact(artifact)) {
+            if (project.hasLifecyclePhase("test-compile")) {
+                return new File(project.getBuild().getTestOutputDirectory());
             }
-        }
-        else
-        {
-            String type = artifact.getProperty( "type", "" );
-            File outputDirectory = new File( project.getBuild().getOutputDirectory() );
+        } else {
+            String type = artifact.getProperty("type", "");
+            File outputDirectory = new File(project.getBuild().getOutputDirectory());
 
             // Check if the project is being built during this session, and if we can expect any output.
             // There is no need to check if the build has created any outputs, see MNG-2222.
-            boolean projectCompiledDuringThisSession
-                    = project.hasLifecyclePhase( "compile" ) && COMPILE_PHASE_TYPES.contains( type );
+            boolean projectCompiledDuringThisSession =
+                    project.hasLifecyclePhase("compile") && COMPILE_PHASE_TYPES.contains(type);
 
             // Check if the project is part of the session (not filtered by -pl, -rf, etc). If so, we check
             // if a possible earlier Maven invocation produced some output for that project which we can use.
-            boolean projectHasOutputFromPreviousSession
-                    = !session.getProjects().contains( project ) && outputDirectory.exists();
+            boolean projectHasOutputFromPreviousSession =
+                    !session.getProjects().contains(project) && outputDirectory.exists();
 
-            if ( projectHasOutputFromPreviousSession || projectCompiledDuringThisSession )
-            {
+            if (projectHasOutputFromPreviousSession || projectCompiledDuringThisSession) {
                 return outputDirectory;
             }
         }
@@ -217,95 +201,76 @@
         return null;
     }
 
-    private File determinePreviouslyPackagedArtifactFile( MavenProject project, Artifact artifact )
-    {
-        if ( artifact == null )
-        {
-            return null;
-        }
-
-        String fileName = String.format( "%s.%s", project.getBuild().getFinalName(), artifact.getExtension() );
-        return new File( project.getBuild().getDirectory(), fileName );
-    }
-
-    private boolean hasArtifactFileFromPackagePhase( Artifact projectArtifact )
-    {
-        return projectArtifact != null && projectArtifact.getFile() != null && projectArtifact.getFile().exists();
-    }
-
-    private boolean isPackagedArtifactUpToDate( MavenProject project, File packagedArtifactFile, Artifact artifact )
-    {
-        Path outputDirectory = Paths.get( project.getBuild().getOutputDirectory() );
-        if ( !outputDirectory.toFile().exists() )
-        {
+    private boolean isPackagedArtifactUpToDate(MavenProject project, File packagedArtifactFile) {
+        Path outputDirectory = Paths.get(project.getBuild().getOutputDirectory());
+        if (!outputDirectory.toFile().exists()) {
             return true;
         }
 
-        try ( Stream<Path> outputFiles = Files.walk( outputDirectory ) )
-        {
+        try (Stream<Path> outputFiles = Files.walk(outputDirectory)) {
             // Not using File#lastModified() to avoid a Linux JDK8 milliseconds precision bug: JDK-8177809.
-            long artifactLastModified = Files.getLastModifiedTime( packagedArtifactFile.toPath() ).toMillis();
+            long artifactLastModified =
+                    Files.getLastModifiedTime(packagedArtifactFile.toPath()).toMillis();
 
-            if ( session.getProjectBuildingRequest().getBuildStartTime() != null )
-            {
-                long buildStartTime = session.getProjectBuildingRequest().getBuildStartTime().getTime();
-                if ( artifactLastModified > buildStartTime )
-                {
+            if (session.getProjectBuildingRequest().getBuildStartTime() != null) {
+                long buildStartTime =
+                        session.getProjectBuildingRequest().getBuildStartTime().getTime();
+                if (artifactLastModified > buildStartTime) {
                     return true;
                 }
             }
 
-            Iterator<Path> iterator = outputFiles.iterator();
-            while ( iterator.hasNext() )
-            {
-                Path outputFile = iterator.next();
-
-                if ( Files.isDirectory(  outputFile ) )
-                {
+            for (Path outputFile : (Iterable<Path>) outputFiles::iterator) {
+                if (Files.isDirectory(outputFile)) {
                     continue;
                 }
 
-                long outputFileLastModified = Files.getLastModifiedTime( outputFile ).toMillis();
-                if ( outputFileLastModified > artifactLastModified )
-                {
-                    File alternative = determineBuildOutputDirectoryForArtifact( project, artifact );
-                    if ( alternative != null )
-                    {
-                        LOGGER.warn( "File '{}' is more recent than the packaged artifact for '{}'; using '{}' instead",
-                                relativizeOutputFile( outputFile ), project.getArtifactId(),
-                                relativizeOutputFile( alternative.toPath() ) );
-                    }
-                    else
-                    {
-                        LOGGER.warn( "File '{}' is more recent than the packaged artifact for '{}'; "
-                                + "cannot use the build output directory for this type of artifact",
-                                relativizeOutputFile( outputFile ), project.getArtifactId() );
-                    }
-                    return false;
+                long outputFileLastModified =
+                        Files.getLastModifiedTime(outputFile).toMillis();
+                if (outputFileLastModified > artifactLastModified) {
+                    LOGGER.warn(
+                            "File '{}' is more recent than the packaged artifact for '{}', "
+                                    + "please run a full `mvn package` build",
+                            relativizeOutputFile(outputFile),
+                            project.getArtifactId());
+                    return true;
                 }
             }
 
             return true;
-        }
-        catch ( IOException e )
-        {
-            LOGGER.warn( "An I/O error occurred while checking if the packaged artifact is up-to-date "
-                    + "against the build output directory. "
-                    + "Continuing with the assumption that it is up-to-date.", e );
+        } catch (IOException e) {
+            LOGGER.warn(
+                    "An I/O error occurred while checking if the packaged artifact is up-to-date "
+                            + "against the build output directory. "
+                            + "Continuing with the assumption that it is up-to-date.",
+                    e);
             return true;
         }
     }
 
-    private boolean hasBeenPackagedDuringThisSession( MavenProject project )
-    {
-        return project.hasLifecyclePhase( "package" ) || project.hasLifecyclePhase( "install" )
-            || project.hasLifecyclePhase( "deploy" );
+    private boolean hasBeenPackagedDuringThisSession(MavenProject project) {
+        boolean packaged = false;
+        for (String phase : getLifecycles(project)) {
+            switch (phase) {
+                case "clean":
+                    packaged = false;
+                    break;
+                case "package":
+                case "install":
+                case "deploy":
+                    packaged = true;
+                    break;
+                default:
+                    break;
+            }
+        }
+        return packaged;
     }
 
-    private Path relativizeOutputFile( final Path outputFile )
-    {
-        Path projectBaseDirectory = Paths.get( session.getRequest().getMultiModuleProjectDirectory().toURI() );
-        return projectBaseDirectory.relativize( outputFile );
+    private Path relativizeOutputFile(final Path outputFile) {
+        Path projectBaseDirectory =
+                Paths.get(session.getRequest().getMultiModuleProjectDirectory().toURI());
+        return projectBaseDirectory.relativize(outputFile);
     }
 
     /**
@@ -315,37 +280,13 @@
      * @param requestedArtifact The artifact to resolve, must not be <code>null</code>.
      * @return The matching artifact from the project or <code>null</code> if not found. Note that this
      */
-    private Artifact findMatchingArtifact( MavenProject project, Artifact requestedArtifact )
-    {
-        String requestedRepositoryConflictId = ArtifactIdUtils.toVersionlessId( requestedArtifact );
-
-        Artifact mainArtifact = RepositoryUtils.toArtifact( project.getArtifact() );
-        if ( requestedRepositoryConflictId.equals( ArtifactIdUtils.toVersionlessId( mainArtifact ) ) )
-        {
-            return mainArtifact;
-        }
-
-        return RepositoryUtils.toArtifacts( project.getAttachedArtifacts() ).stream()
-                .filter( isRequestedArtifact( requestedArtifact ) )
+    private Artifact findMatchingArtifact(MavenProject project, Artifact requestedArtifact) {
+        String requestedRepositoryConflictId = ArtifactIdUtils.toVersionlessId(requestedArtifact);
+        return getProjectArtifacts(project)
+                .filter(artifact ->
+                        Objects.equals(requestedRepositoryConflictId, ArtifactIdUtils.toVersionlessId(artifact)))
                 .findFirst()
-                .orElse( null );
-    }
-
-    /**
-     * We are taking as much as we can from the DefaultArtifact.equals(). The requested artifact has no file, so we want
-     * to remove that from the comparison.
-     *
-     * @param requestArtifact checked against the given artifact.
-     * @return true if equals, false otherwise.
-     */
-    private Predicate<Artifact> isRequestedArtifact( Artifact requestArtifact )
-    {
-        return s -> s.getArtifactId().equals( requestArtifact.getArtifactId() )
-                && s.getGroupId().equals( requestArtifact.getGroupId() )
-                && s.getVersion().equals( requestArtifact.getVersion() )
-                && s.getExtension().equals( requestArtifact.getExtension() )
-                && s.getClassifier().equals( requestArtifact.getClassifier() );
-
+                .orElse(null);
     }
 
     /**
@@ -354,9 +295,216 @@
      * @param artifact The artifact to check, must not be {@code null}.
      * @return {@code true} if the artifact refers to test classes, {@code false} otherwise.
      */
-    private static boolean isTestArtifact( Artifact artifact )
-    {
-        return ( "test-jar".equals( artifact.getProperty( "type", "" ) ) )
-            || ( "jar".equals( artifact.getExtension() ) && "tests".equals( artifact.getClassifier() ) );
+    private static boolean isTestArtifact(Artifact artifact) {
+        return ("test-jar".equals(artifact.getProperty("type", "")))
+                || ("jar".equals(artifact.getExtension()) && "tests".equals(artifact.getClassifier()));
+    }
+
+    private File findInProjectLocalRepository(Artifact artifact) {
+        Path target = getArtifactPath(artifact);
+        return Files.isRegularFile(target) ? target.toFile() : null;
+    }
+
+    /**
+     * We are interested in project success events, in which case we call
+     * the {@link #installIntoProjectLocalRepository(MavenProject)} method.
+     * The mojo started event is also captured to determine the lifecycle
+     * phases the project has been through.
+     *
+     * @param event the execution event
+     */
+    private void processEvent(ExecutionEvent event) {
+        MavenProject project = event.getProject();
+        switch (event.getType()) {
+            case MojoStarted:
+                String phase = event.getMojoExecution().getLifecyclePhase();
+                if (phase != null) {
+                    Deque<String> phases = getLifecycles(project);
+                    if (!Objects.equals(phase, phases.peekLast())) {
+                        phases.addLast(phase);
+                        if ("clean".equals(phase)) {
+                            cleanProjectLocalRepository(project);
+                        }
+                    }
+                }
+                break;
+            case ProjectSucceeded:
+            case ForkedProjectSucceeded:
+                installIntoProjectLocalRepository(project);
+                break;
+            default:
+                break;
+        }
+    }
+
+    private Deque<String> getLifecycles(MavenProject project) {
+        return lifecycles.computeIfAbsent(project.getId(), k -> new ArrayDeque<>());
+    }
+
+    /**
+     * Copy packaged and attached artifacts from this project to the
+     * project local repository.
+     * This allows a subsequent build to resume while still being able
+     * to locate attached artifacts.
+     *
+     * @param project the project to copy artifacts from
+     */
+    private void installIntoProjectLocalRepository(MavenProject project) {
+        if ("pom".equals(project.getPackaging())
+                        && !"clean".equals(getLifecycles(project).peekLast())
+                || hasBeenPackagedDuringThisSession(project)) {
+            getProjectArtifacts(project).filter(this::isRegularFile).forEach(this::installIntoProjectLocalRepository);
+        }
+    }
+
+    private void cleanProjectLocalRepository(MavenProject project) {
+        try {
+            Path artifactPath = getProjectLocalRepo()
+                    .resolve(project.getGroupId())
+                    .resolve(project.getArtifactId())
+                    .resolve(project.getVersion());
+            if (Files.isDirectory(artifactPath)) {
+                try (Stream<Path> paths = Files.list(artifactPath)) {
+                    for (Path path : (Iterable<Path>) paths::iterator) {
+                        Files.delete(path);
+                    }
+                }
+                try {
+                    Files.delete(artifactPath);
+                    Files.delete(artifactPath.getParent());
+                    Files.delete(artifactPath.getParent().getParent());
+                } catch (DirectoryNotEmptyException e) {
+                    // ignore
+                }
+            }
+        } catch (IOException e) {
+            LOGGER.error("Error while cleaning project local repository", e);
+        }
+    }
+
+    /**
+     * Retrieve a stream of the project's artifacts
+     */
+    private Stream<Artifact> getProjectArtifacts(MavenProject project) {
+        Stream<org.apache.maven.artifact.Artifact> artifacts = Stream.concat(
+                Stream.concat(
+                        // pom artifact
+                        Stream.of(new ProjectArtifact(project)),
+                        // main project artifact if not a pom
+                        "pom".equals(project.getPackaging()) ? Stream.empty() : Stream.of(project.getArtifact())),
+                // attached artifacts
+                project.getAttachedArtifacts().stream());
+        return artifacts.map(RepositoryUtils::toArtifact);
+    }
+
+    private boolean isRegularFile(Artifact artifact) {
+        return artifact.getFile() != null && artifact.getFile().isFile();
+    }
+
+    private void installIntoProjectLocalRepository(Artifact artifact) {
+        Path target = getArtifactPath(artifact);
+        try {
+            LOGGER.info("Copying {} to project local repository", artifact);
+            Files.createDirectories(target.getParent());
+            Files.copy(
+                    artifact.getFile().toPath(),
+                    target,
+                    StandardCopyOption.REPLACE_EXISTING,
+                    StandardCopyOption.COPY_ATTRIBUTES);
+        } catch (IOException e) {
+            LOGGER.error("Error while copying artifact to project local repository", e);
+        }
+    }
+
+    private Path getArtifactPath(Artifact artifact) {
+        String groupId = artifact.getGroupId();
+        String artifactId = artifact.getArtifactId();
+        String version = artifact.getBaseVersion();
+        String classifier = artifact.getClassifier();
+        String extension = artifact.getExtension();
+        Path repo = getProjectLocalRepo();
+        return repo.resolve(groupId)
+                .resolve(artifactId)
+                .resolve(version)
+                .resolve(artifactId
+                        + "-" + version
+                        + (classifier != null && !classifier.isEmpty() ? "-" + classifier : "")
+                        + "." + extension);
+    }
+
+    private Path getProjectLocalRepo() {
+        if (projectLocalRepository == null) {
+            Path root = session.getRequest().getMultiModuleProjectDirectory().toPath();
+            List<MavenProject> projects = session.getProjects();
+            if (projects != null) {
+                projectLocalRepository = projects.stream()
+                        .filter(project -> Objects.equals(root.toFile(), project.getBasedir()))
+                        .findFirst()
+                        .map(project -> project.getBuild().getDirectory())
+                        .map(Paths::get)
+                        .orElseGet(() -> root.resolve("target"))
+                        .resolve(PROJECT_LOCAL_REPO);
+            } else {
+                return root.resolve("target").resolve(PROJECT_LOCAL_REPO);
+            }
+        }
+        return projectLocalRepository;
+    }
+
+    private MavenProject getProject(Artifact artifact) {
+        return getProjects()
+                .getOrDefault(artifact.getGroupId(), Collections.emptyMap())
+                .getOrDefault(artifact.getArtifactId(), Collections.emptyMap())
+                .getOrDefault(artifact.getBaseVersion(), null);
+    }
+
+    // groupId -> (artifactId -> (version -> project)))
+    private Map<String, Map<String, Map<String, MavenProject>>> getProjects() {
+        // compute the projects mapping
+        if (projects == null) {
+            List<MavenProject> allProjects = session.getAllProjects();
+            if (allProjects != null) {
+                Map<String, Map<String, Map<String, MavenProject>>> map = new HashMap<>();
+                allProjects.forEach(project -> map.computeIfAbsent(project.getGroupId(), k -> new HashMap<>())
+                        .computeIfAbsent(project.getArtifactId(), k -> new HashMap<>())
+                        .put(project.getVersion(), project));
+                this.projects = map;
+            } else {
+                return Collections.emptyMap();
+            }
+        }
+        return projects;
+    }
+
+    /**
+     * Singleton class used to receive events by implementing the EventSpy.
+     * It simply forwards all {@code ExecutionEvent}s to the {@code ReactorReader}.
+     */
+    @Named
+    @Singleton
+    @SuppressWarnings("unused")
+    static class ReactorReaderSpy implements EventSpy {
+
+        final PlexusContainer container;
+
+        @Inject
+        ReactorReaderSpy(PlexusContainer container) {
+            this.container = container;
+        }
+
+        @Override
+        public void init(Context context) throws Exception {}
+
+        @Override
+        @SuppressWarnings("checkstyle:MissingSwitchDefault")
+        public void onEvent(Object event) throws Exception {
+            if (event instanceof ExecutionEvent) {
+                ReactorReader reactorReader = container.lookup(ReactorReader.class);
+                reactorReader.processEvent((ExecutionEvent) event);
+            }
+        }
+
+        @Override
+        public void close() throws Exception {}
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java b/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java
index ce840ee..0a514a3 100644
--- a/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java
+++ b/maven-core/src/main/java/org/apache/maven/RepositoryUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,7 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
 
+import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -34,6 +34,8 @@
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.ArtifactProperties;
@@ -46,6 +48,8 @@
 import org.eclipse.aether.graph.DependencyNode;
 import org.eclipse.aether.graph.Exclusion;
 import org.eclipse.aether.repository.Authentication;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.LocalRepositoryManager;
 import org.eclipse.aether.repository.Proxy;
 import org.eclipse.aether.repository.RemoteRepository;
 import org.eclipse.aether.repository.RepositoryPolicy;
@@ -57,174 +61,153 @@
  * <strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
  * of the public API. In particular, this class can be changed or deleted without prior notice.
  *
- * @author Benjamin Bentmann
  */
-public class RepositoryUtils
-{
+public class RepositoryUtils {
 
-    private static String nullify( String string )
-    {
-        return ( string == null || string.length() <= 0 ) ? null : string;
+    private static String nullify(String string) {
+        return (string == null || string.length() <= 0) ? null : string;
     }
 
-    private static org.apache.maven.artifact.Artifact toArtifact( Dependency dependency )
-    {
-        if ( dependency == null )
-        {
+    private static org.apache.maven.artifact.Artifact toArtifact(Dependency dependency) {
+        if (dependency == null) {
             return null;
         }
 
-        org.apache.maven.artifact.Artifact result = toArtifact( dependency.getArtifact() );
-        result.setScope( dependency.getScope() );
-        result.setOptional( dependency.isOptional() );
+        org.apache.maven.artifact.Artifact result = toArtifact(dependency.getArtifact());
+        result.setScope(dependency.getScope());
+        result.setOptional(dependency.isOptional());
 
         return result;
     }
 
-    public static org.apache.maven.artifact.Artifact toArtifact( Artifact artifact )
-    {
-        if ( artifact == null )
-        {
+    public static org.apache.maven.artifact.Artifact toArtifact(Artifact artifact) {
+        if (artifact == null) {
             return null;
         }
 
-        ArtifactHandler handler = newHandler( artifact );
+        ArtifactHandler handler = newHandler(artifact);
 
         /*
          * NOTE: From Artifact.hasClassifier(), an empty string and a null both denote "no classifier". However, some
          * plugins only check for null, so be sure to nullify an empty classifier.
          */
-        org.apache.maven.artifact.Artifact result =
-            new org.apache.maven.artifact.DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(),
-                                                           artifact.getVersion(), null,
-                                                           artifact.getProperty( ArtifactProperties.TYPE,
-                                                                                 artifact.getExtension() ),
-                                                           nullify( artifact.getClassifier() ), handler );
+        org.apache.maven.artifact.Artifact result = new org.apache.maven.artifact.DefaultArtifact(
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getVersion(),
+                null,
+                artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension()),
+                nullify(artifact.getClassifier()),
+                handler);
 
-        result.setFile( artifact.getFile() );
-        result.setResolved( artifact.getFile() != null );
+        result.setFile(artifact.getFile());
+        result.setResolved(artifact.getFile() != null);
 
-        List<String> trail = new ArrayList<>( 1 );
-        trail.add( result.getId() );
-        result.setDependencyTrail( trail );
+        List<String> trail = new ArrayList<>(1);
+        trail.add(result.getId());
+        result.setDependencyTrail(trail);
 
         return result;
     }
 
-    public static void toArtifacts( Collection<org.apache.maven.artifact.Artifact> artifacts,
-                                    Collection<? extends DependencyNode> nodes, List<String> trail,
-                                    DependencyFilter filter )
-    {
-        for ( DependencyNode node : nodes )
-        {
-            org.apache.maven.artifact.Artifact artifact = toArtifact( node.getDependency() );
+    public static void toArtifacts(
+            Collection<org.apache.maven.artifact.Artifact> artifacts,
+            Collection<? extends DependencyNode> nodes,
+            List<String> trail,
+            DependencyFilter filter) {
+        for (DependencyNode node : nodes) {
+            org.apache.maven.artifact.Artifact artifact = toArtifact(node.getDependency());
 
-            List<String> nodeTrail = new ArrayList<>( trail.size() + 1 );
-            nodeTrail.addAll( trail );
-            nodeTrail.add( artifact.getId() );
+            List<String> nodeTrail = new ArrayList<>(trail.size() + 1);
+            nodeTrail.addAll(trail);
+            nodeTrail.add(artifact.getId());
 
-            if ( filter == null || filter.accept( node, Collections.emptyList() ) )
-            {
-                artifact.setDependencyTrail( nodeTrail );
-                artifacts.add( artifact );
+            if (filter == null || filter.accept(node, Collections.emptyList())) {
+                artifact.setDependencyTrail(nodeTrail);
+                artifacts.add(artifact);
             }
 
-            toArtifacts( artifacts, node.getChildren(), nodeTrail, filter );
+            toArtifacts(artifacts, node.getChildren(), nodeTrail, filter);
         }
     }
 
-    public static Artifact toArtifact( org.apache.maven.artifact.Artifact artifact )
-    {
-        if ( artifact == null )
-        {
+    public static Artifact toArtifact(org.apache.maven.artifact.Artifact artifact) {
+        if (artifact == null) {
             return null;
         }
 
         String version = artifact.getVersion();
-        if ( version == null && artifact.getVersionRange() != null )
-        {
+        if (version == null && artifact.getVersionRange() != null) {
             version = artifact.getVersionRange().toString();
         }
 
         Map<String, String> props = null;
-        if ( org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
-        {
-            String localPath = ( artifact.getFile() != null ) ? artifact.getFile().getPath() : "";
-            props = Collections.singletonMap( ArtifactProperties.LOCAL_PATH, localPath );
+        if (org.apache.maven.artifact.Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
+            String localPath = (artifact.getFile() != null) ? artifact.getFile().getPath() : "";
+            props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, localPath);
         }
 
-        Artifact result =
-            new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(), artifact.getClassifier(),
-                                 artifact.getArtifactHandler().getExtension(), version, props,
-                                 newArtifactType( artifact.getType(), artifact.getArtifactHandler() ) );
-        result = result.setFile( artifact.getFile() );
+        Artifact result = new DefaultArtifact(
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getClassifier(),
+                artifact.getArtifactHandler().getExtension(),
+                version,
+                props,
+                newArtifactType(artifact.getType(), artifact.getArtifactHandler()));
+        result = result.setFile(artifact.getFile());
 
         return result;
     }
 
-    public static Dependency toDependency( org.apache.maven.artifact.Artifact artifact,
-                                           Collection<org.apache.maven.model.Exclusion> exclusions )
-    {
-        if ( artifact == null )
-        {
+    public static Dependency toDependency(
+            org.apache.maven.artifact.Artifact artifact, Collection<org.apache.maven.model.Exclusion> exclusions) {
+        if (artifact == null) {
             return null;
         }
 
-        Artifact result = toArtifact( artifact );
+        Artifact result = toArtifact(artifact);
 
-        List<Exclusion> excl = Optional.ofNullable( exclusions )
-                .orElse( Collections.emptyList() )
-                .stream()
-                .map( RepositoryUtils::toExclusion )
-                .collect( Collectors.toList() );
-        return new Dependency( result, artifact.getScope(), artifact.isOptional(), excl );
+        List<Exclusion> excl = Optional.ofNullable(exclusions).orElse(Collections.emptyList()).stream()
+                .map(RepositoryUtils::toExclusion)
+                .collect(Collectors.toList());
+        return new Dependency(result, artifact.getScope(), artifact.isOptional(), excl);
     }
 
-    public static List<RemoteRepository> toRepos( List<ArtifactRepository> repos )
-    {
-        return Optional.ofNullable( repos )
-                .orElse( Collections.emptyList() )
-                .stream()
-                .map( RepositoryUtils::toRepo )
-                .collect( Collectors.toList() );
+    public static List<RemoteRepository> toRepos(List<ArtifactRepository> repos) {
+        return Optional.ofNullable(repos).orElse(Collections.emptyList()).stream()
+                .map(RepositoryUtils::toRepo)
+                .collect(Collectors.toList());
     }
 
-    public static RemoteRepository toRepo( ArtifactRepository repo )
-    {
+    public static RemoteRepository toRepo(ArtifactRepository repo) {
         RemoteRepository result = null;
-        if ( repo != null )
-        {
+        if (repo != null) {
             RemoteRepository.Builder builder =
-                new RemoteRepository.Builder( repo.getId(), getLayout( repo ), repo.getUrl() );
-            builder.setSnapshotPolicy( toPolicy( repo.getSnapshots() ) );
-            builder.setReleasePolicy( toPolicy( repo.getReleases() ) );
-            builder.setAuthentication( toAuthentication( repo.getAuthentication() ) );
-            builder.setProxy( toProxy( repo.getProxy() ) );
-            builder.setMirroredRepositories( toRepos( repo.getMirroredRepositories() ) );
-            builder.setBlocked( repo.isBlocked() );
+                    new RemoteRepository.Builder(repo.getId(), getLayout(repo), repo.getUrl());
+            builder.setSnapshotPolicy(toPolicy(repo.getSnapshots()));
+            builder.setReleasePolicy(toPolicy(repo.getReleases()));
+            builder.setAuthentication(toAuthentication(repo.getAuthentication()));
+            builder.setProxy(toProxy(repo.getProxy()));
+            builder.setMirroredRepositories(toRepos(repo.getMirroredRepositories()));
+            builder.setBlocked(repo.isBlocked());
             result = builder.build();
         }
         return result;
     }
 
-    public static String getLayout( ArtifactRepository repo )
-    {
-        try
-        {
+    public static String getLayout(ArtifactRepository repo) {
+        try {
             return repo.getLayout().getId();
-        }
-        catch ( LinkageError e )
-        {
+        } catch (LinkageError e) {
             /*
              * NOTE: getId() was added in 3.x and is as such not implemented by plugins compiled against 2.x APIs.
              */
             String className = repo.getLayout().getClass().getSimpleName();
-            if ( className.endsWith( "RepositoryLayout" ) )
-            {
-                String layout = className.substring( 0, className.length() - "RepositoryLayout".length() );
-                if ( layout.length() > 0 )
-                {
-                    layout = Character.toLowerCase( layout.charAt( 0 ) ) + layout.substring( 1 );
+            if (className.endsWith("RepositoryLayout")) {
+                String layout = className.substring(0, className.length() - "RepositoryLayout".length());
+                if (layout.length() > 0) {
+                    layout = Character.toLowerCase(layout.charAt(0)) + layout.substring(1);
                     return layout;
                 }
             }
@@ -232,145 +215,131 @@
         }
     }
 
-    private static RepositoryPolicy toPolicy( ArtifactRepositoryPolicy policy )
-    {
+    private static RepositoryPolicy toPolicy(ArtifactRepositoryPolicy policy) {
         RepositoryPolicy result = null;
-        if ( policy != null )
-        {
-            result = new RepositoryPolicy( policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy() );
+        if (policy != null) {
+            result = new RepositoryPolicy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy());
         }
         return result;
     }
 
-    private static Authentication toAuthentication( org.apache.maven.artifact.repository.Authentication auth )
-    {
+    private static Authentication toAuthentication(org.apache.maven.artifact.repository.Authentication auth) {
         Authentication result = null;
-        if ( auth != null )
-        {
+        if (auth != null) {
             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
-            authBuilder.addUsername( auth.getUsername() ).addPassword( auth.getPassword() );
-            authBuilder.addPrivateKey( auth.getPrivateKey(), auth.getPassphrase() );
+            authBuilder.addUsername(auth.getUsername()).addPassword(auth.getPassword());
+            authBuilder.addPrivateKey(auth.getPrivateKey(), auth.getPassphrase());
             result = authBuilder.build();
         }
         return result;
     }
 
-    private static Proxy toProxy( org.apache.maven.repository.Proxy proxy )
-    {
+    private static Proxy toProxy(org.apache.maven.repository.Proxy proxy) {
         Proxy result = null;
-        if ( proxy != null )
-        {
+        if (proxy != null) {
             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
-            authBuilder.addUsername( proxy.getUserName() ).addPassword( proxy.getPassword() );
-            result = new Proxy( proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build() );
+            authBuilder.addUsername(proxy.getUserName()).addPassword(proxy.getPassword());
+            result = new Proxy(proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build());
         }
         return result;
     }
 
-    public static ArtifactHandler newHandler( Artifact artifact )
-    {
-        String type = artifact.getProperty( ArtifactProperties.TYPE, artifact.getExtension() );
+    public static ArtifactHandler newHandler(Artifact artifact) {
+        String type = artifact.getProperty(ArtifactProperties.TYPE, artifact.getExtension());
         return new DefaultArtifactHandler(
-            type,
-            artifact.getExtension(),
-            null,
-            null,
-            null,
-            Boolean.parseBoolean( artifact.getProperty( ArtifactProperties.INCLUDES_DEPENDENCIES, "" ) ),
-            artifact.getProperty( ArtifactProperties.LANGUAGE, null ),
-            Boolean.parseBoolean( artifact.getProperty( ArtifactProperties.CONSTITUTES_BUILD_PATH, "" ) )
-        );
+                type,
+                artifact.getExtension(),
+                null,
+                null,
+                null,
+                Boolean.parseBoolean(artifact.getProperty(ArtifactProperties.INCLUDES_DEPENDENCIES, "")),
+                artifact.getProperty(ArtifactProperties.LANGUAGE, null),
+                Boolean.parseBoolean(artifact.getProperty(ArtifactProperties.CONSTITUTES_BUILD_PATH, "")));
     }
 
-    public static ArtifactType newArtifactType( String id, ArtifactHandler handler )
-    {
-        return new DefaultArtifactType( id, handler.getExtension(), handler.getClassifier(), handler.getLanguage(),
-                                        handler.isAddedToClasspath(), handler.isIncludesDependencies() );
+    public static ArtifactType newArtifactType(String id, ArtifactHandler handler) {
+        return new DefaultArtifactType(
+                id,
+                handler.getExtension(),
+                handler.getClassifier(),
+                handler.getLanguage(),
+                handler.isAddedToClasspath(),
+                handler.isIncludesDependencies());
     }
 
-    public static Dependency toDependency( org.apache.maven.model.Dependency dependency,
-                                           ArtifactTypeRegistry stereotypes )
-    {
-        ArtifactType stereotype = stereotypes.get( dependency.getType() );
-        if ( stereotype == null )
-        {
-            stereotype = new DefaultArtifactType( dependency.getType() );
+    public static Dependency toDependency(
+            org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes) {
+        ArtifactType stereotype = stereotypes.get(dependency.getType());
+        if (stereotype == null) {
+            stereotype = new DefaultArtifactType(dependency.getType());
         }
 
-        boolean system = dependency.getSystemPath() != null && dependency.getSystemPath().length() > 0;
+        boolean system =
+                dependency.getSystemPath() != null && dependency.getSystemPath().length() > 0;
 
         Map<String, String> props = null;
-        if ( system )
-        {
-            props = Collections.singletonMap( ArtifactProperties.LOCAL_PATH, dependency.getSystemPath() );
+        if (system) {
+            props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, dependency.getSystemPath());
         }
 
-        Artifact artifact =
-            new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), null,
-                                 dependency.getVersion(), props, stereotype );
+        Artifact artifact = new DefaultArtifact(
+                dependency.getGroupId(),
+                dependency.getArtifactId(),
+                dependency.getClassifier(),
+                null,
+                dependency.getVersion(),
+                props,
+                stereotype);
 
-        List<Exclusion> exclusions =
-                dependency.getExclusions().stream().map( RepositoryUtils::toExclusion ).collect( Collectors.toList() );
+        List<Exclusion> exclusions = dependency.getExclusions().stream()
+                .map(RepositoryUtils::toExclusion)
+                .collect(Collectors.toList());
 
-        return new Dependency( artifact,
-                                            dependency.getScope(),
-                                            dependency.getOptional() != null
-                                                ? dependency.isOptional()
-                                                : null,
-                                            exclusions );
+        return new Dependency(
+                artifact,
+                dependency.getScope(),
+                dependency.getOptional() != null ? dependency.isOptional() : null,
+                exclusions);
     }
 
-    private static Exclusion toExclusion( org.apache.maven.model.Exclusion exclusion )
-    {
-        return new Exclusion( exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*" );
+    private static Exclusion toExclusion(org.apache.maven.model.Exclusion exclusion) {
+        return new Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*");
     }
 
-    public static ArtifactTypeRegistry newArtifactTypeRegistry( ArtifactHandlerManager handlerManager )
-    {
-        return new MavenArtifactTypeRegistry( handlerManager );
+    public static ArtifactTypeRegistry newArtifactTypeRegistry(ArtifactHandlerManager handlerManager) {
+        return new MavenArtifactTypeRegistry(handlerManager);
     }
 
-    static class MavenArtifactTypeRegistry
-        implements ArtifactTypeRegistry
-    {
+    static class MavenArtifactTypeRegistry implements ArtifactTypeRegistry {
 
         private final ArtifactHandlerManager handlerManager;
 
-        MavenArtifactTypeRegistry( ArtifactHandlerManager handlerManager )
-        {
+        MavenArtifactTypeRegistry(ArtifactHandlerManager handlerManager) {
             this.handlerManager = handlerManager;
         }
 
-        public ArtifactType get( String stereotypeId )
-        {
-            ArtifactHandler handler = handlerManager.getArtifactHandler( stereotypeId );
-            return newArtifactType( stereotypeId, handler );
+        public ArtifactType get(String stereotypeId) {
+            ArtifactHandler handler = handlerManager.getArtifactHandler(stereotypeId);
+            return newArtifactType(stereotypeId, handler);
         }
-
     }
 
-    public static Collection<Artifact> toArtifacts( Collection<org.apache.maven.artifact.Artifact> artifactsToConvert )
-    {
-        return artifactsToConvert.stream().map( RepositoryUtils::toArtifact ).collect( Collectors.toList() );
+    public static Collection<Artifact> toArtifacts(Collection<org.apache.maven.artifact.Artifact> artifactsToConvert) {
+        return artifactsToConvert.stream().map(RepositoryUtils::toArtifact).collect(Collectors.toList());
     }
 
-    public static WorkspaceRepository getWorkspace( RepositorySystemSession session )
-    {
+    public static WorkspaceRepository getWorkspace(RepositorySystemSession session) {
         WorkspaceReader reader = session.getWorkspaceReader();
-        return ( reader != null ) ? reader.getRepository() : null;
+        return (reader != null) ? reader.getRepository() : null;
     }
 
-    public static boolean repositoriesEquals( List<RemoteRepository> r1, List<RemoteRepository> r2 )
-    {
-        if ( r1.size() != r2.size() )
-        {
+    public static boolean repositoriesEquals(List<RemoteRepository> r1, List<RemoteRepository> r2) {
+        if (r1.size() != r2.size()) {
             return false;
         }
 
-        for ( Iterator<RemoteRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); )
-        {
-            if ( !repositoryEquals( it1.next(), it2.next() ) )
-            {
+        for (Iterator<RemoteRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); ) {
+            if (!repositoryEquals(it1.next(), it2.next())) {
                 return false;
             }
         }
@@ -378,43 +347,60 @@
         return true;
     }
 
-    public static int repositoriesHashCode( List<RemoteRepository> repositories )
-    {
+    public static int repositoriesHashCode(List<RemoteRepository> repositories) {
         int result = 17;
-        for ( RemoteRepository repository : repositories )
-        {
-            result = 31 * result + repositoryHashCode( repository );
+        for (RemoteRepository repository : repositories) {
+            result = 31 * result + repositoryHashCode(repository);
         }
         return result;
     }
 
-    private static int repositoryHashCode( RemoteRepository repository )
-    {
+    public static RepositorySystemSession overlay(
+            ArtifactRepository repository, RepositorySystemSession session, RepositorySystem system) {
+        if (repository == null || repository.getBasedir() == null) {
+            return session;
+        }
+
+        DefaultRepositorySystemSession newSession;
+        if (session != null) {
+            LocalRepositoryManager lrm = session.getLocalRepositoryManager();
+            if (lrm != null && lrm.getRepository().getBasedir().equals(new File(repository.getBasedir()))) {
+                return session;
+            }
+            newSession = new DefaultRepositorySystemSession(session);
+        } else {
+            newSession = new DefaultRepositorySystemSession();
+        }
+
+        final LocalRepositoryManager llrm =
+                system.newLocalRepositoryManager(newSession, new LocalRepository(repository.getBasedir()));
+        newSession.setLocalRepositoryManager(llrm);
+        return newSession;
+    }
+
+    private static int repositoryHashCode(RemoteRepository repository) {
         int result = 17;
         Object obj = repository.getUrl();
-        result = 31 * result + ( obj != null ? obj.hashCode() : 0 );
+        result = 31 * result + (obj != null ? obj.hashCode() : 0);
         return result;
     }
 
-    private static boolean policyEquals( RepositoryPolicy p1, RepositoryPolicy p2 )
-    {
-        if ( p1 == p2 )
-        {
+    private static boolean policyEquals(RepositoryPolicy p1, RepositoryPolicy p2) {
+        if (p1 == p2) {
             return true;
         }
         // update policy doesn't affect contents
-        return p1.isEnabled() == p2.isEnabled() && Objects.equals( p1.getChecksumPolicy(), p2.getChecksumPolicy() );
+        return p1.isEnabled() == p2.isEnabled() && Objects.equals(p1.getChecksumPolicy(), p2.getChecksumPolicy());
     }
 
-    private static boolean repositoryEquals( RemoteRepository r1, RemoteRepository r2 )
-    {
-        if ( r1 == r2 )
-        {
+    private static boolean repositoryEquals(RemoteRepository r1, RemoteRepository r2) {
+        if (r1 == r2) {
             return true;
         }
 
-        return Objects.equals( r1.getId(), r2.getId() ) && Objects.equals( r1.getUrl(), r2.getUrl() )
-            && policyEquals( r1.getPolicy( false ), r2.getPolicy( false ) )
-            && policyEquals( r1.getPolicy( true ), r2.getPolicy( true ) );
+        return Objects.equals(r1.getId(), r2.getId())
+                && Objects.equals(r1.getUrl(), r2.getUrl())
+                && policyEquals(r1.getPolicy(false), r2.getPolicy(false))
+                && policyEquals(r1.getPolicy(true), r2.getPolicy(true));
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/SessionScoped.java b/maven-core/src/main/java/org/apache/maven/SessionScoped.java
index 7738938..41a8c33 100644
--- a/maven-core/src/main/java/org/apache/maven/SessionScoped.java
+++ b/maven-core/src/main/java/org/apache/maven/SessionScoped.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,25 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+package org.apache.maven;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 import com.google.inject.ScopeAnnotation;
 
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 /**
  * Indicates that annotated component should be instantiated before session execution starts
  * and discarded after session execution completes.
  *
- * @author Jason van Zyl
  * @since 3.2.0
  */
-@Target( { TYPE } )
-@Retention( RUNTIME )
+@Target({TYPE})
+@Retention(RUNTIME)
 @ScopeAnnotation
-public @interface SessionScoped
-{
-}
+public @interface SessionScoped {}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/DependencyResolutionRequiredException.java b/maven-core/src/main/java/org/apache/maven/artifact/DependencyResolutionRequiredException.java
index 9979423..93a7b33 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/DependencyResolutionRequiredException.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/DependencyResolutionRequiredException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,18 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 /**
  * Exception that occurs when an artifact file is used, but has not been resolved.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  * TODO it may be better for artifact.getFile() to throw it - perhaps it is a runtime exception?
  */
-public class DependencyResolutionRequiredException
-    extends Exception
-{
-    public DependencyResolutionRequiredException( Artifact artifact )
-    {
-        super( "Attempted to access the artifact " + artifact + "; which has not yet been resolved" );
+public class DependencyResolutionRequiredException extends Exception {
+    public DependencyResolutionRequiredException(Artifact artifact) {
+        super("Attempted to access the artifact " + artifact + "; which has not yet been resolved");
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/InvalidRepositoryException.java b/maven-core/src/main/java/org/apache/maven/artifact/InvalidRepositoryException.java
index 62991f1..2f9dcd4 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/InvalidRepositoryException.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/InvalidRepositoryException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact;
 
 import java.net.MalformedURLException;
 
@@ -26,40 +25,32 @@
 /**
  * Error constructing an artifact repository.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class InvalidRepositoryException
-    extends Exception
-{
+public class InvalidRepositoryException extends Exception {
     private final String repositoryId;
 
-    public InvalidRepositoryException( String message, String repositoryId, MalformedURLException cause )
-    {
-        super( message, cause );
+    public InvalidRepositoryException(String message, String repositoryId, MalformedURLException cause) {
+        super(message, cause);
         this.repositoryId = repositoryId;
     }
 
-    protected InvalidRepositoryException( String message, String repositoryId, ComponentLookupException cause )
-    {
-        super( message, cause );
+    protected InvalidRepositoryException(String message, String repositoryId, ComponentLookupException cause) {
+        super(message, cause);
         this.repositoryId = repositoryId;
     }
 
     @Deprecated
-    public InvalidRepositoryException( String message, Throwable t )
-    {
-        super( message, t );
+    public InvalidRepositoryException(String message, Throwable t) {
+        super(message, t);
         this.repositoryId = null;
     }
 
-    public InvalidRepositoryException( String message, String repositoryId )
-    {
-        super( message );
+    public InvalidRepositoryException(String message, String repositoryId) {
+        super(message);
         this.repositoryId = repositoryId;
     }
 
-    public String getRepositoryId()
-    {
+    public String getRepositoryId() {
         return repositoryId;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java b/maven-core/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java
index 28f281e..b3b7c36f 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/factory/ArtifactFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.factory;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.factory;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.versioning.VersionRange;
@@ -26,38 +25,56 @@
  * ArtifactFactory - deprecated
  */
 @Deprecated
-@SuppressWarnings( "checkstyle:parameternumber" )
-public interface ArtifactFactory
-{
+@SuppressWarnings("checkstyle:parameternumber")
+public interface ArtifactFactory {
     @Deprecated
     String ROLE = ArtifactFactory.class.getName();
 
-    Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type );
+    Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type);
 
-    Artifact createArtifactWithClassifier( String groupId, String artifactId, String version, String type,
-                                           String classifier );
+    Artifact createArtifactWithClassifier(
+            String groupId, String artifactId, String version, String type, String classifier);
 
-    Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
-                                       String classifier, String scope );
+    Artifact createDependencyArtifact(
+            String groupId, String artifactId, VersionRange versionRange, String type, String classifier, String scope);
 
-    Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
-                                       String classifier, String scope, boolean optional );
+    Artifact createDependencyArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            boolean optional);
 
-    Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
-                                       String classifier, String scope, String inheritedScope );
+    Artifact createDependencyArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope);
 
-    Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
-                                       String classifier, String scope, String inheritedScope, boolean optional );
+    Artifact createDependencyArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope,
+            boolean optional);
 
-    Artifact createBuildArtifact( String groupId, String artifactId, String version, String packaging );
+    Artifact createBuildArtifact(String groupId, String artifactId, String version, String packaging);
 
-    Artifact createProjectArtifact( String groupId, String artifactId, String version );
+    Artifact createProjectArtifact(String groupId, String artifactId, String version);
 
-    Artifact createParentArtifact( String groupId, String artifactId, String version );
+    Artifact createParentArtifact(String groupId, String artifactId, String version);
 
-    Artifact createPluginArtifact( String groupId, String artifactId, VersionRange versionRange );
+    Artifact createPluginArtifact(String groupId, String artifactId, VersionRange versionRange);
 
-    Artifact createProjectArtifact( String groupId, String artifactId, String version, String scope );
+    Artifact createProjectArtifact(String groupId, String artifactId, String version, String scope);
 
-    Artifact createExtensionArtifact( String groupId, String artifactId, VersionRange versionRange );
+    Artifact createExtensionArtifact(String groupId, String artifactId, VersionRange versionRange);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java b/maven-core/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java
index 70466a7..2bc7033 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/factory/DefaultArtifactFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.factory;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.factory;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -35,139 +34,154 @@
  */
 @Named
 @Singleton
-@SuppressWarnings( "checkstyle:parameternumber" )
-public class DefaultArtifactFactory
-    implements ArtifactFactory
-{
+@SuppressWarnings("checkstyle:parameternumber")
+public class DefaultArtifactFactory implements ArtifactFactory {
     private final ArtifactHandlerManager artifactHandlerManager;
 
     @Inject
-    public DefaultArtifactFactory( ArtifactHandlerManager artifactHandlerManager )
-    {
+    public DefaultArtifactFactory(ArtifactHandlerManager artifactHandlerManager) {
         this.artifactHandlerManager = artifactHandlerManager;
     }
 
-    public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type )
-    {
-        return createArtifact( groupId, artifactId, version, scope, type, null, null );
+    public Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type) {
+        return createArtifact(groupId, artifactId, version, scope, type, null, null);
     }
 
-    public Artifact createArtifactWithClassifier( String groupId, String artifactId, String version, String type,
-                                                  String classifier )
-    {
-        return createArtifact( groupId, artifactId, version, null, type, classifier, null );
+    public Artifact createArtifactWithClassifier(
+            String groupId, String artifactId, String version, String type, String classifier) {
+        return createArtifact(groupId, artifactId, version, null, type, classifier, null);
     }
 
-    public Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange,
-                                              String type, String classifier, String scope )
-    {
-        return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, null );
+    public Artifact createDependencyArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope) {
+        return createArtifact(groupId, artifactId, versionRange, type, classifier, scope, null);
     }
 
-    public Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange,
-                                              String type, String classifier, String scope, boolean optional )
-    {
-        return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, null, optional );
+    public Artifact createDependencyArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            boolean optional) {
+        return createArtifact(groupId, artifactId, versionRange, type, classifier, scope, null, optional);
     }
 
-    public Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange,
-                                              String type, String classifier, String scope, String inheritedScope )
-    {
-        return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope );
+    public Artifact createDependencyArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope) {
+        return createArtifact(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope);
     }
 
-    public Artifact createDependencyArtifact( String groupId, String artifactId, VersionRange versionRange,
-                                              String type, String classifier, String scope, String inheritedScope,
-                                              boolean optional )
-    {
-        return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, optional );
+    public Artifact createDependencyArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope,
+            boolean optional) {
+        return createArtifact(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, optional);
     }
 
-    public Artifact createBuildArtifact( String groupId, String artifactId, String version, String packaging )
-    {
-        return createArtifact( groupId, artifactId, version, null, packaging, null, null );
+    public Artifact createBuildArtifact(String groupId, String artifactId, String version, String packaging) {
+        return createArtifact(groupId, artifactId, version, null, packaging, null, null);
     }
 
-    public Artifact createProjectArtifact( String groupId, String artifactId, String version )
-    {
-        return createProjectArtifact( groupId, artifactId, version, null );
+    public Artifact createProjectArtifact(String groupId, String artifactId, String version) {
+        return createProjectArtifact(groupId, artifactId, version, null);
     }
 
-    public Artifact createParentArtifact( String groupId, String artifactId, String version )
-    {
-        return createProjectArtifact( groupId, artifactId, version );
+    public Artifact createParentArtifact(String groupId, String artifactId, String version) {
+        return createProjectArtifact(groupId, artifactId, version);
     }
 
-    public Artifact createPluginArtifact( String groupId, String artifactId, VersionRange versionRange )
-    {
-        return createArtifact( groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null );
+    public Artifact createPluginArtifact(String groupId, String artifactId, VersionRange versionRange) {
+        return createArtifact(groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null);
     }
 
-    public Artifact createProjectArtifact( String groupId, String artifactId, String version, String scope )
-    {
-        return createArtifact( groupId, artifactId, version, scope, "pom" );
+    public Artifact createProjectArtifact(String groupId, String artifactId, String version, String scope) {
+        return createArtifact(groupId, artifactId, version, scope, "pom");
     }
 
-    public Artifact createExtensionArtifact( String groupId, String artifactId, VersionRange versionRange )
-    {
-        return createArtifact( groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null );
+    public Artifact createExtensionArtifact(String groupId, String artifactId, VersionRange versionRange) {
+        return createArtifact(groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null);
     }
 
-    private Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type,
-                                     String classifier, String inheritedScope )
-    {
+    private Artifact createArtifact(
+            String groupId,
+            String artifactId,
+            String version,
+            String scope,
+            String type,
+            String classifier,
+            String inheritedScope) {
         VersionRange versionRange = null;
-        if ( version != null )
-        {
-            versionRange = VersionRange.createFromVersion( version );
+        if (version != null) {
+            versionRange = VersionRange.createFromVersion(version);
         }
-        return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope );
+        return createArtifact(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope);
     }
 
-    private Artifact createArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
-                                     String classifier, String scope, String inheritedScope )
-    {
-        return createArtifact( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false );
+    private Artifact createArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope) {
+        return createArtifact(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false);
     }
 
-    private Artifact createArtifact( String groupId, String artifactId, VersionRange versionRange, String type,
-                                     String classifier, String scope, String inheritedScope, boolean optional )
-    {
+    private Artifact createArtifact(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope,
+            boolean optional) {
         String desiredScope = Artifact.SCOPE_RUNTIME;
 
-        if ( inheritedScope == null )
-        {
+        if (inheritedScope == null) {
             desiredScope = scope;
-        }
-        else if ( Artifact.SCOPE_TEST.equals( scope ) || Artifact.SCOPE_PROVIDED.equals( scope ) )
-        {
+        } else if (Artifact.SCOPE_TEST.equals(scope) || Artifact.SCOPE_PROVIDED.equals(scope)) {
             return null;
-        }
-        else if ( Artifact.SCOPE_COMPILE.equals( scope ) && Artifact.SCOPE_COMPILE.equals( inheritedScope ) )
-        {
+        } else if (Artifact.SCOPE_COMPILE.equals(scope) && Artifact.SCOPE_COMPILE.equals(inheritedScope)) {
             // added to retain compile artifactScope. Remove if you want compile inherited as runtime
             desiredScope = Artifact.SCOPE_COMPILE;
         }
 
-        if ( Artifact.SCOPE_TEST.equals( inheritedScope ) )
-        {
+        if (Artifact.SCOPE_TEST.equals(inheritedScope)) {
             desiredScope = Artifact.SCOPE_TEST;
         }
 
-        if ( Artifact.SCOPE_PROVIDED.equals( inheritedScope ) )
-        {
+        if (Artifact.SCOPE_PROVIDED.equals(inheritedScope)) {
             desiredScope = Artifact.SCOPE_PROVIDED;
         }
 
-        if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
-        {
+        if (Artifact.SCOPE_SYSTEM.equals(scope)) {
             // system scopes come through unchanged...
             desiredScope = Artifact.SCOPE_SYSTEM;
         }
 
-        ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( type );
+        ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(type);
 
-        return new DefaultArtifact( groupId, artifactId, versionRange, desiredScope, type, classifier, handler,
-                                    optional );
+        return new DefaultArtifact(
+                groupId, artifactId, versionRange, desiredScope, type, classifier, handler, optional);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java
index bb90aff..0a08373 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/DefaultArtifactHandler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.handler;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.handler;
 
 import static java.util.Objects.requireNonNull;
 
 /**
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- * @author Jason van Zyl
  */
-public class DefaultArtifactHandler
-    implements ArtifactHandler
-{
+public class DefaultArtifactHandler implements ArtifactHandler {
     private final String type;
 
     private String extension;
@@ -51,35 +46,25 @@
      * @deprecated This ctor is present only for Plexus XML defined component compatibility, do not use it.
      */
     @Deprecated
-    public DefaultArtifactHandler()
-    {
+    public DefaultArtifactHandler() {
         this.type = null;
     }
 
-    public DefaultArtifactHandler( final String type )
-    {
-        this(
-            type,
-            null,
-            null,
-            null,
-            null,
-            false,
-            null,
-            false
-        );
+    public DefaultArtifactHandler(final String type) {
+        this(type, null, null, null, null, false, null, false);
     }
 
-    public DefaultArtifactHandler( final String type,
-                                   final String extension,
-                                   final String classifier,
-                                   final String directory,
-                                   final String packaging,
-                                   final boolean includesDependencies,
-                                   final String language,
-                                   final boolean addedToClasspath )
-    {
-        this.type = requireNonNull( type );
+    @SuppressWarnings("checkstyle:ParameterNumber")
+    public DefaultArtifactHandler(
+            final String type,
+            final String extension,
+            final String classifier,
+            final String directory,
+            final String packaging,
+            final boolean includesDependencies,
+            final String language,
+            final boolean addedToClasspath) {
+        this.type = requireNonNull(type);
         this.extension = extension;
         this.classifier = classifier;
         this.directory = directory;
@@ -89,102 +74,83 @@
         this.addedToClasspath = addedToClasspath;
     }
 
-    public String getType()
-    {
+    public String getType() {
         return type;
     }
 
     @Override
-    public String getExtension()
-    {
-        if ( extension == null )
-        {
+    public String getExtension() {
+        if (extension == null) {
             return type;
         }
         return extension;
     }
 
-    public void setExtension( final String extension )
-    {
+    public void setExtension(final String extension) {
         this.extension = extension;
     }
 
     @Override
-    public String getClassifier()
-    {
+    public String getClassifier() {
         return classifier;
     }
 
-    public void setClassifier( final String classifier )
-    {
+    public void setClassifier(final String classifier) {
         this.classifier = classifier;
     }
 
     @Override
-    public String getDirectory()
-    {
-        if ( directory == null )
-        {
+    public String getDirectory() {
+        if (directory == null) {
             return getPackaging() + "s";
         }
         return directory;
     }
 
-    public void setDirectory( final String directory )
-    {
+    public void setDirectory(final String directory) {
         this.directory = directory;
     }
 
     @Override
-    public String getPackaging()
-    {
-        if ( packaging == null )
-        {
+    public String getPackaging() {
+        if (packaging == null) {
             return type;
         }
         return packaging;
     }
 
-    public void setPackaging( final String packaging )
-    {
+    public void setPackaging(final String packaging) {
         this.packaging = packaging;
     }
 
     @Override
-    public boolean isIncludesDependencies()
-    {
+    public boolean isIncludesDependencies() {
         return includesDependencies;
     }
 
-    public void setIncludesDependencies( final boolean includesDependencies )
-    {
+    public void setIncludesDependencies(final boolean includesDependencies) {
         this.includesDependencies = includesDependencies;
     }
 
     @Override
-    public String getLanguage()
-    {
-        if ( language == null )
-        {
+    public String getLanguage() {
+        if (language == null) {
             return "none";
         }
 
         return language;
     }
 
-    public void setLanguage( final String language )
-    {
+    public void setLanguage(final String language) {
         this.language = language;
     }
 
     @Override
-    public boolean isAddedToClasspath()
-    {
+    public boolean isAddedToClasspath() {
         return addedToClasspath;
     }
 
-    public void setAddedToClasspath( final boolean addedToClasspath )
-    {
+    public void setAddedToClasspath(final boolean addedToClasspath) {
         this.addedToClasspath = addedToClasspath;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/ArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/ArtifactHandlerManager.java
index cada9e9..a398f40 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/ArtifactHandlerManager.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/ArtifactHandlerManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.handler.manager;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,20 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.handler.manager;
 
 import java.util.Map;
 
 import org.apache.maven.artifact.handler.ArtifactHandler;
 
 /**
- * @author Jason van Zyl
  */
-public interface ArtifactHandlerManager
-{
+public interface ArtifactHandlerManager {
     String ROLE = ArtifactHandlerManager.class.getName();
 
-    ArtifactHandler getArtifactHandler( String type );
+    ArtifactHandler getArtifactHandler(String type);
 
     @Deprecated
-    void addHandlers( Map<String, ArtifactHandler> handlers );
+    void addHandlers(Map<String, ArtifactHandler> handlers);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java
index 3145d58..53fab05 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/DefaultArtifactHandlerManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.handler.manager;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,68 +16,71 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+package org.apache.maven.artifact.handler.manager;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.api.Type;
+import org.apache.maven.api.services.TypeRegistry;
 import org.apache.maven.artifact.handler.ArtifactHandler;
 import org.apache.maven.artifact.handler.DefaultArtifactHandler;
+import org.apache.maven.eventspy.AbstractEventSpy;
+import org.apache.maven.execution.ExecutionEvent;
+
+import static java.util.Objects.requireNonNull;
 
 /**
- * @author Jason van Zyl
  */
 @Named
 @Singleton
-public class DefaultArtifactHandlerManager
-    implements ArtifactHandlerManager
-{
+public class DefaultArtifactHandlerManager extends AbstractEventSpy implements ArtifactHandlerManager {
+    private final TypeRegistry typeRegistry;
 
-    private final Map<String, ArtifactHandler> artifactHandlers;
-
-    private final Map<String, ArtifactHandler> allHandlers = new ConcurrentHashMap<>();
+    private final ConcurrentHashMap<String, ArtifactHandler> allHandlers;
 
     @Inject
-    public DefaultArtifactHandlerManager( Map<String, ArtifactHandler> artifactHandlers )
-    {
-        this.artifactHandlers = artifactHandlers;
+    public DefaultArtifactHandlerManager(TypeRegistry typeRegistry) {
+        this.typeRegistry = requireNonNull(typeRegistry, "null typeRegistry");
+        this.allHandlers = new ConcurrentHashMap<>();
     }
 
-    public ArtifactHandler getArtifactHandler( String type )
-    {
-        ArtifactHandler handler = allHandlers.get( type );
-
-        if ( handler == null )
-        {
-            handler = artifactHandlers.get( type );
-
-            if ( handler == null )
-            {
-                handler = new DefaultArtifactHandler( type );
-            }
-            else
-            {
-                allHandlers.put( type, handler );
+    @Override
+    public void onEvent(Object event) {
+        if (event instanceof ExecutionEvent) {
+            ExecutionEvent executionEvent = (ExecutionEvent) event;
+            if (executionEvent.getType() == ExecutionEvent.Type.SessionEnded) {
+                allHandlers.clear();
             }
         }
-
-        return handler;
     }
 
-    public void addHandlers( Map<String, ArtifactHandler> handlers )
-    {
-        // legacy support for maven-gpg-plugin:1.0
-        allHandlers.putAll( handlers );
+    public ArtifactHandler getArtifactHandler(String id) {
+        return allHandlers.computeIfAbsent(id, k -> {
+            Type type = typeRegistry.getType(id);
+            return new DefaultArtifactHandler(
+                    id,
+                    type.getExtension(),
+                    type.getClassifier(),
+                    null,
+                    null,
+                    type.isIncludesDependencies(),
+                    "none",
+                    type.isAddedToClassPath()); // TODO: watch out for module path
+        });
+    }
+
+    public void addHandlers(Map<String, ArtifactHandler> handlers) {
+        throw new UnsupportedOperationException("Adding handlers programmatically is not supported anymore");
     }
 
     @Deprecated
-    public Set<String> getHandlerTypes()
-    {
-        return artifactHandlers.keySet();
+    public Set<String> getHandlerTypes() {
+        throw new UnsupportedOperationException("Querying handlers programmatically is not supported anymore");
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/LegacyArtifactHandlerManager.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/LegacyArtifactHandlerManager.java
new file mode 100644
index 0000000..46e480f
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/artifact/handler/manager/LegacyArtifactHandlerManager.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.handler.manager;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.DefaultArtifactHandler;
+import org.apache.maven.eventspy.AbstractEventSpy;
+import org.apache.maven.execution.ExecutionEvent;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ */
+@Named
+@Singleton
+public class LegacyArtifactHandlerManager extends AbstractEventSpy {
+    private final Map<String, ArtifactHandler> artifactHandlers;
+
+    private final Map<String, ArtifactHandler> allHandlers = new ConcurrentHashMap<>();
+
+    @Inject
+    public LegacyArtifactHandlerManager(Map<String, ArtifactHandler> artifactHandlers) {
+        this.artifactHandlers = requireNonNull(artifactHandlers);
+    }
+
+    @Override
+    public void onEvent(Object event) {
+        if (event instanceof ExecutionEvent) {
+            ExecutionEvent executionEvent = (ExecutionEvent) event;
+            if (executionEvent.getType() == ExecutionEvent.Type.SessionEnded) {
+                allHandlers.clear();
+            }
+        }
+    }
+
+    public ArtifactHandler getArtifactHandler(String type) {
+        requireNonNull(type, "null type");
+        ArtifactHandler handler = allHandlers.get(type);
+        if (handler == null) {
+            handler = artifactHandlers.get(type);
+            if (handler == null) {
+                handler = new DefaultArtifactHandler(type);
+            } else {
+                allHandlers.put(type, handler);
+            }
+        }
+        return handler;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EarArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EarArtifactHandlerProvider.java
deleted file mode 100644
index fbb5fff..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EarArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code ear} artifact handler provider.
- */
-@Named( "ear" )
-@Singleton
-public class EarArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public EarArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "ear",
-            null,
-            null,
-            null,
-            null,
-            true,
-            "java",
-            false
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EjbArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EjbArtifactHandlerProvider.java
deleted file mode 100644
index 5802db6..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EjbArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code ejb} artifact handler provider.
- */
-@Named( "ejb" )
-@Singleton
-public class EjbArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public EjbArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "ejb",
-            "jar",
-            null,
-            null,
-            null,
-            false,
-            "java",
-            true
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EjbClientArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EjbClientArtifactHandlerProvider.java
deleted file mode 100644
index d225b76..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/EjbClientArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code ejb-client} artifact handler provider.
- */
-@Named( "ejb-client" )
-@Singleton
-public class EjbClientArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public EjbClientArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "ejb-client",
-            "jar",
-            "client",
-            null,
-            "ejb",
-            false,
-            "java",
-            true
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JarArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JarArtifactHandlerProvider.java
deleted file mode 100644
index 0e203ba..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JarArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code jar} artifact handler provider.
- */
-@Named( "jar" )
-@Singleton
-public class JarArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public JarArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "jar",
-            null,
-            null,
-            null,
-            null,
-            false,
-            "java",
-            true
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JavaSourceArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JavaSourceArtifactHandlerProvider.java
deleted file mode 100644
index 37bf394..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JavaSourceArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code java-source} artifact handler provider.
- */
-@Named( "java-source" )
-@Singleton
-public class JavaSourceArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public JavaSourceArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "java-source",
-            "jar",
-            "sources",
-            null,
-            null,
-            false,
-            "java",
-            false
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JavadocArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JavadocArtifactHandlerProvider.java
deleted file mode 100644
index d7d40e3..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/JavadocArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code javadoc} artifact handler provider.
- */
-@Named( "javadoc" )
-@Singleton
-public class JavadocArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public JavadocArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "javadoc",
-            "jar",
-            "javadoc",
-            null,
-            null,
-            false,
-            "java",
-            true
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/MavenPluginArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/MavenPluginArtifactHandlerProvider.java
deleted file mode 100644
index c712211..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/MavenPluginArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code maven-plugin} artifact handler provider.
- */
-@Named( "maven-plugin" )
-@Singleton
-public class MavenPluginArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public MavenPluginArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "maven-plugin",
-            "jar",
-            null,
-            null,
-            null,
-            false,
-            "java",
-            true
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/PomArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/PomArtifactHandlerProvider.java
deleted file mode 100644
index 3696159..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/PomArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code pom} artifact handler provider.
- */
-@Named( "pom" )
-@Singleton
-public class PomArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public PomArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "pom",
-            null,
-            null,
-            null,
-            null,
-            false,
-            "none",
-            false
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/RarArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/RarArtifactHandlerProvider.java
deleted file mode 100644
index d2d75b9..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/RarArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code rar} artifact handler provider.
- */
-@Named( "rar" )
-@Singleton
-public class RarArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public RarArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "rar",
-            null,
-            null,
-            null,
-            null,
-            true,
-            "java",
-            false
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/TestJarArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/TestJarArtifactHandlerProvider.java
deleted file mode 100644
index 57bfe49..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/TestJarArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code test-jar} artifact handler provider.
- */
-@Named( "test-jar" )
-@Singleton
-public class TestJarArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public TestJarArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "test-jar",
-            "jar",
-            "tests",
-            null,
-            "jar",
-            false,
-            "java",
-            true
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/WarArtifactHandlerProvider.java b/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/WarArtifactHandlerProvider.java
deleted file mode 100644
index f2dc46e..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/handler/providers/WarArtifactHandlerProvider.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.apache.maven.artifact.handler.providers;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.handler.DefaultArtifactHandler;
-
-/**
- * {@code war} artifact handler provider.
- */
-@Named( "war" )
-@Singleton
-public class WarArtifactHandlerProvider
-    implements Provider<ArtifactHandler>
-{
-    private final ArtifactHandler artifactHandler;
-
-    @Inject
-    public WarArtifactHandlerProvider()
-    {
-        this.artifactHandler = new DefaultArtifactHandler(
-            "war",
-            null,
-            null,
-            null,
-            null,
-            true,
-            "java",
-            false
-        );
-    }
-
-    @Override
-    public ArtifactHandler get()
-    {
-        return artifactHandler;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/metadata/AbstractArtifactMetadata.java b/maven-core/src/main/java/org/apache/maven/artifact/metadata/AbstractArtifactMetadata.java
deleted file mode 100644
index f0de677..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/metadata/AbstractArtifactMetadata.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.apache.maven.artifact.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-
-/**
- * AbstractArtifactMetadata
- */
-@Deprecated
-public abstract class AbstractArtifactMetadata
-    extends org.apache.maven.repository.legacy.metadata.AbstractArtifactMetadata
-    implements org.apache.maven.artifact.metadata.ArtifactMetadata
-{
-    protected AbstractArtifactMetadata( Artifact artifact )
-    {
-        super( artifact );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataRetrievalException.java b/maven-core/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataRetrievalException.java
deleted file mode 100644
index 342c6fe..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataRetrievalException.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package org.apache.maven.artifact.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-
-/**
- * Error while retrieving repository metadata from the repository - deprecated
- */
-@Deprecated
-public class ArtifactMetadataRetrievalException
-    extends org.apache.maven.repository.legacy.metadata.ArtifactMetadataRetrievalException
-{
-
-    /**
-     * @param message a message
-     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
-     */
-    @Deprecated
-    public ArtifactMetadataRetrievalException( String message )
-    {
-        super( message, null, null );
-    }
-
-    /**
-     * @param cause a cause
-     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
-     */
-    @Deprecated
-    public ArtifactMetadataRetrievalException( Throwable cause )
-    {
-        super( null, cause, null );
-    }
-
-    /**
-     * @param message a message
-     * @param cause a cause
-     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
-     */
-    @Deprecated
-    public ArtifactMetadataRetrievalException( String message,
-                                               Throwable cause )
-    {
-        super( message, cause, null );
-    }
-
-    public ArtifactMetadataRetrievalException( String message, Throwable cause, Artifact artifact )
-    {
-        super( message, cause, artifact );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataSource.java b/maven-core/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataSource.java
deleted file mode 100644
index 605230f..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/metadata/ArtifactMetadataSource.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.apache.maven.artifact.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.versioning.ArtifactVersion;
-import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
-
-/**
- * Provides some metadata operations, like querying the remote repository for a list of versions available for an
- * artifact - deprecated
- */
-@Deprecated
-public interface ArtifactMetadataSource
-    extends org.apache.maven.repository.legacy.metadata.ArtifactMetadataSource
-{
-
-    ResolutionGroup retrieve( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException;
-
-    ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                              List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException;
-
-    List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException;
-
-    List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
-                                                     List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException;
-
-    List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact,
-                                                                             ArtifactRepository localRepository,
-                                                                             ArtifactRepository remoteRepository )
-        throws ArtifactMetadataRetrievalException;
-}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/metadata/ResolutionGroup.java b/maven-core/src/main/java/org/apache/maven/artifact/metadata/ResolutionGroup.java
deleted file mode 100644
index 3503265..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/metadata/ResolutionGroup.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.apache.maven.artifact.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-
-/**
- * ResolutionGroup
- */
-@Deprecated
-public class ResolutionGroup
-    extends org.apache.maven.repository.legacy.metadata.ResolutionGroup
-{
-
-    public ResolutionGroup( Artifact pomArtifact, Set<Artifact> artifacts,
-                            List<ArtifactRepository> resolutionRepositories )
-    {
-        super( pomArtifact, artifacts, resolutionRepositories );
-    }
-
-    public ResolutionGroup( Artifact pomArtifact, Artifact relocatedArtifact, Set<Artifact> artifacts,
-                            Map<String, Artifact> managedVersions, List<ArtifactRepository> resolutionRepositories )
-    {
-        super( pomArtifact, relocatedArtifact, artifacts, managedVersions, resolutionRepositories );
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java
index 839094f..45dc040 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/DefaultRepositoryRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -28,11 +27,8 @@
 /**
  * Collects basic settings to access the repository system.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultRepositoryRequest
-    implements RepositoryRequest
-{
+public class DefaultRepositoryRequest implements RepositoryRequest {
 
     private boolean offline;
 
@@ -45,8 +41,7 @@
     /**
      * Creates an empty repository request.
      */
-    public DefaultRepositoryRequest()
-    {
+    public DefaultRepositoryRequest() {
         // enables no-arg constructor
     }
 
@@ -55,80 +50,67 @@
      *
      * @param repositoryRequest The repository request to copy from, must not be {@code null}.
      */
-    public DefaultRepositoryRequest( RepositoryRequest repositoryRequest )
-    {
-        setLocalRepository( repositoryRequest.getLocalRepository() );
-        setRemoteRepositories( repositoryRequest.getRemoteRepositories() );
-        setOffline( repositoryRequest.isOffline() );
-        setForceUpdate( repositoryRequest.isForceUpdate() );
+    public DefaultRepositoryRequest(RepositoryRequest repositoryRequest) {
+        setLocalRepository(repositoryRequest.getLocalRepository());
+        setRemoteRepositories(repositoryRequest.getRemoteRepositories());
+        setOffline(repositoryRequest.isOffline());
+        setForceUpdate(repositoryRequest.isForceUpdate());
     }
 
-    public static RepositoryRequest getRepositoryRequest( MavenSession session, MavenProject project )
-    {
+    public static RepositoryRequest getRepositoryRequest(MavenSession session, MavenProject project) {
         RepositoryRequest request = new DefaultRepositoryRequest();
 
-        request.setLocalRepository( session.getLocalRepository() );
-        if ( project != null )
-        {
-            request.setRemoteRepositories( project.getPluginArtifactRepositories() );
+        request.setLocalRepository(session.getLocalRepository());
+        if (project != null) {
+            request.setRemoteRepositories(project.getPluginArtifactRepositories());
         }
-        request.setOffline( session.isOffline() );
-        request.setForceUpdate( session.getRequest().isUpdateSnapshots() );
+        request.setOffline(session.isOffline());
+        request.setForceUpdate(session.getRequest().isUpdateSnapshots());
 
         return request;
     }
 
-    public boolean isOffline()
-    {
+    public boolean isOffline() {
         return offline;
     }
 
-    public DefaultRepositoryRequest setOffline( boolean offline )
-    {
+    public DefaultRepositoryRequest setOffline(boolean offline) {
         this.offline = offline;
 
         return this;
     }
 
-    public boolean isForceUpdate()
-    {
+    public boolean isForceUpdate() {
         return forceUpdate;
     }
 
-    public DefaultRepositoryRequest setForceUpdate( boolean forceUpdate )
-    {
+    public DefaultRepositoryRequest setForceUpdate(boolean forceUpdate) {
         this.forceUpdate = forceUpdate;
 
         return this;
     }
 
-    public ArtifactRepository getLocalRepository()
-    {
+    public ArtifactRepository getLocalRepository() {
         return localRepository;
     }
 
-    public DefaultRepositoryRequest setLocalRepository( ArtifactRepository localRepository )
-    {
+    public DefaultRepositoryRequest setLocalRepository(ArtifactRepository localRepository) {
         this.localRepository = localRepository;
 
         return this;
     }
 
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
-        if ( remoteRepositories == null )
-        {
+    public List<ArtifactRepository> getRemoteRepositories() {
+        if (remoteRepositories == null) {
             remoteRepositories = new ArrayList<>();
         }
 
         return remoteRepositories;
     }
 
-    public DefaultRepositoryRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
-    {
+    public DefaultRepositoryRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories) {
         this.remoteRepositories = remoteRepositories;
 
         return this;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java
deleted file mode 100644
index acd7d5f..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/LegacyLocalRepositoryManager.java
+++ /dev/null
@@ -1,441 +0,0 @@
-package org.apache.maven.artifact.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-
-import org.apache.maven.RepositoryUtils;
-import org.apache.maven.artifact.metadata.ArtifactMetadata;
-import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
-import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadataStoreException;
-import org.apache.maven.repository.Proxy;
-import org.eclipse.aether.DefaultRepositorySystemSession;
-import org.eclipse.aether.RepositorySystem;
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.metadata.Metadata;
-import org.eclipse.aether.repository.LocalArtifactRegistration;
-import org.eclipse.aether.repository.LocalArtifactRequest;
-import org.eclipse.aether.repository.LocalArtifactResult;
-import org.eclipse.aether.repository.LocalMetadataRegistration;
-import org.eclipse.aether.repository.LocalMetadataRequest;
-import org.eclipse.aether.repository.LocalMetadataResult;
-import org.eclipse.aether.repository.LocalRepository;
-import org.eclipse.aether.repository.LocalRepositoryManager;
-import org.eclipse.aether.repository.RemoteRepository;
-
-/**
- * <strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
- * of the public API. In particular, this class can be changed or deleted without prior notice.
- *
- * @author Benjamin Bentmann
- */
-public class LegacyLocalRepositoryManager
-    implements LocalRepositoryManager
-{
-
-    private final ArtifactRepository delegate;
-
-    private final LocalRepository repo;
-
-    private final boolean realLocalRepo;
-
-    public static RepositorySystemSession overlay( ArtifactRepository repository, RepositorySystemSession session,
-                                                   RepositorySystem system )
-    {
-        if ( repository == null || repository.getBasedir() == null )
-        {
-            return session;
-        }
-
-        if ( session != null )
-        {
-            LocalRepositoryManager lrm = session.getLocalRepositoryManager();
-            if ( lrm != null && lrm.getRepository().getBasedir().equals( new File( repository.getBasedir() ) ) )
-            {
-                return session;
-            }
-        }
-        else
-        {
-            session = new DefaultRepositorySystemSession();
-        }
-
-        final LocalRepositoryManager llrm = new LegacyLocalRepositoryManager( repository );
-
-        return new DefaultRepositorySystemSession( session ).setLocalRepositoryManager( llrm );
-    }
-
-    private LegacyLocalRepositoryManager( ArtifactRepository delegate )
-    {
-        this.delegate = Objects.requireNonNull( delegate, "delegate cannot be null" );
-
-        ArtifactRepositoryLayout layout = delegate.getLayout();
-        repo =
-            new LocalRepository( new File( delegate.getBasedir() ),
-                                 ( layout != null ) ? layout.getClass().getSimpleName() : "legacy" );
-
-        /*
-         * NOTE: "invoker:install" vs "appassembler:assemble": Both mojos use the artifact installer to put an artifact
-         * into a repository. In the first case, the result needs to be a proper local repository that one can use for
-         * local artifact resolution. In the second case, the result needs to precisely obey the path information of the
-         * repository's layout to allow pointing at artifacts within the repository. Unfortunately,
-         * DefaultRepositoryLayout does not correctly describe the layout of a local repository which unlike a remote
-         * repository never uses timestamps in the filename of a snapshot artifact. The discrepancy gets notable when a
-         * remotely resolved snapshot artifact gets passed into pathOf(). So producing a proper local artifact path
-         * using DefaultRepositoryLayout requires us to enforce usage of the artifact's base version. This
-         * transformation however contradicts the other use case of precisely obeying the repository's layout. The below
-         * flag tries to detect which use case applies to make both plugins happy.
-         */
-        realLocalRepo = ( layout instanceof DefaultRepositoryLayout ) && "local".equals( delegate.getId() );
-    }
-
-    public LocalRepository getRepository()
-    {
-        return repo;
-    }
-
-    public String getPathForLocalArtifact( Artifact artifact )
-    {
-        if ( realLocalRepo )
-        {
-            return delegate.pathOf( RepositoryUtils.toArtifact( artifact.setVersion( artifact.getBaseVersion() ) ) );
-        }
-        return delegate.pathOf( RepositoryUtils.toArtifact( artifact ) );
-    }
-
-    public String getPathForRemoteArtifact( Artifact artifact, RemoteRepository repository, String context )
-    {
-        return delegate.pathOf( RepositoryUtils.toArtifact( artifact ) );
-    }
-
-    public String getPathForLocalMetadata( Metadata metadata )
-    {
-        return delegate.pathOfLocalRepositoryMetadata( new ArtifactMetadataAdapter( metadata ), delegate );
-    }
-
-    public String getPathForRemoteMetadata( Metadata metadata, RemoteRepository repository, String context )
-    {
-        return delegate.pathOfLocalRepositoryMetadata( new ArtifactMetadataAdapter( metadata ),
-                                                       new ArtifactRepositoryAdapter( repository ) );
-    }
-
-    public LocalArtifactResult find( RepositorySystemSession session, LocalArtifactRequest request )
-    {
-        String path = getPathForLocalArtifact( request.getArtifact() );
-        File file = new File( getRepository().getBasedir(), path );
-
-        LocalArtifactResult result = new LocalArtifactResult( request );
-        if ( file.isFile() )
-        {
-            result.setFile( file );
-            result.setAvailable( true );
-        }
-
-        return result;
-    }
-
-    public LocalMetadataResult find( RepositorySystemSession session, LocalMetadataRequest request )
-    {
-        Metadata metadata = request.getMetadata();
-
-        String path;
-        if ( request.getRepository() == null )
-        {
-            path = getPathForLocalMetadata( metadata );
-        }
-        else
-        {
-            path = getPathForRemoteMetadata( metadata, request.getRepository(), request.getContext() );
-        }
-
-        File file = new File( getRepository().getBasedir(), path );
-
-        LocalMetadataResult result = new LocalMetadataResult( request );
-        if ( file.isFile() )
-        {
-            result.setFile( file );
-        }
-
-        return result;
-    }
-
-    public void add( RepositorySystemSession session, LocalArtifactRegistration request )
-    {
-        // noop
-    }
-
-    public void add( RepositorySystemSession session, LocalMetadataRegistration request )
-    {
-        // noop
-    }
-
-    static class ArtifactMetadataAdapter
-        implements ArtifactMetadata
-    {
-
-        private final Metadata metadata;
-
-        ArtifactMetadataAdapter( Metadata metadata )
-        {
-            this.metadata = metadata;
-        }
-
-        public boolean storedInArtifactVersionDirectory()
-        {
-            return metadata.getVersion().length() > 0;
-        }
-
-        public boolean storedInGroupDirectory()
-        {
-            return metadata.getArtifactId().length() <= 0;
-        }
-
-        public String getGroupId()
-        {
-            return nullify( metadata.getGroupId() );
-        }
-
-        public String getArtifactId()
-        {
-            return nullify( metadata.getArtifactId() );
-        }
-
-        public String getBaseVersion()
-        {
-            return nullify( metadata.getVersion() );
-        }
-
-        private String nullify( String str )
-        {
-            return ( str == null || str.length() <= 0 ) ? null : str;
-        }
-
-        public Object getKey()
-        {
-            return metadata.toString();
-        }
-
-        public String getRemoteFilename()
-        {
-            return metadata.getType();
-        }
-
-        public String getLocalFilename( ArtifactRepository repository )
-        {
-            return insertRepositoryKey( getRemoteFilename(), repository.getKey() );
-        }
-
-        private String insertRepositoryKey( String filename, String repositoryKey )
-        {
-            String result;
-            int idx = filename.indexOf( '.' );
-            if ( idx < 0 )
-            {
-                result = filename + '-' + repositoryKey;
-            }
-            else
-            {
-                result = filename.substring( 0, idx ) + '-' + repositoryKey + filename.substring( idx );
-            }
-            return result;
-        }
-
-        public void merge( org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata )
-        {
-            // not used
-        }
-
-        public void merge( ArtifactMetadata metadata )
-        {
-            // not used
-        }
-
-        public void storeInLocalRepository( ArtifactRepository localRepository, ArtifactRepository remoteRepository )
-            throws RepositoryMetadataStoreException
-        {
-            // not used
-        }
-
-        public String extendedToString()
-        {
-            return metadata.toString();
-        }
-
-    }
-
-    static class ArtifactRepositoryAdapter
-        implements ArtifactRepository
-    {
-
-        private final RemoteRepository repository;
-
-        ArtifactRepositoryAdapter( RemoteRepository repository )
-        {
-            this.repository = repository;
-        }
-
-        public String pathOf( org.apache.maven.artifact.Artifact artifact )
-        {
-            return null;
-        }
-
-        public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
-        {
-            return null;
-        }
-
-        public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-        {
-            return null;
-        }
-
-        public String getUrl()
-        {
-            return repository.getUrl();
-        }
-
-        public void setUrl( String url )
-        {
-        }
-
-        public String getBasedir()
-        {
-            return null;
-        }
-
-        public String getProtocol()
-        {
-            return repository.getProtocol();
-        }
-
-        public String getId()
-        {
-            return repository.getId();
-        }
-
-        public void setId( String id )
-        {
-        }
-
-        public ArtifactRepositoryPolicy getSnapshots()
-        {
-            return null;
-        }
-
-        public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy policy )
-        {
-        }
-
-        public ArtifactRepositoryPolicy getReleases()
-        {
-            return null;
-        }
-
-        public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy policy )
-        {
-        }
-
-        public ArtifactRepositoryLayout getLayout()
-        {
-            return null;
-        }
-
-        public void setLayout( ArtifactRepositoryLayout layout )
-        {
-        }
-
-        public String getKey()
-        {
-            return getId();
-        }
-
-        public boolean isUniqueVersion()
-        {
-            return true;
-        }
-
-        public boolean isBlacklisted()
-        {
-            return false;
-        }
-
-        public void setBlacklisted( boolean blackListed )
-        {
-        }
-
-        public org.apache.maven.artifact.Artifact find( org.apache.maven.artifact.Artifact artifact )
-        {
-            return null;
-        }
-
-        public List<String> findVersions( org.apache.maven.artifact.Artifact artifact )
-        {
-            return Collections.emptyList();
-        }
-
-        public boolean isProjectAware()
-        {
-            return false;
-        }
-
-        public void setAuthentication( Authentication authentication )
-        {
-        }
-
-        public Authentication getAuthentication()
-        {
-            return null;
-        }
-
-        public void setProxy( Proxy proxy )
-        {
-        }
-
-        public Proxy getProxy()
-        {
-            return null;
-        }
-
-        public List<ArtifactRepository> getMirroredRepositories()
-        {
-            return Collections.emptyList();
-        }
-
-        public void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories )
-        {
-        }
-
-        public boolean isBlocked()
-        {
-            return false;
-        }
-
-        public void setBlocked( boolean blocked )
-        {
-        }
-
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java
index ee513e4..dbd1f57 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/MavenArtifactRepository.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 import java.io.File;
 import java.util.Collections;
@@ -33,10 +32,8 @@
  * Abstraction of an artifact repository. Artifact repositories can be remote, local, or even build reactor or
  * IDE workspace.
  */
-//TODO completely separate local and remote artifact repositories
-public class MavenArtifactRepository
-    implements ArtifactRepository
-{
+// TODO completely separate local and remote artifact repositories
+public class MavenArtifactRepository implements ArtifactRepository {
     private static final String LS = System.lineSeparator();
 
     private String id;
@@ -61,9 +58,7 @@
 
     private boolean blocked;
 
-    public MavenArtifactRepository()
-    {
-    }
+    public MavenArtifactRepository() {}
 
     /**
      * Create a remote download repository.
@@ -74,9 +69,12 @@
      * @param snapshots the policies to use for snapshots
      * @param releases  the policies to use for releases
      */
-    public MavenArtifactRepository( String id, String url, ArtifactRepositoryLayout layout,
-                                    ArtifactRepositoryPolicy snapshots, ArtifactRepositoryPolicy releases )
-    {
+    public MavenArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout layout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases) {
         this.id = id;
         this.url = url;
         this.layout = layout;
@@ -85,137 +83,119 @@
         //
         // Derive these from the URL
         //
-        this.protocol = protocol( url );
-        this.basedir = basedir( url );
+        this.protocol = protocol(url);
+        this.basedir = basedir(url);
     }
 
-    public String pathOf( Artifact artifact )
-    {
-        return layout.pathOf( artifact );
+    public String pathOf(Artifact artifact) {
+        return layout.pathOf(artifact);
     }
 
-    public String pathOfRemoteRepositoryMetadata( ArtifactMetadata artifactMetadata )
-    {
-        return layout.pathOfRemoteRepositoryMetadata( artifactMetadata );
+    public String pathOfRemoteRepositoryMetadata(ArtifactMetadata artifactMetadata) {
+        return layout.pathOfRemoteRepositoryMetadata(artifactMetadata);
     }
 
-    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-    {
-        return layout.pathOfLocalRepositoryMetadata( metadata, repository );
+    public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+        return layout.pathOfLocalRepositoryMetadata(metadata, repository);
     }
 
-    public void setLayout( ArtifactRepositoryLayout layout )
-    {
+    public void setLayout(ArtifactRepositoryLayout layout) {
         this.layout = layout;
     }
 
-    public ArtifactRepositoryLayout getLayout()
-    {
+    public ArtifactRepositoryLayout getLayout() {
         return layout;
     }
 
-    public void setSnapshotUpdatePolicy( ArtifactRepositoryPolicy snapshots )
-    {
+    public void setSnapshotUpdatePolicy(ArtifactRepositoryPolicy snapshots) {
         this.snapshots = snapshots;
     }
 
-    public ArtifactRepositoryPolicy getSnapshots()
-    {
+    public ArtifactRepositoryPolicy getSnapshots() {
         return snapshots;
     }
 
-    public void setReleaseUpdatePolicy( ArtifactRepositoryPolicy releases )
-    {
+    public void setReleaseUpdatePolicy(ArtifactRepositoryPolicy releases) {
         this.releases = releases;
     }
 
-    public ArtifactRepositoryPolicy getReleases()
-    {
+    public ArtifactRepositoryPolicy getReleases() {
         return releases;
     }
 
-    public String getKey()
-    {
+    public String getKey() {
         return getId();
     }
 
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 256 );
+    public String toString() {
+        StringBuilder sb = new StringBuilder(256);
 
-        sb.append( "      id: " ).append( getId() ).append( LS );
-        sb.append( "      url: " ).append( getUrl() ).append( LS );
-        sb.append( "   layout: " ).append( layout != null ? layout : "none" );
+        sb.append("      id: ").append(getId()).append(LS);
+        sb.append("      url: ").append(getUrl()).append(LS);
+        sb.append("   layout: ").append(layout != null ? layout : "none");
 
-        if ( proxy != null )
-        {
-            sb.append( LS ).append( "    proxy: " ).append( proxy.getHost() ).append( ':' ).append( proxy.getPort() );
+        if (proxy != null) {
+            sb.append(LS)
+                    .append("    proxy: ")
+                    .append(proxy.getHost())
+                    .append(':')
+                    .append(proxy.getPort());
         }
 
-        if ( snapshots != null )
-        {
-            sb.append( LS ).append( "snapshots: [enabled => " ).append( snapshots.isEnabled() );
-            sb.append( ", update => " ).append( snapshots.getUpdatePolicy() ).append( ']' );
+        if (snapshots != null) {
+            sb.append(LS).append("snapshots: [enabled => ").append(snapshots.isEnabled());
+            sb.append(", update => ").append(snapshots.getUpdatePolicy()).append(']');
         }
 
-        if ( releases != null )
-        {
-            sb.append( LS ).append( "releases: [enabled => " ).append( releases.isEnabled() );
-            sb.append( ", update => " ).append( releases.getUpdatePolicy() ).append( ']' );
+        if (releases != null) {
+            sb.append(LS).append("releases: [enabled => ").append(releases.isEnabled());
+            sb.append(", update => ").append(releases.getUpdatePolicy()).append(']');
         }
 
-        sb.append( "   blocked: " ).append( isBlocked() ).append( '\n' );
+        sb.append("   blocked: ").append(isBlocked()).append('\n');
 
         return sb.toString();
     }
 
-    public Artifact find( Artifact artifact )
-    {
-        File artifactFile = new File( getBasedir(), pathOf( artifact ) );
+    public Artifact find(Artifact artifact) {
+        File artifactFile = new File(getBasedir(), pathOf(artifact));
 
         // We need to set the file here or the resolver will fail with an NPE, not fully equipped to deal
         // with multiple local repository implementations yet.
-        artifact.setFile( artifactFile );
+        artifact.setFile(artifactFile);
 
         return artifact;
     }
 
-    public List<String> findVersions( Artifact artifact )
-    {
+    public List<String> findVersions(Artifact artifact) {
         return Collections.emptyList();
     }
 
-    public String getId()
-    {
+    public String getId() {
         return id;
     }
 
-    public String getUrl()
-    {
+    public String getUrl() {
         return url;
     }
 
-    public String getBasedir()
-    {
+    public String getBasedir() {
         return basedir;
     }
 
-    public String getProtocol()
-    {
+    public String getProtocol() {
         return protocol;
     }
 
-    public void setId( String id )
-    {
+    public void setId(String id) {
         this.id = id;
     }
 
-    public void setUrl( String url )
-    {
+    public void setUrl(String url) {
         this.url = url;
 
-        this.protocol = protocol( url );
-        this.basedir = basedir( url );
+        this.protocol = protocol(url);
+        this.basedir = basedir(url);
     }
 
     // Path Utils
@@ -229,15 +209,13 @@
      * @param url the url
      * @return the host name
      */
-    private static String protocol( final String url )
-    {
-        final int pos = url.indexOf( ':' );
+    private static String protocol(final String url) {
+        final int pos = url.indexOf(':');
 
-        if ( pos == -1 )
-        {
+        if (pos == -1) {
             return "";
         }
-        return url.substring( 0, pos ).trim();
+        return url.substring(0, pos).trim();
     }
 
     /**
@@ -247,40 +225,30 @@
      * @return the basedir of the repository
      * TODO need to URL decode for spaces?
      */
-    private String basedir( String url )
-    {
+    private String basedir(String url) {
         String retValue = null;
 
-        if ( protocol.equalsIgnoreCase( "file" ) )
-        {
-            retValue = url.substring( protocol.length() + 1 );
-            retValue = decode( retValue );
+        if (protocol.equalsIgnoreCase("file")) {
+            retValue = url.substring(protocol.length() + 1);
+            retValue = decode(retValue);
             // special case: if omitted // on protocol, keep path as is
-            if ( retValue.startsWith( "//" ) )
-            {
-                retValue = retValue.substring( 2 );
+            if (retValue.startsWith("//")) {
+                retValue = retValue.substring(2);
 
-                if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
-                {
+                if (retValue.length() >= 2 && (retValue.charAt(1) == '|' || retValue.charAt(1) == ':')) {
                     // special case: if there is a windows drive letter, then keep the original return value
-                    retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
-                }
-                else
-                {
+                    retValue = retValue.charAt(0) + ":" + retValue.substring(2);
+                } else {
                     // Now we expect the host
-                    int index = retValue.indexOf( '/' );
-                    if ( index >= 0 )
-                    {
-                        retValue = retValue.substring( index + 1 );
+                    int index = retValue.indexOf('/');
+                    if (index >= 0) {
+                        retValue = retValue.substring(index + 1);
                     }
 
                     // special case: if there is a windows drive letter, then keep the original return value
-                    if ( retValue.length() >= 2 && ( retValue.charAt( 1 ) == '|' || retValue.charAt( 1 ) == ':' ) )
-                    {
-                        retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
-                    }
-                    else if ( index >= 0 )
-                    {
+                    if (retValue.length() >= 2 && (retValue.charAt(1) == '|' || retValue.charAt(1) == ':')) {
+                        retValue = retValue.charAt(0) + ":" + retValue.substring(2);
+                    } else if (index >= 0) {
                         // leading / was previously stripped
                         retValue = "/" + retValue;
                     }
@@ -288,17 +256,15 @@
             }
 
             // special case: if there is a windows drive letter using |, switch to :
-            if ( retValue.length() >= 2 && retValue.charAt( 1 ) == '|' )
-            {
-                retValue = retValue.charAt( 0 ) + ":" + retValue.substring( 2 );
+            if (retValue.length() >= 2 && retValue.charAt(1) == '|') {
+                retValue = retValue.charAt(0) + ":" + retValue.substring(2);
             }
 
             // normalize separators
-            retValue = new File( retValue ).getPath();
+            retValue = new File(retValue).getPath();
         }
 
-        if ( retValue == null )
-        {
+        if (retValue == null) {
             retValue = "/";
         }
         return retValue.trim();
@@ -311,123 +277,97 @@
      * @param url The URL to decode, may be <code>null</code>.
      * @return The decoded URL or <code>null</code> if the input was <code>null</code>.
      */
-    private static String decode( String url )
-    {
+    private static String decode(String url) {
         String decoded = url;
-        if ( url != null )
-        {
+        if (url != null) {
             int pos = -1;
-            while ( ( pos = decoded.indexOf( '%', pos + 1 ) ) >= 0 )
-            {
-                if ( pos + 2 < decoded.length() )
-                {
-                    String hexStr = decoded.substring( pos + 1, pos + 3 );
-                    char ch = (char) Integer.parseInt( hexStr, 16 );
-                    decoded = decoded.substring( 0, pos ) + ch + decoded.substring( pos + 3 );
+            while ((pos = decoded.indexOf('%', pos + 1)) >= 0) {
+                if (pos + 2 < decoded.length()) {
+                    String hexStr = decoded.substring(pos + 1, pos + 3);
+                    char ch = (char) Integer.parseInt(hexStr, 16);
+                    decoded = decoded.substring(0, pos) + ch + decoded.substring(pos + 3);
                 }
             }
         }
         return decoded;
     }
 
-    public int hashCode()
-    {
+    public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ( ( getId() == null ) ? 0 : getId().hashCode() );
+        result = prime * result + ((getId() == null) ? 0 : getId().hashCode());
         return result;
     }
 
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
-        if ( obj == null )
-        {
+        if (obj == null) {
             return false;
         }
-        if ( getClass() != obj.getClass() )
-        {
+        if (getClass() != obj.getClass()) {
             return false;
         }
 
         ArtifactRepository other = (ArtifactRepository) obj;
 
-        return eq( getId(), other.getId() );
+        return eq(getId(), other.getId());
     }
 
-    protected static <T> boolean eq( T s1, T s2 )
-    {
-        return Objects.equals( s1, s2 );
+    protected static <T> boolean eq(T s1, T s2) {
+        return Objects.equals(s1, s2);
     }
 
-    public Authentication getAuthentication()
-    {
+    public Authentication getAuthentication() {
         return authentication;
     }
 
-    public void setAuthentication( Authentication authentication )
-    {
+    public void setAuthentication(Authentication authentication) {
         this.authentication = authentication;
     }
 
-    public Proxy getProxy()
-    {
+    public Proxy getProxy() {
         return proxy;
     }
 
-    public void setProxy( Proxy proxy )
-    {
+    public void setProxy(Proxy proxy) {
         this.proxy = proxy;
     }
 
-    public boolean isBlacklisted()
-    {
+    public boolean isBlacklisted() {
         return false;
     }
 
-    public void setBlacklisted( boolean blackListed )
-    {
+    public void setBlacklisted(boolean blackListed) {
         // no op
     }
 
-    public boolean isUniqueVersion()
-    {
+    public boolean isUniqueVersion() {
         return true;
     }
 
-    public boolean isProjectAware()
-    {
+    public boolean isProjectAware() {
         return false;
     }
 
-    public List<ArtifactRepository> getMirroredRepositories()
-    {
+    public List<ArtifactRepository> getMirroredRepositories() {
         return mirroredRepositories;
     }
 
-    public void setMirroredRepositories( List<ArtifactRepository> mirroredRepositories )
-    {
-        if ( mirroredRepositories != null )
-        {
-            this.mirroredRepositories = Collections.unmodifiableList( mirroredRepositories );
-        }
-        else
-        {
+    public void setMirroredRepositories(List<ArtifactRepository> mirroredRepositories) {
+        if (mirroredRepositories != null) {
+            this.mirroredRepositories = Collections.unmodifiableList(mirroredRepositories);
+        } else {
             this.mirroredRepositories = Collections.emptyList();
         }
     }
 
-    public boolean isBlocked()
-    {
+    public boolean isBlocked() {
         return blocked;
     }
 
-    public void setBlocked( boolean blocked )
-    {
+    public void setBlocked(boolean blocked) {
         this.blocked = blocked;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryCache.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryCache.java
index bf79d69..e0e76ec 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryCache.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,20 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 /**
  * Caches auxiliary data used during repository access like already processed metadata. The data in the cache is meant
  * for exclusive consumption by the repository system and is opaque to the cache implementation.
  *
- * @author Benjamin Bentmann
  */
 @Deprecated
 //
 // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
 // this here, possibly indefinitely.
 //
-public interface RepositoryCache
-{
+public interface RepositoryCache {
 
     /**
      * Puts the specified data into the cache. <strong>Warning:</strong> The cache will directly save the provided
@@ -42,7 +39,7 @@
      * @param key The key to use associate the data with, must not be {@code null}.
      * @param data The data to store in the cache, may be {@code null}.
      */
-    void put( RepositoryRequest request, Object key, Object data );
+    void put(RepositoryRequest request, Object key, Object data);
 
     /**
      * Gets the specified data from the cache. <strong>Warning:</strong> The cache will directly return the saved
@@ -53,6 +50,5 @@
      * @param key The key to use for lookup of the data, must not be {@code null}.
      * @return The requested data or {@code null} if none was present in the cache.
      */
-    Object get( RepositoryRequest request, Object key );
-
+    Object get(RepositoryRequest request, Object key);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryRequest.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryRequest.java
index 55f6068..01b8bd8 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/RepositoryRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository;
 
 import java.util.List;
 
 /**
  * Collects basic settings to access the repository system.
  *
- * @author Benjamin Bentmann
  */
-public interface RepositoryRequest
-{
+public interface RepositoryRequest {
 
     /**
      * Indicates whether network access to remote repositories has been disabled.
@@ -42,7 +39,7 @@
      * @param offline {@code true} to disable remote access, {@code false} to allow network access.
      * @return This request, never {@code null}.
      */
-    RepositoryRequest setOffline( boolean offline );
+    RepositoryRequest setOffline(boolean offline);
 
     /**
      * Indicates whether remote repositories should be re-checked for updated artifacts/metadata regardless of their
@@ -60,7 +57,7 @@
      *            false} to use the update policy configured on each repository.
      * @return This request, never {@code null}.
      */
-    RepositoryRequest setForceUpdate( boolean forceUpdate );
+    RepositoryRequest setForceUpdate(boolean forceUpdate);
 
     /**
      * Gets the local repository to use.
@@ -75,7 +72,7 @@
      * @param localRepository The local repository to use.
      * @return This request, never {@code null}.
      */
-    RepositoryRequest setLocalRepository( ArtifactRepository localRepository );
+    RepositoryRequest setLocalRepository(ArtifactRepository localRepository);
 
     /**
      * Gets the remote repositories to use.
@@ -90,6 +87,5 @@
      * @param remoteRepositories The remote repositories to use.
      * @return This request, never {@code null}.
      */
-    RepositoryRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories );
-
+    RepositoryRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout.java
index 0590e53..e933202 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/layout/DefaultRepositoryLayout.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.layout;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.layout;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -28,88 +27,73 @@
 import org.apache.maven.artifact.repository.ArtifactRepository;
 
 /**
- * @author jdcasey
  */
-@Named( "default" )
+@Named("default")
 @Singleton
-public class DefaultRepositoryLayout
-    implements ArtifactRepositoryLayout
-{
+public class DefaultRepositoryLayout implements ArtifactRepositoryLayout {
     private static final char PATH_SEPARATOR = '/';
 
     private static final char GROUP_SEPARATOR = '.';
 
     private static final char ARTIFACT_SEPARATOR = '-';
 
-    public String getId()
-    {
+    public String getId() {
         return "default";
     }
 
-    public String pathOf( Artifact artifact )
-    {
+    public String pathOf(Artifact artifact) {
         ArtifactHandler artifactHandler = artifact.getArtifactHandler();
 
-        StringBuilder path = new StringBuilder( 128 );
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( formatAsDirectory( artifact.getGroupId() ) ).append( PATH_SEPARATOR );
-        path.append( artifact.getArtifactId() ).append( PATH_SEPARATOR );
-        path.append( artifact.getBaseVersion() ).append( PATH_SEPARATOR );
-        path.append( artifact.getArtifactId() ).append( ARTIFACT_SEPARATOR ).append( artifact.getVersion() );
+        path.append(formatAsDirectory(artifact.getGroupId())).append(PATH_SEPARATOR);
+        path.append(artifact.getArtifactId()).append(PATH_SEPARATOR);
+        path.append(artifact.getBaseVersion()).append(PATH_SEPARATOR);
+        path.append(artifact.getArtifactId()).append(ARTIFACT_SEPARATOR).append(artifact.getVersion());
 
-        if ( artifact.hasClassifier() )
-        {
-            path.append( ARTIFACT_SEPARATOR ).append( artifact.getClassifier() );
+        if (artifact.hasClassifier()) {
+            path.append(ARTIFACT_SEPARATOR).append(artifact.getClassifier());
         }
 
-        if ( artifactHandler.getExtension() != null && artifactHandler.getExtension().length() > 0 )
-        {
-            path.append( GROUP_SEPARATOR ).append( artifactHandler.getExtension() );
+        if (artifactHandler.getExtension() != null
+                && artifactHandler.getExtension().length() > 0) {
+            path.append(GROUP_SEPARATOR).append(artifactHandler.getExtension());
         }
 
         return path.toString();
     }
 
-    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-    {
-        return pathOfRepositoryMetadata( metadata, metadata.getLocalFilename( repository ) );
+    public String pathOfLocalRepositoryMetadata(ArtifactMetadata metadata, ArtifactRepository repository) {
+        return pathOfRepositoryMetadata(metadata, metadata.getLocalFilename(repository));
     }
 
-    private String pathOfRepositoryMetadata( ArtifactMetadata metadata,
-                                             String filename )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    private String pathOfRepositoryMetadata(ArtifactMetadata metadata, String filename) {
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( formatAsDirectory( metadata.getGroupId() ) ).append( PATH_SEPARATOR );
-        if ( !metadata.storedInGroupDirectory() )
-        {
-            path.append( metadata.getArtifactId() ).append( PATH_SEPARATOR );
+        path.append(formatAsDirectory(metadata.getGroupId())).append(PATH_SEPARATOR);
+        if (!metadata.storedInGroupDirectory()) {
+            path.append(metadata.getArtifactId()).append(PATH_SEPARATOR);
 
-            if ( metadata.storedInArtifactVersionDirectory() )
-            {
-                path.append( metadata.getBaseVersion() ).append( PATH_SEPARATOR );
+            if (metadata.storedInArtifactVersionDirectory()) {
+                path.append(metadata.getBaseVersion()).append(PATH_SEPARATOR);
             }
         }
 
-        path.append( filename );
+        path.append(filename);
 
         return path.toString();
     }
 
-    public String pathOfRemoteRepositoryMetadata( ArtifactMetadata metadata )
-    {
-        return pathOfRepositoryMetadata( metadata, metadata.getRemoteFilename() );
+    public String pathOfRemoteRepositoryMetadata(ArtifactMetadata metadata) {
+        return pathOfRepositoryMetadata(metadata, metadata.getRemoteFilename());
     }
 
-    private String formatAsDirectory( String directory )
-    {
-        return directory.replace( GROUP_SEPARATOR, PATH_SEPARATOR );
+    private String formatAsDirectory(String directory) {
+        return directory.replace(GROUP_SEPARATOR, PATH_SEPARATOR);
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getId();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
deleted file mode 100644
index ed02da8..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/AbstractRepositoryMetadata.java
+++ /dev/null
@@ -1,234 +0,0 @@
-package org.apache.maven.artifact.repository.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.metadata.ArtifactMetadata;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.WriterFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
-
-/**
- * Shared methods of the repository metadata handling.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public abstract class AbstractRepositoryMetadata
-    implements RepositoryMetadata
-{
-    private static final String LS = System.lineSeparator();
-
-    private Metadata metadata;
-
-    protected AbstractRepositoryMetadata( Metadata metadata )
-    {
-        this.metadata = metadata;
-    }
-
-    public String getRemoteFilename()
-    {
-        return "maven-metadata.xml";
-    }
-
-    public String getLocalFilename( ArtifactRepository repository )
-    {
-        return "maven-metadata-" + repository.getKey() + ".xml";
-    }
-
-    public void storeInLocalRepository( ArtifactRepository localRepository, ArtifactRepository remoteRepository )
-        throws RepositoryMetadataStoreException
-    {
-        try
-        {
-            updateRepositoryMetadata( localRepository, remoteRepository );
-        }
-        catch ( IOException | XmlPullParserException e )
-        {
-            throw new RepositoryMetadataStoreException( "Error updating group repository metadata", e );
-        }
-    }
-
-    protected void updateRepositoryMetadata( ArtifactRepository localRepository, ArtifactRepository remoteRepository )
-        throws IOException, XmlPullParserException
-    {
-        MetadataXpp3Reader mappingReader = new MetadataXpp3Reader();
-
-        Metadata metadata = null;
-
-        File metadataFile = new File( localRepository.getBasedir(),
-                                      localRepository.pathOfLocalRepositoryMetadata( this, remoteRepository ) );
-
-        if ( metadataFile.length() == 0 )
-        {
-            if ( !metadataFile.delete() )
-            {
-                // sleep for 10ms just in case this is windows holding a file lock
-                try
-                {
-                    Thread.sleep( 10 );
-                }
-                catch ( InterruptedException e )
-                {
-                    // ignore
-                }
-                metadataFile.delete(); // if this fails, forget about it, we'll try to overwrite it anyway so no need
-                // to delete on exit
-            }
-        }
-        else if ( metadataFile.exists() )
-        {
-            try ( Reader reader = ReaderFactory.newXmlReader( metadataFile ) )
-            {
-                metadata = mappingReader.read( reader, false );
-            }
-        }
-
-        boolean changed;
-
-        // If file could not be found or was not valid, start from scratch
-        if ( metadata == null )
-        {
-            metadata = this.metadata;
-
-            changed = true;
-        }
-        else
-        {
-            changed = metadata.merge( this.metadata );
-        }
-
-        // beware meta-versions!
-        String version = metadata.getVersion();
-        if ( Artifact.LATEST_VERSION.equals( version ) || Artifact.RELEASE_VERSION.equals( version ) )
-        {
-            // meta-versions are not valid <version/> values...don't write them.
-            metadata.setVersion( null );
-        }
-
-        if ( changed || !metadataFile.exists() )
-        {
-            metadataFile.getParentFile().mkdirs();
-            try ( Writer writer = WriterFactory.newXmlWriter( metadataFile ) )
-            {
-                MetadataXpp3Writer mappingWriter = new MetadataXpp3Writer();
-
-                mappingWriter.write( writer, metadata );
-            }
-        }
-        else
-        {
-            metadataFile.setLastModified( System.currentTimeMillis() );
-        }
-    }
-
-    public String toString()
-    {
-        return "repository metadata for: '" + getKey() + "'";
-    }
-
-    protected static Metadata createMetadata( Artifact artifact, Versioning versioning )
-    {
-        Metadata metadata = new Metadata();
-        metadata.setGroupId( artifact.getGroupId() );
-        metadata.setArtifactId( artifact.getArtifactId() );
-        metadata.setVersion( artifact.getVersion() );
-        metadata.setVersioning( versioning );
-        return metadata;
-    }
-
-    protected static Versioning createVersioning( Snapshot snapshot )
-    {
-        Versioning versioning = new Versioning();
-        versioning.setSnapshot( snapshot );
-        return versioning;
-    }
-
-    public void setMetadata( Metadata metadata )
-    {
-        this.metadata = metadata;
-    }
-
-    public Metadata getMetadata()
-    {
-        return metadata;
-    }
-
-    public void merge( org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata )
-    {
-        // TODO not sure that it should assume this, maybe the calls to addMetadata should pre-merge, then artifact
-        // replaces?
-        AbstractRepositoryMetadata repoMetadata = (AbstractRepositoryMetadata) metadata;
-        this.metadata.merge( repoMetadata.getMetadata() );
-    }
-
-    public void merge( ArtifactMetadata metadata )
-    {
-        // TODO not sure that it should assume this, maybe the calls to addMetadata should pre-merge, then artifact
-        // replaces?
-        AbstractRepositoryMetadata repoMetadata = (AbstractRepositoryMetadata) metadata;
-        this.metadata.merge( repoMetadata.getMetadata() );
-    }
-
-    public String extendedToString()
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-
-        buffer.append( LS ).append( "Repository Metadata" ).append( LS ).append( "--------------------------" );
-        buffer.append( LS ).append( "GroupId: " ).append( getGroupId() );
-        buffer.append( LS ).append( "ArtifactId: " ).append( getArtifactId() );
-        buffer.append( LS ).append( "Metadata Type: " ).append( getClass().getName() );
-
-        return buffer.toString();
-    }
-
-    public int getNature()
-    {
-        return RELEASE;
-    }
-
-    public ArtifactRepositoryPolicy getPolicy( ArtifactRepository repository )
-    {
-        int nature = getNature();
-        if ( ( nature & RepositoryMetadata.RELEASE_OR_SNAPSHOT ) == RepositoryMetadata.RELEASE_OR_SNAPSHOT )
-        {
-            ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy( repository.getReleases() );
-            policy.merge( repository.getSnapshots() );
-            return policy;
-        }
-        else if ( ( nature & RepositoryMetadata.SNAPSHOT ) != 0 )
-        {
-            return repository.getSnapshots();
-        }
-        else
-        {
-            return repository.getReleases();
-        }
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/ArtifactRepositoryMetadata.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/ArtifactRepositoryMetadata.java
deleted file mode 100644
index 85fc601..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/ArtifactRepositoryMetadata.java
+++ /dev/null
@@ -1,129 +0,0 @@
-package org.apache.maven.artifact.repository.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.versioning.ArtifactVersion;
-import org.apache.maven.artifact.versioning.Restriction;
-import org.apache.maven.artifact.versioning.VersionRange;
-
-/**
- * Metadata for the artifact directory of the repository.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public class ArtifactRepositoryMetadata
-    extends AbstractRepositoryMetadata
-{
-    private Artifact artifact;
-
-    public ArtifactRepositoryMetadata( Artifact artifact )
-    {
-        this( artifact, null );
-    }
-
-    public ArtifactRepositoryMetadata( Artifact artifact,
-                                       Versioning versioning )
-    {
-        super( createMetadata( artifact, versioning ) );
-        this.artifact = artifact;
-    }
-
-    public boolean storedInGroupDirectory()
-    {
-        return false;
-    }
-
-    public boolean storedInArtifactVersionDirectory()
-    {
-        return false;
-    }
-
-    public String getGroupId()
-    {
-        return artifact.getGroupId();
-    }
-
-    public String getArtifactId()
-    {
-        return artifact.getArtifactId();
-    }
-
-    public String getBaseVersion()
-    {
-        // Don't want the artifact's version in here, as this is stored in the directory above that
-        return null;
-    }
-
-    public Object getKey()
-    {
-        return "artifact " + artifact.getGroupId() + ":" + artifact.getArtifactId();
-    }
-
-    public boolean isSnapshot()
-    {
-        // Don't consider the artifact's version in here, as this is stored in the directory above that
-        return false;
-    }
-
-    public int getNature()
-    {
-        if ( artifact.getVersion() != null )
-        {
-            return artifact.isSnapshot() ? SNAPSHOT : RELEASE;
-        }
-
-        VersionRange range = artifact.getVersionRange();
-        if ( range != null )
-        {
-            for ( Restriction restriction : range.getRestrictions() )
-            {
-                if ( isSnapshot( restriction.getLowerBound() ) || isSnapshot( restriction.getUpperBound() ) )
-                {
-                    return RELEASE_OR_SNAPSHOT;
-                }
-            }
-        }
-
-        return RELEASE;
-    }
-
-    private boolean isSnapshot( ArtifactVersion version )
-    {
-        return version != null && ArtifactUtils.isSnapshot( version.getQualifier() );
-    }
-
-    public ArtifactRepository getRepository()
-    {
-        return null;
-    }
-
-    public void setRepository( ArtifactRepository remoteRepository )
-    {
-        /*
-         * NOTE: Metadata at the g:a level contains a collection of available versions. After merging, we can't tell
-         * which repository provides which version so the metadata manager must not restrict the artifact resolution to
-         * the repository with the most recent updates.
-         */
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadata.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadata.java
deleted file mode 100644
index d7fe50b..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadata.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.apache.maven.artifact.repository.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-
-/**
- * Describes repository directory metadata.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- * TODO not happy about the store method - they use "this"
- */
-public interface RepositoryMetadata
-    extends org.apache.maven.artifact.metadata.ArtifactMetadata
-{
-
-    int RELEASE = 1;
-
-    int SNAPSHOT = 2;
-
-    int RELEASE_OR_SNAPSHOT = RELEASE | SNAPSHOT;
-
-    /**
-     * Get the repository the metadata was located in.
-     *
-     * @return the repository
-     */
-    ArtifactRepository getRepository();
-
-    /**
-     * Set the repository the metadata was located in.
-     *
-     * @param remoteRepository the repository
-     */
-    void setRepository( ArtifactRepository remoteRepository );
-
-    /**
-     * Get the repository metadata associated with this marker.
-     *
-     * @return the metadata, or <code>null</code> if none loaded
-     */
-    Metadata getMetadata();
-
-    /**
-     * Set the metadata contents.
-     *
-     * @param metadata the metadata
-     */
-    void setMetadata( Metadata metadata );
-
-    /**
-     * Whether this represents a snapshot.
-     *
-     * @return if it is a snapshot
-     */
-    boolean isSnapshot();
-
-    /**
-     * Gets the artifact quality this metadata refers to. One of {@link #RELEASE}, {@link #SNAPSHOT} or
-     * {@link #RELEASE_OR_SNAPSHOT}.
-     *
-     * @return The artifact quality this metadata refers to.
-     */
-    int getNature();
-
-    /**
-     * Gets the policy that applies to this metadata regarding the specified repository.
-     *
-     * @param repository The repository for which to determine the policy, must not be {@code null}.
-     * @return The policy, never {@code null}.
-     */
-    ArtifactRepositoryPolicy getPolicy( ArtifactRepository repository );
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException.java
deleted file mode 100644
index 9454565..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataDeploymentException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.maven.artifact.repository.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Error while deploying repository metadata.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public class RepositoryMetadataDeploymentException
-    extends Throwable
-{
-    public RepositoryMetadataDeploymentException( String message )
-    {
-        super( message );
-    }
-
-    public RepositoryMetadataDeploymentException( String message,
-                                                  Exception e )
-    {
-        super( message, e );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException.java
deleted file mode 100644
index 55bb57e..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataInstallationException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.maven.artifact.repository.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Error while installing repository metadata.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public class RepositoryMetadataInstallationException
-    extends Throwable
-{
-    public RepositoryMetadataInstallationException( String message )
-    {
-        super( message );
-    }
-
-    public RepositoryMetadataInstallationException( String message,
-                                                    Exception e )
-    {
-        super( message, e );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager.java
deleted file mode 100644
index 3eb67f1..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataManager.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.apache.maven.artifact.repository.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.artifact.metadata.ArtifactMetadata;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.RepositoryRequest;
-
-/**
- * RepositoryMetadataManager
- */
-public interface RepositoryMetadataManager
-{
-
-    void resolve( RepositoryMetadata repositoryMetadata, RepositoryRequest repositoryRequest )
-        throws RepositoryMetadataResolutionException;
-
-    void resolve( RepositoryMetadata repositoryMetadata, List<ArtifactRepository> repositories,
-                  ArtifactRepository localRepository )
-        throws RepositoryMetadataResolutionException;
-
-    void resolveAlways( RepositoryMetadata metadata, ArtifactRepository localRepository,
-                        ArtifactRepository remoteRepository )
-        throws RepositoryMetadataResolutionException;
-
-    /**
-     * Deploy metadata to the remote repository.
-     *
-     * @param metadata             the metadata to deploy
-     * @param localRepository      the local repository to install to first
-     * @param deploymentRepository the remote repository to deploy to
-     * @throws RepositoryMetadataDeploymentException in case of metadata deployment issue
-     */
-    void deploy( ArtifactMetadata metadata, ArtifactRepository localRepository,
-                 ArtifactRepository deploymentRepository )
-        throws RepositoryMetadataDeploymentException;
-
-    /**
-     * Install the metadata in the local repository.
-     *
-     * @param metadata        the metadata
-     * @param localRepository the local repository
-     * @throws RepositoryMetadataInstallationException in case of metadata installation issue
-     */
-    void install( ArtifactMetadata metadata, ArtifactRepository localRepository )
-        throws RepositoryMetadataInstallationException;
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException.java
deleted file mode 100644
index 8a6f38d..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/RepositoryMetadataResolutionException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.maven.artifact.repository.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Error while retrieving repository metadata from the repository.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public class RepositoryMetadataResolutionException
-    extends Exception
-{
-    public RepositoryMetadataResolutionException( String message )
-    {
-        super( message );
-    }
-
-    public RepositoryMetadataResolutionException( String message,
-                                                  Exception e )
-    {
-        super( message, e );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java
index e4ca4f9..dc5cf5b 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/DefaultMetadataReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,75 +16,66 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata.io;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.nio.file.Files;
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.artifact.repository.metadata.Metadata;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 /**
  * Handles deserialization of metadata from some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultMetadataReader
-    implements MetadataReader
-{
+public class DefaultMetadataReader implements MetadataReader {
 
-    public Metadata read( File input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Metadata read(File input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        return read( ReaderFactory.newXmlReader( input ), options );
+        return read(Files.newInputStream(input.toPath()), options);
     }
 
-    public Metadata read( Reader input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Metadata read(Reader input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        try ( Reader in = input )
-        {
-            return new MetadataXpp3Reader().read( in, isStrict( options ) );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new MetadataParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        try (Reader in = input) {
+            return new Metadata(new MetadataStaxReader().read(in, isStrict(options)));
+        } catch (XMLStreamException e) {
+            throw new MetadataParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
         }
     }
 
-    public Metadata read( InputStream input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Metadata read(InputStream input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        try ( InputStream in = input )
-        {
-            return new MetadataXpp3Reader().read( in, isStrict( options ) );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new MetadataParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        try (InputStream in = input) {
+            return new Metadata(new MetadataStaxReader().read(in, isStrict(options)));
+        } catch (XMLStreamException e) {
+            throw new MetadataParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
         }
     }
 
-    private boolean isStrict( Map<String, ?> options )
-    {
-        Object value = ( options != null ) ? options.get( IS_STRICT ) : null;
-        return value == null || Boolean.parseBoolean( value.toString() );
+    private boolean isStrict(Map<String, ?> options) {
+        Object value = (options != null) ? options.get(IS_STRICT) : null;
+        return value == null || Boolean.parseBoolean(value.toString());
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataParseException.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataParseException.java
index 427141a..ad25a58 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataParseException.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataParseException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata.io;
 
 import java.io.IOException;
 
 /**
  * Signals a failure to parse the metadata due to invalid syntax (e.g. non well formed XML or unknown elements).
  *
- * @author Benjamin Bentmann
  */
-public class MetadataParseException
-    extends IOException
-{
+public class MetadataParseException extends IOException {
 
     /**
      * The one-based index of the line containing the error.
@@ -47,9 +43,8 @@
      * @param lineNumber The one-based index of the line containing the error or {@code -1} if unknown.
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      */
-    public MetadataParseException( String message, int lineNumber, int columnNumber )
-    {
-        super( message );
+    public MetadataParseException(String message, int lineNumber, int columnNumber) {
+        super(message);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -62,10 +57,9 @@
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      * @param cause The nested cause of this error, may be {@code null}.
      */
-    public MetadataParseException( String message, int lineNumber, int columnNumber, Throwable cause )
-    {
-        super( message );
-        initCause( cause );
+    public MetadataParseException(String message, int lineNumber, int columnNumber, Throwable cause) {
+        super(message);
+        initCause(cause);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -75,8 +69,7 @@
      *
      * @return The one-based index of the line containing the error or a non-positive value if unknown.
      */
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
 
@@ -85,9 +78,7 @@
      *
      * @return The one-based index of the column containing the error or non-positive value if unknown.
      */
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataReader.java b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataReader.java
index 232246f..f8a4500 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataReader.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/repository/metadata/io/MetadataReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata.io;
 
 import java.io.File;
 import java.io.IOException;
@@ -30,10 +29,8 @@
 /**
  * Handles deserialization of metadata from some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
-public interface MetadataReader
-{
+public interface MetadataReader {
 
     /**
      * The key for the option to enable strict parsing. This option is of type {@link Boolean} and defaults to {@code
@@ -50,8 +47,7 @@
      * @throws IOException If the metadata could not be deserialized.
      * @throws MetadataParseException If the input format could not be parsed.
      */
-    Metadata read( File input, Map<String, ?> options )
-        throws IOException, MetadataParseException;
+    Metadata read(File input, Map<String, ?> options) throws IOException, MetadataParseException;
 
     /**
      * Reads the metadata from the specified character reader. The reader will be automatically closed before the method
@@ -63,8 +59,7 @@
      * @throws IOException If the metadata could not be deserialized.
      * @throws MetadataParseException If the input format could not be parsed.
      */
-    Metadata read( Reader input, Map<String, ?> options )
-        throws IOException, MetadataParseException;
+    Metadata read(Reader input, Map<String, ?> options) throws IOException, MetadataParseException;
 
     /**
      * Reads the metadata from the specified byte stream. The stream will be automatically closed before the method
@@ -76,7 +71,5 @@
      * @throws IOException If the metadata could not be deserialized.
      * @throws MetadataParseException If the input format could not be parsed.
      */
-    Metadata read( InputStream input, Map<String, ?> options )
-        throws IOException, MetadataParseException;
-
+    Metadata read(InputStream input, Map<String, ?> options) throws IOException, MetadataParseException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionRequest.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionRequest.java
deleted file mode 100644
index acf66b1..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionRequest.java
+++ /dev/null
@@ -1,330 +0,0 @@
-package org.apache.maven.artifact.resolver;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.RepositoryCache;
-import org.apache.maven.artifact.repository.RepositoryRequest;
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-import org.apache.maven.settings.Mirror;
-import org.apache.maven.settings.Proxy;
-import org.apache.maven.settings.Server;
-
-/**
- * A resolution request allows you to either use an existing MavenProject, or a coordinate (gid:aid:version)
- * to process a POMs dependencies.
- *
- * @author Jason van Zyl
- */
-public class ArtifactResolutionRequest
-    implements RepositoryRequest
-{
-    private static final String LS = System.lineSeparator();
-
-    private Artifact artifact;
-
-    // Needs to go away
-    // These are really overrides now, projects defining dependencies for a plugin that override what is
-    // specified in the plugin itself.
-    private Set<Artifact> artifactDependencies;
-
-    private ArtifactRepository localRepository;
-
-    private List<ArtifactRepository> remoteRepositories;
-
-    private ArtifactFilter collectionFilter;
-
-    private ArtifactFilter resolutionFilter;
-
-    // Needs to go away
-    private List<ResolutionListener> listeners = new ArrayList<>();
-
-    // This is like a filter but overrides all transitive versions
-    private Map<String, Artifact> managedVersionMap;
-
-    private boolean resolveRoot = true;
-
-    private boolean resolveTransitively = false;
-
-    private boolean offline;
-
-    private boolean forceUpdate;
-
-    private List<Server> servers;
-
-    private List<Mirror> mirrors;
-
-    private List<Proxy> proxies;
-
-    public ArtifactResolutionRequest()
-    {
-        // nothing here
-    }
-
-    public ArtifactResolutionRequest( RepositoryRequest request )
-    {
-        setLocalRepository( request.getLocalRepository() );
-        setRemoteRepositories( request.getRemoteRepositories() );
-        setOffline( request.isOffline() );
-        setForceUpdate( request.isForceUpdate() );
-    }
-
-    public Artifact getArtifact()
-    {
-        return artifact;
-    }
-
-    public ArtifactResolutionRequest setArtifact( Artifact artifact )
-    {
-        this.artifact = artifact;
-
-        return this;
-    }
-
-    public ArtifactResolutionRequest setArtifactDependencies( Set<Artifact> artifactDependencies )
-    {
-        this.artifactDependencies = artifactDependencies;
-
-        return this;
-    }
-
-    public Set<Artifact> getArtifactDependencies()
-    {
-        return artifactDependencies;
-    }
-
-    public ArtifactRepository getLocalRepository()
-    {
-        return localRepository;
-    }
-
-    public ArtifactResolutionRequest setLocalRepository( ArtifactRepository localRepository )
-    {
-        this.localRepository = localRepository;
-
-        return this;
-    }
-
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
-        return remoteRepositories;
-    }
-
-    public ArtifactResolutionRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
-    {
-        this.remoteRepositories = remoteRepositories;
-
-        return this;
-    }
-
-    /**
-     * Gets the artifact filter that controls traversal of the dependency graph.
-     *
-     * @return The filter used to determine which of the artifacts in the dependency graph should be traversed or
-     *         {@code null} to collect all transitive dependencies.
-     */
-    public ArtifactFilter getCollectionFilter()
-    {
-        return collectionFilter;
-    }
-
-    public ArtifactResolutionRequest setCollectionFilter( ArtifactFilter filter )
-    {
-        this.collectionFilter = filter;
-
-        return this;
-    }
-
-    /**
-     * Gets the artifact filter that controls downloading of artifact files. This filter operates on those artifacts
-     * that have been included by the {@link #getCollectionFilter()}.
-     *
-     * @return The filter used to determine which of the artifacts should have their files resolved or {@code null} to
-     *         resolve the files for all collected artifacts.
-     */
-    public ArtifactFilter getResolutionFilter()
-    {
-        return resolutionFilter;
-    }
-
-    public ArtifactResolutionRequest setResolutionFilter( ArtifactFilter filter )
-    {
-        this.resolutionFilter = filter;
-
-        return this;
-    }
-
-    public List<ResolutionListener> getListeners()
-    {
-        return listeners;
-    }
-
-    public ArtifactResolutionRequest setListeners( List<ResolutionListener> listeners )
-    {
-        this.listeners = listeners;
-
-        return this;
-    }
-
-    public ArtifactResolutionRequest addListener( ResolutionListener listener )
-    {
-        listeners.add( listener );
-
-        return this;
-    }
-
-    public Map<String, Artifact> getManagedVersionMap()
-    {
-        return managedVersionMap;
-    }
-
-    public ArtifactResolutionRequest setManagedVersionMap( Map<String, Artifact> managedVersionMap )
-    {
-        this.managedVersionMap = managedVersionMap;
-
-        return this;
-    }
-
-    public ArtifactResolutionRequest setResolveRoot( boolean resolveRoot )
-    {
-        this.resolveRoot = resolveRoot;
-
-        return this;
-    }
-
-    public boolean isResolveRoot()
-    {
-        return resolveRoot;
-    }
-
-    public ArtifactResolutionRequest setResolveTransitively( boolean resolveDependencies )
-    {
-        this.resolveTransitively = resolveDependencies;
-
-        return this;
-    }
-
-    public boolean isResolveTransitively()
-    {
-        return resolveTransitively;
-    }
-
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder()
-                .append( "REQUEST: " ).append( LS )
-                .append( "artifact: " ).append( artifact ).append( LS )
-                .append( artifactDependencies ).append( LS )
-                .append( "localRepository: " ).append( localRepository ).append( LS )
-                .append( "remoteRepositories: " ).append( remoteRepositories );
-
-        return sb.toString();
-    }
-
-    public boolean isOffline()
-    {
-        return offline;
-    }
-
-    public ArtifactResolutionRequest setOffline( boolean offline )
-    {
-        this.offline = offline;
-
-        return this;
-    }
-
-    public boolean isForceUpdate()
-    {
-        return forceUpdate;
-    }
-
-    public ArtifactResolutionRequest setForceUpdate( boolean forceUpdate )
-    {
-        this.forceUpdate = forceUpdate;
-
-        return this;
-    }
-
-    public ArtifactResolutionRequest setServers( List<Server> servers )
-    {
-        this.servers = servers;
-
-        return this;
-    }
-
-    public List<Server> getServers()
-    {
-        if ( servers == null )
-        {
-            servers = new ArrayList<>();
-        }
-
-        return servers;
-    }
-
-    public ArtifactResolutionRequest setMirrors( List<Mirror> mirrors )
-    {
-        this.mirrors = mirrors;
-
-        return this;
-    }
-
-    public List<Mirror> getMirrors()
-    {
-        if ( mirrors == null )
-        {
-            mirrors = new ArrayList<>();
-        }
-
-        return mirrors;
-    }
-
-    public ArtifactResolutionRequest setProxies( List<Proxy> proxies )
-    {
-        this.proxies = proxies;
-
-        return this;
-    }
-
-    public List<Proxy> getProxies()
-    {
-        if ( proxies == null )
-        {
-            proxies = new ArrayList<>();
-        }
-
-        return proxies;
-    }
-
-    //
-    // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
-    // this here, possibly indefinitely.
-    //
-    public ArtifactResolutionRequest setCache( RepositoryCache cache )
-    {
-        return this;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java
deleted file mode 100644
index e5c2a16..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ArtifactResolutionResult.java
+++ /dev/null
@@ -1,379 +0,0 @@
-package org.apache.maven.artifact.resolver;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
-
-/**
- * Specific problems during resolution that we want to account for:
- * <ul>
- *   <li>missing metadata</li>
- *   <li>version range violations</li>
- *   <li>version circular dependencies</li>
- *   <li>missing artifacts</li>
- *   <li>network/transfer errors</li>
- *   <li>file system errors: permissions</li>
- * </ul>
- *
- * @author Jason van Zyl
- * TODO carlos: all these possible has*Exceptions and get*Exceptions methods make the clients too
- *       complex requiring a long list of checks, need to create a parent/interface/encapsulation
- *       for the types of exceptions
- */
-public class ArtifactResolutionResult
-{
-    private static final String LS = System.lineSeparator();
-
-    private Artifact originatingArtifact;
-
-    private List<Artifact> missingArtifacts;
-
-    // Exceptions
-
-    private List<Exception> exceptions;
-
-    private List<Exception> versionRangeViolations;
-
-    private List<ArtifactResolutionException> metadataResolutionExceptions;
-
-    private List<CyclicDependencyException> circularDependencyExceptions;
-
-    private List<ArtifactResolutionException> errorArtifactExceptions;
-
-    // file system errors
-
-    private List<ArtifactRepository> repositories;
-
-    private Set<Artifact> artifacts;
-
-    private Set<ResolutionNode> resolutionNodes;
-
-    public Artifact getOriginatingArtifact()
-    {
-        return originatingArtifact;
-    }
-
-    public ArtifactResolutionResult setOriginatingArtifact( final Artifact originatingArtifact )
-    {
-        this.originatingArtifact = originatingArtifact;
-
-        return this;
-    }
-
-    public void addArtifact( Artifact artifact )
-    {
-        if ( artifacts == null )
-        {
-            artifacts = new LinkedHashSet<>();
-        }
-
-        artifacts.add( artifact );
-    }
-
-    public Set<Artifact> getArtifacts()
-    {
-        if ( artifacts == null )
-        {
-            artifacts = new LinkedHashSet<>();
-        }
-
-        return artifacts;
-    }
-
-    public void setArtifacts( Set<Artifact> artifacts )
-    {
-        this.artifacts = artifacts;
-    }
-
-    public Set<ResolutionNode> getArtifactResolutionNodes()
-    {
-        if ( resolutionNodes == null )
-        {
-            resolutionNodes = new LinkedHashSet<>();
-        }
-
-        return resolutionNodes;
-    }
-
-    public void setArtifactResolutionNodes( Set<ResolutionNode> resolutionNodes )
-    {
-        this.resolutionNodes = resolutionNodes;
-    }
-
-    public boolean hasMissingArtifacts()
-    {
-        return missingArtifacts != null && !missingArtifacts.isEmpty();
-    }
-
-    public List<Artifact> getMissingArtifacts()
-    {
-        return missingArtifacts == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( missingArtifacts );
-
-    }
-
-    public ArtifactResolutionResult addMissingArtifact( Artifact artifact )
-    {
-        missingArtifacts = initList( missingArtifacts );
-
-        missingArtifacts.add( artifact );
-
-        return this;
-    }
-
-    public ArtifactResolutionResult setUnresolvedArtifacts( final List<Artifact> unresolvedArtifacts )
-    {
-        this.missingArtifacts = unresolvedArtifacts;
-
-        return this;
-    }
-
-    public boolean isSuccess()
-    {
-        return !( hasMissingArtifacts() || hasExceptions() );
-    }
-
-    // ------------------------------------------------------------------------
-    // Exceptions
-    // ------------------------------------------------------------------------
-
-    public boolean hasExceptions()
-    {
-        return exceptions != null && !exceptions.isEmpty();
-    }
-
-    public List<Exception> getExceptions()
-    {
-        return exceptions == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( exceptions );
-
-    }
-
-    // ------------------------------------------------------------------------
-    // Version Range Violations
-    // ------------------------------------------------------------------------
-
-    public boolean hasVersionRangeViolations()
-    {
-        return versionRangeViolations != null;
-    }
-
-    /**
-     * TODO this needs to accept a {@link OverConstrainedVersionException} as returned by
-     *       {@link #getVersionRangeViolation(int)} but it's not used like that in
-     *       DefaultLegacyArtifactCollector
-     *
-     * @param e an exception
-     * @return {@code this}
-     */
-    public ArtifactResolutionResult addVersionRangeViolation( Exception e )
-    {
-        versionRangeViolations = initList( versionRangeViolations );
-
-        versionRangeViolations.add( e );
-
-        exceptions = initList( exceptions );
-
-        exceptions.add( e );
-
-        return this;
-    }
-
-    public OverConstrainedVersionException getVersionRangeViolation( int i )
-    {
-        return (OverConstrainedVersionException) versionRangeViolations.get( i );
-    }
-
-    public List<Exception> getVersionRangeViolations()
-    {
-        return versionRangeViolations == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( versionRangeViolations );
-
-    }
-
-    // ------------------------------------------------------------------------
-    // Metadata Resolution Exceptions: ArtifactResolutionExceptions
-    // ------------------------------------------------------------------------
-
-    public boolean hasMetadataResolutionExceptions()
-    {
-        return metadataResolutionExceptions != null;
-    }
-
-    public ArtifactResolutionResult addMetadataResolutionException( ArtifactResolutionException e )
-    {
-        metadataResolutionExceptions = initList( metadataResolutionExceptions );
-
-        metadataResolutionExceptions.add( e );
-
-        exceptions = initList( exceptions );
-
-        exceptions.add( e );
-
-        return this;
-    }
-
-    public ArtifactResolutionException getMetadataResolutionException( int i )
-    {
-        return metadataResolutionExceptions.get( i );
-    }
-
-    public List<ArtifactResolutionException> getMetadataResolutionExceptions()
-    {
-        return metadataResolutionExceptions == null
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( metadataResolutionExceptions );
-
-    }
-
-    // ------------------------------------------------------------------------
-    // ErrorArtifactExceptions: ArtifactResolutionExceptions
-    // ------------------------------------------------------------------------
-
-    public boolean hasErrorArtifactExceptions()
-    {
-        return errorArtifactExceptions != null;
-    }
-
-    public ArtifactResolutionResult addErrorArtifactException( ArtifactResolutionException e )
-    {
-        errorArtifactExceptions = initList( errorArtifactExceptions );
-
-        errorArtifactExceptions.add( e );
-
-        exceptions = initList( exceptions );
-
-        exceptions.add( e );
-
-        return this;
-    }
-
-    public List<ArtifactResolutionException> getErrorArtifactExceptions()
-    {
-        if ( errorArtifactExceptions == null )
-        {
-            return Collections.emptyList();
-        }
-
-        return Collections.unmodifiableList( errorArtifactExceptions );
-    }
-
-    // ------------------------------------------------------------------------
-    // Circular Dependency Exceptions
-    // ------------------------------------------------------------------------
-
-    public boolean hasCircularDependencyExceptions()
-    {
-        return circularDependencyExceptions != null;
-    }
-
-    public ArtifactResolutionResult addCircularDependencyException( CyclicDependencyException e )
-    {
-        circularDependencyExceptions = initList( circularDependencyExceptions );
-
-        circularDependencyExceptions.add( e );
-
-        exceptions = initList( exceptions );
-
-        exceptions.add( e );
-
-        return this;
-    }
-
-    public CyclicDependencyException getCircularDependencyException( int i )
-    {
-        return circularDependencyExceptions.get( i );
-    }
-
-    public List<CyclicDependencyException> getCircularDependencyExceptions()
-    {
-        if ( circularDependencyExceptions == null )
-        {
-            return Collections.emptyList();
-        }
-
-        return Collections.unmodifiableList( circularDependencyExceptions );
-    }
-
-    // ------------------------------------------------------------------------
-    // Repositories
-    // ------------------------------------------------------------------------
-
-    public List<ArtifactRepository> getRepositories()
-    {
-        if ( repositories == null )
-        {
-            return Collections.emptyList();
-        }
-
-        return Collections.unmodifiableList( repositories );
-    }
-
-    public ArtifactResolutionResult setRepositories( final List<ArtifactRepository> repositories )
-    {
-        this.repositories = repositories;
-
-        return this;
-    }
-
-    //
-    // Internal
-    //
-
-    private <T> List<T> initList( final List<T> l )
-    {
-        if ( l == null )
-        {
-            return new ArrayList<>();
-        }
-        return l;
-    }
-
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder();
-
-        if ( artifacts != null )
-        {
-            int i = 1;
-            sb.append( "---------" ).append( LS );
-            sb.append( artifacts.size() ).append( LS );
-            for ( Artifact a : artifacts )
-            {
-                sb.append( i ).append( ' ' ).append( a ).append( LS );
-                i++;
-            }
-            sb.append( "---------" );
-        }
-
-        return sb.toString();
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler.java
deleted file mode 100644
index d1603f3..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/DefaultResolutionErrorHandler.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.apache.maven.artifact.resolver;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-/**
- * @author Benjamin Bentmann
- */
-@Named
-@Singleton
-public class DefaultResolutionErrorHandler
-    implements ResolutionErrorHandler
-{
-
-    public void throwErrors( ArtifactResolutionRequest request, ArtifactResolutionResult result )
-        throws ArtifactResolutionException
-    {
-        // Metadata cannot be found
-
-        if ( result.hasMetadataResolutionExceptions() )
-        {
-            throw result.getMetadataResolutionException( 0 );
-        }
-
-        // Metadata cannot be retrieved
-
-        // Cyclic Dependency Error
-
-        if ( result.hasCircularDependencyExceptions() )
-        {
-            throw result.getCircularDependencyException( 0 );
-        }
-
-        // Version Range Violation
-
-        if ( result.hasVersionRangeViolations() )
-        {
-            throw result.getVersionRangeViolation( 0 );
-        }
-
-        // Transfer Error
-
-        if ( result.hasErrorArtifactExceptions() )
-        {
-            throw result.getErrorArtifactExceptions().get( 0 );
-        }
-
-        if ( result.hasMissingArtifacts() )
-        {
-            throw new MultipleArtifactsNotFoundException( request.getArtifact(), toList( result.getArtifacts() ),
-                                                          result.getMissingArtifacts(),
-                                                          request.getRemoteRepositories() );
-        }
-
-        // this should never happen since we checked all possible error sources before but better be sure
-        if ( result.hasExceptions() )
-        {
-            throw new ArtifactResolutionException( "Unknown error during artifact resolution, " + request + ", "
-                + result.getExceptions(), request.getArtifact(), request.getRemoteRepositories() );
-        }
-    }
-
-    private static <T> List<T> toList( Collection<T> items )
-    {
-        return ( items != null ) ? new ArrayList<>( items ) : null;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionErrorHandler.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionErrorHandler.java
deleted file mode 100644
index c54e5b6..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionErrorHandler.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.apache.maven.artifact.resolver;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * @author Benjamin Bentmann
- */
-public interface ResolutionErrorHandler
-{
-
-    void throwErrors( ArtifactResolutionRequest request, ArtifactResolutionResult result )
-        throws ArtifactResolutionException;
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionListener.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionListener.java
deleted file mode 100644
index 97687de..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionListener.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.apache.maven.artifact.resolver;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.versioning.VersionRange;
-
-/**
- * Listens to the resolution process and handles events.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public interface ResolutionListener
-{
-    String ROLE = ResolutionListener.class.getName();
-
-    int TEST_ARTIFACT = 1;
-
-    int PROCESS_CHILDREN = 2;
-
-    int FINISH_PROCESSING_CHILDREN = 3;
-
-    int INCLUDE_ARTIFACT = 4;
-
-    int OMIT_FOR_NEARER = 5;
-
-    int UPDATE_SCOPE = 6;
-
-    @Deprecated
-    int MANAGE_ARTIFACT = 7;
-
-    int OMIT_FOR_CYCLE = 8;
-
-    /**
-     * this event means that the artifactScope has NOT been updated to a farther node artifactScope because current
-     * node is in the first level pom
-     */
-    int UPDATE_SCOPE_CURRENT_POM = 9;
-
-    int SELECT_VERSION_FROM_RANGE = 10;
-
-    int RESTRICT_RANGE = 11;
-
-    int MANAGE_ARTIFACT_VERSION = 12;
-
-    int MANAGE_ARTIFACT_SCOPE = 13;
-
-    int MANAGE_ARTIFACT_SYSTEM_PATH = 14;
-
-    void testArtifact( Artifact node );
-
-    void startProcessChildren( Artifact artifact );
-
-    void endProcessChildren( Artifact artifact );
-
-    void includeArtifact( Artifact artifact );
-
-    void omitForNearer( Artifact omitted,
-                        Artifact kept );
-
-    void updateScope( Artifact artifact,
-                      String scope );
-
-    @Deprecated
-    void manageArtifact( Artifact artifact,
-                         Artifact replacement );
-
-    // TODO Use the following two instead of manageArtifact
-    // TODO Remove ResolutionListenerDM interface
-
-    //void manageArtifactVersion( Artifact artifact, Artifact replacement );
-
-    //void manageArtifactScope( Artifact artifact, Artifact replacement );
-
-    void omitForCycle( Artifact artifact );
-
-    /**
-     * This event means that the artifactScope has NOT been updated to a farther node artifactScope because current
-     * node is in the first level pom
-     *
-     * @param artifact     current node artifact, the one in the first level pom
-     * @param ignoredScope artifactScope that was ignored because artifact was in first level pom
-     */
-    void updateScopeCurrentPom( Artifact artifact,
-                                String ignoredScope );
-
-    void selectVersionFromRange( Artifact artifact );
-
-    void restrictRange( Artifact artifact,
-                        Artifact replacement,
-                        VersionRange newRange );
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java
deleted file mode 100644
index b51c49b..0000000
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/ResolutionNode.java
+++ /dev/null
@@ -1,257 +0,0 @@
-package org.apache.maven.artifact.resolver;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-import org.apache.maven.artifact.versioning.ArtifactVersion;
-import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
-
-/**
- * ResolutionNode
- */
-public class ResolutionNode
-{
-    private Artifact artifact;
-
-    private List<ResolutionNode> children;
-
-    private final List<Object> parents;
-
-    private final int depth;
-
-    private final ResolutionNode parent;
-
-    private final List<ArtifactRepository> remoteRepositories;
-
-    private boolean active = true;
-
-    private List<Artifact> trail;
-
-    public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories )
-    {
-        this.artifact = artifact;
-        this.remoteRepositories = remoteRepositories;
-        depth = 0;
-        parents = Collections.emptyList();
-        parent = null;
-    }
-
-    public ResolutionNode( Artifact artifact, List<ArtifactRepository> remoteRepositories, ResolutionNode parent )
-    {
-        this.artifact = artifact;
-        this.remoteRepositories = remoteRepositories;
-        depth = parent.depth + 1;
-        parents = new ArrayList<>();
-        parents.addAll( parent.parents );
-        parents.add( parent.getKey() );
-        this.parent = parent;
-    }
-
-    public Artifact getArtifact()
-    {
-        return artifact;
-    }
-
-    public Object getKey()
-    {
-        return artifact.getDependencyConflictId();
-    }
-
-    public void addDependencies( Set<Artifact> artifacts, List<ArtifactRepository> remoteRepositories,
-                                 ArtifactFilter filter )
-        throws CyclicDependencyException, OverConstrainedVersionException
-    {
-        if ( artifacts != null && !artifacts.isEmpty() )
-        {
-            children = new ArrayList<>( artifacts.size() );
-
-            for ( Artifact a : artifacts )
-            {
-                if ( parents.contains( a.getDependencyConflictId() ) )
-                {
-                    a.setDependencyTrail( getDependencyTrail() );
-
-                    throw new CyclicDependencyException( "A dependency has introduced a cycle", a );
-                }
-
-                children.add( new ResolutionNode( a, remoteRepositories, this ) );
-            }
-            children = Collections.unmodifiableList( children );
-        }
-        else
-        {
-            children = Collections.emptyList();
-        }
-        trail = null;
-    }
-
-    /**
-     * @return {@link List} &lt; {@link String} &gt; with artifact ids
-     * @throws OverConstrainedVersionException if version specification is over constrained
-     */
-    public List<String> getDependencyTrail()
-        throws OverConstrainedVersionException
-    {
-        List<Artifact> trial = getTrail();
-
-        List<String> ret = new ArrayList<>( trial.size() );
-
-        for ( Artifact artifact : trial )
-        {
-            ret.add( artifact.getId() );
-        }
-
-        return ret;
-    }
-
-    private List<Artifact> getTrail()
-        throws OverConstrainedVersionException
-    {
-        if ( trail == null )
-        {
-            List<Artifact> ids = new LinkedList<>();
-            ResolutionNode node = this;
-            while ( node != null )
-            {
-                Artifact artifact = node.getArtifact();
-                if ( artifact.getVersion() == null )
-                {
-                    // set the recommended version
-                    ArtifactVersion selected = artifact.getSelectedVersion();
-                    // MNG-2123: null is a valid response to getSelectedVersion, don't
-                    // assume it won't ever be.
-                    if ( selected != null )
-                    {
-                        artifact.selectVersion( selected.toString() );
-                    }
-                    else
-                    {
-                        throw new OverConstrainedVersionException( "Unable to get a selected Version for "
-                            + artifact.getArtifactId(), artifact );
-                    }
-                }
-
-                ids.add( 0, artifact );
-                node = node.parent;
-            }
-            trail = ids;
-        }
-        return trail;
-    }
-
-    public boolean isResolved()
-    {
-        return children != null;
-    }
-
-    /**
-     * Test whether the node is direct or transitive dependency.
-     *
-     * @return whether the node is direct or transitive dependency
-     */
-    public boolean isChildOfRootNode()
-    {
-        return parent != null && parent.parent == null;
-    }
-
-    public Iterator<ResolutionNode> getChildrenIterator()
-    {
-        return children.iterator();
-    }
-
-    public int getDepth()
-    {
-        return depth;
-    }
-
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
-        return remoteRepositories;
-    }
-
-    public boolean isActive()
-    {
-        return active;
-    }
-
-    public void enable()
-    {
-        active = true;
-
-        // TODO if it was null, we really need to go find them now... or is this taken care of by the ordering?
-        if ( children != null )
-        {
-            for ( ResolutionNode node : children )
-            {
-                node.enable();
-            }
-        }
-    }
-
-    public void disable()
-    {
-        active = false;
-        if ( children != null )
-        {
-            for ( ResolutionNode node : children )
-            {
-                node.disable();
-            }
-        }
-    }
-
-    public boolean filterTrail( ArtifactFilter filter )
-        throws OverConstrainedVersionException
-    {
-        boolean success = true;
-        if ( filter != null )
-        {
-            for ( Artifact artifact : getTrail() )
-            {
-                if ( !filter.include( artifact ) )
-                {
-                    success = false;
-                }
-            }
-        }
-        return success;
-    }
-
-    @Override
-    public String toString()
-    {
-        return artifact.toString() + " (" + depth + "; " + ( active ? "enabled" : "disabled" ) + ")";
-    }
-
-    public void setArtifact( Artifact artifact )
-    {
-        this.artifact = artifact;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AbstractScopeArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AbstractScopeArtifactFilter.java
index 95872db..14c2e26 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AbstractScopeArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AbstractScopeArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import org.apache.maven.artifact.Artifact;
 
 /**
  * Filter to only retain objects in the given artifactScope or better.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-abstract class AbstractScopeArtifactFilter
-    implements ArtifactFilter
-{
+abstract class AbstractScopeArtifactFilter implements ArtifactFilter {
 
     private boolean compileScope;
 
@@ -40,34 +36,24 @@
 
     private boolean systemScope;
 
-    void addScopeInternal( String scope )
-    {
-        if ( Artifact.SCOPE_COMPILE.equals( scope ) )
-        {
+    void addScopeInternal(String scope) {
+        if (Artifact.SCOPE_COMPILE.equals(scope)) {
             systemScope = true;
             providedScope = true;
             compileScope = true;
-        }
-        else if ( Artifact.SCOPE_RUNTIME.equals( scope ) )
-        {
+        } else if (Artifact.SCOPE_RUNTIME.equals(scope)) {
             compileScope = true;
             runtimeScope = true;
-        }
-        else if ( Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals( scope ) )
-        {
+        } else if (Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals(scope)) {
             systemScope = true;
             providedScope = true;
             compileScope = true;
             runtimeScope = true;
-        }
-        else if ( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM.equals( scope ) )
-        {
+        } else if (Artifact.SCOPE_RUNTIME_PLUS_SYSTEM.equals(scope)) {
             systemScope = true;
             compileScope = true;
             runtimeScope = true;
-        }
-        else if ( Artifact.SCOPE_TEST.equals( scope ) )
-        {
+        } else if (Artifact.SCOPE_TEST.equals(scope)) {
             systemScope = true;
             providedScope = true;
             compileScope = true;
@@ -76,32 +62,19 @@
         }
     }
 
-    public boolean include( Artifact artifact )
-    {
-        if ( Artifact.SCOPE_COMPILE.equals( artifact.getScope() ) )
-        {
+    public boolean include(Artifact artifact) {
+        if (Artifact.SCOPE_COMPILE.equals(artifact.getScope())) {
             return compileScope;
-        }
-        else if ( Artifact.SCOPE_RUNTIME.equals( artifact.getScope() ) )
-        {
+        } else if (Artifact.SCOPE_RUNTIME.equals(artifact.getScope())) {
             return runtimeScope;
-        }
-        else if ( Artifact.SCOPE_TEST.equals( artifact.getScope() ) )
-        {
+        } else if (Artifact.SCOPE_TEST.equals(artifact.getScope())) {
             return testScope;
-        }
-        else if ( Artifact.SCOPE_PROVIDED.equals( artifact.getScope() ) )
-        {
+        } else if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope())) {
             return providedScope;
-        }
-        else if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
-        {
+        } else if (Artifact.SCOPE_SYSTEM.equals(artifact.getScope())) {
             return systemScope;
-        }
-        else
-        {
+        } else {
             return true;
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilter.java
index 669773d..13928c4 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/AndArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -30,70 +29,56 @@
 /**
  * Apply multiple filters.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class AndArtifactFilter
-    implements ArtifactFilter
-{
+public class AndArtifactFilter implements ArtifactFilter {
     private Set<ArtifactFilter> filters;
 
-    public AndArtifactFilter()
-    {
+    public AndArtifactFilter() {
         this.filters = new LinkedHashSet<>();
     }
 
-    public AndArtifactFilter( List<ArtifactFilter> filters )
-    {
-        this.filters = new LinkedHashSet<>( filters );
+    public AndArtifactFilter(List<ArtifactFilter> filters) {
+        this.filters = new LinkedHashSet<>(filters);
     }
 
-    public boolean include( Artifact artifact )
-    {
+    public boolean include(Artifact artifact) {
         boolean include = true;
-        for ( Iterator<ArtifactFilter> i = filters.iterator(); i.hasNext() && include; )
-        {
+        for (Iterator<ArtifactFilter> i = filters.iterator(); i.hasNext() && include; ) {
             ArtifactFilter filter = i.next();
-            if ( !filter.include( artifact ) )
-            {
+            if (!filter.include(artifact)) {
                 include = false;
             }
         }
         return include;
     }
 
-    public void add( ArtifactFilter artifactFilter )
-    {
-        filters.add( artifactFilter );
+    public void add(ArtifactFilter artifactFilter) {
+        filters.add(artifactFilter);
     }
 
-    public List<ArtifactFilter> getFilters()
-    {
-        return new ArrayList<>( filters );
+    public List<ArtifactFilter> getFilters() {
+        return new ArrayList<>(filters);
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
         hash = hash * 31 + filters.hashCode();
         return hash;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof AndArtifactFilter ) )
-        {
+        if (!(obj instanceof AndArtifactFilter)) {
             return false;
         }
 
         AndArtifactFilter other = (AndArtifactFilter) obj;
 
-        return filters.equals( other.filters );
+        return filters.equals(other.filters);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/CumulativeScopeArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/CumulativeScopeArtifactFilter.java
index e92ece2..5f7235b 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/CumulativeScopeArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/CumulativeScopeArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -29,12 +28,8 @@
  * single step. This should be a more efficient implementation of multiple standard {@link ScopeArtifactFilter}
  * instances ORed together.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- * @author jdcasey
  */
-public class CumulativeScopeArtifactFilter
-    extends AbstractScopeArtifactFilter
-{
+public class CumulativeScopeArtifactFilter extends AbstractScopeArtifactFilter {
 
     private Set<String> scopes;
 
@@ -43,11 +38,10 @@
      *
      * @param scopes The scopes to enable, along with all implied scopes, may be {@code null}.
      */
-    public CumulativeScopeArtifactFilter( Collection<String> scopes )
-    {
+    public CumulativeScopeArtifactFilter(Collection<String> scopes) {
         this.scopes = new HashSet<>();
 
-        addScopes( scopes );
+        addScopes(scopes);
     }
 
     /**
@@ -55,45 +49,36 @@
      *
      * @param filters The filters to combine, may be {@code null}.
      */
-    public CumulativeScopeArtifactFilter( CumulativeScopeArtifactFilter... filters )
-    {
+    public CumulativeScopeArtifactFilter(CumulativeScopeArtifactFilter... filters) {
         this.scopes = new HashSet<>();
 
-        if ( filters != null )
-        {
-            for ( CumulativeScopeArtifactFilter filter : filters )
-            {
-                addScopes( filter.getScopes() );
+        if (filters != null) {
+            for (CumulativeScopeArtifactFilter filter : filters) {
+                addScopes(filter.getScopes());
             }
         }
     }
 
-    private void addScopes( Collection<String> scopes )
-    {
-        if ( scopes != null )
-        {
-            for ( String scope : scopes )
-            {
-                addScope( scope );
+    private void addScopes(Collection<String> scopes) {
+        if (scopes != null) {
+            for (String scope : scopes) {
+                addScope(scope);
             }
         }
     }
 
-    private void addScope( String scope )
-    {
-        this.scopes.add( scope );
+    private void addScope(String scope) {
+        this.scopes.add(scope);
 
-        addScopeInternal( scope );
+        addScopeInternal(scope);
     }
 
-    public Set<String> getScopes()
-    {
+    public Set<String> getScopes() {
         return scopes;
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
 
         hash = hash * 31 + scopes.hashCode();
@@ -102,21 +87,17 @@
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof CumulativeScopeArtifactFilter ) )
-        {
+        if (!(obj instanceof CumulativeScopeArtifactFilter)) {
             return false;
         }
 
         CumulativeScopeArtifactFilter that = (CumulativeScopeArtifactFilter) obj;
 
-        return scopes.equals( that.scopes );
+        return scopes.equals(that.scopes);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExcludesArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExcludesArtifactFilter.java
index e448af4..ebe1203 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExcludesArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExcludesArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.List;
 
@@ -26,19 +25,14 @@
 /**
  * Filter to exclude from a list of artifact patterns.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  * TODO I think this is equiv. to exclusion set filter in maven-core
  */
-public class ExcludesArtifactFilter
-    extends IncludesArtifactFilter
-{
-    public ExcludesArtifactFilter( List<String> patterns )
-    {
-        super( patterns );
+public class ExcludesArtifactFilter extends IncludesArtifactFilter {
+    public ExcludesArtifactFilter(List<String> patterns) {
+        super(patterns);
     }
 
-    public boolean include( Artifact artifact )
-    {
-        return !super.include( artifact );
+    public boolean include(Artifact artifact) {
+        return !super.include(artifact);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java
index 18d4e83..1defc48 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,9 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
+import java.lang.reflect.Proxy;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
 import java.util.List;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.model.Exclusion;
@@ -28,44 +32,43 @@
 /**
  * Filter to exclude from a list of artifact patterns.
  */
-public class ExclusionArtifactFilter implements ArtifactFilter
-{
-    private static final String WILDCARD = "*";
+public class ExclusionArtifactFilter implements ArtifactFilter {
 
     private final List<Exclusion> exclusions;
+    private final List<Predicate<Artifact>> predicates;
 
-    public ExclusionArtifactFilter( List<Exclusion> exclusions )
-    {
+    public ExclusionArtifactFilter(List<Exclusion> exclusions) {
         this.exclusions = exclusions;
-    }
-
-    private Predicate<Exclusion> sameArtifactId( Artifact artifact )
-    {
-        return exclusion -> exclusion.getArtifactId().equals( artifact.getArtifactId() );
-    }
-
-    private Predicate<Exclusion> sameGroupId( Artifact artifact )
-    {
-        return exclusion -> exclusion.getGroupId().equals( artifact.getGroupId() );
-    }
-
-    private Predicate<Exclusion> groupIdIsWildcard = exclusion -> WILDCARD.equals( exclusion.getGroupId() );
-
-    private Predicate<Exclusion> artifactIdIsWildcard = exclusion -> WILDCARD.equals( exclusion.getArtifactId() );
-
-    private Predicate<Exclusion> groupIdAndArtifactIdIsWildcard = groupIdIsWildcard.and( artifactIdIsWildcard );
-
-    private Predicate<Exclusion> exclude( Artifact artifact )
-    {
-        return groupIdAndArtifactIdIsWildcard
-                .or( groupIdIsWildcard.and( sameArtifactId( artifact ) ) )
-                .or( artifactIdIsWildcard.and( sameGroupId( artifact ) ) )
-                .or( sameGroupId( artifact ).and( sameArtifactId( artifact ) ) );
+        this.predicates =
+                exclusions.stream().map(ExclusionArtifactFilter::toPredicate).collect(Collectors.toList());
     }
 
     @Override
-    public boolean include( Artifact artifact )
-    {
-        return !exclusions.stream().anyMatch( exclude( artifact ) );
+    public boolean include(Artifact artifact) {
+        return predicates.stream().noneMatch(p -> p.test(artifact));
+    }
+
+    private static Predicate<Artifact> toPredicate(Exclusion exclusion) {
+        PathMatcher groupId = FileSystems.getDefault().getPathMatcher("glob:" + exclusion.getGroupId());
+        PathMatcher artifactId = FileSystems.getDefault().getPathMatcher("glob:" + exclusion.getArtifactId());
+        Predicate<Artifact> predGroupId = a -> groupId.matches(createPathProxy(a.getGroupId()));
+        Predicate<Artifact> predArtifactId = a -> artifactId.matches(createPathProxy(a.getArtifactId()));
+        return predGroupId.and(predArtifactId);
+    }
+
+    /**
+     * In order to reuse the glob matcher from the filesystem, we need
+     * to create Path instances.  Those are only used with the toString method.
+     * This hack works because the only system-dependent thing is the path
+     * separator which should not be part of the groupId or artifactId.
+     */
+    private static Path createPathProxy(String value) {
+        return (Path) Proxy.newProxyInstance(
+                ExclusionArtifactFilter.class.getClassLoader(), new Class[] {Path.class}, (proxy1, method, args) -> {
+                    if ("toString".equals(method.getName())) {
+                        return value;
+                    }
+                    throw new UnsupportedOperationException();
+                });
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionSetFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionSetFilter.java
index 57c6177..7e57e94 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionSetFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ExclusionSetFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Arrays;
 import java.util.LinkedHashSet;
@@ -26,61 +25,49 @@
 import org.apache.maven.artifact.Artifact;
 
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-public class ExclusionSetFilter
-    implements ArtifactFilter
-{
+public class ExclusionSetFilter implements ArtifactFilter {
     private Set<String> excludes;
 
-    public ExclusionSetFilter( String[] excludes )
-    {
-        this.excludes = new LinkedHashSet<>( Arrays.asList( excludes ) );
+    public ExclusionSetFilter(String[] excludes) {
+        this.excludes = new LinkedHashSet<>(Arrays.asList(excludes));
     }
 
-    public ExclusionSetFilter( Set<String> excludes )
-    {
+    public ExclusionSetFilter(Set<String> excludes) {
         this.excludes = excludes;
     }
 
-    public boolean include( Artifact artifact )
-    {
+    public boolean include(Artifact artifact) {
         String id = artifact.getArtifactId();
 
-        if ( excludes.contains( id ) )
-        {
+        if (excludes.contains(id)) {
             return false;
         }
 
         id = artifact.getGroupId() + ':' + id;
 
-        return !excludes.contains( id );
-
+        return !excludes.contains(id);
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
         hash = hash * 31 + excludes.hashCode();
         return hash;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof ExclusionSetFilter ) )
-        {
+        if (!(obj instanceof ExclusionSetFilter)) {
             return false;
         }
 
         ExclusionSetFilter other = (ExclusionSetFilter) obj;
 
-        return excludes.equals( other.excludes );
+        return excludes.equals(other.excludes);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/IncludesArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/IncludesArtifactFilter.java
index 7a3b6c7..8ee8ce4 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/IncludesArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/IncludesArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -30,42 +29,33 @@
 /**
  * Filter to include from a list of artifact patterns.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class IncludesArtifactFilter
-    implements ArtifactFilter
-{
+public class IncludesArtifactFilter implements ArtifactFilter {
     private final Set<String> patterns;
 
-    public IncludesArtifactFilter( List<String> patterns )
-    {
-        this.patterns = new LinkedHashSet<>( patterns );
+    public IncludesArtifactFilter(List<String> patterns) {
+        this.patterns = new LinkedHashSet<>(patterns);
     }
 
-    public boolean include( Artifact artifact )
-    {
+    public boolean include(Artifact artifact) {
         String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
 
         boolean matched = false;
-        for ( Iterator<String> i = patterns.iterator(); i.hasNext() & !matched; )
-        {
+        for (Iterator<String> i = patterns.iterator(); i.hasNext() & !matched; ) {
             // TODO what about wildcards? Just specifying groups? versions?
-            if ( id.equals( i.next() ) )
-            {
+            if (id.equals(i.next())) {
                 matched = true;
             }
         }
         return matched;
     }
 
-    public List<String> getPatterns()
-    {
-        return new ArrayList<>( patterns );
+    public List<String> getPatterns() {
+        return new ArrayList<>(patterns);
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
         hash = hash * 31 + patterns.hashCode();
 
@@ -73,21 +63,18 @@
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
         // make sure IncludesArtifactFilter is not equal ExcludesArtifactFilter!
-        if ( obj == null || getClass() != obj.getClass() )
-        {
+        if (obj == null || getClass() != obj.getClass()) {
             return false;
         }
 
         IncludesArtifactFilter other = (IncludesArtifactFilter) obj;
 
-        return patterns.equals( other.patterns );
+        return patterns.equals(other.patterns);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilter.java b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilter.java
index d87ee85..28ca6e7 100644
--- a/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilter.java
+++ b/maven-core/src/main/java/org/apache/maven/artifact/resolver/filter/ScopeArtifactFilter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,58 +16,49 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Objects;
 
 /**
  * Filter to only retain objects in the given artifactScope or better.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class ScopeArtifactFilter
-    extends AbstractScopeArtifactFilter
-{
+public class ScopeArtifactFilter extends AbstractScopeArtifactFilter {
 
     private final String scope;
 
-    public ScopeArtifactFilter( String scope )
-    {
+    public ScopeArtifactFilter(String scope) {
         this.scope = scope;
 
-        addScopeInternal( scope );
+        addScopeInternal(scope);
     }
 
-    public String getScope()
-    {
+    public String getScope() {
         return scope;
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         int hash = 17;
 
-        hash = hash * 31 + ( scope != null ? scope.hashCode() : 0 );
+        hash = hash * 31 + (scope != null ? scope.hashCode() : 0);
 
         return hash;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof ScopeArtifactFilter ) )
-        {
+        if (!(obj instanceof ScopeArtifactFilter)) {
             return false;
         }
 
         ScopeArtifactFilter other = (ScopeArtifactFilter) obj;
 
-        return Objects.equals( scope, other.scope );
+        return Objects.equals(scope, other.scope);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java b/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java
index 7956382..54766d5 100644
--- a/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java
+++ b/maven-core/src/main/java/org/apache/maven/bridge/MavenRepositorySystem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.bridge;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.bridge;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.net.MalformedURLException;
@@ -31,10 +34,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.DefaultArtifact;
@@ -55,9 +54,7 @@
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.repository.Proxy;
-import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.settings.Mirror;
-import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.repository.AuthenticationContext;
 import org.eclipse.aether.repository.AuthenticationSelector;
@@ -65,141 +62,124 @@
 import org.eclipse.aether.repository.RemoteRepository;
 
 /**
- * @author Jason van Zyl
  */
-@Named( "default" )
+@Named("default")
 @Singleton
-public class MavenRepositorySystem
-{
+public class MavenRepositorySystem {
+
+    public static final String DEFAULT_REMOTE_REPO_ID = "central";
+
+    public static final String DEFAULT_REMOTE_REPO_URL = "https://repo.maven.apache.org/maven2";
+
+    public static final String DEFAULT_LOCAL_REPO_ID = "local";
+
     private final ArtifactHandlerManager artifactHandlerManager;
 
     private final Map<String, ArtifactRepositoryLayout> layouts;
 
     @Inject
-    public MavenRepositorySystem( ArtifactHandlerManager artifactHandlerManager,
-            Map<String, ArtifactRepositoryLayout> layouts )
-    {
+    public MavenRepositorySystem(
+            ArtifactHandlerManager artifactHandlerManager, Map<String, ArtifactRepositoryLayout> layouts) {
         this.artifactHandlerManager = artifactHandlerManager;
         this.layouts = layouts;
     }
 
     // DefaultProjectBuilder
-    public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type )
-    {
-        return createArtifactX( groupId, artifactId, version, scope, type );
+    public Artifact createArtifact(String groupId, String artifactId, String version, String scope, String type) {
+        return createArtifactX(groupId, artifactId, version, scope, type);
     }
 
     // DefaultProjectBuilder
-    public Artifact createProjectArtifact( String groupId, String artifactId, String metaVersionId )
-    {
-        return createProjectArtifactX( groupId, artifactId, metaVersionId );
+    public Artifact createProjectArtifact(String groupId, String artifactId, String metaVersionId) {
+        return createProjectArtifactX(groupId, artifactId, metaVersionId);
     }
 
     // DefaultProjectBuilder
-    public Artifact createDependencyArtifact( Dependency d )
-    {
-        if ( d.getVersion() == null )
-        {
+    public Artifact createDependencyArtifact(Dependency d) {
+        if (d.getVersion() == null) {
             return null;
         }
 
         VersionRange versionRange;
-        try
-        {
-            versionRange = VersionRange.createFromVersionSpec( d.getVersion() );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
+        try {
+            versionRange = VersionRange.createFromVersionSpec(d.getVersion());
+        } catch (InvalidVersionSpecificationException e) {
             return null;
         }
 
-        Artifact artifact =
-            createDependencyArtifactX( d.getGroupId(), d.getArtifactId(), versionRange, d.getType(),
-                                                      d.getClassifier(), d.getScope(), d.isOptional() );
+        Artifact artifact = createDependencyArtifactX(
+                d.getGroupId(),
+                d.getArtifactId(),
+                versionRange,
+                d.getType(),
+                d.getClassifier(),
+                d.getScope(),
+                d.isOptional());
 
-        if ( Artifact.SCOPE_SYSTEM.equals( d.getScope() ) && d.getSystemPath() != null )
-        {
-            artifact.setFile( new File( d.getSystemPath() ) );
+        if (Artifact.SCOPE_SYSTEM.equals(d.getScope()) && d.getSystemPath() != null) {
+            artifact.setFile(new File(d.getSystemPath()));
         }
 
-        if ( !d.getExclusions().isEmpty() )
-        {
-            artifact.setDependencyFilter( new ExclusionArtifactFilter( d.getExclusions() ) );
+        if (!d.getExclusions().isEmpty()) {
+            artifact.setDependencyFilter(new ExclusionArtifactFilter(d.getExclusions()));
         }
 
         return artifact;
     }
 
     // DefaultProjectBuilder
-    public Artifact createExtensionArtifact( String groupId, String artifactId, String version )
-    {
+    public Artifact createExtensionArtifact(String groupId, String artifactId, String version) {
         VersionRange versionRange;
-        try
-        {
-            versionRange = VersionRange.createFromVersionSpec( version );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
+        try {
+            versionRange = VersionRange.createFromVersionSpec(version);
+        } catch (InvalidVersionSpecificationException e) {
             return null;
         }
 
-        return createExtensionArtifactX( groupId, artifactId, versionRange );
+        return createExtensionArtifactX(groupId, artifactId, versionRange);
     }
 
     // DefaultProjectBuilder
-    public Artifact createParentArtifact( String groupId, String artifactId, String version )
-    {
-        return createParentArtifactX( groupId, artifactId, version );
+    public Artifact createParentArtifact(String groupId, String artifactId, String version) {
+        return createParentArtifactX(groupId, artifactId, version);
     }
 
     // DefaultProjectBuilder
-    public Artifact createPluginArtifact( Plugin plugin )
-    {
+    public Artifact createPluginArtifact(Plugin plugin) {
         VersionRange versionRange;
-        try
-        {
+        try {
             String version = plugin.getVersion();
-            if ( StringUtils.isEmpty( version ) )
-            {
+            if (version == null || version.isEmpty()) {
                 version = "RELEASE";
             }
-            versionRange = VersionRange.createFromVersionSpec( version );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
+            versionRange = VersionRange.createFromVersionSpec(version);
+        } catch (InvalidVersionSpecificationException e) {
             return null;
         }
 
-        return createPluginArtifactX( plugin.getGroupId(), plugin.getArtifactId(), versionRange );
+        return createPluginArtifactX(plugin.getGroupId(), plugin.getArtifactId(), versionRange);
     }
 
-    public void injectMirror( List<ArtifactRepository> repositories, List<Mirror> mirrors )
-    {
-        if ( repositories != null && mirrors != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                Mirror mirror = getMirror( repository, mirrors );
-                injectMirror( repository, mirror );
+    public void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
+        if (repositories != null && mirrors != null) {
+            for (ArtifactRepository repository : repositories) {
+                Mirror mirror = getMirror(repository, mirrors);
+                injectMirror(repository, mirror);
             }
         }
     }
 
-    private Mirror getMirror( RepositorySystemSession session, ArtifactRepository repository )
-    {
-        if ( session != null )
-        {
+    private Mirror getMirror(RepositorySystemSession session, ArtifactRepository repository) {
+        if (session != null) {
             org.eclipse.aether.repository.MirrorSelector selector = session.getMirrorSelector();
-            if ( selector != null )
-            {
-                RemoteRepository repo = selector.getMirror( RepositoryUtils.toRepo( repository ) );
-                if ( repo != null )
-                {
+            if (selector != null) {
+                RemoteRepository repo = selector.getMirror(RepositoryUtils.toRepo(repository));
+                if (repo != null) {
                     Mirror mirror = new Mirror();
-                    mirror.setId( repo.getId() );
-                    mirror.setUrl( repo.getUrl() );
-                    mirror.setLayout( repo.getContentType() );
-                    mirror.setBlocked( repo.isBlocked() );
+                    mirror.setId(repo.getId());
+                    mirror.setUrl(repo.getUrl());
+                    mirror.setLayout(repo.getContentType());
+                    mirror.setBlocked(repo.isBlocked());
                     return mirror;
                 }
             }
@@ -207,58 +187,52 @@
         return null;
     }
 
-    public void injectMirror( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-        if ( repositories != null && session != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                Mirror mirror = getMirror( session, repository );
-                injectMirror( repository, mirror );
+    public void injectMirror(RepositorySystemSession session, List<ArtifactRepository> repositories) {
+        if (repositories != null && session != null) {
+            for (ArtifactRepository repository : repositories) {
+                Mirror mirror = getMirror(session, repository);
+                injectMirror(repository, mirror);
             }
         }
     }
 
-    private void injectMirror( ArtifactRepository repository, Mirror mirror )
-    {
-        if ( mirror != null )
-        {
-            ArtifactRepository original =
-                createArtifactRepository( repository.getId(), repository.getUrl(), repository.getLayout(),
-                                          repository.getSnapshots(), repository.getReleases() );
+    private void injectMirror(ArtifactRepository repository, Mirror mirror) {
+        if (mirror != null) {
+            ArtifactRepository original = createArtifactRepository(
+                    repository.getId(),
+                    repository.getUrl(),
+                    repository.getLayout(),
+                    repository.getSnapshots(),
+                    repository.getReleases());
 
-            repository.setMirroredRepositories( Collections.singletonList( original ) );
+            repository.setMirroredRepositories(Collections.singletonList(original));
 
-            repository.setId( mirror.getId() );
-            repository.setUrl( mirror.getUrl() );
+            repository.setId(mirror.getId());
+            repository.setUrl(mirror.getUrl());
 
-            if ( StringUtils.isNotEmpty( mirror.getLayout() ) )
-            {
-                repository.setLayout( getLayout( mirror.getLayout() ) );
+            if (mirror.getLayout() != null && !mirror.getLayout().isEmpty()) {
+                repository.setLayout(getLayout(mirror.getLayout()));
             }
 
-            repository.setBlocked( mirror.isBlocked() );
+            repository.setBlocked(mirror.isBlocked());
         }
     }
 
-    private Authentication getAuthentication( RepositorySystemSession session, ArtifactRepository repository )
-    {
-        if ( session != null )
-        {
+    private Authentication getAuthentication(RepositorySystemSession session, ArtifactRepository repository) {
+        if (session != null) {
             AuthenticationSelector selector = session.getAuthenticationSelector();
-            if ( selector != null )
-            {
-                RemoteRepository repo = RepositoryUtils.toRepo( repository );
-                org.eclipse.aether.repository.Authentication auth = selector.getAuthentication( repo );
-                if ( auth != null )
-                {
-                    repo = new RemoteRepository.Builder( repo ).setAuthentication( auth ).build();
-                    AuthenticationContext authCtx = AuthenticationContext.forRepository( session, repo );
-                    Authentication result =
-                        new Authentication( authCtx.get( AuthenticationContext.USERNAME ),
-                                            authCtx.get( AuthenticationContext.PASSWORD ) );
-                    result.setPrivateKey( authCtx.get( AuthenticationContext.PRIVATE_KEY_PATH ) );
-                    result.setPassphrase( authCtx.get( AuthenticationContext.PRIVATE_KEY_PASSPHRASE ) );
+            if (selector != null) {
+                RemoteRepository repo = RepositoryUtils.toRepo(repository);
+                org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
+                if (auth != null) {
+                    repo = new RemoteRepository.Builder(repo)
+                            .setAuthentication(auth)
+                            .build();
+                    AuthenticationContext authCtx = AuthenticationContext.forRepository(session, repo);
+                    Authentication result = new Authentication(
+                            authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
+                    result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
+                    result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
                     authCtx.close();
                     return result;
                 }
@@ -267,40 +241,34 @@
         return null;
     }
 
-    public void injectAuthentication( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-        if ( repositories != null && session != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                repository.setAuthentication( getAuthentication( session, repository ) );
+    public void injectAuthentication(RepositorySystemSession session, List<ArtifactRepository> repositories) {
+        if (repositories != null && session != null) {
+            for (ArtifactRepository repository : repositories) {
+                repository.setAuthentication(getAuthentication(session, repository));
             }
         }
     }
 
-    private Proxy getProxy( RepositorySystemSession session, ArtifactRepository repository )
-    {
-        if ( session != null )
-        {
+    private Proxy getProxy(RepositorySystemSession session, ArtifactRepository repository) {
+        if (session != null) {
             ProxySelector selector = session.getProxySelector();
-            if ( selector != null )
-            {
-                RemoteRepository repo = RepositoryUtils.toRepo( repository );
-                org.eclipse.aether.repository.Proxy proxy = selector.getProxy( repo );
-                if ( proxy != null )
-                {
+            if (selector != null) {
+                RemoteRepository repo = RepositoryUtils.toRepo(repository);
+                org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
+                if (proxy != null) {
                     Proxy p = new Proxy();
-                    p.setHost( proxy.getHost() );
-                    p.setProtocol( proxy.getType() );
-                    p.setPort( proxy.getPort() );
-                    if ( proxy.getAuthentication() != null )
-                    {
-                        repo = new RemoteRepository.Builder( repo ).setProxy( proxy ).build();
-                        AuthenticationContext authCtx = AuthenticationContext.forProxy( session, repo );
-                        p.setUserName( authCtx.get( AuthenticationContext.USERNAME ) );
-                        p.setPassword( authCtx.get( AuthenticationContext.PASSWORD ) );
-                        p.setNtlmDomain( authCtx.get( AuthenticationContext.NTLM_DOMAIN ) );
-                        p.setNtlmHost( authCtx.get( AuthenticationContext.NTLM_WORKSTATION ) );
+                    p.setHost(proxy.getHost());
+                    p.setProtocol(proxy.getType());
+                    p.setPort(proxy.getPort());
+                    if (proxy.getAuthentication() != null) {
+                        repo = new RemoteRepository.Builder(repo)
+                                .setProxy(proxy)
+                                .build();
+                        AuthenticationContext authCtx = AuthenticationContext.forProxy(session, repo);
+                        p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
+                        p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
+                        p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
+                        p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
                         authCtx.close();
                     }
                     return p;
@@ -310,301 +278,291 @@
         return null;
     }
 
-    public void injectProxy( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-        if ( repositories != null && session != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                repository.setProxy( getProxy( session, repository ) );
+    public void injectProxy(RepositorySystemSession session, List<ArtifactRepository> repositories) {
+        if (repositories != null && session != null) {
+            for (ArtifactRepository repository : repositories) {
+                repository.setProxy(getProxy(session, repository));
             }
         }
     }
 
-    private ArtifactRepositoryLayout getLayout( String id )
-    {
-        return layouts.get( id );
+    private ArtifactRepositoryLayout getLayout(String id) {
+        return layouts.get(id);
     }
 
-
     //
     // Taken from LegacyRepositorySystem
     //
 
-    public static org.apache.maven.model.Repository fromSettingsRepository( org.apache.maven.settings.Repository
-                                                                            settingsRepository )
-    {
+    public static org.apache.maven.model.Repository fromSettingsRepository(
+            org.apache.maven.settings.Repository settingsRepository) {
         org.apache.maven.model.Repository modelRepository = new org.apache.maven.model.Repository();
-        modelRepository.setId( settingsRepository.getId() );
-        modelRepository.setLayout( settingsRepository.getLayout() );
-        modelRepository.setName( settingsRepository.getName() );
-        modelRepository.setUrl( settingsRepository.getUrl() );
-        modelRepository.setReleases( fromSettingsRepositoryPolicy( settingsRepository.getReleases() ) );
-        modelRepository.setSnapshots( fromSettingsRepositoryPolicy( settingsRepository.getSnapshots() ) );
+        modelRepository.setId(settingsRepository.getId());
+        modelRepository.setLayout(settingsRepository.getLayout());
+        modelRepository.setName(settingsRepository.getName());
+        modelRepository.setUrl(settingsRepository.getUrl());
+        modelRepository.setReleases(fromSettingsRepositoryPolicy(settingsRepository.getReleases()));
+        modelRepository.setSnapshots(fromSettingsRepositoryPolicy(settingsRepository.getSnapshots()));
         return modelRepository;
     }
 
     public static org.apache.maven.model.RepositoryPolicy fromSettingsRepositoryPolicy(
-                                                 org.apache.maven.settings.RepositoryPolicy settingsRepositoryPolicy )
-    {
+            org.apache.maven.settings.RepositoryPolicy settingsRepositoryPolicy) {
         org.apache.maven.model.RepositoryPolicy modelRepositoryPolicy = new org.apache.maven.model.RepositoryPolicy();
-        if ( settingsRepositoryPolicy != null )
-        {
-            modelRepositoryPolicy.setEnabled( settingsRepositoryPolicy.isEnabled() );
-            modelRepositoryPolicy.setUpdatePolicy( settingsRepositoryPolicy.getUpdatePolicy() );
-            modelRepositoryPolicy.setChecksumPolicy( settingsRepositoryPolicy.getChecksumPolicy() );
+        if (settingsRepositoryPolicy != null) {
+            modelRepositoryPolicy.setEnabled(settingsRepositoryPolicy.isEnabled());
+            modelRepositoryPolicy.setUpdatePolicy(settingsRepositoryPolicy.getUpdatePolicy());
+            modelRepositoryPolicy.setChecksumPolicy(settingsRepositoryPolicy.getChecksumPolicy());
         }
         return modelRepositoryPolicy;
     }
 
-    public static ArtifactRepository buildArtifactRepository( org.apache.maven.settings.Repository repo )
-        throws InvalidRepositoryException
-    {
-        return buildArtifactRepository( fromSettingsRepository( repo ) );
+    public static ArtifactRepository buildArtifactRepository(org.apache.maven.settings.Repository repo)
+            throws InvalidRepositoryException {
+        return buildArtifactRepository(fromSettingsRepository(repo));
     }
 
-    public static ArtifactRepository buildArtifactRepository( org.apache.maven.model.Repository repo )
-        throws InvalidRepositoryException
-    {
-        if ( repo != null )
-        {
+    public static ArtifactRepository buildArtifactRepository(org.apache.maven.model.Repository repo)
+            throws InvalidRepositoryException {
+        if (repo != null) {
             String id = repo.getId();
 
-            if ( StringUtils.isEmpty( id ) )
-            {
-                throw new InvalidRepositoryException( "Repository identifier missing", "" );
+            if (id == null || id.isEmpty()) {
+                throw new InvalidRepositoryException("Repository identifier missing", "");
             }
 
             String url = repo.getUrl();
 
-            if ( StringUtils.isEmpty( url ) )
-            {
-                throw new InvalidRepositoryException( "URL missing for repository " + id, id );
+            if (url == null || url.isEmpty()) {
+                throw new InvalidRepositoryException("URL missing for repository " + id, id);
             }
 
-            ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy( repo.getSnapshots() );
+            ArtifactRepositoryPolicy snapshots = buildArtifactRepositoryPolicy(repo.getSnapshots());
 
-            ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy( repo.getReleases() );
+            ArtifactRepositoryPolicy releases = buildArtifactRepositoryPolicy(repo.getReleases());
 
             ArtifactRepositoryLayout layout = new DefaultRepositoryLayout();
 
-            return createArtifactRepository( id, url, layout, snapshots, releases );
-        }
-        else
-        {
+            return createArtifactRepository(id, url, layout, snapshots, releases);
+        } else {
             return null;
         }
     }
 
-    public static ArtifactRepositoryPolicy buildArtifactRepositoryPolicy( org.apache.maven.model.RepositoryPolicy
-                                                                          policy )
-    {
+    public static ArtifactRepositoryPolicy buildArtifactRepositoryPolicy(
+            org.apache.maven.model.RepositoryPolicy policy) {
         boolean enabled = true;
 
         String updatePolicy = null;
 
         String checksumPolicy = null;
 
-        if ( policy != null )
-        {
+        if (policy != null) {
             enabled = policy.isEnabled();
 
-            if ( policy.getUpdatePolicy() != null )
-            {
+            if (policy.getUpdatePolicy() != null) {
                 updatePolicy = policy.getUpdatePolicy();
             }
-            if ( policy.getChecksumPolicy() != null )
-            {
+            if (policy.getChecksumPolicy() != null) {
                 checksumPolicy = policy.getChecksumPolicy();
             }
         }
 
-        return new ArtifactRepositoryPolicy( enabled, updatePolicy, checksumPolicy );
+        return new ArtifactRepositoryPolicy(enabled, updatePolicy, checksumPolicy);
     }
 
-    public ArtifactRepository createArtifactRepository( String id, String url, String layoutId,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-        throws Exception
-    {
-        ArtifactRepositoryLayout layout = layouts.get( layoutId );
+    public ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            String layoutId,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases)
+            throws InvalidRepositoryException {
+        ArtifactRepositoryLayout layout = layouts.get(layoutId);
 
-        checkLayout( id, layoutId, layout );
+        checkLayout(id, layoutId, layout);
 
-        return createArtifactRepository( id, url, layout, snapshots, releases );
+        return createArtifactRepository(id, url, layout, snapshots, releases);
     }
 
-    private void checkLayout( String repositoryId, String layoutId, ArtifactRepositoryLayout layout )
-        throws Exception
-    {
-        if ( layout == null )
-        {
-            throw new Exception( String.format( "Cannot find ArtifactRepositoryLayout instance for: %s %s", layoutId,
-                                                repositoryId ) );
+    private void checkLayout(String repositoryId, String layoutId, ArtifactRepositoryLayout layout)
+            throws InvalidRepositoryException {
+        if (layout == null) {
+            throw new InvalidRepositoryException(
+                    String.format("Cannot find ArtifactRepositoryLayout instance for: %s %s", layoutId, repositoryId),
+                    repositoryId);
         }
     }
 
-    public static ArtifactRepository createArtifactRepository( String id, String url,
-                                                        ArtifactRepositoryLayout repositoryLayout,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-    {
-        if ( snapshots == null )
-        {
+    public static ArtifactRepository createArtifactRepository(
+            String id,
+            String url,
+            ArtifactRepositoryLayout repositoryLayout,
+            ArtifactRepositoryPolicy snapshots,
+            ArtifactRepositoryPolicy releases) {
+        if (snapshots == null) {
             snapshots = new ArtifactRepositoryPolicy();
         }
 
-        if ( releases == null )
-        {
+        if (releases == null) {
             releases = new ArtifactRepositoryPolicy();
         }
 
         ArtifactRepository repository;
-        if ( repositoryLayout instanceof ArtifactRepositoryLayout2 )
-        {
-            repository =
-                ( (ArtifactRepositoryLayout2) repositoryLayout ).newMavenArtifactRepository( id, url, snapshots,
-                                                                                             releases );
-        }
-        else
-        {
-            repository = new MavenArtifactRepository( id, url, repositoryLayout, snapshots, releases );
+        if (repositoryLayout instanceof ArtifactRepositoryLayout2) {
+            repository = ((ArtifactRepositoryLayout2) repositoryLayout)
+                    .newMavenArtifactRepository(id, url, snapshots, releases);
+        } else {
+            repository = new MavenArtifactRepository(id, url, repositoryLayout, snapshots, releases);
         }
 
         return repository;
     }
 
     // ArtifactFactory
-    private Artifact createArtifactX( String groupId, String artifactId, String version, String scope, String type )
-    {
-        return createArtifactX( groupId, artifactId, version, scope, type, null, null );
+    private Artifact createArtifactX(String groupId, String artifactId, String version, String scope, String type) {
+        return createArtifactX(groupId, artifactId, version, scope, type, null, null);
     }
 
-    private Artifact createDependencyArtifactX( String groupId, String artifactId, VersionRange versionRange,
-                                               String type, String classifier, String scope, boolean optional )
-    {
-        return createArtifactX( groupId, artifactId, versionRange, type, classifier, scope, null, optional );
+    private Artifact createDependencyArtifactX(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            boolean optional) {
+        return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, null, optional);
     }
 
-    private Artifact createProjectArtifactX( String groupId, String artifactId, String version )
-    {
-        return createProjectArtifactX( groupId, artifactId, version, null );
+    private Artifact createProjectArtifactX(String groupId, String artifactId, String version) {
+        return createProjectArtifactX(groupId, artifactId, version, null);
     }
 
-    private Artifact createParentArtifactX( String groupId, String artifactId, String version )
-    {
-        return createProjectArtifactX( groupId, artifactId, version );
+    private Artifact createParentArtifactX(String groupId, String artifactId, String version) {
+        return createProjectArtifactX(groupId, artifactId, version);
     }
 
-    private Artifact createPluginArtifactX( String groupId, String artifactId, VersionRange versionRange )
-    {
-        return createArtifactX( groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null );
+    private Artifact createPluginArtifactX(String groupId, String artifactId, VersionRange versionRange) {
+        return createArtifactX(groupId, artifactId, versionRange, "maven-plugin", null, Artifact.SCOPE_RUNTIME, null);
     }
 
-    private Artifact createProjectArtifactX( String groupId, String artifactId, String version, String scope )
-    {
-        return createArtifactX( groupId, artifactId, version, scope, "pom" );
+    private Artifact createProjectArtifactX(String groupId, String artifactId, String version, String scope) {
+        return createArtifactX(groupId, artifactId, version, scope, "pom");
     }
 
-    private Artifact createExtensionArtifactX( String groupId, String artifactId, VersionRange versionRange )
-    {
-        return createArtifactX( groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null );
+    private Artifact createExtensionArtifactX(String groupId, String artifactId, VersionRange versionRange) {
+        return createArtifactX(groupId, artifactId, versionRange, "jar", null, Artifact.SCOPE_RUNTIME, null);
     }
 
-    private Artifact createArtifactX( String groupId, String artifactId, String version, String scope, String type,
-                                     String classifier, String inheritedScope )
-    {
+    private Artifact createArtifactX(
+            String groupId,
+            String artifactId,
+            String version,
+            String scope,
+            String type,
+            String classifier,
+            String inheritedScope) {
         VersionRange versionRange = null;
-        if ( version != null )
-        {
-            versionRange = VersionRange.createFromVersion( version );
+        if (version != null) {
+            versionRange = VersionRange.createFromVersion(version);
         }
-        return createArtifactX( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope );
+        return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope);
     }
 
-    private Artifact createArtifactX( String groupId, String artifactId, VersionRange versionRange, String type,
-                                     String classifier, String scope, String inheritedScope )
-    {
-        return createArtifactX( groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false );
+    private Artifact createArtifactX(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope) {
+        return createArtifactX(groupId, artifactId, versionRange, type, classifier, scope, inheritedScope, false);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private Artifact createArtifactX( String groupId, String artifactId, VersionRange versionRange, String type,
-                                     String classifier, String scope, String inheritedScope, boolean optional )
-    {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private Artifact createArtifactX(
+            String groupId,
+            String artifactId,
+            VersionRange versionRange,
+            String type,
+            String classifier,
+            String scope,
+            String inheritedScope,
+            boolean optional) {
         String desiredScope = Artifact.SCOPE_RUNTIME;
 
-        if ( inheritedScope == null )
-        {
+        if (inheritedScope == null) {
             desiredScope = scope;
-        }
-        else if ( Artifact.SCOPE_TEST.equals( scope ) || Artifact.SCOPE_PROVIDED.equals( scope ) )
-        {
+        } else if (Artifact.SCOPE_TEST.equals(scope) || Artifact.SCOPE_PROVIDED.equals(scope)) {
             return null;
-        }
-        else if ( Artifact.SCOPE_COMPILE.equals( scope ) && Artifact.SCOPE_COMPILE.equals( inheritedScope ) )
-        {
+        } else if (Artifact.SCOPE_COMPILE.equals(scope) && Artifact.SCOPE_COMPILE.equals(inheritedScope)) {
             // added to retain compile artifactScope. Remove if you want compile inherited as runtime
             desiredScope = Artifact.SCOPE_COMPILE;
         }
 
-        if ( Artifact.SCOPE_TEST.equals( inheritedScope ) )
-        {
+        if (Artifact.SCOPE_TEST.equals(inheritedScope)) {
             desiredScope = Artifact.SCOPE_TEST;
         }
 
-        if ( Artifact.SCOPE_PROVIDED.equals( inheritedScope ) )
-        {
+        if (Artifact.SCOPE_PROVIDED.equals(inheritedScope)) {
             desiredScope = Artifact.SCOPE_PROVIDED;
         }
 
-        if ( Artifact.SCOPE_SYSTEM.equals( scope ) )
-        {
+        if (Artifact.SCOPE_SYSTEM.equals(scope)) {
             // system scopes come through unchanged...
             desiredScope = Artifact.SCOPE_SYSTEM;
         }
 
-        ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( type );
+        ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(type);
 
-        return new DefaultArtifact( groupId, artifactId, versionRange, desiredScope, type, classifier, handler,
-                                    optional );
+        return new DefaultArtifact(
+                groupId, artifactId, versionRange, desiredScope, type, classifier, handler, optional);
     }
 
     //
     // Code taken from LegacyRepositorySystem
     //
-
-    public ArtifactRepository createDefaultRemoteRepository( MavenExecutionRequest request )
-        throws Exception
-    {
-        return createRepository( RepositorySystem.DEFAULT_REMOTE_REPO_URL, RepositorySystem.DEFAULT_REMOTE_REPO_ID,
-                                 true, ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY, false,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
-                                 ArtifactRepositoryPolicy.DEFAULT_CHECKSUM_POLICY );
+    public ArtifactRepository createDefaultRemoteRepository() throws Exception {
+        return createDefaultRemoteRepository(null);
     }
 
-    public ArtifactRepository createRepository( String url, String repositoryId, boolean releases,
-                                                 String releaseUpdates, boolean snapshots, String snapshotUpdates,
-                                                 String checksumPolicy ) throws Exception
-    {
+    public ArtifactRepository createDefaultRemoteRepository(MavenExecutionRequest request) throws Exception {
+        return createRepository(
+                MavenRepositorySystem.DEFAULT_REMOTE_REPO_URL,
+                MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
+                false,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
+                ArtifactRepositoryPolicy.DEFAULT_CHECKSUM_POLICY);
+    }
+
+    public ArtifactRepository createRepository(
+            String url,
+            String repositoryId,
+            boolean releases,
+            String releaseUpdates,
+            boolean snapshots,
+            String snapshotUpdates,
+            String checksumPolicy)
+            throws InvalidRepositoryException {
         ArtifactRepositoryPolicy snapshotsPolicy =
-            new ArtifactRepositoryPolicy( snapshots, snapshotUpdates, checksumPolicy );
+                new ArtifactRepositoryPolicy(snapshots, snapshotUpdates, checksumPolicy);
 
         ArtifactRepositoryPolicy releasesPolicy =
-            new ArtifactRepositoryPolicy( releases, releaseUpdates, checksumPolicy );
+                new ArtifactRepositoryPolicy(releases, releaseUpdates, checksumPolicy);
 
-        return createArtifactRepository( repositoryId, url, "default", snapshotsPolicy, releasesPolicy );
+        return createArtifactRepository(repositoryId, url, "default", snapshotsPolicy, releasesPolicy);
     }
 
-    public Set<String> getRepoIds( List<ArtifactRepository> repositories )
-    {
+    public Set<String> getRepoIds(List<ArtifactRepository> repositories) {
         Set<String> repoIds = new HashSet<>();
 
-        if ( repositories != null )
-        {
-            for ( ArtifactRepository repository : repositories )
-            {
-                repoIds.add( repository.getId() );
+        if (repositories != null) {
+            for (ArtifactRepository repository : repositories) {
+                repoIds.add(repository.getId());
             }
         }
 
@@ -618,98 +576,90 @@
      * @return corresponding effective repositories
      * @since 3.6.1
      */
-    public List<ArtifactRepository> getEffectiveRepositories( List<ArtifactRepository> repositories )
-    {
-        if ( repositories == null )
-        {
+    public List<ArtifactRepository> getEffectiveRepositories(List<ArtifactRepository> repositories) {
+        if (repositories == null) {
             return null;
         }
 
         Map<String, List<ArtifactRepository>> reposByKey = new LinkedHashMap<>();
 
-        for ( ArtifactRepository repository : repositories )
-        {
+        for (ArtifactRepository repository : repositories) {
             String key = repository.getId();
 
-            List<ArtifactRepository> aliasedRepos = reposByKey.computeIfAbsent( key, k -> new ArrayList<>() );
+            List<ArtifactRepository> aliasedRepos = reposByKey.computeIfAbsent(key, k -> new ArrayList<>());
 
-            aliasedRepos.add( repository );
+            aliasedRepos.add(repository);
         }
 
         List<ArtifactRepository> effectiveRepositories = new ArrayList<>();
 
-        for ( List<ArtifactRepository> aliasedRepos : reposByKey.values() )
-        {
+        for (List<ArtifactRepository> aliasedRepos : reposByKey.values()) {
             List<ArtifactRepository> mirroredRepos = new ArrayList<>();
 
-            List<ArtifactRepositoryPolicy> releasePolicies =
-                    new ArrayList<>( aliasedRepos.size() );
+            List<ArtifactRepositoryPolicy> releasePolicies = new ArrayList<>(aliasedRepos.size());
 
-            for ( ArtifactRepository aliasedRepo : aliasedRepos )
-            {
-                releasePolicies.add( aliasedRepo.getReleases() );
-                mirroredRepos.addAll( aliasedRepo.getMirroredRepositories() );
+            for (ArtifactRepository aliasedRepo : aliasedRepos) {
+                releasePolicies.add(aliasedRepo.getReleases());
+                mirroredRepos.addAll(aliasedRepo.getMirroredRepositories());
             }
 
-            ArtifactRepositoryPolicy releasePolicy = getEffectivePolicy( releasePolicies );
+            ArtifactRepositoryPolicy releasePolicy = getEffectivePolicy(releasePolicies);
 
-            List<ArtifactRepositoryPolicy> snapshotPolicies =
-                    new ArrayList<>( aliasedRepos.size() );
+            List<ArtifactRepositoryPolicy> snapshotPolicies = new ArrayList<>(aliasedRepos.size());
 
-            for ( ArtifactRepository aliasedRepo : aliasedRepos )
-            {
-                snapshotPolicies.add( aliasedRepo.getSnapshots() );
+            for (ArtifactRepository aliasedRepo : aliasedRepos) {
+                snapshotPolicies.add(aliasedRepo.getSnapshots());
             }
 
-            ArtifactRepositoryPolicy snapshotPolicy = getEffectivePolicy( snapshotPolicies );
+            ArtifactRepositoryPolicy snapshotPolicy = getEffectivePolicy(snapshotPolicies);
 
-            ArtifactRepository aliasedRepo = aliasedRepos.get( 0 );
+            ArtifactRepository aliasedRepo = aliasedRepos.get(0);
 
-            ArtifactRepository effectiveRepository =
-                    createArtifactRepository( aliasedRepo.getId(), aliasedRepo.getUrl(), aliasedRepo.getLayout(),
-                            snapshotPolicy, releasePolicy );
+            ArtifactRepository effectiveRepository = createArtifactRepository(
+                    aliasedRepo.getId(), aliasedRepo.getUrl(), aliasedRepo.getLayout(), snapshotPolicy, releasePolicy);
 
-            effectiveRepository.setAuthentication( aliasedRepo.getAuthentication() );
+            effectiveRepository.setAuthentication(aliasedRepo.getAuthentication());
 
-            effectiveRepository.setProxy( aliasedRepo.getProxy() );
+            effectiveRepository.setProxy(aliasedRepo.getProxy());
 
-            effectiveRepository.setMirroredRepositories( mirroredRepos );
+            effectiveRepository.setMirroredRepositories(mirroredRepos);
 
-            effectiveRepository.setBlocked( aliasedRepo.isBlocked() );
+            effectiveRepository.setBlocked(aliasedRepo.isBlocked());
 
-            effectiveRepositories.add( effectiveRepository );
+            effectiveRepositories.add(effectiveRepository);
         }
 
         return effectiveRepositories;
     }
 
-    private ArtifactRepositoryPolicy getEffectivePolicy( Collection<ArtifactRepositoryPolicy> policies )
-    {
+    private ArtifactRepositoryPolicy getEffectivePolicy(Collection<ArtifactRepositoryPolicy> policies) {
         ArtifactRepositoryPolicy effectivePolicy = null;
 
-        for ( ArtifactRepositoryPolicy policy : policies )
-        {
-            if ( effectivePolicy == null )
-            {
-                effectivePolicy = new ArtifactRepositoryPolicy( policy );
-            }
-            else
-            {
-                effectivePolicy.merge( policy );
+        for (ArtifactRepositoryPolicy policy : policies) {
+            if (effectivePolicy == null) {
+                effectivePolicy = new ArtifactRepositoryPolicy(policy);
+            } else {
+                effectivePolicy.merge(policy);
             }
         }
 
         return effectivePolicy;
     }
 
-    public ArtifactRepository createLocalRepository( MavenExecutionRequest request, File localRepository )
-        throws Exception
-    {
-        return createRepository( "file://" + localRepository.toURI().getRawPath(),
-                                 RepositorySystem.DEFAULT_LOCAL_REPO_ID, true,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, true,
-                                 ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
-                                 ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE );
+    public ArtifactRepository createLocalRepository(MavenExecutionRequest request, File localRepository)
+            throws InvalidRepositoryException {
+        return createLocalRepository(localRepository);
+    }
+
+    public ArtifactRepository createLocalRepository(File localRepository) throws InvalidRepositoryException {
+        return createRepository(
+                "file://" + localRepository.toURI().getRawPath(),
+                MavenRepositorySystem.DEFAULT_LOCAL_REPO_ID,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                true,
+                ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
     }
 
     private static final String WILDCARD = "*";
@@ -718,24 +668,18 @@
 
     private static final String EXTERNAL_HTTP_WILDCARD = "external:http:*";
 
-    public static Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
-    {
+    public static Mirror getMirror(ArtifactRepository repository, List<Mirror> mirrors) {
         String repoId = repository.getId();
 
-        if ( repoId != null && mirrors != null )
-        {
-            for ( Mirror mirror : mirrors )
-            {
-                if ( repoId.equals( mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
-                {
+        if (repoId != null && mirrors != null) {
+            for (Mirror mirror : mirrors) {
+                if (repoId.equals(mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
                     return mirror;
                 }
             }
 
-            for ( Mirror mirror : mirrors )
-            {
-                if ( matchPattern( repository, mirror.getMirrorOf() ) && matchesLayout( repository, mirror ) )
-                {
+            for (Mirror mirror : mirrors) {
+                if (matchPattern(repository, mirror.getMirrorOf()) && matchesLayout(repository, mirror)) {
                     return mirror;
                 }
             }
@@ -758,52 +702,40 @@
      * @param pattern used for match.
      * @return true if the repository is a match to this pattern.
      */
-    static boolean matchPattern( ArtifactRepository originalRepository, String pattern )
-    {
+    static boolean matchPattern(ArtifactRepository originalRepository, String pattern) {
         boolean result = false;
         String originalId = originalRepository.getId();
 
         // simple checks first to short circuit processing below.
-        if ( WILDCARD.equals( pattern ) || pattern.equals( originalId ) )
-        {
+        if (WILDCARD.equals(pattern) || pattern.equals(originalId)) {
             result = true;
-        }
-        else
-        {
+        } else {
             // process the list
-            String[] repos = pattern.split( "," );
-            for ( String repo : repos )
-            {
+            String[] repos = pattern.split(",");
+            for (String repo : repos) {
                 // see if this is a negative match
-                if ( repo.length() > 1 && repo.startsWith( "!" ) )
-                {
-                    if ( repo.substring( 1 ).equals( originalId ) )
-                    {
+                if (repo.length() > 1 && repo.startsWith("!")) {
+                    if (repo.substring(1).equals(originalId)) {
                         // explicitly exclude. Set result and stop processing.
                         result = false;
                         break;
                     }
                 }
                 // check for exact match
-                else if ( repo.equals( originalId ) )
-                {
+                else if (repo.equals(originalId)) {
                     result = true;
                     break;
                 }
                 // check for external:*
-                else if ( EXTERNAL_WILDCARD.equals( repo ) && isExternalRepo( originalRepository ) )
-                {
+                else if (EXTERNAL_WILDCARD.equals(repo) && isExternalRepo(originalRepository)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
                 }
                 // check for external:http:*
-                else if ( EXTERNAL_HTTP_WILDCARD.equals( repo ) && isExternalHttpRepo( originalRepository ) )
-                {
+                else if (EXTERNAL_HTTP_WILDCARD.equals(repo) && isExternalHttpRepo(originalRepository)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
-                }
-                else if ( WILDCARD.equals( repo ) )
-                {
+                } else if (WILDCARD.equals(repo)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
                 }
@@ -818,23 +750,18 @@
      * @param originalRepository
      * @return true if external.
      */
-    static boolean isExternalRepo( ArtifactRepository originalRepository )
-    {
-        try
-        {
-            URL url = new URL( originalRepository.getUrl() );
-            return !( isLocal( url.getHost() ) || url.getProtocol().equals( "file" ) );
-        }
-        catch ( MalformedURLException e )
-        {
+    static boolean isExternalRepo(ArtifactRepository originalRepository) {
+        try {
+            URL url = new URL(originalRepository.getUrl());
+            return !(isLocal(url.getHost()) || url.getProtocol().equals("file"));
+        } catch (MalformedURLException e) {
             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
             return false;
         }
     }
 
-    private static boolean isLocal( String host )
-    {
-        return "localhost".equals( host ) || "127.0.0.1".equals( host );
+    private static boolean isLocal(String host) {
+        return "localhost".equals(host) || "127.0.0.1".equals(host);
     }
 
     /**
@@ -843,25 +770,22 @@
      * @param originalRepository
      * @return true if external.
      */
-    static boolean isExternalHttpRepo( ArtifactRepository originalRepository )
-    {
-        try
-        {
-            URL url = new URL( originalRepository.getUrl() );
-            return ( "http".equalsIgnoreCase( url.getProtocol() ) || "dav".equalsIgnoreCase( url.getProtocol() )
-                || "dav:http".equalsIgnoreCase( url.getProtocol() )
-                || "dav+http".equalsIgnoreCase( url.getProtocol() ) ) && !isLocal( url.getHost() );
-        }
-        catch ( MalformedURLException e )
-        {
+    static boolean isExternalHttpRepo(ArtifactRepository originalRepository) {
+        try {
+            URL url = new URL(originalRepository.getUrl());
+            return ("http".equalsIgnoreCase(url.getProtocol())
+                            || "dav".equalsIgnoreCase(url.getProtocol())
+                            || "dav:http".equalsIgnoreCase(url.getProtocol())
+                            || "dav+http".equalsIgnoreCase(url.getProtocol()))
+                    && !isLocal(url.getHost());
+        } catch (MalformedURLException e) {
             // bad url just skip it here. It should have been validated already, but the wagon lookup will deal with it
             return false;
         }
     }
 
-    static boolean matchesLayout( ArtifactRepository repository, Mirror mirror )
-    {
-        return matchesLayout( RepositoryUtils.getLayout( repository ), mirror.getMirrorOfLayouts() );
+    static boolean matchesLayout(ArtifactRepository repository, Mirror mirror) {
+        return matchesLayout(RepositoryUtils.getLayout(repository), mirror.getMirrorOfLayouts());
     }
 
     /**
@@ -872,43 +796,31 @@
      * @return {@code true} if the layouts associated with the mirror match the layout of the original repository,
      *         {@code false} otherwise.
      */
-    static boolean matchesLayout( String repoLayout, String mirrorLayout )
-    {
+    static boolean matchesLayout(String repoLayout, String mirrorLayout) {
         boolean result = false;
 
         // simple checks first to short circuit processing below.
-        if ( StringUtils.isEmpty( mirrorLayout ) || WILDCARD.equals( mirrorLayout ) )
-        {
+        if ((mirrorLayout == null || mirrorLayout.isEmpty()) || WILDCARD.equals(mirrorLayout)) {
             result = true;
-        }
-        else if ( mirrorLayout.equals( repoLayout ) )
-        {
+        } else if (mirrorLayout.equals(repoLayout)) {
             result = true;
-        }
-        else
-        {
+        } else {
             // process the list
-            String[] layouts = mirrorLayout.split( "," );
-            for ( String layout : layouts )
-            {
+            String[] layouts = mirrorLayout.split(",");
+            for (String layout : layouts) {
                 // see if this is a negative match
-                if ( layout.length() > 1 && layout.startsWith( "!" ) )
-                {
-                    if ( layout.substring( 1 ).equals( repoLayout ) )
-                    {
+                if (layout.length() > 1 && layout.startsWith("!")) {
+                    if (layout.substring(1).equals(repoLayout)) {
                         // explicitly exclude. Set result and stop processing.
                         result = false;
                         break;
                     }
                 }
                 // check for exact match
-                else if ( layout.equals( repoLayout ) )
-                {
+                else if (layout.equals(repoLayout)) {
                     result = true;
                     break;
-                }
-                else if ( WILDCARD.equals( layout ) )
-                {
+                } else if (WILDCARD.equals(layout)) {
                     result = true;
                     // don't stop processing in case a future segment explicitly excludes this repo
                 }
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/ArtifactClassRealmConstituent.java b/maven-core/src/main/java/org/apache/maven/classrealm/ArtifactClassRealmConstituent.java
index 16d3e7b..7b03114 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/ArtifactClassRealmConstituent.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/ArtifactClassRealmConstituent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.classrealm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,59 +16,48 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.classrealm;
 
 import java.io.File;
 
 import org.eclipse.aether.artifact.Artifact;
 
 /**
- * @author Benjamin Bentmann
  */
-class ArtifactClassRealmConstituent
-    implements ClassRealmConstituent
-{
+class ArtifactClassRealmConstituent implements ClassRealmConstituent {
 
     private final Artifact artifact;
 
-    ArtifactClassRealmConstituent( Artifact artifact )
-    {
+    ArtifactClassRealmConstituent(Artifact artifact) {
         this.artifact = artifact;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return artifact.getGroupId();
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifact.getArtifactId();
     }
 
-    public String getType()
-    {
+    public String getType() {
         return artifact.getExtension();
     }
 
-    public String getClassifier()
-    {
+    public String getClassifier() {
         return artifact.getClassifier();
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return artifact.getBaseVersion();
     }
 
-    public File getFile()
-    {
+    public File getFile() {
         return artifact.getFile();
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return artifact.toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmConstituent.java b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmConstituent.java
index f658eb4..6fec111 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmConstituent.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmConstituent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.classrealm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.classrealm;
 
 import java.io.File;
 
 /**
  * Describes a constituent of a class realm.
  *
- * @author Benjamin Bentmann
  */
-public interface ClassRealmConstituent
-{
+public interface ClassRealmConstituent {
 
     /**
      * Gets the group id of the constituent's artifact.
@@ -70,5 +67,4 @@
      * @return The file, never {@code null}.
      */
     File getFile();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java
index e5d1514..b0386f0 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.classrealm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.classrealm;
 
 import java.util.List;
 import java.util.Map;
@@ -32,10 +31,8 @@
  * public for technical reasons, it is not part of the public API. In particular, this interface can be changed or
  * deleted without prior notice.
  *
- * @author Benjamin Bentmann
  */
-public interface ClassRealmManager
-{
+public interface ClassRealmManager {
 
     /**
      * Gets the class realm hosting the Maven core.
@@ -59,7 +56,7 @@
      *            missing file) will automatically be excluded from the realm.
      * @return The new project realm, never {@code null}.
      */
-    ClassRealm createProjectRealm( Model model, List<Artifact> artifacts );
+    ClassRealm createProjectRealm(Model model, List<Artifact> artifacts);
 
     /**
      * Creates a new class realm for the specified build extension.
@@ -69,7 +66,7 @@
      *            missing file) will automatically be excluded from the realm.
      * @return The new extension realm, never {@code null}.
      */
-    ClassRealm createExtensionRealm( Plugin extension, List<Artifact> artifacts );
+    ClassRealm createExtensionRealm(Plugin extension, List<Artifact> artifacts);
 
     /**
      * Creates a new class realm for the specified plugin.
@@ -82,7 +79,10 @@
      *            missing file) will automatically be excluded from the realm.
      * @return The new plugin realm, never {@code null}.
      */
-    ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> parentImports,
-                                  Map<String, ClassLoader> foreignImports, List<Artifact> artifacts );
-
+    ClassRealm createPluginRealm(
+            Plugin plugin,
+            ClassLoader parent,
+            List<String> parentImports,
+            Map<String, ClassLoader> foreignImports,
+            List<Artifact> artifacts);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManagerDelegate.java b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManagerDelegate.java
index b0229b9..d56eac5 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManagerDelegate.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmManagerDelegate.java
@@ -1,5 +1,3 @@
-package org.apache.maven.classrealm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
+package org.apache.maven.classrealm;
 
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 
@@ -26,11 +24,8 @@
  * ClassRealmManagerDelegate is used to perform addition configuration of
  * class realms created by ClassRealmManager.
  *
- * @author igor
  */
-public interface ClassRealmManagerDelegate
-{
+public interface ClassRealmManagerDelegate {
 
-    void setupRealm( ClassRealm classRealm, ClassRealmRequest request );
-
+    void setupRealm(ClassRealm classRealm, ClassRealmRequest request);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmRequest.java b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmRequest.java
index f1dc427..b5fd0d9 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/ClassRealmRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.classrealm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.classrealm;
 
 import java.util.List;
 import java.util.Map;
@@ -25,16 +24,13 @@
 /**
  * Describes the requirements for a new class realm.
  *
- * @author Benjamin Bentmann
  */
-public interface ClassRealmRequest
-{
+public interface ClassRealmRequest {
 
     /**
      * The type of a class realm.
      */
-    enum RealmType
-    {
+    enum RealmType {
         /**
          * The class realm for the public API of the Maven core.
          */
@@ -97,5 +93,4 @@
      * @return The modifiable list of constituents for the class realm, never {@code null}.
      */
     List<ClassRealmConstituent> getConstituents();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java
index 50e0e3c..512e7ca 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.classrealm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.classrealm;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.net.MalformedURLException;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -31,10 +33,6 @@
 import java.util.Set;
 import java.util.TreeMap;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.classrealm.ClassRealmRequest.RealmType;
 import org.apache.maven.extension.internal.CoreExports;
@@ -45,7 +43,6 @@
 import org.codehaus.plexus.classworlds.ClassWorld;
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.classworlds.realm.DuplicateRealmException;
-import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -55,13 +52,10 @@
  * public for technical reasons, it is not part of the public API. In particular, this class can be changed or deleted
  * without prior notice.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultClassRealmManager
-    implements ClassRealmManager
-{
+public class DefaultClassRealmManager implements ClassRealmManager {
     public static final String API_REALMID = "maven.api";
 
     /**
@@ -74,7 +68,7 @@
      */
     private static final ClassLoader PARENT_CLASSLOADER = ClassWorld.class.getClassLoader();
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final ClassWorld world;
 
@@ -92,54 +86,46 @@
     private final Set<String> providedArtifacts;
 
     @Inject
-    public DefaultClassRealmManager( PlexusContainer container,
-                                     List<ClassRealmManagerDelegate> delegates,
-                                     CoreExports exports )
-    {
-        this.world = ( (MutablePlexusContainer) container ).getClassWorld();
+    public DefaultClassRealmManager(
+            PlexusContainer container, List<ClassRealmManagerDelegate> delegates, CoreExports exports) {
+        this.world = ((MutablePlexusContainer) container).getClassWorld();
         this.containerRealm = container.getContainerRealm();
         this.delegates = delegates;
 
         Map<String, ClassLoader> foreignImports = exports.getExportedPackages();
 
-        this.mavenApiRealm =
-            createRealm( API_REALMID, RealmType.Core, null /* parent */, null /* parentImports */,
-                         foreignImports, null /* artifacts */ );
+        this.mavenApiRealm = createRealm(
+                API_REALMID,
+                RealmType.Core,
+                null /* parent */,
+                null /* parentImports */,
+                foreignImports,
+                null /* artifacts */);
 
         this.providedArtifacts = exports.getExportedArtifacts();
     }
 
-    private ClassRealm newRealm( String id )
-    {
-        synchronized ( world )
-        {
+    private ClassRealm newRealm(String id) {
+        synchronized (world) {
             String realmId = id;
 
             Random random = new Random();
 
-            while ( true )
-            {
-                try
-                {
-                    ClassRealm classRealm = world.newRealm( realmId, null );
+            while (true) {
+                try {
+                    ClassRealm classRealm = world.newRealm(realmId, null);
 
-                    if ( logger.isDebugEnabled() )
-                    {
-                        logger.debug( "Created new class realm " + realmId );
-                    }
+                    logger.debug("Created new class realm {}", realmId);
 
                     return classRealm;
-                }
-                catch ( DuplicateRealmException e )
-                {
+                } catch (DuplicateRealmException e) {
                     realmId = id + '-' + random.nextInt();
                 }
             }
         }
     }
 
-    public ClassRealm getMavenApiRealm()
-    {
+    public ClassRealm getMavenApiRealm() {
         return mavenApiRealm;
     }
 
@@ -155,254 +141,199 @@
      *            missing file) will automatically be excluded from the realm.
      * @return The created class realm, never {@code null}.
      */
-    private ClassRealm createRealm( String baseRealmId, RealmType type, ClassLoader parent, List<String> parentImports,
-                                    Map<String, ClassLoader> foreignImports, List<Artifact> artifacts )
-    {
-        Set<String> artifactIds = new LinkedHashSet<>();
+    private ClassRealm createRealm(
+            String baseRealmId,
+            RealmType type,
+            ClassLoader parent,
+            List<String> parentImports,
+            Map<String, ClassLoader> foreignImports,
+            List<Artifact> artifacts) {
+        List<ClassRealmConstituent> constituents = new ArrayList<>(artifacts == null ? 0 : artifacts.size());
 
-        List<ClassRealmConstituent> constituents = new ArrayList<>();
-
-        if ( artifacts != null )
-        {
-            for ( Artifact artifact : artifacts )
-            {
-                if ( !isProvidedArtifact( artifact ) )
-                {
-                    artifactIds.add( getId( artifact ) );
-                    if ( artifact.getFile() != null )
-                    {
-                        constituents.add( new ArtifactClassRealmConstituent( artifact ) );
-                    }
+        if (artifacts != null && !artifacts.isEmpty()) {
+            for (Artifact artifact : artifacts) {
+                if (!isProvidedArtifact(artifact) && artifact.getFile() != null) {
+                    constituents.add(new ArtifactClassRealmConstituent(artifact));
+                } else if (logger.isDebugEnabled()) {
+                    logger.debug("  Excluded: {}", getId(artifact));
                 }
             }
         }
 
-        if ( parentImports != null )
-        {
-            parentImports = new ArrayList<>( parentImports );
-        }
-        else
-        {
+        if (parentImports != null) {
+            parentImports = new ArrayList<>(parentImports);
+        } else {
             parentImports = new ArrayList<>();
         }
 
-        if ( foreignImports != null )
-        {
-            foreignImports = new TreeMap<>( foreignImports );
-        }
-        else
-        {
+        if (foreignImports != null) {
+            foreignImports = new TreeMap<>(foreignImports);
+        } else {
             foreignImports = new TreeMap<>();
         }
 
-        ClassRealm classRealm = newRealm( baseRealmId );
+        ClassRealm classRealm = newRealm(baseRealmId);
 
-        if ( parent != null )
-        {
-            classRealm.setParentClassLoader( parent );
+        if (parent != null) {
+            classRealm.setParentClassLoader(parent);
         }
 
-        callDelegates( classRealm, type, parent, parentImports, foreignImports, constituents );
+        callDelegates(classRealm, type, parent, parentImports, foreignImports, constituents);
 
-        wireRealm( classRealm, parentImports, foreignImports );
+        wireRealm(classRealm, parentImports, foreignImports);
 
-        Set<String> includedIds = populateRealm( classRealm, constituents );
-
-        if ( logger.isDebugEnabled() )
-        {
-            artifactIds.removeAll( includedIds );
-
-            for ( String id : artifactIds )
-            {
-                logger.debug( "  Excluded: " + id );
-            }
-        }
+        populateRealm(classRealm, constituents);
 
         return classRealm;
     }
 
-    public ClassRealm getCoreRealm()
-    {
+    public ClassRealm getCoreRealm() {
         return containerRealm;
     }
 
-    public ClassRealm createProjectRealm( Model model, List<Artifact> artifacts )
-    {
-        Objects.requireNonNull( model, "model cannot be null" );
+    public ClassRealm createProjectRealm(Model model, List<Artifact> artifacts) {
+        Objects.requireNonNull(model, "model cannot be null");
 
         ClassLoader parent = getMavenApiRealm();
 
-        return createRealm( getKey( model ), RealmType.Project, parent, null, null, artifacts );
+        return createRealm(getKey(model), RealmType.Project, parent, null, null, artifacts);
     }
 
-    private static String getKey( Model model )
-    {
+    private static String getKey(Model model) {
         return "project>" + model.getGroupId() + ":" + model.getArtifactId() + ":" + model.getVersion();
     }
 
-    public ClassRealm createExtensionRealm( Plugin plugin, List<Artifact> artifacts )
-    {
-        Objects.requireNonNull( plugin, "plugin cannot be null" );
+    public ClassRealm createExtensionRealm(Plugin plugin, List<Artifact> artifacts) {
+        Objects.requireNonNull(plugin, "plugin cannot be null");
 
-        Map<String, ClassLoader> foreignImports =
-            Collections.singletonMap( "", getMavenApiRealm() );
+        Map<String, ClassLoader> foreignImports = Collections.singletonMap("", getMavenApiRealm());
 
-        return createRealm( getKey( plugin, true ), RealmType.Extension, PARENT_CLASSLOADER, null,
-                foreignImports, artifacts );
+        return createRealm(
+                getKey(plugin, true), RealmType.Extension, PARENT_CLASSLOADER, null, foreignImports, artifacts);
     }
 
-    private boolean isProvidedArtifact( Artifact artifact )
-    {
-        return providedArtifacts.contains( artifact.getGroupId() + ":" + artifact.getArtifactId() );
+    private boolean isProvidedArtifact(Artifact artifact) {
+        return providedArtifacts.contains(artifact.getGroupId() + ":" + artifact.getArtifactId());
     }
 
-    public ClassRealm createPluginRealm( Plugin plugin, ClassLoader parent, List<String> parentImports,
-                                         Map<String, ClassLoader> foreignImports, List<Artifact> artifacts )
-    {
-        Objects.requireNonNull( plugin, "plugin cannot be null" );
+    public ClassRealm createPluginRealm(
+            Plugin plugin,
+            ClassLoader parent,
+            List<String> parentImports,
+            Map<String, ClassLoader> foreignImports,
+            List<Artifact> artifacts) {
+        Objects.requireNonNull(plugin, "plugin cannot be null");
 
-        if ( parent == null )
-        {
+        if (parent == null) {
             parent = PARENT_CLASSLOADER;
         }
 
-        return createRealm( getKey( plugin, false ), RealmType.Plugin, parent, parentImports, foreignImports,
-                            artifacts );
+        return createRealm(getKey(plugin, false), RealmType.Plugin, parent, parentImports, foreignImports, artifacts);
     }
 
-    private static String getKey( Plugin plugin, boolean extension )
-    {
-        String version = ArtifactUtils.toSnapshotVersion( plugin.getVersion() );
-        return ( extension ? "extension>" : "plugin>" ) + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":"
-            + version;
+    private static String getKey(Plugin plugin, boolean extension) {
+        String version = ArtifactUtils.toSnapshotVersion(plugin.getVersion());
+        return (extension ? "extension>" : "plugin>") + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":"
+                + version;
     }
 
-    private static String getId( Artifact artifact )
-    {
-        return getId( artifact.getGroupId(), artifact.getArtifactId(), artifact.getExtension(),
-                      artifact.getClassifier(), artifact.getBaseVersion() );
+    private static String getId(Artifact artifact) {
+        return getId(
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getExtension(),
+                artifact.getClassifier(),
+                artifact.getBaseVersion());
     }
 
-    private static String getId( ClassRealmConstituent constituent )
-    {
-        return getId( constituent.getGroupId(), constituent.getArtifactId(), constituent.getType(),
-                      constituent.getClassifier(), constituent.getVersion() );
+    private static String getId(ClassRealmConstituent constituent) {
+        return getId(
+                constituent.getGroupId(),
+                constituent.getArtifactId(),
+                constituent.getType(),
+                constituent.getClassifier(),
+                constituent.getVersion());
     }
 
-    private static String getId( String gid, String aid, String type, String cls, String ver )
-    {
-        return gid + ':' + aid + ':' + type + ( StringUtils.isNotEmpty( cls ) ? ':' + cls : "" ) + ':' + ver;
+    private static String getId(String gid, String aid, String type, String cls, String ver) {
+        return gid + ':' + aid + ':' + type + ((cls != null && !cls.isEmpty()) ? ':' + cls : "") + ':' + ver;
     }
 
-    private void callDelegates( ClassRealm classRealm, RealmType type, ClassLoader parent, List<String> parentImports,
-                                Map<String, ClassLoader> foreignImports, List<ClassRealmConstituent> constituents )
-    {
-        List<ClassRealmManagerDelegate> delegates = new ArrayList<>( this.delegates );
+    private void callDelegates(
+            ClassRealm classRealm,
+            RealmType type,
+            ClassLoader parent,
+            List<String> parentImports,
+            Map<String, ClassLoader> foreignImports,
+            List<ClassRealmConstituent> constituents) {
+        List<ClassRealmManagerDelegate> delegates = new ArrayList<>(this.delegates);
 
-        if ( !delegates.isEmpty() )
-        {
+        if (!delegates.isEmpty()) {
             ClassRealmRequest request =
-                new DefaultClassRealmRequest( type, parent, parentImports, foreignImports, constituents );
+                    new DefaultClassRealmRequest(type, parent, parentImports, foreignImports, constituents);
 
-            for ( ClassRealmManagerDelegate delegate : delegates )
-            {
-                try
-                {
-                    delegate.setupRealm( classRealm, request );
-                }
-                catch ( Exception e )
-                {
-                    logger.error( delegate.getClass().getName() + " failed to setup class realm " + classRealm + ": "
-                        + e.getMessage(), e );
+            for (ClassRealmManagerDelegate delegate : delegates) {
+                try {
+                    delegate.setupRealm(classRealm, request);
+                } catch (Exception e) {
+                    logger.error(
+                            delegate.getClass().getName() + " failed to setup class realm " + classRealm + ": "
+                                    + e.getMessage(),
+                            e);
                 }
             }
         }
     }
 
-    private Set<String> populateRealm( ClassRealm classRealm, List<ClassRealmConstituent> constituents )
-    {
-        Set<String> includedIds = new LinkedHashSet<>();
+    private void populateRealm(ClassRealm classRealm, List<ClassRealmConstituent> constituents) {
+        logger.debug("Populating class realm {}", classRealm.getId());
 
-        if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "Populating class realm " + classRealm.getId() );
-        }
-
-        for ( ClassRealmConstituent constituent : constituents )
-        {
+        for (ClassRealmConstituent constituent : constituents) {
             File file = constituent.getFile();
 
-            String id = getId( constituent );
-            includedIds.add( id );
-
-            if ( logger.isDebugEnabled() )
-            {
-                logger.debug( "  Included: " + id );
+            if (logger.isDebugEnabled()) {
+                String id = getId(constituent);
+                logger.debug("  Included: {}", id);
             }
 
-            try
-            {
-                classRealm.addURL( file.toURI().toURL() );
-            }
-            catch ( MalformedURLException e )
-            {
+            try {
+                classRealm.addURL(file.toURI().toURL());
+            } catch (MalformedURLException e) {
                 // Not going to happen
-                logger.error( e.getMessage(), e );
+                logger.error(e.getMessage(), e);
             }
         }
-
-        return includedIds;
     }
 
-    private void wireRealm( ClassRealm classRealm, List<String> parentImports, Map<String, ClassLoader> foreignImports )
-    {
-        if ( foreignImports != null && !foreignImports.isEmpty() )
-        {
-            if ( logger.isDebugEnabled() )
-            {
-                logger.debug( "Importing foreign packages into class realm " + classRealm.getId() );
-            }
+    private void wireRealm(ClassRealm classRealm, List<String> parentImports, Map<String, ClassLoader> foreignImports) {
+        if (foreignImports != null && !foreignImports.isEmpty()) {
+            logger.debug("Importing foreign packages into class realm {}", classRealm.getId());
 
-            for ( Map.Entry<String, ClassLoader> entry : foreignImports.entrySet() )
-            {
+            for (Map.Entry<String, ClassLoader> entry : foreignImports.entrySet()) {
                 ClassLoader importedRealm = entry.getValue();
                 String imp = entry.getKey();
 
-                if ( logger.isDebugEnabled() )
-                {
-                    logger.debug( "  Imported: " + imp + " < " + getId( importedRealm ) );
-                }
+                logger.debug("  Imported: {} < {}", imp, getId(importedRealm));
 
-                classRealm.importFrom( importedRealm, imp );
+                classRealm.importFrom(importedRealm, imp);
             }
         }
 
-        if ( parentImports != null && !parentImports.isEmpty() )
-        {
-            if ( logger.isDebugEnabled() )
-            {
-                logger.debug( "Importing parent packages into class realm " + classRealm.getId() );
-            }
+        if (parentImports != null && !parentImports.isEmpty()) {
+            logger.debug("Importing parent packages into class realm {}", classRealm.getId());
 
-            for ( String imp : parentImports )
-            {
-                if ( logger.isDebugEnabled() )
-                {
-                    logger.debug( "  Imported: " + imp + " < " + getId( classRealm.getParentClassLoader() ) );
-                }
+            for (String imp : parentImports) {
+                logger.debug("  Imported: {} < {}", imp, getId(classRealm.getParentClassLoader()));
 
-                classRealm.importFromParent( imp );
+                classRealm.importFromParent(imp);
             }
         }
     }
 
-    private String getId( ClassLoader classLoader )
-    {
-        if ( classLoader instanceof ClassRealm )
-        {
-            return ( (ClassRealm) classLoader ).getId();
+    private static Object getId(ClassLoader classLoader) {
+        if (classLoader instanceof ClassRealm) {
+            return ((ClassRealm) classLoader).getId();
         }
-        return String.valueOf( classLoader );
+        return classLoader;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmRequest.java b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmRequest.java
index 8694b01..168ecdf 100644
--- a/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/classrealm/DefaultClassRealmRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.classrealm;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.classrealm;
 
 import java.util.List;
 import java.util.Map;
 
 /**
- * @author Benjamin Bentmann
  */
-class DefaultClassRealmRequest
-    implements ClassRealmRequest
-{
+class DefaultClassRealmRequest implements ClassRealmRequest {
 
     private final RealmType type;
 
@@ -39,9 +35,12 @@
 
     private final List<ClassRealmConstituent> constituents;
 
-    DefaultClassRealmRequest( RealmType type, ClassLoader parent, List<String> parentImports,
-                              Map<String, ClassLoader> foreignImports, List<ClassRealmConstituent> constituents )
-    {
+    DefaultClassRealmRequest(
+            RealmType type,
+            ClassLoader parent,
+            List<String> parentImports,
+            Map<String, ClassLoader> foreignImports,
+            List<ClassRealmConstituent> constituents) {
         this.type = type;
         this.parent = parent;
         this.parentImports = parentImports;
@@ -49,34 +48,27 @@
         this.constituents = constituents;
     }
 
-    public RealmType getType()
-    {
+    public RealmType getType() {
         return type;
     }
 
-    public ClassLoader getParent()
-    {
+    public ClassLoader getParent() {
         return parent;
     }
 
-    public List<String> getImports()
-    {
+    public List<String> getImports() {
         return getParentImports();
     }
 
-    public List<String> getParentImports()
-    {
+    public List<String> getParentImports() {
         return parentImports;
     }
 
-    public Map<String, ClassLoader> getForeignImports()
-    {
+    public Map<String, ClassLoader> getForeignImports() {
         return foreignImports;
     }
 
-    public List<ClassRealmConstituent> getConstituents()
-    {
+    public List<ClassRealmConstituent> getConstituents() {
         return constituents;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/BasedirBeanConfigurationPathTranslator.java b/maven-core/src/main/java/org/apache/maven/configuration/BasedirBeanConfigurationPathTranslator.java
index 9859f58..774fa64 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/BasedirBeanConfigurationPathTranslator.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/BasedirBeanConfigurationPathTranslator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
 
 import java.io.File;
 
 /**
  * A path translator that resolves relative paths against a specific base directory.
  *
- * @author Benjamin Bentmann
  */
-public class BasedirBeanConfigurationPathTranslator
-    implements BeanConfigurationPathTranslator
-{
+public class BasedirBeanConfigurationPathTranslator implements BeanConfigurationPathTranslator {
 
     private final File basedir;
 
@@ -38,34 +34,25 @@
      * @param basedir The base directory to resolve relative paths against, may be {@code null} to disable path
      *            translation.
      */
-    public BasedirBeanConfigurationPathTranslator( File basedir )
-    {
+    public BasedirBeanConfigurationPathTranslator(File basedir) {
         this.basedir = basedir;
     }
 
-    public File translatePath( File path )
-    {
+    public File translatePath(File path) {
         File result = path;
 
-        if ( path != null && basedir != null )
-        {
-            if ( path.isAbsolute() )
-            {
+        if (path != null && basedir != null) {
+            if (path.isAbsolute()) {
                 // path is already absolute, we're done
-            }
-            else if ( path.getPath().startsWith( File.separator ) )
-            {
+            } else if (path.getPath().startsWith(File.separator)) {
                 // drive-relative Windows path, don't align with base dir but with drive root
                 result = path.getAbsoluteFile();
-            }
-            else
-            {
+            } else {
                 // an ordinary relative path, align with base dir
-                result = new File( new File( basedir, path.getPath() ).toURI().normalize() ).getAbsoluteFile();
+                result = new File(new File(basedir, path.getPath()).toURI().normalize()).getAbsoluteFile();
             }
         }
 
         return result;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationException.java b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationException.java
index 3d10ed4..03e8543 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationException.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,24 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
 
 /**
  * Thrown when a bean couldn't be configured.
  *
- * @author Benjamin Bentmann
  */
-public class BeanConfigurationException
-    extends Exception
-{
+public class BeanConfigurationException extends Exception {
 
-    public BeanConfigurationException( String message )
-    {
-        super( message );
+    public BeanConfigurationException(String message) {
+        super(message);
     }
 
-    public BeanConfigurationException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public BeanConfigurationException(String message, Throwable cause) {
+        super(message, cause);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationPathTranslator.java b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationPathTranslator.java
index 3966339..f7b065e 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationPathTranslator.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationPathTranslator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
 
 import java.io.File;
 
@@ -25,10 +24,8 @@
  * Postprocesses filesystem paths. For instance, a path translator might want to resolve relative paths given in the
  * bean configuration against some base directory.
  *
- * @author Benjamin Bentmann
  */
-public interface BeanConfigurationPathTranslator
-{
+public interface BeanConfigurationPathTranslator {
 
     /**
      * Translates the specified path.
@@ -36,6 +33,5 @@
      * @param path The path to translate, may be {@code null}.
      * @return The translated path or {@code null} if none.
      */
-    File translatePath( File path );
-
+    File translatePath(File path);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationRequest.java b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationRequest.java
index 91d687f..31b178a 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
 
 /**
  * A request to configure a bean from some configuration in the POM or similar.
  *
- * @author Benjamin Bentmann
  */
-public interface BeanConfigurationRequest
-{
+public interface BeanConfigurationRequest {
 
     /**
      * Gets the bean to configure. Eventually, a valid request must have a bean set.
@@ -40,7 +37,7 @@
      * @param bean The bean to configure, may be {@code null}.
      * @return This request for chaining, never {@code null}.
      */
-    BeanConfigurationRequest setBean( Object bean );
+    BeanConfigurationRequest setBean(Object bean);
 
     /**
      * Gets the configuration to unmarshal into the bean.
@@ -57,7 +54,7 @@
      * @param configuration The configuration to unmarshal, may be {@code null}.
      * @return This request for chaining, never {@code null}.
      */
-    BeanConfigurationRequest setConfiguration( Object configuration );
+    BeanConfigurationRequest setConfiguration(Object configuration);
 
     /**
      * Sets the configuration to unmarshal into the bean. The configuration should be taken from
@@ -69,7 +66,7 @@
      * @param element Configuration element name to unmarshal or {@code null} to unmarshal entire configuration.
      * @return This request for chaining, never {@code null}.
      */
-    BeanConfigurationRequest setConfiguration( Object configuration, String element );
+    BeanConfigurationRequest setConfiguration(Object configuration, String element);
 
     /**
      * Returns configuration element name or {@code null}.
@@ -95,7 +92,7 @@
      * @param classLoader The class loader to load referenced types from, may be {@code null}.
      * @return This request for chaining, never {@code null}.
      */
-    BeanConfigurationRequest setClassLoader( ClassLoader classLoader );
+    BeanConfigurationRequest setClassLoader(ClassLoader classLoader);
 
     /**
      * Gets the optional preprocessor for configuration values.
@@ -110,7 +107,7 @@
      * @param valuePreprocessor The preprocessor for configuration values, may be {@code null} if unneeded.
      * @return This request for chaining, never {@code null}.
      */
-    BeanConfigurationRequest setValuePreprocessor( BeanConfigurationValuePreprocessor valuePreprocessor );
+    BeanConfigurationRequest setValuePreprocessor(BeanConfigurationValuePreprocessor valuePreprocessor);
 
     /**
      * Gets the optional path translator for configuration values unmarshalled to files.
@@ -125,6 +122,5 @@
      * @param pathTranslator The path translator for files, may be {@code null} if unneeded.
      * @return This request for chaining, never {@code null}.
      */
-    BeanConfigurationRequest setPathTranslator( BeanConfigurationPathTranslator pathTranslator );
-
+    BeanConfigurationRequest setPathTranslator(BeanConfigurationPathTranslator pathTranslator);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationValuePreprocessor.java b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationValuePreprocessor.java
index 63f8517..c554a8d 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationValuePreprocessor.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurationValuePreprocessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
 
 /**
  * Preprocesses a value from a bean configuration before the bean configurator unmarshals it into a bean property. A
  * common use case for such preprocessing is the evaluation of variables within the configuration value.
  *
- * @author Benjamin Bentmann
  */
-public interface BeanConfigurationValuePreprocessor
-{
+public interface BeanConfigurationValuePreprocessor {
 
     /**
      * Preprocesses the specified bean configuration value. The optional type provided to this method is a hint (not a
@@ -39,7 +36,5 @@
      * @return The processed configuration value or {@code null} if none.
      * @throws BeanConfigurationException If an error occurred while preprocessing the value.
      */
-    Object preprocessValue( String value, Class<?> type )
-        throws BeanConfigurationException;
-
+    Object preprocessValue(String value, Class<?> type) throws BeanConfigurationException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurator.java b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurator.java
index 36d23ec..e7ba168 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurator.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/BeanConfigurator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
 
 /**
  * Unmarshals some textual configuration from the POM or similar into the properties of a bean. This component works
@@ -26,10 +25,8 @@
  * have a public setter or be backed by an equally named field (of any visibility).
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface BeanConfigurator
-{
+public interface BeanConfigurator {
 
     /**
      * Performs the specified bean configuration.
@@ -38,7 +35,5 @@
      *            {@code null}.
      * @throws BeanConfigurationException If the bean configuration could not be successfully processed.
      */
-    void configureBean( BeanConfigurationRequest request )
-        throws BeanConfigurationException;
-
+    void configureBean(BeanConfigurationRequest request) throws BeanConfigurationException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/DefaultBeanConfigurationRequest.java b/maven-core/src/main/java/org/apache/maven/configuration/DefaultBeanConfigurationRequest.java
index 5ec69f5..232fcde 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/DefaultBeanConfigurationRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/DefaultBeanConfigurationRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,23 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
 
-import org.apache.commons.lang3.Validate;
+import java.util.Objects;
+
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginExecution;
 import org.apache.maven.model.PluginManagement;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * A basic bean configuration request.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultBeanConfigurationRequest
-    implements BeanConfigurationRequest
-{
+public class DefaultBeanConfigurationRequest implements BeanConfigurationRequest {
 
     private Object bean;
 
@@ -48,34 +44,28 @@
 
     private BeanConfigurationPathTranslator pathTranslator;
 
-    public Object getBean()
-    {
+    public Object getBean() {
         return bean;
     }
 
-    public DefaultBeanConfigurationRequest setBean( Object bean )
-    {
+    public DefaultBeanConfigurationRequest setBean(Object bean) {
         this.bean = bean;
         return this;
     }
 
-    public Object getConfiguration()
-    {
+    public Object getConfiguration() {
         return configuration;
     }
 
-    public String getConfigurationElement()
-    {
+    public String getConfigurationElement() {
         return configurationElement;
     }
 
-    public DefaultBeanConfigurationRequest setConfiguration( Object configuration )
-    {
-        return setConfiguration( configuration, null );
+    public DefaultBeanConfigurationRequest setConfiguration(Object configuration) {
+        return setConfiguration(configuration, null);
     }
 
-    public DefaultBeanConfigurationRequest setConfiguration( Object configuration, String element )
-    {
+    public DefaultBeanConfigurationRequest setConfiguration(Object configuration, String element) {
         this.configuration = configuration;
         this.configurationElement = element;
         return this;
@@ -94,56 +84,45 @@
      *            empty to use the general plugin configuration.
      * @return This request for chaining, never {@code null}.
      */
-    public DefaultBeanConfigurationRequest setConfiguration( Model model, String pluginGroupId,
-                                                             String pluginArtifactId, String pluginExecutionId )
-    {
-        Plugin plugin = findPlugin( model, pluginGroupId, pluginArtifactId );
-        if ( plugin != null )
-        {
-            if ( StringUtils.isNotEmpty( pluginExecutionId ) )
-            {
-                for ( PluginExecution execution : plugin.getExecutions() )
-                {
-                    if ( pluginExecutionId.equals( execution.getId() ) )
-                    {
-                        setConfiguration( execution.getConfiguration() );
+    public DefaultBeanConfigurationRequest setConfiguration(
+            Model model, String pluginGroupId, String pluginArtifactId, String pluginExecutionId) {
+        Plugin plugin = findPlugin(model, pluginGroupId, pluginArtifactId);
+        if (plugin != null) {
+            if (pluginExecutionId != null && !pluginExecutionId.isEmpty()) {
+                for (PluginExecution execution : plugin.getExecutions()) {
+                    if (pluginExecutionId.equals(execution.getId())) {
+                        setConfiguration(execution.getConfiguration());
                         break;
                     }
                 }
-            }
-            else
-            {
-                setConfiguration( plugin.getConfiguration() );
+            } else {
+                setConfiguration(plugin.getConfiguration());
             }
         }
         return this;
     }
 
-    private Plugin findPlugin( Model model, String groupId, String artifactId )
-    {
-        Validate.notBlank( groupId, "groupId can neither be null, empty nor blank" );
-        Validate.notBlank( artifactId, "artifactId can neither be null, empty nor blank" );
+    private Plugin findPlugin(Model model, String groupId, String artifactId) {
+        if (Objects.requireNonNull(groupId, "groupId cannot be null").isEmpty()) {
+            throw new IllegalArgumentException("groupId cannot be empty");
+        }
+        if (Objects.requireNonNull(artifactId, "artifactId cannot be null").isEmpty()) {
+            throw new IllegalArgumentException("artifactId cannot be empty");
+        }
 
-        if ( model != null )
-        {
+        if (model != null) {
             Build build = model.getBuild();
-            if ( build != null )
-            {
-                for ( Plugin plugin : build.getPlugins() )
-                {
-                    if ( groupId.equals( plugin.getGroupId() ) && artifactId.equals( plugin.getArtifactId() ) )
-                    {
+            if (build != null) {
+                for (Plugin plugin : build.getPlugins()) {
+                    if (groupId.equals(plugin.getGroupId()) && artifactId.equals(plugin.getArtifactId())) {
                         return plugin;
                     }
                 }
 
                 PluginManagement mgmt = build.getPluginManagement();
-                if ( mgmt != null )
-                {
-                    for ( Plugin plugin : mgmt.getPlugins() )
-                    {
-                        if ( groupId.equals( plugin.getGroupId() ) && artifactId.equals( plugin.getArtifactId() ) )
-                        {
+                if (mgmt != null) {
+                    for (Plugin plugin : mgmt.getPlugins()) {
+                        if (groupId.equals(plugin.getGroupId()) && artifactId.equals(plugin.getArtifactId())) {
                             return plugin;
                         }
                     }
@@ -154,37 +133,30 @@
         return null;
     }
 
-    public ClassLoader getClassLoader()
-    {
+    public ClassLoader getClassLoader() {
         return classLoader;
     }
 
-    public DefaultBeanConfigurationRequest setClassLoader( ClassLoader classLoader )
-    {
+    public DefaultBeanConfigurationRequest setClassLoader(ClassLoader classLoader) {
         this.classLoader = classLoader;
         return this;
     }
 
-    public BeanConfigurationValuePreprocessor getValuePreprocessor()
-    {
+    public BeanConfigurationValuePreprocessor getValuePreprocessor() {
         return valuePreprocessor;
     }
 
-    public DefaultBeanConfigurationRequest setValuePreprocessor( BeanConfigurationValuePreprocessor valuePreprocessor )
-    {
+    public DefaultBeanConfigurationRequest setValuePreprocessor(BeanConfigurationValuePreprocessor valuePreprocessor) {
         this.valuePreprocessor = valuePreprocessor;
         return this;
     }
 
-    public BeanConfigurationPathTranslator getPathTranslator()
-    {
+    public BeanConfigurationPathTranslator getPathTranslator() {
         return pathTranslator;
     }
 
-    public DefaultBeanConfigurationRequest setPathTranslator( BeanConfigurationPathTranslator pathTranslator )
-    {
+    public DefaultBeanConfigurationRequest setPathTranslator(BeanConfigurationPathTranslator pathTranslator) {
         this.pathTranslator = pathTranslator;
         return this;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/internal/DefaultBeanConfigurator.java b/maven-core/src/main/java/org/apache/maven/configuration/internal/DefaultBeanConfigurator.java
index ed01875..42e9848 100644
--- a/maven-core/src/main/java/org/apache/maven/configuration/internal/DefaultBeanConfigurator.java
+++ b/maven-core/src/main/java/org/apache/maven/configuration/internal/DefaultBeanConfigurator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,23 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.util.Objects;
+package org.apache.maven.configuration.internal;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.configuration.BeanConfigurationException;
 import org.apache.maven.configuration.BeanConfigurationPathTranslator;
 import org.apache.maven.configuration.BeanConfigurationRequest;
 import org.apache.maven.configuration.BeanConfigurationValuePreprocessor;
 import org.apache.maven.configuration.BeanConfigurator;
+import org.apache.maven.internal.xml.XmlNodeImpl;
 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.ConfigurationListener;
+import org.codehaus.plexus.component.configurator.converters.AbstractConfigurationConverter;
+import org.codehaus.plexus.component.configurator.converters.basic.AbstractBasicConverter;
 import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter;
 import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
-import org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
 import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
 import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
@@ -44,114 +52,153 @@
  * <strong>Warning:</strong> This is an internal class that is only public for technical reasons, it is not part of the
  * public API. In particular, this class can be changed or deleted without prior notice.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultBeanConfigurator
-    implements BeanConfigurator
-{
+public class DefaultBeanConfigurator implements BeanConfigurator {
 
-    private final ConverterLookup converterLookup = new DefaultConverterLookup();
+    private final ConverterLookup converterLookup;
 
-    public void configureBean( BeanConfigurationRequest request )
-        throws BeanConfigurationException
-    {
-        Objects.requireNonNull( request, "request cannot be null" );
-        Objects.requireNonNull( request.getBean(), "request.bean cannot be null" );
+    public DefaultBeanConfigurator() {
+        converterLookup = new EnhancedConverterLookup();
+    }
+
+    public void configureBean(BeanConfigurationRequest request) throws BeanConfigurationException {
+        Objects.requireNonNull(request, "request cannot be null");
+        Objects.requireNonNull(request.getBean(), "request.bean cannot be null");
 
         Object configuration = request.getConfiguration();
-        if ( configuration == null )
-        {
+        if (configuration == null) {
             return;
         }
 
         PlexusConfiguration plexusConfig;
-        if ( configuration instanceof PlexusConfiguration )
-        {
+        if (configuration instanceof PlexusConfiguration) {
             plexusConfig = (PlexusConfiguration) configuration;
-        }
-        else if ( configuration instanceof Xpp3Dom )
-        {
-            plexusConfig = new XmlPlexusConfiguration( (Xpp3Dom) configuration );
-        }
-        else
-        {
-            throw new BeanConfigurationException( "unsupported bean configuration source ("
-                + configuration.getClass().getName() + ")" );
+        } else if (configuration instanceof Xpp3Dom) {
+            plexusConfig = new XmlPlexusConfiguration((Xpp3Dom) configuration);
+        } else {
+            throw new BeanConfigurationException("unsupported bean configuration source ("
+                    + configuration.getClass().getName() + ")");
         }
 
-        if ( request.getConfigurationElement() != null )
-        {
-            plexusConfig = plexusConfig.getChild( request.getConfigurationElement() );
+        if (request.getConfigurationElement() != null) {
+            plexusConfig = plexusConfig.getChild(request.getConfigurationElement());
         }
 
         ClassLoader classLoader = request.getClassLoader();
-        if ( classLoader == null )
-        {
+        if (classLoader == null) {
             classLoader = request.getBean().getClass().getClassLoader();
         }
 
-        BeanExpressionEvaluator evaluator = new BeanExpressionEvaluator( request );
+        BeanExpressionEvaluator evaluator = new BeanExpressionEvaluator(request);
 
-        ObjectWithFieldsConverter converter = new ObjectWithFieldsConverter();
+        ObjectWithFieldsConverter converter = new EnhancedConfigurationConverter();
 
-        try
-        {
-            converter.processConfiguration( converterLookup, request.getBean(), classLoader, plexusConfig, evaluator );
-        }
-        catch ( ComponentConfigurationException e )
-        {
-            throw new BeanConfigurationException( e.getMessage(), e );
+        try {
+            converter.processConfiguration(
+                    converterLookup, request.getBean(), classLoader, plexusConfig, evaluator, null);
+        } catch (ComponentConfigurationException e) {
+            throw new BeanConfigurationException(e.getMessage(), e);
         }
     }
 
-    static class BeanExpressionEvaluator
-        implements TypeAwareExpressionEvaluator
-    {
+    static class BeanExpressionEvaluator implements TypeAwareExpressionEvaluator {
 
         private final BeanConfigurationValuePreprocessor preprocessor;
 
         private final BeanConfigurationPathTranslator translator;
 
-        BeanExpressionEvaluator( BeanConfigurationRequest request )
-        {
+        BeanExpressionEvaluator(BeanConfigurationRequest request) {
             preprocessor = request.getValuePreprocessor();
             translator = request.getPathTranslator();
         }
 
-        public Object evaluate( String expression, Class<?> type )
-            throws ExpressionEvaluationException
-        {
-            if ( preprocessor != null )
-            {
-                try
-                {
-                    return preprocessor.preprocessValue( expression, type );
-                }
-                catch ( BeanConfigurationException e )
-                {
-                    throw new ExpressionEvaluationException( e.getMessage(), e );
+        public Object evaluate(String expression, Class<?> type) throws ExpressionEvaluationException {
+            if (preprocessor != null) {
+                try {
+                    return preprocessor.preprocessValue(expression, type);
+                } catch (BeanConfigurationException e) {
+                    throw new ExpressionEvaluationException(e.getMessage(), e);
                 }
             }
             return expression;
         }
 
-        public Object evaluate( String expression )
-            throws ExpressionEvaluationException
-        {
-            return evaluate( expression, null );
+        public Object evaluate(String expression) throws ExpressionEvaluationException {
+            return evaluate(expression, null);
         }
 
-        public File alignToBaseDirectory( File file )
-        {
-            if ( translator != null )
-            {
-                return translator.translatePath( file );
+        public File alignToBaseDirectory(File file) {
+            if (translator != null) {
+                return translator.translatePath(file);
             }
             return file;
         }
-
     }
 
+    static class XmlConverter extends AbstractConfigurationConverter {
+        @Override
+        public boolean canConvert(Class<?> type) {
+            return XmlNode.class.equals(type);
+        }
+
+        @Override
+        public Object fromConfiguration(
+                final ConverterLookup lookup,
+                final PlexusConfiguration configuration,
+                final Class<?> type,
+                final Class<?> enclosingType,
+                final ClassLoader loader,
+                final ExpressionEvaluator evaluator,
+                final ConfigurationListener listener)
+                throws ComponentConfigurationException {
+
+            try {
+                return toXml(configuration, evaluator);
+            } catch (ExpressionEvaluationException e) {
+                throw new ComponentConfigurationException("Unable to convert configuration to xml node", e);
+            }
+        }
+
+        XmlNode toXml(PlexusConfiguration config, ExpressionEvaluator evaluator) throws ExpressionEvaluationException {
+            List<XmlNode> children = new ArrayList<>();
+            for (PlexusConfiguration c : config.getChildren()) {
+                children.add(toXml(c, evaluator));
+            }
+            String name = config.getName();
+            Object value = evaluator.evaluate(config.getValue());
+            return new XmlNodeImpl(name, value != null ? value.toString() : null, null, children, null);
+        }
+    }
+
+    static class PathConverter extends AbstractBasicConverter {
+        @Override
+        public boolean canConvert(Class<?> type) {
+            return Path.class.equals(type);
+        }
+
+        @Override
+        protected Object fromString(String value) throws ComponentConfigurationException {
+            return Paths.get(value.replace('/' == File.separatorChar ? '\\' : '/', File.separatorChar));
+        }
+
+        @Override
+        public Object fromConfiguration(
+                final ConverterLookup lookup,
+                final PlexusConfiguration configuration,
+                final Class<?> type,
+                final Class<?> enclosingType,
+                final ClassLoader loader,
+                final ExpressionEvaluator evaluator,
+                final ConfigurationListener listener)
+                throws ComponentConfigurationException {
+            final Object result =
+                    super.fromConfiguration(lookup, configuration, type, enclosingType, loader, evaluator, listener);
+
+            return result instanceof Path
+                    ? evaluator.alignToBaseDirectory(((Path) result).toFile()).toPath()
+                    : result;
+        }
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedComponentConfigurator.java b/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedComponentConfigurator.java
new file mode 100644
index 0000000..f41a1d6
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedComponentConfigurator.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.configuration.internal;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.component.configurator.BasicComponentConfigurator;
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.ConfigurationListener;
+import org.codehaus.plexus.component.configurator.converters.special.ClassRealmConverter;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+
+/**
+ * A component configurator which can leverage the {@link EnhancedConfigurationConverter}
+ * and {@link EnhancedConverterLookup}.
+ */
+@Singleton
+@Named("enhanced")
+public class EnhancedComponentConfigurator extends BasicComponentConfigurator {
+
+    public EnhancedComponentConfigurator() {
+        converterLookup = new EnhancedConverterLookup();
+    }
+
+    @Override
+    public void configureComponent(
+            final Object component,
+            final PlexusConfiguration configuration,
+            final ExpressionEvaluator evaluator,
+            final ClassRealm realm,
+            final ConfigurationListener listener)
+            throws ComponentConfigurationException {
+        try {
+            ClassRealmConverter.pushContextRealm(realm);
+
+            new EnhancedConfigurationConverter()
+                    .processConfiguration(
+                            converterLookup,
+                            component,
+                            realm, //
+                            configuration,
+                            evaluator,
+                            listener);
+        } finally {
+            ClassRealmConverter.popContextRealm();
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedConfigurationConverter.java b/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedConfigurationConverter.java
new file mode 100644
index 0000000..f782763
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedConfigurationConverter.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.configuration.internal;
+
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.ConfigurationListener;
+import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter;
+import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.eclipse.sisu.plexus.CompositeBeanHelper;
+
+/**
+ * An enhanced {@link ObjectWithFieldsConverter} leveraging the {@link TypeAwareExpressionEvaluator}
+ * interface.
+ */
+class EnhancedConfigurationConverter extends ObjectWithFieldsConverter {
+    protected Object fromExpression(
+            final PlexusConfiguration configuration, final ExpressionEvaluator evaluator, final Class<?> type)
+            throws ComponentConfigurationException {
+        String value = configuration.getValue();
+        try {
+            Object result = null;
+            if (null != value && value.length() > 0) {
+                if (evaluator instanceof TypeAwareExpressionEvaluator) {
+                    result = ((TypeAwareExpressionEvaluator) evaluator).evaluate(value, type);
+                } else {
+                    result = evaluator.evaluate(value);
+                }
+            }
+            if (null == result && configuration.getChildCount() == 0) {
+                value = configuration.getAttribute("default-value");
+                if (null != value && value.length() > 0) {
+                    if (evaluator instanceof TypeAwareExpressionEvaluator) {
+                        result = ((TypeAwareExpressionEvaluator) evaluator).evaluate(value, type);
+                    } else {
+                        result = evaluator.evaluate(value);
+                    }
+                }
+            }
+            failIfNotTypeCompatible(result, type, configuration);
+            return result;
+        } catch (final ExpressionEvaluationException e) {
+            final String reason = String.format(
+                    "Cannot evaluate expression '%s' for configuration entry '%s'", value, configuration.getName());
+
+            throw new ComponentConfigurationException(configuration, reason, e);
+        }
+    }
+
+    public Object fromConfiguration(
+            final ConverterLookup lookup,
+            final PlexusConfiguration configuration,
+            final Class<?> type,
+            final Class<?> enclosingType,
+            final ClassLoader loader,
+            final ExpressionEvaluator evaluator,
+            final ConfigurationListener listener)
+            throws ComponentConfigurationException {
+        final Object value = fromExpression(configuration, evaluator, type);
+        if (type.isInstance(value)) {
+            return value;
+        }
+        try {
+            final Class<?> implType = getClassForImplementationHint(type, configuration, loader);
+            if (null == value && implType.isInterface() && configuration.getChildCount() == 0) {
+                return null; // nothing to process
+            }
+            final Object bean = instantiateObject(implType);
+            if (null == value) {
+                processConfiguration(lookup, bean, loader, configuration, evaluator, listener);
+            } else {
+                new CompositeBeanHelper(lookup, loader, evaluator, listener).setDefault(bean, value, configuration);
+            }
+            return bean;
+        } catch (final ComponentConfigurationException e) {
+            if (null == e.getFailedConfiguration()) {
+                e.setFailedConfiguration(configuration);
+            }
+            throw e;
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedConverterLookup.java b/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedConverterLookup.java
new file mode 100644
index 0000000..55c2a5c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/configuration/internal/EnhancedConverterLookup.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.configuration.internal;
+
+import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
+import org.codehaus.plexus.component.configurator.converters.ConfigurationConverter;
+import org.codehaus.plexus.component.configurator.converters.composite.ObjectWithFieldsConverter;
+import org.codehaus.plexus.component.configurator.converters.lookup.ConverterLookup;
+import org.codehaus.plexus.component.configurator.converters.lookup.DefaultConverterLookup;
+
+class EnhancedConverterLookup implements ConverterLookup {
+    private final ConverterLookup delegate = new DefaultConverterLookup();
+
+    EnhancedConverterLookup() {
+        registerConverter(new DefaultBeanConfigurator.PathConverter());
+        registerConverter(new DefaultBeanConfigurator.XmlConverter());
+    }
+
+    @Override
+    public void registerConverter(ConfigurationConverter converter) {
+        delegate.registerConverter(converter);
+    }
+
+    @Override
+    public ConfigurationConverter lookupConverterForType(Class<?> type) throws ComponentConfigurationException {
+        ConfigurationConverter converter = delegate.lookupConverterForType(type);
+        return converter.getClass().equals(ObjectWithFieldsConverter.class)
+                ? new EnhancedConfigurationConverter()
+                : converter;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/eventspy/AbstractEventSpy.java b/maven-core/src/main/java/org/apache/maven/eventspy/AbstractEventSpy.java
index 0913227..13efb34 100644
--- a/maven-core/src/main/java/org/apache/maven/eventspy/AbstractEventSpy.java
+++ b/maven-core/src/main/java/org/apache/maven/eventspy/AbstractEventSpy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.eventspy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,28 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.eventspy;
 
 /**
  * A skeleton eventspy that does nothing other than helping implementors.
  * @since 3.0.2
  */
-public abstract class AbstractEventSpy
-    implements EventSpy
-{
+public abstract class AbstractEventSpy implements EventSpy {
 
-    public void init( Context context )
-        throws Exception
-    {
-    }
+    public void init(Context context) throws Exception {}
 
-    public void onEvent( Object event )
-        throws Exception
-    {
-    }
+    public void onEvent(Object event) throws Exception {}
 
-    public void close()
-        throws Exception
-    {
-    }
-
+    public void close() throws Exception {}
 }
diff --git a/maven-core/src/main/java/org/apache/maven/eventspy/EventSpy.java b/maven-core/src/main/java/org/apache/maven/eventspy/EventSpy.java
index cd7e1cc..14f6d57 100644
--- a/maven-core/src/main/java/org/apache/maven/eventspy/EventSpy.java
+++ b/maven-core/src/main/java/org/apache/maven/eventspy/EventSpy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.eventspy;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,24 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.eventspy;
 
 import java.util.Map;
 
 /**
  * A core extension to monitor Maven's execution. Typically, such an extension gets loaded into Maven by specifying the
- * system property {@code maven.ext.class.path} on the command line. As soon as dependency injection is set up, Maven
+ * property {@code maven.ext.class.path} on the command line. As soon as dependency injection is set up, Maven
  * looks up all implementers of this interface and calls their {@link #init(Context)} method. <em>Note:</em>
  * Implementors are strongly advised to inherit from {@link AbstractEventSpy} instead of directly implementing this
  * interface.
  * @since 3.0.2
  */
-public interface EventSpy
-{
+public interface EventSpy {
     /**
      * Context
      */
-    interface Context
-    {
+    interface Context {
 
         /**
          * Gets key-value pairs providing information about the Maven runtime.
@@ -43,7 +40,6 @@
          * @return The key-value pairs, never {@code null}.
          */
         Map<String, Object> getData();
-
     }
 
     /**
@@ -51,8 +47,7 @@
      *
      * @param context The event spy context, never {@code null}.
      */
-    void init( Context context )
-        throws Exception;
+    void init(Context context) throws Exception;
 
     /**
      * Notifies the spy of some build event/operation.
@@ -67,13 +62,10 @@
      * @see org.apache.maven.execution.ExecutionEvent
      * @see org.eclipse.aether.RepositoryEvent
      */
-    void onEvent( Object event )
-        throws Exception;
+    void onEvent(Object event) throws Exception;
 
     /**
      * Notifies the spy of Maven's termination, allowing it to free any resources allocated by it.
      */
-    void close()
-        throws Exception;
-
+    void close() throws Exception;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyDispatcher.java b/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyDispatcher.java
index 4b04a18..7b1d682 100644
--- a/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyDispatcher.java
+++ b/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyDispatcher.java
@@ -1,5 +1,3 @@
-package org.apache.maven.eventspy.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.List;
+package org.apache.maven.eventspy.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.maven.eventspy.EventSpy;
 import org.apache.maven.execution.ExecutionListener;
 import org.eclipse.aether.RepositoryListener;
@@ -38,106 +37,77 @@
  */
 @Named
 @Singleton
-public class EventSpyDispatcher
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class EventSpyDispatcher {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final List<EventSpy> eventSpies;
 
     @Inject
-    public EventSpyDispatcher( List<EventSpy> eventSpies )
-    {
+    public EventSpyDispatcher(List<EventSpy> eventSpies) {
         // make copy to get rid of needless overhead for dynamic lookups
-        this.eventSpies = new ArrayList<>( eventSpies );
+        this.eventSpies = new ArrayList<>(eventSpies);
     }
 
-    public ExecutionListener chainListener( ExecutionListener listener )
-    {
-        if ( eventSpies.isEmpty() )
-        {
+    public ExecutionListener chainListener(ExecutionListener listener) {
+        if (eventSpies.isEmpty()) {
             return listener;
         }
-        return new EventSpyExecutionListener( this, listener );
+        return new EventSpyExecutionListener(this, listener);
     }
 
-    public RepositoryListener chainListener( RepositoryListener listener )
-    {
-        if ( eventSpies.isEmpty() )
-        {
+    public RepositoryListener chainListener(RepositoryListener listener) {
+        if (eventSpies.isEmpty()) {
             return listener;
         }
-        return new EventSpyRepositoryListener( this, listener );
+        return new EventSpyRepositoryListener(this, listener);
     }
 
-    public void init( EventSpy.Context context )
-    {
-        if ( eventSpies.isEmpty() )
-        {
+    public void init(EventSpy.Context context) {
+        if (eventSpies.isEmpty()) {
             return;
         }
-        for ( EventSpy eventSpy : eventSpies )
-        {
-            try
-            {
-                eventSpy.init( context );
-            }
-            catch ( Exception | LinkageError e )
-            {
-                logError( "initialize", e, eventSpy );
+        for (EventSpy eventSpy : eventSpies) {
+            try {
+                eventSpy.init(context);
+            } catch (Exception | LinkageError e) {
+                logError("initialize", e, eventSpy);
             }
         }
     }
 
-    public void onEvent( Object event )
-    {
-        if ( eventSpies.isEmpty() )
-        {
+    public void onEvent(Object event) {
+        if (eventSpies.isEmpty()) {
             return;
         }
-        for ( EventSpy eventSpy : eventSpies )
-        {
-            try
-            {
-                eventSpy.onEvent( event );
-            }
-            catch ( Exception | LinkageError e )
-            {
-                logError( "notify", e, eventSpy );
+        for (EventSpy eventSpy : eventSpies) {
+            try {
+                eventSpy.onEvent(event);
+            } catch (Exception | LinkageError e) {
+                logError("notify", e, eventSpy);
             }
         }
     }
 
-    public void close()
-    {
-        if ( eventSpies.isEmpty() )
-        {
+    public void close() {
+        if (eventSpies.isEmpty()) {
             return;
         }
-        for ( EventSpy eventSpy : eventSpies )
-        {
-            try
-            {
+        for (EventSpy eventSpy : eventSpies) {
+            try {
                 eventSpy.close();
-            }
-            catch ( Exception | LinkageError e )
-            {
-                logError( "close", e, eventSpy );
+            } catch (Exception | LinkageError e) {
+                logError("close", e, eventSpy);
             }
         }
     }
 
-    private void logError( String action, Throwable e, EventSpy spy )
-    {
+    private void logError(String action, Throwable e, EventSpy spy) {
         String msg = "Failed to " + action + " spy " + spy.getClass().getName() + ": " + e.getMessage();
 
-        if ( logger.isDebugEnabled() )
-        {
-            logger.warn( msg, e );
-        }
-        else
-        {
-            logger.warn( msg );
+        if (logger.isDebugEnabled()) {
+            logger.warn(msg, e);
+        } else {
+            logger.warn(msg);
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyExecutionListener.java b/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyExecutionListener.java
index b79b720..e240d54 100644
--- a/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.eventspy.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.eventspy.internal;
 
 import org.apache.maven.execution.AbstractExecutionListener;
 import org.apache.maven.execution.ExecutionEvent;
@@ -27,137 +26,116 @@
  * Forwards execution events to EventSpies.
  * @since 3.0.2
  */
-class EventSpyExecutionListener
-    extends AbstractExecutionListener
-{
+class EventSpyExecutionListener extends AbstractExecutionListener {
 
     private final EventSpyDispatcher dispatcher;
 
     private final ExecutionListener delegate;
 
-    EventSpyExecutionListener( EventSpyDispatcher dispatcher, ExecutionListener delegate )
-    {
+    EventSpyExecutionListener(EventSpyDispatcher dispatcher, ExecutionListener delegate) {
         this.dispatcher = dispatcher;
         this.delegate = delegate;
     }
 
     @Override
-    public void projectDiscoveryStarted( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.projectDiscoveryStarted( event );
+    public void projectDiscoveryStarted(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.projectDiscoveryStarted(event);
     }
 
     @Override
-    public void sessionStarted( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.sessionStarted( event );
+    public void sessionStarted(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.sessionStarted(event);
     }
 
     @Override
-    public void sessionEnded( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.sessionEnded( event );
+    public void sessionEnded(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.sessionEnded(event);
     }
 
     @Override
-    public void projectSkipped( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.projectSkipped( event );
+    public void projectSkipped(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.projectSkipped(event);
     }
 
     @Override
-    public void projectStarted( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.projectStarted( event );
+    public void projectStarted(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.projectStarted(event);
     }
 
     @Override
-    public void projectSucceeded( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.projectSucceeded( event );
+    public void projectSucceeded(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.projectSucceeded(event);
     }
 
     @Override
-    public void projectFailed( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.projectFailed( event );
+    public void projectFailed(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.projectFailed(event);
     }
 
     @Override
-    public void forkStarted( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.forkStarted( event );
+    public void forkStarted(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.forkStarted(event);
     }
 
     @Override
-    public void forkSucceeded( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.forkSucceeded( event );
+    public void forkSucceeded(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.forkSucceeded(event);
     }
 
     @Override
-    public void forkFailed( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.forkFailed( event );
+    public void forkFailed(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.forkFailed(event);
     }
 
     @Override
-    public void mojoSkipped( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.mojoSkipped( event );
+    public void mojoSkipped(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.mojoSkipped(event);
     }
 
     @Override
-    public void mojoStarted( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.mojoStarted( event );
+    public void mojoStarted(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.mojoStarted(event);
     }
 
     @Override
-    public void mojoSucceeded( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.mojoSucceeded( event );
+    public void mojoSucceeded(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.mojoSucceeded(event);
     }
 
     @Override
-    public void mojoFailed( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.mojoFailed( event );
+    public void mojoFailed(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.mojoFailed(event);
     }
 
     @Override
-    public void forkedProjectStarted( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.forkedProjectStarted( event );
+    public void forkedProjectStarted(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.forkedProjectStarted(event);
     }
 
     @Override
-    public void forkedProjectSucceeded( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.forkedProjectSucceeded( event );
+    public void forkedProjectSucceeded(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.forkedProjectSucceeded(event);
     }
 
     @Override
-    public void forkedProjectFailed( ExecutionEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.forkedProjectFailed( event );
+    public void forkedProjectFailed(ExecutionEvent event) {
+        dispatcher.onEvent(event);
+        delegate.forkedProjectFailed(event);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyRepositoryListener.java b/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyRepositoryListener.java
index aef3226..fe2724c 100644
--- a/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyRepositoryListener.java
+++ b/maven-core/src/main/java/org/apache/maven/eventspy/internal/EventSpyRepositoryListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.eventspy.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.eventspy.internal;
 
 import org.eclipse.aether.AbstractRepositoryListener;
 import org.eclipse.aether.RepositoryEvent;
@@ -27,150 +26,127 @@
  * Forwards repository events to EventSpies.
  * @since 3.0.2
  */
-class EventSpyRepositoryListener
-    extends AbstractRepositoryListener
-{
+class EventSpyRepositoryListener extends AbstractRepositoryListener {
     private final EventSpyDispatcher dispatcher;
 
     private final RepositoryListener delegate;
 
-    EventSpyRepositoryListener( EventSpyDispatcher dispatcher, RepositoryListener delegate )
-    {
+    EventSpyRepositoryListener(EventSpyDispatcher dispatcher, RepositoryListener delegate) {
         this.dispatcher = dispatcher;
         this.delegate = delegate;
     }
 
     @Override
-    public void artifactDeployed( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactDeployed( event );
+    public void artifactDeployed(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactDeployed(event);
     }
 
     @Override
-    public void artifactDeploying( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactDeploying( event );
+    public void artifactDeploying(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactDeploying(event);
     }
 
     @Override
-    public void artifactDescriptorInvalid( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactDescriptorInvalid( event );
+    public void artifactDescriptorInvalid(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactDescriptorInvalid(event);
     }
 
     @Override
-    public void artifactDescriptorMissing( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactDescriptorMissing( event );
+    public void artifactDescriptorMissing(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactDescriptorMissing(event);
     }
 
     @Override
-    public void artifactInstalled( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactInstalled( event );
+    public void artifactInstalled(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactInstalled(event);
     }
 
     @Override
-    public void artifactInstalling( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactInstalling( event );
+    public void artifactInstalling(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactInstalling(event);
     }
 
     @Override
-    public void artifactResolved( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactResolved( event );
+    public void artifactResolved(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactResolved(event);
     }
 
     @Override
-    public void artifactResolving( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactResolving( event );
+    public void artifactResolving(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactResolving(event);
     }
 
     @Override
-    public void metadataDeployed( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataDeployed( event );
+    public void metadataDeployed(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataDeployed(event);
     }
 
     @Override
-    public void metadataDeploying( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataDeploying( event );
+    public void metadataDeploying(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataDeploying(event);
     }
 
     @Override
-    public void metadataInstalled( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataInstalled( event );
+    public void metadataInstalled(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataInstalled(event);
     }
 
     @Override
-    public void metadataInstalling( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataInstalling( event );
+    public void metadataInstalling(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataInstalling(event);
     }
 
     @Override
-    public void metadataInvalid( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataInvalid( event );
+    public void metadataInvalid(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataInvalid(event);
     }
 
     @Override
-    public void metadataResolved( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataResolved( event );
+    public void metadataResolved(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataResolved(event);
     }
 
     @Override
-    public void metadataResolving( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataResolving( event );
+    public void metadataResolving(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataResolving(event);
     }
 
     @Override
-    public void artifactDownloaded( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactDownloaded( event );
+    public void artifactDownloaded(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactDownloaded(event);
     }
 
     @Override
-    public void artifactDownloading( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.artifactDownloading( event );
+    public void artifactDownloading(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.artifactDownloading(event);
     }
 
     @Override
-    public void metadataDownloaded( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataDownloaded( event );
+    public void metadataDownloaded(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataDownloaded(event);
     }
 
     @Override
-    public void metadataDownloading( RepositoryEvent event )
-    {
-        dispatcher.onEvent( event );
-        delegate.metadataDownloading( event );
+    public void metadataDownloading(RepositoryEvent event) {
+        dispatcher.onEvent(event);
+        delegate.metadataDownloading(event);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java b/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java
index 3e21587..f1d0afd 100644
--- a/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java
+++ b/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.exception;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.exception;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.IOException;
 import java.net.ConnectException;
@@ -25,9 +27,6 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.building.ModelProblem;
 import org.apache.maven.model.building.ModelProblemUtils;
@@ -38,7 +37,6 @@
 import org.apache.maven.plugin.PluginExecutionException;
 import org.apache.maven.project.ProjectBuildingException;
 import org.apache.maven.project.ProjectBuildingResult;
-import org.codehaus.plexus.util.StringUtils;
 
 /*
 
@@ -90,248 +88,185 @@
  */
 @Named
 @Singleton
-public class DefaultExceptionHandler
-    implements ExceptionHandler
-{
+public class DefaultExceptionHandler implements ExceptionHandler {
 
-    public ExceptionSummary handleException( Throwable exception )
-    {
-        return handle( "", exception );
+    public ExceptionSummary handleException(Throwable exception) {
+        return handle("", exception);
     }
 
-    private ExceptionSummary handle( String message, Throwable exception )
-    {
-        String reference = getReference( exception );
+    private ExceptionSummary handle(String message, Throwable exception) {
+        String reference = getReference(exception);
 
         List<ExceptionSummary> children = null;
 
-        if ( exception instanceof ProjectBuildingException )
-        {
-            List<ProjectBuildingResult> results = ( (ProjectBuildingException) exception ).getResults();
+        if (exception instanceof ProjectBuildingException) {
+            List<ProjectBuildingResult> results = ((ProjectBuildingException) exception).getResults();
 
             children = new ArrayList<>();
 
-            for ( ProjectBuildingResult result : results )
-            {
-                ExceptionSummary child = handle( result );
-                if ( child != null )
-                {
-                    children.add( child );
+            for (ProjectBuildingResult result : results) {
+                ExceptionSummary child = handle(result);
+                if (child != null) {
+                    children.add(child);
                 }
             }
 
-            message = "The build could not read " + children.size() + " project" + ( children.size() == 1 ? "" : "s" );
-        }
-        else
-        {
-            message = getMessage( message, exception );
+            message = "The build could not read " + children.size() + " project" + (children.size() == 1 ? "" : "s");
+        } else {
+            message = getMessage(message, exception);
         }
 
-        return new ExceptionSummary( exception, message, reference, children );
+        return new ExceptionSummary(exception, message, reference, children);
     }
 
-    private ExceptionSummary handle( ProjectBuildingResult result )
-    {
+    private ExceptionSummary handle(ProjectBuildingResult result) {
         List<ExceptionSummary> children = new ArrayList<>();
 
-        for ( ModelProblem problem : result.getProblems() )
-        {
-            ExceptionSummary child = handle( problem, result.getProjectId() );
-            if ( child != null )
-            {
-                children.add( child );
+        for (ModelProblem problem : result.getProblems()) {
+            ExceptionSummary child = handle(problem, result.getProjectId());
+            if (child != null) {
+                children.add(child);
             }
         }
 
-        if ( children.isEmpty() )
-        {
+        if (children.isEmpty()) {
             return null;
         }
 
         String message = System.lineSeparator()
-            + "The project " + ( result.getProjectId().isEmpty() ? "" : result.getProjectId() + " " )
-            + "(" + result.getPomFile() + ") has "
-            + children.size() + " error" + ( children.size() == 1 ? "" : "s" );
+                + "The project " + (result.getProjectId().isEmpty() ? "" : result.getProjectId() + " ")
+                + "(" + result.getPomFile() + ") has "
+                + children.size() + " error" + (children.size() == 1 ? "" : "s");
 
-        return new ExceptionSummary( null, message, null, children );
+        return new ExceptionSummary(null, message, null, children);
     }
 
-    private ExceptionSummary handle( ModelProblem problem, String projectId )
-    {
-        if ( ModelProblem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
-        {
+    private ExceptionSummary handle(ModelProblem problem, String projectId) {
+        if (ModelProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
             String message = problem.getMessage();
 
-            String location = ModelProblemUtils.formatLocation( problem, projectId );
+            String location = ModelProblemUtils.formatLocation(problem, projectId);
 
-            if ( !location.isEmpty() )
-            {
+            if (!location.isEmpty()) {
                 message += " @ " + location;
             }
 
-            return handle( message, problem.getException() );
-        }
-        else
-        {
+            return handle(message, problem.getException());
+        } else {
             return null;
         }
     }
 
-    private String getReference( Throwable exception )
-    {
+    private String getReference(Throwable exception) {
         String reference = "";
 
-        if ( exception != null )
-        {
-            if ( exception instanceof MojoExecutionException )
-            {
+        if (exception != null) {
+            if (exception instanceof MojoExecutionException) {
                 reference = MojoExecutionException.class.getSimpleName();
 
                 Throwable cause = exception.getCause();
-                if ( cause instanceof IOException )
-                {
+                if (cause instanceof IOException) {
                     cause = cause.getCause();
-                    if ( cause instanceof ConnectException )
-                    {
+                    if (cause instanceof ConnectException) {
                         reference = ConnectException.class.getSimpleName();
                     }
                 }
-            }
-            else if ( exception instanceof MojoFailureException )
-            {
+            } else if (exception instanceof MojoFailureException) {
                 reference = MojoFailureException.class.getSimpleName();
-            }
-            else if ( exception instanceof LinkageError )
-            {
+            } else if (exception instanceof LinkageError) {
                 reference = LinkageError.class.getSimpleName();
-            }
-            else if ( exception instanceof PluginExecutionException )
-            {
+            } else if (exception instanceof PluginExecutionException) {
                 Throwable cause = exception.getCause();
 
-                if ( cause instanceof PluginContainerException )
-                {
+                if (cause instanceof PluginContainerException) {
                     Throwable cause2 = cause.getCause();
 
-                    if ( cause2 instanceof NoClassDefFoundError )
-                    {
+                    if (cause2 instanceof NoClassDefFoundError) {
                         String message = cause2.getMessage();
-                        if ( message != null && message.contains( "org/sonatype/aether/" ) )
-                        {
+                        if (message != null && message.contains("org/sonatype/aether/")) {
                             reference = "AetherClassNotFound";
                         }
                     }
                 }
 
-                if ( StringUtils.isEmpty( reference ) )
-                {
-                    reference = getReference( cause );
+                if (reference == null || reference.isEmpty()) {
+                    reference = getReference(cause);
                 }
 
-                if ( StringUtils.isEmpty( reference ) )
-                {
+                if (reference == null || reference.isEmpty()) {
                     reference = exception.getClass().getSimpleName();
                 }
-            }
-            else if ( exception instanceof LifecycleExecutionException )
-            {
-                reference = getReference( exception.getCause() );
-            }
-            else if ( isNoteworthyException( exception ) )
-            {
+            } else if (exception instanceof LifecycleExecutionException) {
+                reference = getReference(exception.getCause());
+            } else if (isNoteworthyException(exception)) {
                 reference = exception.getClass().getSimpleName();
             }
         }
 
-        if ( StringUtils.isNotEmpty( reference ) && !reference.startsWith( "http:" ) )
-        {
+        if ((reference != null && !reference.isEmpty()) && !reference.startsWith("http:")) {
             reference = "http://cwiki.apache.org/confluence/display/MAVEN/" + reference;
         }
 
         return reference;
     }
 
-    private boolean isNoteworthyException( Throwable exception )
-    {
-        if ( exception == null )
-        {
+    private boolean isNoteworthyException(Throwable exception) {
+        if (exception == null) {
             return false;
-        }
-        else if ( exception instanceof Error )
-        {
+        } else if (exception instanceof Error) {
             return true;
-        }
-        else if ( exception instanceof RuntimeException )
-        {
+        } else if (exception instanceof RuntimeException) {
             return false;
-        }
-        else
-        {
-            return !exception.getClass().getName().startsWith( "java" );
+        } else {
+            return !exception.getClass().getName().startsWith("java");
         }
     }
 
-    private String getMessage( String message, Throwable exception )
-    {
-        String fullMessage = ( message != null ) ? message : "";
+    private String getMessage(String message, Throwable exception) {
+        String fullMessage = (message != null) ? message : "";
 
-        for ( Throwable t = exception; t != null; t = t.getCause() )
-        {
+        // To break out of possible endless loop when getCause returns "this"
+        for (Throwable t = exception; t != null && t != t.getCause(); t = t.getCause()) {
             String exceptionMessage = t.getMessage();
 
-            if ( t instanceof AbstractMojoExecutionException )
-            {
-                String longMessage = ( (AbstractMojoExecutionException) t ).getLongMessage();
-                if ( StringUtils.isNotEmpty( longMessage ) )
-                {
-                    if ( StringUtils.isEmpty( exceptionMessage ) || longMessage.contains( exceptionMessage ) )
-                    {
+            if (t instanceof AbstractMojoExecutionException) {
+                String longMessage = ((AbstractMojoExecutionException) t).getLongMessage();
+                if (longMessage != null && !longMessage.isEmpty()) {
+                    if ((exceptionMessage == null || exceptionMessage.isEmpty())
+                            || longMessage.contains(exceptionMessage)) {
                         exceptionMessage = longMessage;
-                    }
-                    else if ( !exceptionMessage.contains( longMessage ) )
-                    {
-                        exceptionMessage = join( exceptionMessage, System.lineSeparator() + longMessage );
+                    } else if (!exceptionMessage.contains(longMessage)) {
+                        exceptionMessage = join(exceptionMessage, System.lineSeparator() + longMessage);
                     }
                 }
             }
 
-            if ( StringUtils.isEmpty( exceptionMessage ) )
-            {
+            if (exceptionMessage == null || exceptionMessage.isEmpty()) {
                 exceptionMessage = t.getClass().getSimpleName();
             }
 
-            if ( t instanceof UnknownHostException && !fullMessage.contains( "host" ) )
-            {
-                fullMessage = join( fullMessage, "Unknown host " + exceptionMessage );
-            }
-            else if ( !fullMessage.contains( exceptionMessage ) )
-            {
-                fullMessage = join( fullMessage, exceptionMessage );
+            if (t instanceof UnknownHostException && !fullMessage.contains("host")) {
+                fullMessage = join(fullMessage, "Unknown host " + exceptionMessage);
+            } else if (!fullMessage.contains(exceptionMessage)) {
+                fullMessage = join(fullMessage, exceptionMessage);
             }
         }
 
         return fullMessage.trim();
     }
 
-    private String join( String message1, String message2 )
-    {
+    private String join(String message1, String message2) {
         String message = "";
 
-        if ( StringUtils.isNotEmpty( message1 ) )
-        {
+        if (message1 != null && !message1.isEmpty()) {
             message = message1.trim();
         }
 
-        if ( StringUtils.isNotEmpty( message2 ) )
-        {
-            if ( StringUtils.isNotEmpty( message ) )
-            {
-                if ( message.endsWith( "." ) || message.endsWith( "!" ) || message.endsWith( ":" ) )
-                {
+        if (message2 != null && !message2.isEmpty()) {
+            if (message != null && !message.isEmpty()) {
+                if (message.endsWith(".") || message.endsWith("!") || message.endsWith(":")) {
                     message += " ";
-                }
-                else
-                {
+                } else {
                     message += ": ";
                 }
             }
@@ -341,5 +276,4 @@
 
         return message;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/exception/ExceptionHandler.java b/maven-core/src/main/java/org/apache/maven/exception/ExceptionHandler.java
index 47865f6..b68f378 100644
--- a/maven-core/src/main/java/org/apache/maven/exception/ExceptionHandler.java
+++ b/maven-core/src/main/java/org/apache/maven/exception/ExceptionHandler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.exception;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.exception;
 
 /**
  * Transform an exception into useful end-user message.
  *
  * @since 3.0-alpha-3
  */
-public interface ExceptionHandler
-{
-    ExceptionSummary handleException( Throwable e );
+public interface ExceptionHandler {
+    ExceptionSummary handleException(Throwable e);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java b/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java
index b72bab6..7473e38 100644
--- a/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java
+++ b/maven-core/src/main/java/org/apache/maven/exception/ExceptionSummary.java
@@ -1,5 +1,3 @@
-package org.apache.maven.exception;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.exception;
 
 import java.util.Collections;
 import java.util.List;
@@ -32,8 +31,7 @@
  * <li>child exception summaries.</li>
  * </ul>
  */
-public class ExceptionSummary
-{
+public class ExceptionSummary {
 
     private Throwable exception;
 
@@ -43,40 +41,30 @@
 
     private List<ExceptionSummary> children;
 
-    public ExceptionSummary( Throwable exception, String message, String reference )
-    {
-        this( exception, message, reference, null );
+    public ExceptionSummary(Throwable exception, String message, String reference) {
+        this(exception, message, reference, null);
     }
 
-    public ExceptionSummary( Throwable exception, String message, String reference, List<ExceptionSummary> children )
-    {
+    public ExceptionSummary(Throwable exception, String message, String reference, List<ExceptionSummary> children) {
         this.exception = exception;
-        this.message = ( message != null ) ? message : "";
-        this.reference = ( reference != null ) ? reference : "";
-        this.children = ( children != null )
-                            ? Collections.unmodifiableList( children )
-                            : Collections.emptyList();
-
+        this.message = (message != null) ? message : "";
+        this.reference = (reference != null) ? reference : "";
+        this.children = (children != null) ? Collections.unmodifiableList(children) : Collections.emptyList();
     }
 
-    public Throwable getException()
-    {
+    public Throwable getException() {
         return exception;
     }
 
-    public String getMessage()
-    {
+    public String getMessage() {
         return message;
     }
 
-    public String getReference()
-    {
+    public String getReference() {
         return reference;
     }
 
-    public List<ExceptionSummary> getChildren()
-    {
+    public List<ExceptionSummary> getChildren() {
         return children;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/AbstractExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/AbstractExecutionListener.java
index 8966500..058300a 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/AbstractExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/AbstractExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,99 +16,79 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 /**
  * Provides a skeleton implementation for execution listeners. The methods of this class are empty.
  *
- * @author Benjamin Bentmann
  */
-public class AbstractExecutionListener
-    implements ExecutionListener
-{
+public class AbstractExecutionListener implements ExecutionListener {
 
-    public void projectDiscoveryStarted( ExecutionEvent event )
-    {
+    public void projectDiscoveryStarted(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void sessionStarted( ExecutionEvent event )
-    {
+    public void sessionStarted(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void sessionEnded( ExecutionEvent event )
-    {
+    public void sessionEnded(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void projectSkipped( ExecutionEvent event )
-    {
+    public void projectSkipped(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void projectStarted( ExecutionEvent event )
-    {
+    public void projectStarted(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void projectSucceeded( ExecutionEvent event )
-    {
+    public void projectSucceeded(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void projectFailed( ExecutionEvent event )
-    {
+    public void projectFailed(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void forkStarted( ExecutionEvent event )
-    {
+    public void forkStarted(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void forkSucceeded( ExecutionEvent event )
-    {
+    public void forkSucceeded(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void forkFailed( ExecutionEvent event )
-    {
+    public void forkFailed(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void mojoSkipped( ExecutionEvent event )
-    {
+    public void mojoSkipped(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void mojoStarted( ExecutionEvent event )
-    {
+    public void mojoStarted(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void mojoSucceeded( ExecutionEvent event )
-    {
+    public void mojoSucceeded(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void mojoFailed( ExecutionEvent event )
-    {
+    public void mojoFailed(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void forkedProjectStarted( ExecutionEvent event )
-    {
+    public void forkedProjectStarted(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void forkedProjectSucceeded( ExecutionEvent event )
-    {
+    public void forkedProjectSucceeded(ExecutionEvent event) {
         // default does nothing
     }
 
-    public void forkedProjectFailed( ExecutionEvent event )
-    {
+    public void forkedProjectFailed(ExecutionEvent event) {
         // default does nothing
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java b/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java
index 4e8f8a2..a56b1f7 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ActivationSettings.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 /**
  * Describes whether a target should be activated or not, and if that is required or optional.
  */
-enum ActivationSettings
-{
-    ACTIVATION_OPTIONAL( true, true ),
-    ACTIVATION_REQUIRED( true, false ),
-    DEACTIVATION_OPTIONAL( false, true ),
-    DEACTIVATION_REQUIRED( false, false );
+enum ActivationSettings {
+    ACTIVATION_OPTIONAL(true, true),
+    ACTIVATION_REQUIRED(true, false),
+    DEACTIVATION_OPTIONAL(false, true),
+    DEACTIVATION_REQUIRED(false, false);
 
     /**
      * Should the target be active?
@@ -38,20 +36,15 @@
      */
     final boolean optional;
 
-    ActivationSettings( final boolean active, final boolean optional )
-    {
+    ActivationSettings(final boolean active, final boolean optional) {
         this.active = active;
         this.optional = optional;
     }
 
-    static ActivationSettings of( final boolean active, final boolean optional )
-    {
-        if ( optional )
-        {
+    static ActivationSettings of(final boolean active, final boolean optional) {
+        if (optional) {
             return active ? ACTIVATION_OPTIONAL : DEACTIVATION_OPTIONAL;
-        }
-        else
-        {
+        } else {
             return active ? ACTIVATION_REQUIRED : DEACTIVATION_REQUIRED;
         }
     }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildFailure.java b/maven-core/src/main/java/org/apache/maven/execution/BuildFailure.java
index bf8f62b..cd71550 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildFailure.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildFailure.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.project.MavenProject;
 
 /**
  * Summarizes the result of a failed project build in the reactor.
  *
- * @author Benjamin Bentmann
  */
-public class BuildFailure
-    extends BuildSummary
-{
+public class BuildFailure extends BuildSummary {
 
     /**
      * The cause of the build failure.
@@ -42,9 +38,8 @@
      * @param time The build time of the project in milliseconds.
      * @param cause The cause of the build failure, may be {@code null}.
      */
-    public BuildFailure( MavenProject project, long time, Throwable cause )
-    {
-        super( project, time );
+    public BuildFailure(MavenProject project, long time, Throwable cause) {
+        super(project, time);
         this.cause = cause;
     }
 
@@ -53,9 +48,7 @@
      *
      * @return The cause of the build failure or {@code null} if unknown.
      */
-    public Throwable getCause()
-    {
+    public Throwable getCause() {
         return cause;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionAnalyzer.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionAnalyzer.java
index fa3db8a..0ce454a 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionAnalyzer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionAnalyzer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.Optional;
 
@@ -25,12 +24,11 @@
  * Instances of this class are responsible for determining whether it makes sense to "resume" a build (i.e., using
  * the {@code --resume} flag.
  */
-public interface BuildResumptionAnalyzer
-{
+public interface BuildResumptionAnalyzer {
     /**
      * Construct an instance of {@link BuildResumptionData} based on the outcome of the current Maven build.
      * @param result Outcome of the current Maven build.
      * @return A {@link BuildResumptionData} instance or {@link Optional#empty()} if resuming the build is not possible.
      */
-    Optional<BuildResumptionData> determineBuildResumptionData( MavenExecutionResult result );
+    Optional<BuildResumptionData> determineBuildResumptionData(MavenExecutionResult result);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
index 4aa5e25..d46adf2 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionData.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,21 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.List;
 
 /**
  * This class holds the information required to enable resuming a Maven build with {@code --resume}.
  */
-public class BuildResumptionData
-{
+public class BuildResumptionData {
     /**
      * The list of projects that remain to be built.
      */
     private final List<String> remainingProjects;
 
-    public BuildResumptionData ( final List<String> remainingProjects )
-    {
+    public BuildResumptionData(final List<String> remainingProjects) {
         this.remainingProjects = remainingProjects;
     }
 
@@ -40,9 +37,7 @@
      * Returns the projects that still need to be built when resuming.
      * @return A list containing the group and artifact id of the projects.
      */
-    public List<String> getRemainingProjects()
-    {
+    public List<String> getRemainingProjects() {
         return this.remainingProjects;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
index 36453f6..fa09f1f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionDataRepository.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.project.MavenProject;
 
@@ -26,8 +25,7 @@
  * builds of the same project, that have the -r command-line flag, skip successfully built projects during earlier
  * invocations of Maven.
  */
-public interface BuildResumptionDataRepository
-{
+public interface BuildResumptionDataRepository {
     /**
      * Persists any data needed to resume the build at a later point in time, using a new Maven invocation. This method
      * may also decide it is not needed or meaningful to persist such data, and return <code>false</code> to indicate
@@ -37,7 +35,7 @@
      * @param buildResumptionData Information needed to resume the build.
      * @throws BuildResumptionPersistenceException When an error occurs while persisting data.
      */
-    void persistResumptionData( MavenProject rootProject, BuildResumptionData buildResumptionData )
+    void persistResumptionData(MavenProject rootProject, BuildResumptionData buildResumptionData)
             throws BuildResumptionPersistenceException;
 
     /**
@@ -45,12 +43,11 @@
      * @param request The execution request that will be enriched.
      * @param rootProject The root project that is being built.
      */
-    void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject );
+    void applyResumptionData(MavenExecutionRequest request, MavenProject rootProject);
 
     /**
      * Removes previously stored resumption data.
      * @param rootProject The root project that is being built.
      */
-    void removeResumptionData( MavenProject rootProject );
-
+    void removeResumptionData(MavenProject rootProject);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
index 1f9e802..2b5566e 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildResumptionPersistenceException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 /**
  * This exception will be thrown when something fails while persisting build resumption data.
  * @see BuildResumptionDataRepository#persistResumptionData
  */
-public class BuildResumptionPersistenceException extends Exception
-{
-    public BuildResumptionPersistenceException( String message, Throwable cause )
-    {
-        super( message, cause );
+public class BuildResumptionPersistenceException extends Exception {
+    public BuildResumptionPersistenceException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildSuccess.java b/maven-core/src/main/java/org/apache/maven/execution/BuildSuccess.java
index 3d0e8bd..0f0310d 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildSuccess.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildSuccess.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.project.MavenProject;
 
 /**
  * Summarizes the result of a successful project build in the reactor.
  *
- * @author Benjamin Bentmann
  */
-public class BuildSuccess
-    extends BuildSummary
-{
+public class BuildSuccess extends BuildSummary {
 
     /**
      * Creates a new build summary for the specified project.
@@ -36,9 +32,7 @@
      * @param project The project being summarized, must not be {@code null}.
      * @param time The build time of the project in milliseconds.
      */
-    public BuildSuccess( MavenProject project, long time )
-    {
-        super( project, time );
+    public BuildSuccess(MavenProject project, long time) {
+        super(project, time);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/BuildSummary.java b/maven-core/src/main/java/org/apache/maven/execution/BuildSummary.java
index 79599b5..657afb3 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/BuildSummary.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/BuildSummary.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.Objects;
 
@@ -26,10 +25,8 @@
 /**
  * Summarizes the result of a project build in the reactor.
  *
- * @author Benjamin Bentmann
  */
-public abstract class BuildSummary
-{
+public abstract class BuildSummary {
 
     /**
      * The project being summarized.
@@ -47,9 +44,8 @@
      * @param project The project being summarized, must not be {@code null}.
      * @param time The build time of the project in milliseconds.
      */
-    protected BuildSummary( MavenProject project, long time )
-    {
-        this.project = Objects.requireNonNull( project, "project cannot be null" );
+    protected BuildSummary(MavenProject project, long time) {
+        this.project = Objects.requireNonNull(project, "project cannot be null");
         // TODO Validate for < 0?
         this.time = time;
     }
@@ -59,8 +55,7 @@
      *
      * @return The project being summarized, never {@code null}.
      */
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
@@ -69,9 +64,7 @@
      *
      * @return The build time of the project in milliseconds.
      */
-    public long getTime()
-    {
+    public long getTime() {
         return time;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzer.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzer.java
index d8d1183..0bc99bd 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzer.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,57 +16,53 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 import org.apache.maven.project.MavenProject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.util.List;
-import java.util.Optional;
-import java.util.stream.Collectors;
-
 /**
  * Default implementation of {@link BuildResumptionAnalyzer}.
  */
 @Named
 @Singleton
-public class DefaultBuildResumptionAnalyzer implements BuildResumptionAnalyzer
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionAnalyzer.class );
+public class DefaultBuildResumptionAnalyzer implements BuildResumptionAnalyzer {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultBuildResumptionAnalyzer.class);
 
     @Override
-    public Optional<BuildResumptionData> determineBuildResumptionData( final MavenExecutionResult result )
-    {
-        if ( !result.hasExceptions() )
-        {
+    public Optional<BuildResumptionData> determineBuildResumptionData(final MavenExecutionResult result) {
+        if (!result.hasExceptions()) {
             return Optional.empty();
         }
 
         List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
 
-        boolean hasNoSuccess = sortedProjects.stream()
-                .noneMatch( project -> result.getBuildSummary( project ) instanceof BuildSuccess );
+        boolean hasNoSuccess =
+                sortedProjects.stream().noneMatch(project -> result.getBuildSummary(project) instanceof BuildSuccess);
 
-        if ( hasNoSuccess )
-        {
+        if (hasNoSuccess) {
             return Optional.empty();
         }
 
         List<String> remainingProjects = sortedProjects.stream()
-                .filter( project -> result.getBuildSummary( project ) == null
-                        || result.getBuildSummary( project ) instanceof BuildFailure )
-                .map( project -> project.getGroupId() + ":" + project.getArtifactId() )
-                .collect( Collectors.toList() );
+                .filter(project -> result.getBuildSummary(project) == null
+                        || result.getBuildSummary(project) instanceof BuildFailure)
+                .map(project -> project.getGroupId() + ":" + project.getArtifactId())
+                .collect(Collectors.toList());
 
-        if ( remainingProjects.isEmpty() )
-        {
-            LOGGER.info( "No remaining projects found, resuming the build would not make sense." );
+        if (remainingProjects.isEmpty()) {
+            LOGGER.info("No remaining projects found, resuming the build would not make sense.");
             return Optional.empty();
         }
 
-        return Optional.of( new BuildResumptionData( remainingProjects ) );
+        return Optional.of(new BuildResumptionData(remainingProjects));
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
index 73a0c1a..8a4ded8 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultBuildResumptionDataRepository.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.commons.lang3.StringUtils;
-import org.apache.maven.project.MavenProject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+package org.apache.maven.execution;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
+
 import java.io.IOException;
 import java.io.Reader;
 import java.io.Writer;
@@ -35,105 +30,91 @@
 import java.util.Properties;
 import java.util.stream.Stream;
 
+import org.apache.maven.project.MavenProject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * This implementation of {@link BuildResumptionDataRepository} persists information in a properties file. The file is
  * stored in the build output directory under the Maven execution root.
  */
 @Named
 @Singleton
-public class DefaultBuildResumptionDataRepository implements BuildResumptionDataRepository
-{
+public class DefaultBuildResumptionDataRepository implements BuildResumptionDataRepository {
     private static final String RESUME_PROPERTIES_FILENAME = "resume.properties";
     private static final String REMAINING_PROJECTS = "remainingProjects";
     private static final String PROPERTY_DELIMITER = ", ";
-    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultBuildResumptionDataRepository.class );
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultBuildResumptionDataRepository.class);
 
     @Override
-    public void persistResumptionData( MavenProject rootProject, BuildResumptionData buildResumptionData )
-            throws BuildResumptionPersistenceException
-    {
-        Properties properties = convertToProperties( buildResumptionData );
+    public void persistResumptionData(MavenProject rootProject, BuildResumptionData buildResumptionData)
+            throws BuildResumptionPersistenceException {
+        Properties properties = convertToProperties(buildResumptionData);
 
-        Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
-        try
-        {
-            Files.createDirectories( resumeProperties.getParent() );
-            try ( Writer writer = Files.newBufferedWriter( resumeProperties ) )
-            {
-                properties.store( writer, null );
+        Path resumeProperties = Paths.get(rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME);
+        try {
+            Files.createDirectories(resumeProperties.getParent());
+            try (Writer writer = Files.newBufferedWriter(resumeProperties)) {
+                properties.store(writer, null);
             }
-        }
-        catch ( IOException e )
-        {
+        } catch (IOException e) {
             String message = "Could not create " + RESUME_PROPERTIES_FILENAME + " file.";
-            throw new BuildResumptionPersistenceException( message, e );
+            throw new BuildResumptionPersistenceException(message, e);
         }
     }
 
-    private Properties convertToProperties( final BuildResumptionData buildResumptionData )
-    {
+    private Properties convertToProperties(final BuildResumptionData buildResumptionData) {
         Properties properties = new Properties();
 
-        String value = String.join( PROPERTY_DELIMITER, buildResumptionData.getRemainingProjects() );
-        properties.setProperty( REMAINING_PROJECTS, value );
+        String value = String.join(PROPERTY_DELIMITER, buildResumptionData.getRemainingProjects());
+        properties.setProperty(REMAINING_PROJECTS, value);
 
         return properties;
     }
 
     @Override
-    public void applyResumptionData( MavenExecutionRequest request, MavenProject rootProject )
-    {
-        Properties properties = loadResumptionFile( Paths.get( rootProject.getBuild().getDirectory() ) );
-        applyResumptionProperties( request, properties );
+    public void applyResumptionData(MavenExecutionRequest request, MavenProject rootProject) {
+        Properties properties =
+                loadResumptionFile(Paths.get(rootProject.getBuild().getDirectory()));
+        applyResumptionProperties(request, properties);
     }
 
     @Override
-    public void removeResumptionData( MavenProject rootProject )
-    {
-        Path resumeProperties = Paths.get( rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME );
-        try
-        {
-            Files.deleteIfExists( resumeProperties );
-        }
-        catch ( IOException e )
-        {
-            LOGGER.warn( "Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e );
+    public void removeResumptionData(MavenProject rootProject) {
+        Path resumeProperties = Paths.get(rootProject.getBuild().getDirectory(), RESUME_PROPERTIES_FILENAME);
+        try {
+            Files.deleteIfExists(resumeProperties);
+        } catch (IOException e) {
+            LOGGER.warn("Could not delete {} file. ", RESUME_PROPERTIES_FILENAME, e);
         }
     }
 
-    private Properties loadResumptionFile( Path rootBuildDirectory )
-    {
+    private Properties loadResumptionFile(Path rootBuildDirectory) {
         Properties properties = new Properties();
-        Path path = rootBuildDirectory.resolve( RESUME_PROPERTIES_FILENAME );
-        if ( !Files.exists( path ) )
-        {
-            LOGGER.warn( "The {} file does not exist. The --resume / -r feature will not work.", path );
+        Path path = rootBuildDirectory.resolve(RESUME_PROPERTIES_FILENAME);
+        if (!Files.exists(path)) {
+            LOGGER.warn("The {} file does not exist. The --resume / -r feature will not work.", path);
             return properties;
         }
 
-        try ( Reader reader = Files.newBufferedReader( path ) )
-        {
-            properties.load( reader );
-        }
-        catch ( IOException e )
-        {
-            LOGGER.warn( "Unable to read {}. The --resume / -r feature will not work.", path );
+        try (Reader reader = Files.newBufferedReader(path)) {
+            properties.load(reader);
+        } catch (IOException e) {
+            LOGGER.warn("Unable to read {}. The --resume / -r feature will not work.", path);
         }
 
         return properties;
     }
 
     // This method is made package-private for testing purposes
-    void applyResumptionProperties( MavenExecutionRequest request, Properties properties )
-    {
-        if ( properties.containsKey( REMAINING_PROJECTS )
-                && StringUtils.isEmpty( request.getResumeFrom() ) )
-        {
-            String propertyValue = properties.getProperty( REMAINING_PROJECTS );
-            Stream.of( propertyValue.split( PROPERTY_DELIMITER ) )
-                    .filter( StringUtils::isNotEmpty )
-                    .forEach( request.getProjectActivation()::activateOptionalProject );
-            LOGGER.info( "Resuming from {} due to the --resume / -r feature.", propertyValue );
+    void applyResumptionProperties(MavenExecutionRequest request, Properties properties) {
+        String str1 = request.getResumeFrom();
+        if (properties.containsKey(REMAINING_PROJECTS) && !(str1 != null && !str1.isEmpty())) {
+            String propertyValue = properties.getProperty(REMAINING_PROJECTS);
+            Stream.of(propertyValue.split(PROPERTY_DELIMITER))
+                    .filter(str -> str != null && !str.isEmpty())
+                    .forEach(request.getProjectActivation()::activateOptionalProject);
+            LOGGER.info("Resuming from {} due to the --resume / -r feature.", propertyValue);
         }
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
index b559fb9..7f2bb95 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
@@ -31,6 +31,7 @@
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.model.Profile;
+import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.project.DefaultProjectBuildingRequest;
 import org.apache.maven.project.ProjectBuildingRequest;
 import org.apache.maven.properties.internal.SystemProperties;
@@ -44,11 +45,8 @@
 import org.eclipse.aether.transfer.TransferListener;
 
 /**
- * @author Jason van Zyl
  */
-public class DefaultMavenExecutionRequest
-    implements MavenExecutionRequest
-{
+public class DefaultMavenExecutionRequest implements MavenExecutionRequest {
 
     private RepositoryCache repositoryCache = new DefaultRepositoryCache();
 
@@ -68,6 +66,10 @@
 
     private boolean cacheNotFound = false;
 
+    private boolean ignoreMissingArtifactDescriptor = true;
+
+    private boolean ignoreInvalidArtifactDescriptor = true;
+
     private List<Proxy> proxies;
 
     private List<Server> servers;
@@ -91,6 +93,8 @@
 
     private File userSettingsFile;
 
+    private File projectSettingsFile;
+
     private File globalSettingsFile;
 
     private File userToolchainsFile;
@@ -105,6 +109,10 @@
 
     private File basedir;
 
+    private Path rootDirectory;
+
+    private Path topDirectory;
+
     private List<String> goals;
 
     private boolean useReactor = false;
@@ -160,59 +168,55 @@
 
     private Map<String, Object> data;
 
-    public DefaultMavenExecutionRequest()
-    {
-    }
+    public DefaultMavenExecutionRequest() {}
 
-    public static MavenExecutionRequest copy( MavenExecutionRequest original )
-    {
+    public static MavenExecutionRequest copy(MavenExecutionRequest original) {
         DefaultMavenExecutionRequest copy = new DefaultMavenExecutionRequest();
-        copy.setLocalRepository( original.getLocalRepository() );
-        copy.setLocalRepositoryPath( original.getLocalRepositoryPath() );
-        copy.setOffline( original.isOffline() );
-        copy.setInteractiveMode( original.isInteractiveMode() );
-        copy.setCacheNotFound( original.isCacheNotFound() );
-        copy.setCacheTransferError( original.isCacheTransferError() );
-        copy.setProxies( original.getProxies() );
-        copy.setServers( original.getServers() );
-        copy.setMirrors( original.getMirrors() );
-        copy.setProfiles( original.getProfiles() );
-        copy.setPluginGroups( original.getPluginGroups() );
-        copy.setProjectPresent( original.isProjectPresent() );
-        copy.setUserSettingsFile( original.getUserSettingsFile() );
-        copy.setGlobalSettingsFile( original.getGlobalSettingsFile() );
-        copy.setUserToolchainsFile( original.getUserToolchainsFile() );
-        copy.setGlobalToolchainsFile( original.getGlobalToolchainsFile() );
-        copy.setBaseDirectory( ( original.getBaseDirectory() != null ) ? new File( original.getBaseDirectory() )
-                                                                       : null );
-        copy.setGoals( original.getGoals() );
-        copy.setRecursive( original.isRecursive() );
-        copy.setPom( original.getPom() );
-        copy.setSystemProperties( original.getSystemProperties() );
-        copy.setUserProperties( original.getUserProperties() );
-        copy.setShowErrors( original.isShowErrors() );
-        copy.setActiveProfiles( original.getActiveProfiles() );
-        copy.setInactiveProfiles( original.getInactiveProfiles() );
-        copy.setTransferListener( original.getTransferListener() );
-        copy.setLoggingLevel( original.getLoggingLevel() );
-        copy.setGlobalChecksumPolicy( original.getGlobalChecksumPolicy() );
-        copy.setUpdateSnapshots( original.isUpdateSnapshots() );
-        copy.setRemoteRepositories( original.getRemoteRepositories() );
-        copy.setPluginArtifactRepositories( original.getPluginArtifactRepositories() );
-        copy.setRepositoryCache( original.getRepositoryCache() );
-        copy.setWorkspaceReader( original.getWorkspaceReader() );
-        copy.setNoSnapshotUpdates( original.isNoSnapshotUpdates() );
-        copy.setExecutionListener( original.getExecutionListener() );
-        copy.setUseLegacyLocalRepository( original.isUseLegacyLocalRepository() );
-        copy.setBuilderId( original.getBuilderId() );
+        copy.setLocalRepository(original.getLocalRepository());
+        copy.setLocalRepositoryPath(original.getLocalRepositoryPath());
+        copy.setOffline(original.isOffline());
+        copy.setInteractiveMode(original.isInteractiveMode());
+        copy.setCacheNotFound(original.isCacheNotFound());
+        copy.setCacheTransferError(original.isCacheTransferError());
+        copy.setIgnoreMissingArtifactDescriptor(original.isIgnoreMissingArtifactDescriptor());
+        copy.setIgnoreInvalidArtifactDescriptor(original.isIgnoreInvalidArtifactDescriptor());
+        copy.setProxies(original.getProxies());
+        copy.setServers(original.getServers());
+        copy.setMirrors(original.getMirrors());
+        copy.setProfiles(original.getProfiles());
+        copy.setPluginGroups(original.getPluginGroups());
+        copy.setProjectPresent(original.isProjectPresent());
+        copy.setUserSettingsFile(original.getUserSettingsFile());
+        copy.setGlobalSettingsFile(original.getGlobalSettingsFile());
+        copy.setUserToolchainsFile(original.getUserToolchainsFile());
+        copy.setGlobalToolchainsFile(original.getGlobalToolchainsFile());
+        copy.setBaseDirectory((original.getBaseDirectory() != null) ? new File(original.getBaseDirectory()) : null);
+        copy.setGoals(original.getGoals());
+        copy.setRecursive(original.isRecursive());
+        copy.setPom(original.getPom());
+        copy.setSystemProperties(original.getSystemProperties());
+        copy.setUserProperties(original.getUserProperties());
+        copy.setShowErrors(original.isShowErrors());
+        copy.setActiveProfiles(original.getActiveProfiles());
+        copy.setInactiveProfiles(original.getInactiveProfiles());
+        copy.setTransferListener(original.getTransferListener());
+        copy.setLoggingLevel(original.getLoggingLevel());
+        copy.setGlobalChecksumPolicy(original.getGlobalChecksumPolicy());
+        copy.setUpdateSnapshots(original.isUpdateSnapshots());
+        copy.setRemoteRepositories(original.getRemoteRepositories());
+        copy.setPluginArtifactRepositories(original.getPluginArtifactRepositories());
+        copy.setRepositoryCache(original.getRepositoryCache());
+        copy.setWorkspaceReader(original.getWorkspaceReader());
+        copy.setNoSnapshotUpdates(original.isNoSnapshotUpdates());
+        copy.setExecutionListener(original.getExecutionListener());
+        copy.setUseLegacyLocalRepository(original.isUseLegacyLocalRepository());
+        copy.setBuilderId(original.getBuilderId());
         return copy;
     }
 
     @Override
-    public String getBaseDirectory()
-    {
-        if ( basedir == null )
-        {
+    public String getBaseDirectory() {
+        if (basedir == null) {
             return null;
         }
 
@@ -220,32 +224,26 @@
     }
 
     @Override
-    public ArtifactRepository getLocalRepository()
-    {
+    public ArtifactRepository getLocalRepository() {
         return localRepository;
     }
 
     @Override
-    public File getLocalRepositoryPath()
-    {
+    public File getLocalRepositoryPath() {
         return localRepositoryPath;
     }
 
     @Override
-    public List<String> getGoals()
-    {
-        if ( goals == null )
-        {
+    public List<String> getGoals() {
+        if (goals == null) {
             goals = new ArrayList<>();
         }
         return goals;
     }
 
     @Override
-    public Properties getSystemProperties()
-    {
-        if ( systemProperties == null )
-        {
+    public Properties getSystemProperties() {
+        if (systemProperties == null) {
             systemProperties = new Properties();
         }
 
@@ -253,10 +251,8 @@
     }
 
     @Override
-    public Properties getUserProperties()
-    {
-        if ( userProperties == null )
-        {
+    public Properties getUserProperties() {
+        if (userProperties == null) {
             userProperties = new Properties();
         }
 
@@ -264,108 +260,88 @@
     }
 
     @Override
-    public File getPom()
-    {
+    public File getPom() {
         return pom;
     }
 
     @Override
-    public String getReactorFailureBehavior()
-    {
+    public String getReactorFailureBehavior() {
         return reactorFailureBehavior;
     }
 
     @Override
-    public List<String> getSelectedProjects()
-    {
+    public List<String> getSelectedProjects() {
         return this.projectActivation.getSelectedProjects();
     }
 
     @Override
-    public List<String> getExcludedProjects()
-    {
+    public List<String> getExcludedProjects() {
         return this.projectActivation.getExcludedProjects();
     }
 
     @Override
-    public boolean isResume()
-    {
+    public boolean isResume() {
         return resume;
     }
 
     @Override
-    public String getResumeFrom()
-    {
+    public String getResumeFrom() {
         return resumeFrom;
     }
 
     @Override
-    public String getMakeBehavior()
-    {
+    public String getMakeBehavior() {
         return makeBehavior;
     }
 
     @Override
-    public Date getStartTime()
-    {
+    public Date getStartTime() {
         return startTime;
     }
 
     @Override
-    public boolean isShowErrors()
-    {
+    public boolean isShowErrors() {
         return showErrors;
     }
 
     @Override
-    public boolean isInteractiveMode()
-    {
+    public boolean isInteractiveMode() {
         return interactiveMode;
     }
 
     @Override
-    public MavenExecutionRequest setActiveProfiles( List<String> activeProfiles )
-    {
-        if ( activeProfiles != null )
-        {
-            this.profileActivation.overwriteActiveProfiles( activeProfiles );
+    public MavenExecutionRequest setActiveProfiles(List<String> activeProfiles) {
+        if (activeProfiles != null) {
+            this.profileActivation.overwriteActiveProfiles(activeProfiles);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setInactiveProfiles( List<String> inactiveProfiles )
-    {
-        if ( inactiveProfiles != null )
-        {
-            this.profileActivation.overwriteInactiveProfiles( inactiveProfiles );
+    public MavenExecutionRequest setInactiveProfiles(List<String> inactiveProfiles) {
+        if (inactiveProfiles != null) {
+            this.profileActivation.overwriteInactiveProfiles(inactiveProfiles);
         }
 
         return this;
     }
 
     @Override
-    public ProjectActivation getProjectActivation()
-    {
+    public ProjectActivation getProjectActivation() {
         return this.projectActivation;
     }
 
     @Override
-    public ProfileActivation getProfileActivation()
-    {
+    public ProfileActivation getProfileActivation() {
         return this.profileActivation;
     }
 
     @Override
-    public MavenExecutionRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
-    {
-        if ( remoteRepositories != null )
-        {
-            this.remoteRepositories = new ArrayList<>( remoteRepositories );
-        }
-        else
-        {
+    public MavenExecutionRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories) {
+        if (remoteRepositories != null) {
+            this.remoteRepositories = new ArrayList<>(remoteRepositories);
+        } else {
             this.remoteRepositories = null;
         }
 
@@ -373,76 +349,62 @@
     }
 
     @Override
-    public MavenExecutionRequest setPluginArtifactRepositories( List<ArtifactRepository> pluginArtifactRepositories )
-    {
-        if ( pluginArtifactRepositories != null )
-        {
-            this.pluginArtifactRepositories = new ArrayList<>( pluginArtifactRepositories );
-        }
-        else
-        {
+    public MavenExecutionRequest setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories) {
+        if (pluginArtifactRepositories != null) {
+            this.pluginArtifactRepositories = new ArrayList<>(pluginArtifactRepositories);
+        } else {
             this.pluginArtifactRepositories = null;
         }
 
         return this;
     }
 
-    public void setProjectBuildingConfiguration( ProjectBuildingRequest projectBuildingConfiguration )
-    {
+    public void setProjectBuildingConfiguration(ProjectBuildingRequest projectBuildingConfiguration) {
         this.projectBuildingRequest = projectBuildingConfiguration;
     }
 
     @Override
-    public List<String> getActiveProfiles()
-    {
+    public List<String> getActiveProfiles() {
         return this.profileActivation.getActiveProfiles();
     }
 
     @Override
-    public List<String> getInactiveProfiles()
-    {
+    public List<String> getInactiveProfiles() {
         return this.profileActivation.getInactiveProfiles();
     }
 
     @Override
-    public TransferListener getTransferListener()
-    {
+    public TransferListener getTransferListener() {
         return transferListener;
     }
 
     @Override
-    public int getLoggingLevel()
-    {
+    public int getLoggingLevel() {
         return loggingLevel;
     }
 
     @Override
-    public boolean isOffline()
-    {
+    public boolean isOffline() {
         return offline;
     }
 
     @Override
-    public boolean isUpdateSnapshots()
-    {
+    public boolean isUpdateSnapshots() {
         return updateSnapshots;
     }
 
     @Override
-    public boolean isNoSnapshotUpdates()
-    {
+    public boolean isNoSnapshotUpdates() {
         return noSnapshotUpdates;
     }
 
     @Override
-    public String getGlobalChecksumPolicy()
-    {
+    public String getGlobalChecksumPolicy() {
         return globalChecksumPolicy;
     }
 
     @Override
-    public boolean isRecursive()
-    {
+    public boolean isRecursive() {
         return recursive;
     }
 
@@ -451,38 +413,31 @@
     // ----------------------------------------------------------------------
 
     @Override
-    public MavenExecutionRequest setBaseDirectory( File basedir )
-    {
+    public MavenExecutionRequest setBaseDirectory(File basedir) {
         this.basedir = basedir;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setStartTime( Date startTime )
-    {
+    public MavenExecutionRequest setStartTime(Date startTime) {
         this.startTime = startTime;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setShowErrors( boolean showErrors )
-    {
+    public MavenExecutionRequest setShowErrors(boolean showErrors) {
         this.showErrors = showErrors;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setGoals( List<String> goals )
-    {
-        if ( goals != null )
-        {
-            this.goals = new ArrayList<>( goals );
-        }
-        else
-        {
+    public MavenExecutionRequest setGoals(List<String> goals) {
+        if (goals != null) {
+            this.goals = new ArrayList<>(goals);
+        } else {
             this.goals = null;
         }
 
@@ -490,43 +445,35 @@
     }
 
     @Override
-    public MavenExecutionRequest setLocalRepository( ArtifactRepository localRepository )
-    {
+    public MavenExecutionRequest setLocalRepository(ArtifactRepository localRepository) {
         this.localRepository = localRepository;
 
-        if ( localRepository != null )
-        {
-            setLocalRepositoryPath( new File( localRepository.getBasedir() ).getAbsoluteFile() );
+        if (localRepository != null) {
+            setLocalRepositoryPath(new File(localRepository.getBasedir()).getAbsoluteFile());
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setLocalRepositoryPath( File localRepository )
-    {
+    public MavenExecutionRequest setLocalRepositoryPath(File localRepository) {
         localRepositoryPath = localRepository;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setLocalRepositoryPath( String localRepository )
-    {
-        localRepositoryPath = ( localRepository != null ) ? new File( localRepository ) : null;
+    public MavenExecutionRequest setLocalRepositoryPath(String localRepository) {
+        localRepositoryPath = (localRepository != null) ? new File(localRepository) : null;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setSystemProperties( Properties properties )
-    {
-        if ( properties != null )
-        {
-            this.systemProperties = SystemProperties.copyProperties( properties );
-        }
-        else
-        {
+    public MavenExecutionRequest setSystemProperties(Properties properties) {
+        if (properties != null) {
+            this.systemProperties = SystemProperties.copyProperties(properties);
+        } else {
             this.systemProperties = null;
         }
 
@@ -534,15 +481,11 @@
     }
 
     @Override
-    public MavenExecutionRequest setUserProperties( Properties userProperties )
-    {
-        if ( userProperties != null )
-        {
+    public MavenExecutionRequest setUserProperties(Properties userProperties) {
+        if (userProperties != null) {
             this.userProperties = new Properties();
-            this.userProperties.putAll( userProperties );
-        }
-        else
-        {
+            this.userProperties.putAll(userProperties);
+        } else {
             this.userProperties = null;
         }
 
@@ -550,186 +493,158 @@
     }
 
     @Override
-    public MavenExecutionRequest setReactorFailureBehavior( String failureBehavior )
-    {
+    public MavenExecutionRequest setReactorFailureBehavior(String failureBehavior) {
         reactorFailureBehavior = failureBehavior;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setSelectedProjects( List<String> selectedProjects )
-    {
-        if ( selectedProjects != null )
-        {
-            this.projectActivation.overwriteActiveProjects( selectedProjects );
+    public MavenExecutionRequest setSelectedProjects(List<String> selectedProjects) {
+        if (selectedProjects != null) {
+            this.projectActivation.overwriteActiveProjects(selectedProjects);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setExcludedProjects( List<String> excludedProjects )
-    {
-        if ( excludedProjects != null )
-        {
-            this.projectActivation.overwriteInactiveProjects( excludedProjects );
+    public MavenExecutionRequest setExcludedProjects(List<String> excludedProjects) {
+        if (excludedProjects != null) {
+            this.projectActivation.overwriteInactiveProjects(excludedProjects);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setResume( boolean resume )
-    {
+    public MavenExecutionRequest setResume(boolean resume) {
         this.resume = resume;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setResumeFrom( String project )
-    {
+    public MavenExecutionRequest setResumeFrom(String project) {
         this.resumeFrom = project;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setMakeBehavior( String makeBehavior )
-    {
+    public MavenExecutionRequest setMakeBehavior(String makeBehavior) {
         this.makeBehavior = makeBehavior;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest addActiveProfile( String profile )
-    {
-        if ( !getActiveProfiles().contains( profile ) )
-        {
-            getActiveProfiles().add( profile );
+    public MavenExecutionRequest addActiveProfile(String profile) {
+        if (!getActiveProfiles().contains(profile)) {
+            getActiveProfiles().add(profile);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest addInactiveProfile( String profile )
-    {
-        if ( !getInactiveProfiles().contains( profile ) )
-        {
-            getInactiveProfiles().add( profile );
+    public MavenExecutionRequest addInactiveProfile(String profile) {
+        if (!getInactiveProfiles().contains(profile)) {
+            getInactiveProfiles().add(profile);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest addActiveProfiles( List<String> profiles )
-    {
-        for ( String profile : profiles )
-        {
-            addActiveProfile( profile );
+    public MavenExecutionRequest addActiveProfiles(List<String> profiles) {
+        for (String profile : profiles) {
+            addActiveProfile(profile);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest addInactiveProfiles( List<String> profiles )
-    {
-        for ( String profile : profiles )
-        {
-            addInactiveProfile( profile );
+    public MavenExecutionRequest addInactiveProfiles(List<String> profiles) {
+        for (String profile : profiles) {
+            addInactiveProfile(profile);
         }
 
         return this;
     }
 
-    public MavenExecutionRequest setUseReactor( boolean reactorActive )
-    {
+    public MavenExecutionRequest setUseReactor(boolean reactorActive) {
         useReactor = reactorActive;
 
         return this;
     }
 
-    public boolean useReactor()
-    {
+    public boolean useReactor() {
         return useReactor;
     }
 
     /** @deprecated use {@link #setPom(File)} */
     @Deprecated
-    public MavenExecutionRequest setPomFile( String pomFilename )
-    {
-        if ( pomFilename != null )
-        {
-            pom = new File( pomFilename );
+    public MavenExecutionRequest setPomFile(String pomFilename) {
+        if (pomFilename != null) {
+            pom = new File(pomFilename);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setPom( File pom )
-    {
+    public MavenExecutionRequest setPom(File pom) {
         this.pom = pom;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setInteractiveMode( boolean interactive )
-    {
+    public MavenExecutionRequest setInteractiveMode(boolean interactive) {
         interactiveMode = interactive;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setTransferListener( TransferListener transferListener )
-    {
+    public MavenExecutionRequest setTransferListener(TransferListener transferListener) {
         this.transferListener = transferListener;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setLoggingLevel( int loggingLevel )
-    {
+    public MavenExecutionRequest setLoggingLevel(int loggingLevel) {
         this.loggingLevel = loggingLevel;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setOffline( boolean offline )
-    {
+    public MavenExecutionRequest setOffline(boolean offline) {
         this.offline = offline;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setUpdateSnapshots( boolean updateSnapshots )
-    {
+    public MavenExecutionRequest setUpdateSnapshots(boolean updateSnapshots) {
         this.updateSnapshots = updateSnapshots;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setNoSnapshotUpdates( boolean noSnapshotUpdates )
-    {
+    public MavenExecutionRequest setNoSnapshotUpdates(boolean noSnapshotUpdates) {
         this.noSnapshotUpdates = noSnapshotUpdates;
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setGlobalChecksumPolicy( String globalChecksumPolicy )
-    {
+    public MavenExecutionRequest setGlobalChecksumPolicy(String globalChecksumPolicy) {
         this.globalChecksumPolicy = globalChecksumPolicy;
 
         return this;
@@ -740,24 +655,18 @@
     // ----------------------------------------------------------------------------
 
     @Override
-    public List<Proxy> getProxies()
-    {
-        if ( proxies == null )
-        {
+    public List<Proxy> getProxies() {
+        if (proxies == null) {
             proxies = new ArrayList<>();
         }
         return proxies;
     }
 
     @Override
-    public MavenExecutionRequest setProxies( List<Proxy> proxies )
-    {
-        if ( proxies != null )
-        {
-            this.proxies = new ArrayList<>( proxies );
-        }
-        else
-        {
+    public MavenExecutionRequest setProxies(List<Proxy> proxies) {
+        if (proxies != null) {
+            this.proxies = new ArrayList<>(proxies);
+        } else {
             this.proxies = null;
         }
 
@@ -765,42 +674,33 @@
     }
 
     @Override
-    public MavenExecutionRequest addProxy( Proxy proxy )
-    {
-        Objects.requireNonNull( proxy, "proxy cannot be null" );
+    public MavenExecutionRequest addProxy(Proxy proxy) {
+        Objects.requireNonNull(proxy, "proxy cannot be null");
 
-        for ( Proxy p : getProxies() )
-        {
-            if ( p.getId() != null && p.getId().equals( proxy.getId() ) )
-            {
+        for (Proxy p : getProxies()) {
+            if (p.getId() != null && p.getId().equals(proxy.getId())) {
                 return this;
             }
         }
 
-        getProxies().add( proxy );
+        getProxies().add(proxy);
 
         return this;
     }
 
     @Override
-    public List<Server> getServers()
-    {
-        if ( servers == null )
-        {
+    public List<Server> getServers() {
+        if (servers == null) {
             servers = new ArrayList<>();
         }
         return servers;
     }
 
     @Override
-    public MavenExecutionRequest setServers( List<Server> servers )
-    {
-        if ( servers != null )
-        {
-            this.servers = new ArrayList<>( servers );
-        }
-        else
-        {
+    public MavenExecutionRequest setServers(List<Server> servers) {
+        if (servers != null) {
+            this.servers = new ArrayList<>(servers);
+        } else {
             this.servers = null;
         }
 
@@ -808,42 +708,33 @@
     }
 
     @Override
-    public MavenExecutionRequest addServer( Server server )
-    {
-        Objects.requireNonNull( server, "server cannot be null" );
+    public MavenExecutionRequest addServer(Server server) {
+        Objects.requireNonNull(server, "server cannot be null");
 
-        for ( Server p : getServers() )
-        {
-            if ( p.getId() != null && p.getId().equals( server.getId() ) )
-            {
+        for (Server p : getServers()) {
+            if (p.getId() != null && p.getId().equals(server.getId())) {
                 return this;
             }
         }
 
-        getServers().add( server );
+        getServers().add(server);
 
         return this;
     }
 
     @Override
-    public List<Mirror> getMirrors()
-    {
-        if ( mirrors == null )
-        {
+    public List<Mirror> getMirrors() {
+        if (mirrors == null) {
             mirrors = new ArrayList<>();
         }
         return mirrors;
     }
 
     @Override
-    public MavenExecutionRequest setMirrors( List<Mirror> mirrors )
-    {
-        if ( mirrors != null )
-        {
-            this.mirrors = new ArrayList<>( mirrors );
-        }
-        else
-        {
+    public MavenExecutionRequest setMirrors(List<Mirror> mirrors) {
+        if (mirrors != null) {
+            this.mirrors = new ArrayList<>(mirrors);
+        } else {
             this.mirrors = null;
         }
 
@@ -851,42 +742,33 @@
     }
 
     @Override
-    public MavenExecutionRequest addMirror( Mirror mirror )
-    {
-        Objects.requireNonNull( mirror, "mirror cannot be null" );
+    public MavenExecutionRequest addMirror(Mirror mirror) {
+        Objects.requireNonNull(mirror, "mirror cannot be null");
 
-        for ( Mirror p : getMirrors() )
-        {
-            if ( p.getId() != null && p.getId().equals( mirror.getId() ) )
-            {
+        for (Mirror p : getMirrors()) {
+            if (p.getId() != null && p.getId().equals(mirror.getId())) {
                 return this;
             }
         }
 
-        getMirrors().add( mirror );
+        getMirrors().add(mirror);
 
         return this;
     }
 
     @Override
-    public List<Profile> getProfiles()
-    {
-        if ( profiles == null )
-        {
+    public List<Profile> getProfiles() {
+        if (profiles == null) {
             profiles = new ArrayList<>();
         }
         return profiles;
     }
 
     @Override
-    public MavenExecutionRequest setProfiles( List<Profile> profiles )
-    {
-        if ( profiles != null )
-        {
-            this.profiles = new ArrayList<>( profiles );
-        }
-        else
-        {
+    public MavenExecutionRequest setProfiles(List<Profile> profiles) {
+        if (profiles != null) {
+            this.profiles = new ArrayList<>(profiles);
+        } else {
             this.profiles = null;
         }
 
@@ -894,10 +776,8 @@
     }
 
     @Override
-    public List<String> getPluginGroups()
-    {
-        if ( pluginGroups == null )
-        {
+    public List<String> getPluginGroups() {
+        if (pluginGroups == null) {
             pluginGroups = new ArrayList<>();
         }
 
@@ -905,14 +785,10 @@
     }
 
     @Override
-    public MavenExecutionRequest setPluginGroups( List<String> pluginGroups )
-    {
-        if ( pluginGroups != null )
-        {
-            this.pluginGroups = new ArrayList<>( pluginGroups );
-        }
-        else
-        {
+    public MavenExecutionRequest setPluginGroups(List<String> pluginGroups) {
+        if (pluginGroups != null) {
+            this.pluginGroups = new ArrayList<>(pluginGroups);
+        } else {
             this.pluginGroups = null;
         }
 
@@ -920,30 +796,25 @@
     }
 
     @Override
-    public MavenExecutionRequest addPluginGroup( String pluginGroup )
-    {
-        if ( !getPluginGroups().contains( pluginGroup ) )
-        {
-            getPluginGroups().add( pluginGroup );
+    public MavenExecutionRequest addPluginGroup(String pluginGroup) {
+        if (!getPluginGroups().contains(pluginGroup)) {
+            getPluginGroups().add(pluginGroup);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest addPluginGroups( List<String> pluginGroups )
-    {
-        for ( String pluginGroup : pluginGroups )
-        {
-            addPluginGroup( pluginGroup );
+    public MavenExecutionRequest addPluginGroups(List<String> pluginGroups) {
+        for (String pluginGroup : pluginGroups) {
+            addPluginGroup(pluginGroup);
         }
 
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setRecursive( boolean recursive )
-    {
+    public MavenExecutionRequest setRecursive(boolean recursive) {
         this.recursive = recursive;
 
         return this;
@@ -953,14 +824,12 @@
     private ProjectBuildingRequest projectBuildingRequest;
 
     @Override
-    public boolean isProjectPresent()
-    {
+    public boolean isProjectPresent() {
         return isProjectPresent;
     }
 
     @Override
-    public MavenExecutionRequest setProjectPresent( boolean projectPresent )
-    {
+    public MavenExecutionRequest setProjectPresent(boolean projectPresent) {
         isProjectPresent = projectPresent;
 
         return this;
@@ -969,107 +838,101 @@
     // Settings files
 
     @Override
-    public File getUserSettingsFile()
-    {
+    public File getUserSettingsFile() {
         return userSettingsFile;
     }
 
     @Override
-    public MavenExecutionRequest setUserSettingsFile( File userSettingsFile )
-    {
+    public MavenExecutionRequest setUserSettingsFile(File userSettingsFile) {
         this.userSettingsFile = userSettingsFile;
 
         return this;
     }
 
     @Override
-    public File getGlobalSettingsFile()
-    {
+    public File getProjectSettingsFile() {
+        return projectSettingsFile;
+    }
+
+    @Override
+    public MavenExecutionRequest setProjectSettingsFile(File projectSettingsFile) {
+        this.projectSettingsFile = projectSettingsFile;
+
+        return this;
+    }
+
+    @Override
+    public File getGlobalSettingsFile() {
         return globalSettingsFile;
     }
 
     @Override
-    public MavenExecutionRequest setGlobalSettingsFile( File globalSettingsFile )
-    {
+    public MavenExecutionRequest setGlobalSettingsFile(File globalSettingsFile) {
         this.globalSettingsFile = globalSettingsFile;
 
         return this;
     }
 
     @Override
-    public File getUserToolchainsFile()
-    {
+    public File getUserToolchainsFile() {
         return userToolchainsFile;
     }
 
     @Override
-    public MavenExecutionRequest setUserToolchainsFile( File userToolchainsFile )
-    {
+    public MavenExecutionRequest setUserToolchainsFile(File userToolchainsFile) {
         this.userToolchainsFile = userToolchainsFile;
 
         return this;
     }
 
     @Override
-    public File getGlobalToolchainsFile()
-    {
+    public File getGlobalToolchainsFile() {
         return globalToolchainsFile;
     }
 
     @Override
-    public MavenExecutionRequest setGlobalToolchainsFile( File globalToolchainsFile )
-    {
+    public MavenExecutionRequest setGlobalToolchainsFile(File globalToolchainsFile) {
         this.globalToolchainsFile = globalToolchainsFile;
         return this;
     }
 
     @Override
-    public MavenExecutionRequest addRemoteRepository( ArtifactRepository repository )
-    {
-        for ( ArtifactRepository repo : getRemoteRepositories() )
-        {
-            if ( repo.getId() != null && repo.getId().equals( repository.getId() ) )
-            {
+    public MavenExecutionRequest addRemoteRepository(ArtifactRepository repository) {
+        for (ArtifactRepository repo : getRemoteRepositories()) {
+            if (repo.getId() != null && repo.getId().equals(repository.getId())) {
                 return this;
             }
         }
 
-        getRemoteRepositories().add( repository );
+        getRemoteRepositories().add(repository);
 
         return this;
     }
 
     @Override
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
-        if ( remoteRepositories == null )
-        {
+    public List<ArtifactRepository> getRemoteRepositories() {
+        if (remoteRepositories == null) {
             remoteRepositories = new ArrayList<>();
         }
         return remoteRepositories;
     }
 
     @Override
-    public MavenExecutionRequest addPluginArtifactRepository( ArtifactRepository repository )
-    {
-        for ( ArtifactRepository repo : getPluginArtifactRepositories() )
-        {
-            if ( repo.getId() != null && repo.getId().equals( repository.getId() ) )
-            {
+    public MavenExecutionRequest addPluginArtifactRepository(ArtifactRepository repository) {
+        for (ArtifactRepository repo : getPluginArtifactRepositories()) {
+            if (repo.getId() != null && repo.getId().equals(repository.getId())) {
                 return this;
             }
         }
 
-        getPluginArtifactRepositories().add( repository );
+        getPluginArtifactRepositories().add(repository);
 
         return this;
     }
 
     @Override
-    public List<ArtifactRepository> getPluginArtifactRepositories()
-    {
-        if ( pluginArtifactRepositories == null )
-        {
+    public List<ArtifactRepository> getPluginArtifactRepositories() {
+        if (pluginArtifactRepositories == null) {
             pluginArtifactRepositories = new ArrayList<>();
         }
         return pluginArtifactRepositories;
@@ -1077,196 +940,215 @@
 
     // TODO this does not belong here.
     @Override
-    public ProjectBuildingRequest getProjectBuildingRequest()
-    {
-        if ( projectBuildingRequest == null )
-        {
+    public ProjectBuildingRequest getProjectBuildingRequest() {
+        if (projectBuildingRequest == null) {
             projectBuildingRequest = new DefaultProjectBuildingRequest();
-            projectBuildingRequest.setLocalRepository( getLocalRepository() );
-            projectBuildingRequest.setSystemProperties( getSystemProperties() );
-            projectBuildingRequest.setUserProperties( getUserProperties() );
-            projectBuildingRequest.setRemoteRepositories( getRemoteRepositories() );
-            projectBuildingRequest.setPluginArtifactRepositories( getPluginArtifactRepositories() );
-            projectBuildingRequest.setActiveProfileIds( getActiveProfiles() );
-            projectBuildingRequest.setInactiveProfileIds( getInactiveProfiles() );
-            projectBuildingRequest.setProfiles( getProfiles() );
-            projectBuildingRequest.setProcessPlugins( true );
-            projectBuildingRequest.setBuildStartTime( getStartTime() );
+            projectBuildingRequest.setLocalRepository(getLocalRepository());
+            projectBuildingRequest.setSystemProperties(getSystemProperties());
+            projectBuildingRequest.setUserProperties(getUserProperties());
+            projectBuildingRequest.setRemoteRepositories(getRemoteRepositories());
+            projectBuildingRequest.setPluginArtifactRepositories(getPluginArtifactRepositories());
+            projectBuildingRequest.setActiveProfileIds(getActiveProfiles());
+            projectBuildingRequest.setInactiveProfileIds(getInactiveProfiles());
+            projectBuildingRequest.setProfiles(getProfiles());
+            projectBuildingRequest.setProcessPlugins(true);
+            projectBuildingRequest.setBuildStartTime(getStartTime());
         }
 
         return projectBuildingRequest;
     }
 
     @Override
-    public MavenExecutionRequest addProfile( Profile profile )
-    {
-        Objects.requireNonNull( profile, "profile cannot be null" );
+    public MavenExecutionRequest addProfile(Profile profile) {
+        Objects.requireNonNull(profile, "profile cannot be null");
 
-        for ( Profile p : getProfiles() )
-        {
-            if ( p.getId() != null && p.getId().equals( profile.getId() ) )
-            {
+        for (Profile p : getProfiles()) {
+            if (p.getId() != null && p.getId().equals(profile.getId())) {
                 return this;
             }
         }
 
-        getProfiles().add( profile );
+        getProfiles().add(profile);
 
         return this;
     }
 
     @Override
-    public RepositoryCache getRepositoryCache()
-    {
+    public RepositoryCache getRepositoryCache() {
         return repositoryCache;
     }
 
     @Override
-    public MavenExecutionRequest setRepositoryCache( RepositoryCache repositoryCache )
-    {
+    public MavenExecutionRequest setRepositoryCache(RepositoryCache repositoryCache) {
         this.repositoryCache = repositoryCache;
 
         return this;
     }
 
     @Override
-    public ExecutionListener getExecutionListener()
-    {
+    public ExecutionListener getExecutionListener() {
         return executionListener;
     }
 
     @Override
-    public MavenExecutionRequest setExecutionListener( ExecutionListener executionListener )
-    {
+    public MavenExecutionRequest setExecutionListener(ExecutionListener executionListener) {
         this.executionListener = executionListener;
 
         return this;
     }
 
     @Override
-    public void setDegreeOfConcurrency( final int degreeOfConcurrency )
-    {
+    public void setDegreeOfConcurrency(final int degreeOfConcurrency) {
         this.degreeOfConcurrency = degreeOfConcurrency;
     }
 
     @Override
-    public int getDegreeOfConcurrency()
-    {
+    public int getDegreeOfConcurrency() {
         return degreeOfConcurrency;
     }
 
     @Override
-    public WorkspaceReader getWorkspaceReader()
-    {
+    public WorkspaceReader getWorkspaceReader() {
         return workspaceReader;
     }
 
     @Override
-    public MavenExecutionRequest setWorkspaceReader( WorkspaceReader workspaceReader )
-    {
+    public MavenExecutionRequest setWorkspaceReader(WorkspaceReader workspaceReader) {
         this.workspaceReader = workspaceReader;
         return this;
     }
 
     @Override
-    public boolean isCacheTransferError()
-    {
+    public boolean isCacheTransferError() {
         return cacheTransferError;
     }
 
     @Override
-    public MavenExecutionRequest setCacheTransferError( boolean cacheTransferError )
-    {
+    public MavenExecutionRequest setCacheTransferError(boolean cacheTransferError) {
         this.cacheTransferError = cacheTransferError;
         return this;
     }
 
     @Override
-    public boolean isCacheNotFound()
-    {
+    public boolean isCacheNotFound() {
         return cacheNotFound;
     }
 
     @Override
-    public MavenExecutionRequest setCacheNotFound( boolean cacheNotFound )
-    {
+    public MavenExecutionRequest setCacheNotFound(boolean cacheNotFound) {
         this.cacheNotFound = cacheNotFound;
         return this;
     }
 
     @Override
-    public boolean isUseLegacyLocalRepository()
-    {
-        return this.useLegacyLocalRepositoryManager;
+    public boolean isIgnoreMissingArtifactDescriptor() {
+        return ignoreMissingArtifactDescriptor;
     }
 
     @Override
-    public MavenExecutionRequest setUseLegacyLocalRepository( boolean useLegacyLocalRepositoryManager )
-    {
-        this.useLegacyLocalRepositoryManager = useLegacyLocalRepositoryManager;
+    public MavenExecutionRequest setIgnoreMissingArtifactDescriptor(boolean ignoreMissing) {
+        this.ignoreMissingArtifactDescriptor = ignoreMissing;
         return this;
     }
 
     @Override
-    public MavenExecutionRequest setBuilderId( String builderId )
-    {
+    public boolean isIgnoreInvalidArtifactDescriptor() {
+        return ignoreInvalidArtifactDescriptor;
+    }
+
+    @Override
+    public MavenExecutionRequest setIgnoreInvalidArtifactDescriptor(boolean ignoreInvalid) {
+        this.ignoreInvalidArtifactDescriptor = ignoreInvalid;
+        return this;
+    }
+
+    @Override
+    public boolean isUseLegacyLocalRepository() {
+        return this.useLegacyLocalRepositoryManager;
+    }
+
+    @Override
+    public MavenExecutionRequest setUseLegacyLocalRepository(boolean useLegacyLocalRepositoryManager) {
+        this.useLegacyLocalRepositoryManager = false;
+        return this;
+    }
+
+    @Override
+    public MavenExecutionRequest setBuilderId(String builderId) {
         this.builderId = builderId;
         return this;
     }
 
     @Override
-    public String getBuilderId()
-    {
+    public String getBuilderId() {
         return builderId;
     }
 
     @Override
-    public Map<String, List<ToolchainModel>> getToolchains()
-    {
-        if ( toolchains == null )
-        {
+    public Map<String, List<ToolchainModel>> getToolchains() {
+        if (toolchains == null) {
             toolchains = new HashMap<>();
         }
         return toolchains;
     }
 
     @Override
-    public MavenExecutionRequest setToolchains( Map<String, List<ToolchainModel>> toolchains )
-    {
+    public MavenExecutionRequest setToolchains(Map<String, List<ToolchainModel>> toolchains) {
         this.toolchains = toolchains;
         return this;
     }
 
+    @Deprecated
     @Override
-    public void setMultiModuleProjectDirectory( File directory )
-    {
+    public void setMultiModuleProjectDirectory(File directory) {
         this.multiModuleProjectDirectory = directory;
     }
 
+    @Deprecated
     @Override
-    public File getMultiModuleProjectDirectory()
-    {
+    public File getMultiModuleProjectDirectory() {
         return multiModuleProjectDirectory;
     }
 
     @Override
-    public MavenExecutionRequest setEventSpyDispatcher( EventSpyDispatcher eventSpyDispatcher )
-    {
+    public Path getRootDirectory() {
+        if (rootDirectory == null) {
+            throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
+        }
+        return rootDirectory;
+    }
+
+    @Override
+    public MavenExecutionRequest setRootDirectory(Path rootDirectory) {
+        this.rootDirectory = rootDirectory;
+        return this;
+    }
+
+    @Override
+    public Path getTopDirectory() {
+        return topDirectory;
+    }
+
+    @Override
+    public MavenExecutionRequest setTopDirectory(Path topDirectory) {
+        this.topDirectory = topDirectory;
+        return this;
+    }
+
+    @Override
+    public MavenExecutionRequest setEventSpyDispatcher(EventSpyDispatcher eventSpyDispatcher) {
         this.eventSpyDispatcher = eventSpyDispatcher;
         return this;
     }
 
     @Override
-    public EventSpyDispatcher getEventSpyDispatcher()
-    {
+    public EventSpyDispatcher getEventSpyDispatcher() {
         return eventSpyDispatcher;
     }
 
     @Override
-    public Map<String, Object> getData()
-    {
-        if ( data == null )
-        {
+    public Map<String, Object> getData() {
+        if (data == null) {
             data = new HashMap<>();
         }
 
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulator.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulator.java
index 94e9ecc..ab548a3 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulator.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,92 +16,71 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
 
 import org.apache.maven.artifact.InvalidRepositoryException;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.bridge.MavenRepositorySystem;
-import org.apache.maven.repository.RepositorySystem;
-//
-// All of this needs to go away and be couched in terms of the execution request
-//
 import org.apache.maven.settings.Mirror;
 import org.apache.maven.settings.Proxy;
 import org.apache.maven.settings.Repository;
 import org.apache.maven.settings.Server;
 import org.apache.maven.settings.Settings;
 import org.apache.maven.settings.SettingsUtils;
-//
-// Settings in core
-//
 import org.apache.maven.toolchain.model.PersistedToolchains;
 import org.apache.maven.toolchain.model.ToolchainModel;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Assists in populating an execution request for invocation of Maven.
  */
 @Named
 @Singleton
-public class DefaultMavenExecutionRequestPopulator
-    implements MavenExecutionRequestPopulator
-{
+public class DefaultMavenExecutionRequestPopulator implements MavenExecutionRequestPopulator {
 
     private final MavenRepositorySystem repositorySystem;
 
     @Inject
-    public DefaultMavenExecutionRequestPopulator( MavenRepositorySystem repositorySystem )
-    {
+    public DefaultMavenExecutionRequestPopulator(MavenRepositorySystem repositorySystem) {
         this.repositorySystem = repositorySystem;
     }
 
-
     @Override
-    public MavenExecutionRequest populateFromToolchains( MavenExecutionRequest request, PersistedToolchains toolchains )
-        throws MavenExecutionRequestPopulationException
-    {
-        if ( toolchains != null )
-        {
-            Map<String, List<ToolchainModel>> groupedToolchains = new HashMap<>( 2 );
+    public MavenExecutionRequest populateFromToolchains(MavenExecutionRequest request, PersistedToolchains toolchains)
+            throws MavenExecutionRequestPopulationException {
+        if (toolchains != null) {
+            Map<String, List<ToolchainModel>> groupedToolchains = new HashMap<>(2);
 
-            for ( ToolchainModel model : toolchains.getToolchains() )
-            {
-                if ( !groupedToolchains.containsKey( model.getType() ) )
-                {
-                    groupedToolchains.put( model.getType(), new ArrayList<>() );
+            for (ToolchainModel model : toolchains.getToolchains()) {
+                if (!groupedToolchains.containsKey(model.getType())) {
+                    groupedToolchains.put(model.getType(), new ArrayList<>());
                 }
 
-                groupedToolchains.get( model.getType() ).add( model );
+                groupedToolchains.get(model.getType()).add(model);
             }
 
-            request.setToolchains( groupedToolchains );
+            request.setToolchains(groupedToolchains);
         }
         return request;
     }
 
     @Override
-    public MavenExecutionRequest populateDefaults( MavenExecutionRequest request )
-        throws MavenExecutionRequestPopulationException
-    {
-        baseDirectory( request );
+    public MavenExecutionRequest populateDefaults(MavenExecutionRequest request)
+            throws MavenExecutionRequestPopulationException {
+        baseDirectory(request);
 
-        localRepository( request );
+        localRepository(request);
 
-        populateDefaultPluginGroups( request );
-
-        injectDefaultRepositories( request );
-
-        injectDefaultPluginRepositories( request );
+        populateDefaultPluginGroups(request);
 
         return request;
     }
@@ -112,51 +89,12 @@
     //
     //
 
-    private void populateDefaultPluginGroups( MavenExecutionRequest request )
-    {
-        request.addPluginGroup( "org.apache.maven.plugins" );
-        request.addPluginGroup( "org.codehaus.mojo" );
+    private void populateDefaultPluginGroups(MavenExecutionRequest request) {
+        request.addPluginGroup("org.apache.maven.plugins");
+        request.addPluginGroup("org.codehaus.mojo");
     }
 
-    private void injectDefaultRepositories( MavenExecutionRequest request )
-        throws MavenExecutionRequestPopulationException
-    {
-        Set<String> definedRepositories = repositorySystem.getRepoIds( request.getRemoteRepositories() );
-
-        if ( !definedRepositories.contains( RepositorySystem.DEFAULT_REMOTE_REPO_ID ) )
-        {
-            try
-            {
-                request.addRemoteRepository( repositorySystem.createDefaultRemoteRepository( request ) );
-            }
-            catch ( Exception e )
-            {
-                throw new MavenExecutionRequestPopulationException( "Cannot create default remote repository.", e );
-            }
-        }
-    }
-
-    private void injectDefaultPluginRepositories( MavenExecutionRequest request )
-        throws MavenExecutionRequestPopulationException
-    {
-        Set<String> definedRepositories = repositorySystem.getRepoIds( request.getPluginArtifactRepositories() );
-
-        if ( !definedRepositories.contains( RepositorySystem.DEFAULT_REMOTE_REPO_ID ) )
-        {
-            try
-            {
-                request.addPluginArtifactRepository( repositorySystem.createDefaultRemoteRepository( request ) );
-            }
-            catch ( Exception e )
-            {
-                throw new MavenExecutionRequestPopulationException( "Cannot create default remote repository.", e );
-            }
-        }
-    }
-
-    private void localRepository( MavenExecutionRequest request )
-        throws MavenExecutionRequestPopulationException
-    {
+    private void localRepository(MavenExecutionRequest request) throws MavenExecutionRequestPopulationException {
         // ------------------------------------------------------------------------
         // Local Repository
         //
@@ -165,14 +103,12 @@
         // 3. Use default value
         // ------------------------------------------------------------------------
 
-        if ( request.getLocalRepository() == null )
-        {
-            request.setLocalRepository( createLocalRepository( request ) );
+        if (request.getLocalRepository() == null) {
+            request.setLocalRepository(createLocalRepository(request));
         }
 
-        if ( request.getLocalRepositoryPath() == null )
-        {
-            request.setLocalRepositoryPath( new File( request.getLocalRepository().getBasedir() ).getAbsoluteFile() );
+        if (request.getLocalRepositoryPath() == null) {
+            request.setLocalRepositoryPath(new File(request.getLocalRepository().getBasedir()).getAbsoluteFile());
         }
     }
 
@@ -180,36 +116,28 @@
     // Artifact Transfer Mechanism
     // ------------------------------------------------------------------------
 
-    private ArtifactRepository createLocalRepository( MavenExecutionRequest request )
-        throws MavenExecutionRequestPopulationException
-    {
+    private ArtifactRepository createLocalRepository(MavenExecutionRequest request)
+            throws MavenExecutionRequestPopulationException {
         String localRepositoryPath = null;
 
-        if ( request.getLocalRepositoryPath() != null )
-        {
+        if (request.getLocalRepositoryPath() != null) {
             localRepositoryPath = request.getLocalRepositoryPath().getAbsolutePath();
         }
 
-        if ( StringUtils.isEmpty( localRepositoryPath ) )
-        {
-            localRepositoryPath = RepositorySystem.defaultUserLocalRepository.getAbsolutePath();
+        if (localRepositoryPath == null || localRepositoryPath.isEmpty()) {
+            localRepositoryPath = new File(System.getProperty("user.home"), ".m2/repository").getAbsolutePath();
         }
 
-        try
-        {
-            return repositorySystem.createLocalRepository( request, new File( localRepositoryPath ) );
-        }
-        catch ( Exception e )
-        {
-            throw new MavenExecutionRequestPopulationException( "Cannot create local repository.", e );
+        try {
+            return repositorySystem.createLocalRepository(new File(localRepositoryPath));
+        } catch (Exception e) {
+            throw new MavenExecutionRequestPopulationException("Cannot create local repository.", e);
         }
     }
 
-    private void baseDirectory( MavenExecutionRequest request )
-    {
-        if ( request.getBaseDirectory() == null && request.getPom() != null )
-        {
-            request.setBaseDirectory( request.getPom().getAbsoluteFile().getParentFile() );
+    private void baseDirectory(MavenExecutionRequest request) {
+        if (request.getBaseDirectory() == null && request.getPom() != null) {
+            request.setBaseDirectory(request.getPom().getAbsoluteFile().getParentFile());
         }
     }
 
@@ -217,27 +145,24 @@
 
     @Override
     @Deprecated
-    public MavenExecutionRequest populateFromSettings( MavenExecutionRequest request, Settings settings )
-        throws MavenExecutionRequestPopulationException
-    {
-        if ( settings == null )
-        {
+    public MavenExecutionRequest populateFromSettings(MavenExecutionRequest request, Settings settings)
+            throws MavenExecutionRequestPopulationException {
+        if (settings == null) {
             return request;
         }
 
-        request.setOffline( settings.isOffline() );
+        request.setOffline(settings.isOffline());
 
-        request.setInteractiveMode( settings.isInteractiveMode() );
+        request.setInteractiveMode(settings.isInteractiveMode());
 
-        request.setPluginGroups( settings.getPluginGroups() );
+        request.setPluginGroups(settings.getPluginGroups());
 
-        request.setLocalRepositoryPath( settings.getLocalRepository() );
+        request.setLocalRepositoryPath(settings.getLocalRepository());
 
-        for ( Server server : settings.getServers() )
-        {
+        for (Server server : settings.getServers()) {
             server = server.clone();
 
-            request.addServer( server );
+            request.addServer(server);
         }
 
         //  <proxies>
@@ -252,16 +177,14 @@
         //    </proxy>
         //  </proxies>
 
-        for ( Proxy proxy : settings.getProxies() )
-        {
-            if ( !proxy.isActive() )
-            {
+        for (Proxy proxy : settings.getProxies()) {
+            if (!proxy.isActive()) {
                 continue;
             }
 
             proxy = proxy.clone();
 
-            request.addProxy( proxy );
+            request.addProxy(proxy);
         }
 
         // <mirrors>
@@ -272,43 +195,32 @@
         //   </mirror>
         // </mirrors>
 
-        for ( Mirror mirror : settings.getMirrors() )
-        {
+        for (Mirror mirror : settings.getMirrors()) {
             mirror = mirror.clone();
 
-            request.addMirror( mirror );
+            request.addMirror(mirror);
         }
 
-        request.setActiveProfiles( settings.getActiveProfiles() );
+        request.setActiveProfiles(settings.getActiveProfiles());
 
-        for ( org.apache.maven.settings.Profile rawProfile : settings.getProfiles() )
-        {
-            request.addProfile( SettingsUtils.convertFromSettingsProfile( rawProfile ) );
+        for (org.apache.maven.settings.Profile rawProfile : settings.getProfiles()) {
+            request.addProfile(SettingsUtils.convertFromSettingsProfile(rawProfile));
 
-            if ( settings.getActiveProfiles().contains( rawProfile.getId() ) )
-            {
+            if (settings.getActiveProfiles().contains(rawProfile.getId())) {
                 List<Repository> remoteRepositories = rawProfile.getRepositories();
-                for ( Repository remoteRepository : remoteRepositories )
-                {
-                    try
-                    {
-                        request.addRemoteRepository( repositorySystem.buildArtifactRepository( remoteRepository ) );
-                    }
-                    catch ( InvalidRepositoryException e )
-                    {
+                for (Repository remoteRepository : remoteRepositories) {
+                    try {
+                        request.addRemoteRepository(MavenRepositorySystem.buildArtifactRepository(remoteRepository));
+                    } catch (InvalidRepositoryException e) {
                         // do nothing for now
                     }
                 }
 
                 List<Repository> pluginRepositories = rawProfile.getPluginRepositories();
-                for ( Repository pluginRepo : pluginRepositories )
-                {
-                    try
-                    {
-                        request.addPluginArtifactRepository( repositorySystem.buildArtifactRepository( pluginRepo ) );
-                    }
-                    catch ( InvalidRepositoryException e )
-                    {
+                for (Repository pluginRepo : pluginRepositories) {
+                    try {
+                        request.addPluginArtifactRepository(MavenRepositorySystem.buildArtifactRepository(pluginRepo));
+                    } catch (InvalidRepositoryException e) {
                         // do nothing for now
                     }
                 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
index ecddd66..580ddde 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/DefaultMavenExecutionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.Collections;
 import java.util.IdentityHashMap;
@@ -28,10 +27,7 @@
 import org.apache.maven.project.DependencyResolutionResult;
 import org.apache.maven.project.MavenProject;
 
-/** @author Jason van Zyl */
-public class DefaultMavenExecutionResult
-    implements MavenExecutionResult
-{
+public class DefaultMavenExecutionResult implements MavenExecutionResult {
     private MavenProject project;
 
     private List<MavenProject> topologicallySortedProjects = Collections.emptyList();
@@ -40,86 +36,71 @@
 
     private final List<Throwable> exceptions = new CopyOnWriteArrayList<>();
 
-    private final Map<MavenProject, BuildSummary> buildSummaries =
-        Collections.synchronizedMap( new IdentityHashMap<>() );
+    private final Map<MavenProject, BuildSummary> buildSummaries = Collections.synchronizedMap(new IdentityHashMap<>());
 
     private boolean canResume = false;
 
-    public MavenExecutionResult setProject( MavenProject project )
-    {
+    public MavenExecutionResult setProject(MavenProject project) {
         this.project = project;
 
         return this;
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public MavenExecutionResult setTopologicallySortedProjects( List<MavenProject> topologicallySortedProjects )
-    {
+    public MavenExecutionResult setTopologicallySortedProjects(List<MavenProject> topologicallySortedProjects) {
         this.topologicallySortedProjects = topologicallySortedProjects;
 
         return this;
     }
 
-    public List<MavenProject> getTopologicallySortedProjects()
-    {
+    public List<MavenProject> getTopologicallySortedProjects() {
         return null == topologicallySortedProjects
-                   ? Collections.emptyList()
-                   : Collections.unmodifiableList( topologicallySortedProjects );
-
+                ? Collections.emptyList()
+                : Collections.unmodifiableList(topologicallySortedProjects);
     }
 
-    public DependencyResolutionResult getDependencyResolutionResult()
-    {
+    public DependencyResolutionResult getDependencyResolutionResult() {
         return dependencyResolutionResult;
     }
 
-    public MavenExecutionResult setDependencyResolutionResult( DependencyResolutionResult dependencyResolutionResult )
-    {
+    public MavenExecutionResult setDependencyResolutionResult(DependencyResolutionResult dependencyResolutionResult) {
         this.dependencyResolutionResult = dependencyResolutionResult;
 
         return this;
     }
 
-    public List<Throwable> getExceptions()
-    {
+    public List<Throwable> getExceptions() {
         return exceptions;
     }
 
-    public MavenExecutionResult addException( Throwable t )
-    {
-        exceptions.add( t );
+    public MavenExecutionResult addException(Throwable t) {
+        exceptions.add(t);
 
         return this;
     }
 
-    public boolean hasExceptions()
-    {
+    public boolean hasExceptions() {
         return !getExceptions().isEmpty();
     }
 
-    public BuildSummary getBuildSummary( MavenProject project )
-    {
-        return buildSummaries.get( project );
+    public BuildSummary getBuildSummary(MavenProject project) {
+        return buildSummaries.get(project);
     }
 
-    public void addBuildSummary( BuildSummary summary )
-    {
-        buildSummaries.put( summary.getProject(), summary );
+    public void addBuildSummary(BuildSummary summary) {
+        buildSummaries.put(summary.getProject(), summary);
     }
 
     @Override
-    public boolean canResume()
-    {
+    public boolean canResume() {
         return canResume;
     }
 
     @Override
-    public void setCanResume( boolean canResume )
-    {
+    public void setCanResume(boolean canResume) {
         this.canResume = canResume;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ExecutionEvent.java b/maven-core/src/main/java/org/apache/maven/execution/ExecutionEvent.java
index 0ee7f57..4b8d1ec 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ExecutionEvent.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ExecutionEvent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.project.MavenProject;
@@ -25,16 +24,13 @@
 /**
  * Holds data relevant for an execution event.
  *
- * @author Benjamin Bentmann
  */
-public interface ExecutionEvent
-{
+public interface ExecutionEvent {
 
     /**
      * The possible types of execution events.
      */
-    enum Type
-    {
+    enum Type {
         ProjectDiscoveryStarted,
         SessionStarted,
         SessionEnded,
@@ -88,5 +84,4 @@
      * @return The exception or {@code null} if none.
      */
     Exception getException();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/ExecutionListener.java
index ad3f345..b18a52a 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,49 +16,47 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 /**
  * Defines events that Maven fires during a build. <strong>Warning:</strong> This interface might be extended in future
  * Maven versions to support further events. Hence it is strongly recommended to derive custom listeners from
  * {@link AbstractExecutionListener} in order to avoid interoperability problems.
  *
- * @author Benjamin Bentmann
  */
-public interface ExecutionListener
-{
+public interface ExecutionListener {
 
-    void projectDiscoveryStarted( ExecutionEvent event );
+    void projectDiscoveryStarted(ExecutionEvent event);
 
-    void sessionStarted( ExecutionEvent event );
+    void sessionStarted(ExecutionEvent event);
 
-    void sessionEnded( ExecutionEvent event );
+    void sessionEnded(ExecutionEvent event);
 
-    void projectSkipped( ExecutionEvent event );
+    void projectSkipped(ExecutionEvent event);
 
-    void projectStarted( ExecutionEvent event );
+    void projectStarted(ExecutionEvent event);
 
-    void projectSucceeded( ExecutionEvent event );
+    void projectSucceeded(ExecutionEvent event);
 
-    void projectFailed( ExecutionEvent event );
+    void projectFailed(ExecutionEvent event);
 
-    void mojoSkipped( ExecutionEvent event );
+    void mojoSkipped(ExecutionEvent event);
 
-    void mojoStarted( ExecutionEvent event );
+    void mojoStarted(ExecutionEvent event);
 
-    void mojoSucceeded( ExecutionEvent event );
+    void mojoSucceeded(ExecutionEvent event);
 
-    void mojoFailed( ExecutionEvent event );
+    void mojoFailed(ExecutionEvent event);
 
-    void forkStarted( ExecutionEvent event );
+    void forkStarted(ExecutionEvent event);
 
-    void forkSucceeded( ExecutionEvent event );
+    void forkSucceeded(ExecutionEvent event);
 
-    void forkFailed( ExecutionEvent event );
+    void forkFailed(ExecutionEvent event);
 
-    void forkedProjectStarted( ExecutionEvent event );
+    void forkedProjectStarted(ExecutionEvent event);
 
-    void forkedProjectSucceeded( ExecutionEvent event );
+    void forkedProjectSucceeded(ExecutionEvent event);
 
-    void forkedProjectFailed( ExecutionEvent event );
-
+    void forkedProjectFailed(ExecutionEvent event);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
index 3989c5f..c5bcb6a 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
@@ -30,13 +30,9 @@
 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.model.Profile;
 import org.apache.maven.project.ProjectBuildingRequest;
-//
-// These settings values need to be removed and pushed down into a provider of configuration information
-//
 import org.apache.maven.settings.Mirror;
 import org.apache.maven.settings.Proxy;
 import org.apache.maven.settings.Server;
-//
 import org.apache.maven.toolchain.model.ToolchainModel;
 import org.codehaus.plexus.logging.Logger;
 import org.eclipse.aether.RepositoryCache;
@@ -44,10 +40,8 @@
 import org.eclipse.aether.transfer.TransferListener;
 
 /**
- * @author Jason van Zyl
  */
-public interface MavenExecutionRequest
-{
+public interface MavenExecutionRequest {
     // ----------------------------------------------------------------------
     // Logging
     // ----------------------------------------------------------------------
@@ -97,17 +91,26 @@
     // ----------------------------------------------------------------------
 
     // Base directory
-    MavenExecutionRequest setBaseDirectory( File basedir );
 
+    /**
+     * @deprecated use {@link #setTopDirectory(Path)} instead
+     */
+    @Deprecated
+    MavenExecutionRequest setBaseDirectory(File basedir);
+
+    /**
+     * @deprecated use {@link #getTopDirectory()} instead
+     */
+    @Deprecated
     String getBaseDirectory();
 
     // Timing (remove this)
-    MavenExecutionRequest setStartTime( Date start );
+    MavenExecutionRequest setStartTime(Date start);
 
     Date getStartTime();
 
     // Goals
-    MavenExecutionRequest setGoals( List<String> goals );
+    MavenExecutionRequest setGoals(List<String> goals);
 
     List<String> getGoals();
 
@@ -120,7 +123,7 @@
      * @param systemProperties The system properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    MavenExecutionRequest setSystemProperties( Properties systemProperties );
+    MavenExecutionRequest setSystemProperties(Properties systemProperties);
 
     /**
      * Gets the system properties to use for interpolation and profile activation. The system properties are collected
@@ -138,7 +141,7 @@
      * @param userProperties The user properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    MavenExecutionRequest setUserProperties( Properties userProperties );
+    MavenExecutionRequest setUserProperties(Properties userProperties);
 
     /**
      * Gets the user properties to use for interpolation and profile activation. The user properties have been
@@ -150,7 +153,7 @@
     Properties getUserProperties();
 
     // Reactor
-    MavenExecutionRequest setReactorFailureBehavior( String failureBehavior );
+    MavenExecutionRequest setReactorFailureBehavior(String failureBehavior);
 
     String getReactorFailureBehavior();
 
@@ -158,7 +161,7 @@
      * @deprecated Since Maven 4: use {@link #getProjectActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest setSelectedProjects( List<String> projects );
+    MavenExecutionRequest setSelectedProjects(List<String> projects);
 
     /**
      * @deprecated Since Maven 4: use {@link #getProjectActivation()}.
@@ -173,7 +176,7 @@
      * @deprecated Since Maven 4: use {@link #getProjectActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest setExcludedProjects( List<String> projects );
+    MavenExecutionRequest setExcludedProjects(List<String> projects);
 
     /**
      * @return the excluded projects, never {@code null}
@@ -188,18 +191,18 @@
      * @param resume Whether or not to resume a previous build.
      * @return This request, never {@code null}.
      */
-    MavenExecutionRequest setResume( boolean resume );
+    MavenExecutionRequest setResume(boolean resume);
 
     /**
      * @return Whether the build should be resumed from the data in the resume.properties file.
      */
     boolean isResume();
 
-    MavenExecutionRequest setResumeFrom( String project );
+    MavenExecutionRequest setResumeFrom(String project);
 
     String getResumeFrom();
 
-    MavenExecutionRequest setMakeBehavior( String makeBehavior );
+    MavenExecutionRequest setMakeBehavior(String makeBehavior);
 
     String getMakeBehavior();
 
@@ -208,7 +211,7 @@
      *
      * @param degreeOfConcurrency
      */
-    void setDegreeOfConcurrency( int degreeOfConcurrency );
+    void setDegreeOfConcurrency(int degreeOfConcurrency);
 
     /**
      * @return the degree of concurrency for the build.
@@ -216,96 +219,116 @@
     int getDegreeOfConcurrency();
 
     // Recursive (really to just process the top-level POM)
-    MavenExecutionRequest setRecursive( boolean recursive );
+    MavenExecutionRequest setRecursive(boolean recursive);
 
     boolean isRecursive();
 
-    MavenExecutionRequest setPom( File pom );
+    MavenExecutionRequest setPom(File pom);
 
     File getPom();
 
     // Errors
-    MavenExecutionRequest setShowErrors( boolean showErrors );
+    MavenExecutionRequest setShowErrors(boolean showErrors);
 
     boolean isShowErrors();
 
     // Transfer listeners
-    MavenExecutionRequest setTransferListener( TransferListener transferListener );
+    MavenExecutionRequest setTransferListener(TransferListener transferListener);
 
     TransferListener getTransferListener();
 
     // Logging
-    MavenExecutionRequest setLoggingLevel( int loggingLevel );
+    MavenExecutionRequest setLoggingLevel(int loggingLevel);
 
     int getLoggingLevel();
 
     // Update snapshots
-    MavenExecutionRequest setUpdateSnapshots( boolean updateSnapshots );
+    MavenExecutionRequest setUpdateSnapshots(boolean updateSnapshots);
 
     boolean isUpdateSnapshots();
 
-    MavenExecutionRequest setNoSnapshotUpdates( boolean noSnapshotUpdates );
+    MavenExecutionRequest setNoSnapshotUpdates(boolean noSnapshotUpdates);
 
     boolean isNoSnapshotUpdates();
 
     // Checksum policy
-    MavenExecutionRequest setGlobalChecksumPolicy( String globalChecksumPolicy );
+    MavenExecutionRequest setGlobalChecksumPolicy(String globalChecksumPolicy);
 
     String getGlobalChecksumPolicy();
 
     // Local repository
-    MavenExecutionRequest setLocalRepositoryPath( String localRepository );
+    MavenExecutionRequest setLocalRepositoryPath(String localRepository);
 
-    MavenExecutionRequest setLocalRepositoryPath( File localRepository );
+    MavenExecutionRequest setLocalRepositoryPath(File localRepository);
 
     File getLocalRepositoryPath();
 
-    MavenExecutionRequest setLocalRepository( ArtifactRepository repository );
+    MavenExecutionRequest setLocalRepository(ArtifactRepository repository);
 
     ArtifactRepository getLocalRepository();
 
     // Interactive
-    MavenExecutionRequest setInteractiveMode( boolean interactive );
+    MavenExecutionRequest setInteractiveMode(boolean interactive);
 
     boolean isInteractiveMode();
 
     // Offline
-    MavenExecutionRequest setOffline( boolean offline );
+    MavenExecutionRequest setOffline(boolean offline);
 
     boolean isOffline();
 
     boolean isCacheTransferError();
 
-    MavenExecutionRequest setCacheTransferError( boolean cacheTransferError );
+    MavenExecutionRequest setCacheTransferError(boolean cacheTransferError);
 
     boolean isCacheNotFound();
 
-    MavenExecutionRequest setCacheNotFound( boolean cacheNotFound );
+    MavenExecutionRequest setCacheNotFound(boolean cacheNotFound);
+
+    /**
+     * @since 4.0.0
+     */
+    boolean isIgnoreMissingArtifactDescriptor();
+
+    /**
+     * @since 4.0.0
+     */
+    MavenExecutionRequest setIgnoreMissingArtifactDescriptor(boolean ignoreMissing);
+
+    /**
+     * @since 4.0.0
+     */
+    boolean isIgnoreInvalidArtifactDescriptor();
+
+    /**
+     * @since 4.0.0
+     */
+    MavenExecutionRequest setIgnoreInvalidArtifactDescriptor(boolean ignoreInvalid);
 
     // Profiles
     List<Profile> getProfiles();
 
-    MavenExecutionRequest addProfile( Profile profile );
+    MavenExecutionRequest addProfile(Profile profile);
 
-    MavenExecutionRequest setProfiles( List<Profile> profiles );
+    MavenExecutionRequest setProfiles(List<Profile> profiles);
 
     /**
      * @deprecated Since Maven 4: use {@link #getProfileActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest addActiveProfile( String profile );
+    MavenExecutionRequest addActiveProfile(String profile);
 
     /**
      * @deprecated Since Maven 4: use {@link #getProfileActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest addActiveProfiles( List<String> profiles );
+    MavenExecutionRequest addActiveProfiles(List<String> profiles);
 
     /**
      * @deprecated Since Maven 4: use {@link #getProfileActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest setActiveProfiles( List<String> profiles );
+    MavenExecutionRequest setActiveProfiles(List<String> profiles);
 
     /**
      * @return The list of profiles that the user wants to activate.
@@ -318,19 +341,19 @@
      * @deprecated Since Maven 4: use {@link #getProfileActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest addInactiveProfile( String profile );
+    MavenExecutionRequest addInactiveProfile(String profile);
 
     /**
      * @deprecated Since Maven 4: use {@link #getProfileActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest addInactiveProfiles( List<String> profiles );
+    MavenExecutionRequest addInactiveProfiles(List<String> profiles);
 
     /**
      * @deprecated Since Maven 4: use {@link #getProfileActivation()}.
      */
     @Deprecated
-    MavenExecutionRequest setInactiveProfiles( List<String> profiles );
+    MavenExecutionRequest setInactiveProfiles(List<String> profiles);
 
     /**
      * @return The list of profiles that the user wants to de-activate.
@@ -354,48 +377,52 @@
     // Proxies
     List<Proxy> getProxies();
 
-    MavenExecutionRequest setProxies( List<Proxy> proxies );
+    MavenExecutionRequest setProxies(List<Proxy> proxies);
 
-    MavenExecutionRequest addProxy( Proxy proxy );
+    MavenExecutionRequest addProxy(Proxy proxy);
 
     // Servers
     List<Server> getServers();
 
-    MavenExecutionRequest setServers( List<Server> servers );
+    MavenExecutionRequest setServers(List<Server> servers);
 
-    MavenExecutionRequest addServer( Server server );
+    MavenExecutionRequest addServer(Server server);
 
     // Mirrors
     List<Mirror> getMirrors();
 
-    MavenExecutionRequest setMirrors( List<Mirror> mirrors );
+    MavenExecutionRequest setMirrors(List<Mirror> mirrors);
 
-    MavenExecutionRequest addMirror( Mirror mirror );
+    MavenExecutionRequest addMirror(Mirror mirror);
 
     // Plugin groups
     List<String> getPluginGroups();
 
-    MavenExecutionRequest setPluginGroups( List<String> pluginGroups );
+    MavenExecutionRequest setPluginGroups(List<String> pluginGroups);
 
-    MavenExecutionRequest addPluginGroup( String pluginGroup );
+    MavenExecutionRequest addPluginGroup(String pluginGroup);
 
-    MavenExecutionRequest addPluginGroups( List<String> pluginGroups );
+    MavenExecutionRequest addPluginGroups(List<String> pluginGroups);
 
     boolean isProjectPresent();
 
-    MavenExecutionRequest setProjectPresent( boolean isProjectPresent );
+    MavenExecutionRequest setProjectPresent(boolean isProjectPresent);
 
     File getUserSettingsFile();
 
-    MavenExecutionRequest setUserSettingsFile( File userSettingsFile );
+    MavenExecutionRequest setUserSettingsFile(File userSettingsFile);
+
+    File getProjectSettingsFile();
+
+    MavenExecutionRequest setProjectSettingsFile(File projectSettingsFile);
 
     File getGlobalSettingsFile();
 
-    MavenExecutionRequest setGlobalSettingsFile( File globalSettingsFile );
+    MavenExecutionRequest setGlobalSettingsFile(File globalSettingsFile);
 
-    MavenExecutionRequest addRemoteRepository( ArtifactRepository repository );
+    MavenExecutionRequest addRemoteRepository(ArtifactRepository repository);
 
-    MavenExecutionRequest addPluginArtifactRepository( ArtifactRepository repository );
+    MavenExecutionRequest addPluginArtifactRepository(ArtifactRepository repository);
 
     /**
      * Set a new list of remote repositories to use the execution request. This is necessary if you perform
@@ -405,25 +432,25 @@
      * @param repositories
      * @return This request, never {@code null}.
      */
-    MavenExecutionRequest setRemoteRepositories( List<ArtifactRepository> repositories );
+    MavenExecutionRequest setRemoteRepositories(List<ArtifactRepository> repositories);
 
     List<ArtifactRepository> getRemoteRepositories();
 
-    MavenExecutionRequest setPluginArtifactRepositories( List<ArtifactRepository> repositories );
+    MavenExecutionRequest setPluginArtifactRepositories(List<ArtifactRepository> repositories);
 
     List<ArtifactRepository> getPluginArtifactRepositories();
 
-    MavenExecutionRequest setRepositoryCache( RepositoryCache repositoryCache );
+    MavenExecutionRequest setRepositoryCache(RepositoryCache repositoryCache);
 
     RepositoryCache getRepositoryCache();
 
     WorkspaceReader getWorkspaceReader();
 
-    MavenExecutionRequest setWorkspaceReader( WorkspaceReader workspaceReader );
+    MavenExecutionRequest setWorkspaceReader(WorkspaceReader workspaceReader);
 
     File getUserToolchainsFile();
 
-    MavenExecutionRequest setUserToolchainsFile( File userToolchainsFile );
+    MavenExecutionRequest setUserToolchainsFile(File userToolchainsFile);
 
     /**
      *
@@ -439,23 +466,33 @@
      * @return this request
      * @since 3.3.0
      */
-    MavenExecutionRequest setGlobalToolchainsFile( File globalToolchainsFile );
+    MavenExecutionRequest setGlobalToolchainsFile(File globalToolchainsFile);
 
     ExecutionListener getExecutionListener();
 
-    MavenExecutionRequest setExecutionListener( ExecutionListener executionListener );
+    MavenExecutionRequest setExecutionListener(ExecutionListener executionListener);
 
     ProjectBuildingRequest getProjectBuildingRequest();
 
     /**
      * @since 3.1
+     * @deprecated Since 3.9 there is no direct Maven2 interop offered at LRM level. See
+     * <a href="https://maven.apache.org/resolver/configuration.html">Resolver Configuration</a> page option
+     * {@code aether.artifactResolver.simpleLrmInterop} that provides similar semantics. This method should
+     * be never invoked, and always returns {@code false}.
      */
+    @Deprecated
     boolean isUseLegacyLocalRepository();
 
     /**
      * @since 3.1
+     * @deprecated Since 3.9 there is no direct Maven2 interop offered at LRM level. See
+     * <a href="https://maven.apache.org/resolver/configuration.html">Resolver Configuration</a> page option
+     * {@code aether.artifactResolver.simpleLrmInterop} that provides similar semantics. This method should
+     * be never invoked, and ignores parameter (value remains always {@code false}).
      */
-    MavenExecutionRequest setUseLegacyLocalRepository( boolean useLegacyLocalRepository );
+    @Deprecated
+    MavenExecutionRequest setUseLegacyLocalRepository(boolean useLegacyLocalRepository);
 
     /**
      * Controls the {@link org.apache.maven.lifecycle.internal.builder.Builder} used by Maven by specification
@@ -463,7 +500,7 @@
      *
      * @since 3.2.0
      */
-    MavenExecutionRequest setBuilderId( String builderId );
+    MavenExecutionRequest setBuilderId(String builderId);
 
     /**
      * Controls the {@link org.apache.maven.lifecycle.internal.builder.Builder} used by Maven by specification
@@ -479,7 +516,7 @@
      * @return this request
      * @since 3.3.0
      */
-    MavenExecutionRequest setToolchains( Map<String, List<ToolchainModel>> toolchains );
+    MavenExecutionRequest setToolchains(Map<String, List<ToolchainModel>> toolchains);
 
     /**
      *
@@ -490,18 +527,55 @@
 
     /**
      * @since 3.3.0
+     * @deprecated use {@link #setRootDirectory(Path)} instead
      */
-    void setMultiModuleProjectDirectory( File file );
+    @Deprecated
+    void setMultiModuleProjectDirectory(File file);
 
     /**
      * @since 3.3.0
+     * @deprecated use {@link #getRootDirectory()} instead
      */
+    @Deprecated
     File getMultiModuleProjectDirectory();
 
     /**
+     * Sets the top directory of the project.
+     *
+     * @since 4.0.0
+     */
+    MavenExecutionRequest setTopDirectory(Path topDirectory);
+
+    /**
+     * Gets the directory of the topmost project being built, usually the current directory or the
+     * directory pointed at by the {@code -f/--file} command line argument.
+     *
+     * @since 4.0.0
+     */
+    Path getTopDirectory();
+
+    /**
+     * Sets the root directory of the project.
+     *
+     * @since 4.0.0
+     */
+    MavenExecutionRequest setRootDirectory(Path rootDirectory);
+
+    /**
+     * Gets the root directory of the top project, which is the parent directory containing the {@code .mvn}
+     * directory or a {@code pom.xml} file with the {@code root="true"} attribute.
+     * If there's no such directory, an {@code IllegalStateException} will be thrown.
+     *
+     * @throws IllegalStateException if the root directory could not be found
+     * @see #getTopDirectory()
+     * @since 4.0.0
+     */
+    Path getRootDirectory();
+
+    /**
      * @since 3.3.0
      */
-    MavenExecutionRequest setEventSpyDispatcher( EventSpyDispatcher eventSpyDispatcher );
+    MavenExecutionRequest setEventSpyDispatcher(EventSpyDispatcher eventSpyDispatcher);
 
     /**
      * @since 3.3.0
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulationException.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulationException.java
index ddd6ad2..7c86d31 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulationException.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,26 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 /**
- * @author Jason van Zyl
  */
-public class MavenExecutionRequestPopulationException
-    extends Exception
-{
-    public MavenExecutionRequestPopulationException( String message )
-    {
-        super( message );
+public class MavenExecutionRequestPopulationException extends Exception {
+    public MavenExecutionRequestPopulationException(String message) {
+        super(message);
     }
 
-    public MavenExecutionRequestPopulationException( Throwable cause )
-    {
-        super( cause );
+    public MavenExecutionRequestPopulationException(Throwable cause) {
+        super(cause);
     }
 
-    public MavenExecutionRequestPopulationException( String message,
-                                   Throwable cause )
-    {
-        super( message, cause );
+    public MavenExecutionRequestPopulationException(String message, Throwable cause) {
+        super(message, cause);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulator.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulator.java
index c2d4c84..f391cc7 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulator.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionRequestPopulator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.settings.Settings;
 import org.apache.maven.toolchain.model.PersistedToolchains;
@@ -25,10 +24,8 @@
 /**
  * Assists in populating an execution request for invocation of Maven.
  *
- * @author Benjamin Bentmann
  */
-public interface MavenExecutionRequestPopulator
-{
+public interface MavenExecutionRequestPopulator {
     /**
      * Copies the values from the given toolchains into the specified execution request. This method will replace any
      * existing values in the execution request that are controlled by the toolchains. Hence, it is expected that this
@@ -40,8 +37,8 @@
      * @throws MavenExecutionRequestPopulationException If the execution request could not be populated.
      * @since 3.3.0
      */
-    MavenExecutionRequest populateFromToolchains( MavenExecutionRequest request, PersistedToolchains toolchains )
-        throws MavenExecutionRequestPopulationException;
+    MavenExecutionRequest populateFromToolchains(MavenExecutionRequest request, PersistedToolchains toolchains)
+            throws MavenExecutionRequestPopulationException;
 
     /**
      * Injects default values like plugin groups or repositories into the specified execution request.
@@ -50,8 +47,8 @@
      * @return The populated execution request, never {@code null}.
      * @throws MavenExecutionRequestPopulationException If the execution request could not be populated.
      */
-    MavenExecutionRequest populateDefaults( MavenExecutionRequest request )
-        throws MavenExecutionRequestPopulationException;
+    MavenExecutionRequest populateDefaults(MavenExecutionRequest request)
+            throws MavenExecutionRequestPopulationException;
 
     /*if_not[MAVEN4]*/
 
@@ -66,8 +63,8 @@
      * @throws MavenExecutionRequestPopulationException If the execution request could not be populated.
      */
     @Deprecated
-    MavenExecutionRequest populateFromSettings( MavenExecutionRequest request, Settings settings )
-        throws MavenExecutionRequestPopulationException;
+    MavenExecutionRequest populateFromSettings(MavenExecutionRequest request, Settings settings)
+            throws MavenExecutionRequestPopulationException;
 
     /*end[MAVEN4]*/
 
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
index 8a099bb..260de18 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenExecutionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.List;
 
@@ -25,21 +24,21 @@
 import org.apache.maven.project.MavenProject;
 
 /**
- * @author Jason van Zyl
  */
-public interface MavenExecutionResult
-{
-    MavenExecutionResult setProject( MavenProject project );
+public interface MavenExecutionResult {
+    MavenExecutionResult setProject(MavenProject project);
+
     MavenProject getProject();
 
-    MavenExecutionResult setTopologicallySortedProjects( List<MavenProject> projects );
+    MavenExecutionResult setTopologicallySortedProjects(List<MavenProject> projects);
 
     /**
      * @return the sorted list, or an empty list if there are no projects.
      */
     List<MavenProject> getTopologicallySortedProjects();
 
-    MavenExecutionResult setDependencyResolutionResult( DependencyResolutionResult result );
+    MavenExecutionResult setDependencyResolutionResult(DependencyResolutionResult result);
+
     DependencyResolutionResult getDependencyResolutionResult();
 
     // for each exception
@@ -49,7 +48,7 @@
     // - xmlpull parser exception
     List<Throwable> getExceptions();
 
-    MavenExecutionResult addException( Throwable e );
+    MavenExecutionResult addException(Throwable e);
 
     boolean hasExceptions();
 
@@ -59,14 +58,14 @@
      * @param project The project to get the build summary for, must not be {@code null}.
      * @return The build summary for the project or {@code null} if the project has not been built (yet).
      */
-    BuildSummary getBuildSummary( MavenProject project );
+    BuildSummary getBuildSummary(MavenProject project);
 
     /**
      * Add the specified build summary.
      *
      * @param summary The build summary to add, must not be {@code null}.
      */
-    void addBuildSummary( BuildSummary summary );
+    void addBuildSummary(BuildSummary summary);
 
     /**
      * Indicates whether or not the build could be resumed by a second invocation of Maven.
@@ -81,5 +80,5 @@
      * @see BuildResumptionDataRepository
      * @see #canResume()
      */
-    void setCanResume( boolean canResume );
+    void setCanResume(boolean canResume);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java
index 4551ccf..ac6c1ed 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MavenSession.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Date;
 import java.util.List;
@@ -27,33 +27,39 @@
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
 
+import org.apache.maven.api.Session;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.repository.RepositoryCache;
+import org.apache.maven.model.Profile;
 import org.apache.maven.monitor.event.EventDispatcher;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Server;
 import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.SettingsUtilsV4;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.eclipse.aether.RepositorySystemSession;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * A Maven execution session.
  *
- * @author Jason van Zyl
  */
-public class MavenSession
-    implements Cloneable
-{
-    private MavenExecutionRequest request;
+public class MavenSession implements Cloneable {
+    private final MavenExecutionRequest request;
 
-    private MavenExecutionResult result;
+    private final MavenExecutionResult result;
 
-    private RepositorySystemSession repositorySession;
+    private final RepositorySystemSession repositorySystemSession;
 
-    private Properties executionProperties;
+    private final Properties executionProperties;
 
     private ThreadLocal<MavenProject> currentProject = new ThreadLocal<>();
 
@@ -81,36 +87,30 @@
      * ({@link PluginDescriptor#getPluginLookupKey()}). Plugin contexts itself are mappings of {@link String} keys to
      * {@link Object} values.
      */
-    @SuppressWarnings( "checkstyle:linelength" )
-    private final ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<String, Object>>> pluginContextsByProjectAndPluginKey =
-        new ConcurrentHashMap<>();
+    @SuppressWarnings("checkstyle:linelength")
+    private final ConcurrentMap<String, ConcurrentMap<String, ConcurrentMap<String, Object>>>
+            pluginContextsByProjectAndPluginKey = new ConcurrentHashMap<>();
 
-
-    public void setProjects( List<MavenProject> projects )
-    {
-        if ( !projects.isEmpty() )
-        {
-            MavenProject first = projects.get( 0 );
-            this.currentProject = ThreadLocal.withInitial( () -> first );
-            this.topLevelProject =
-                    projects.stream().filter( project -> project.isExecutionRoot() ).findFirst()
-                            .orElse( first );
-        }
-        else
-        {
+    public void setProjects(List<MavenProject> projects) {
+        if (!projects.isEmpty()) {
+            MavenProject first = projects.get(0);
+            this.currentProject = ThreadLocal.withInitial(() -> first);
+            this.topLevelProject = projects.stream()
+                    .filter(project -> project.isExecutionRoot())
+                    .findFirst()
+                    .orElse(first);
+        } else {
             this.currentProject = new ThreadLocal<>();
             this.topLevelProject = null;
         }
         this.projects = projects;
     }
 
-    public ArtifactRepository getLocalRepository()
-    {
+    public ArtifactRepository getLocalRepository() {
         return request.getLocalRepository();
     }
 
-    public List<String> getGoals()
-    {
+    public List<String> getGoals() {
         return request.getGoals();
     }
 
@@ -121,8 +121,7 @@
      *
      * @return The user properties, never {@code null}.
      */
-    public Properties getUserProperties()
-    {
+    public Properties getUserProperties() {
         return request.getUserProperties();
     }
 
@@ -132,69 +131,76 @@
      *
      * @return The system properties, never {@code null}.
      */
-    public Properties getSystemProperties()
-    {
+    public Properties getSystemProperties() {
         return request.getSystemProperties();
     }
 
-    public Settings getSettings()
-    {
+    public Settings getSettings() {
         return settings;
     }
 
-    public List<MavenProject> getProjects()
-    {
+    public List<MavenProject> getProjects() {
         return projects;
     }
 
-    public String getExecutionRootDirectory()
-    {
+    /**
+     * @deprecated use {@link #getTopDirectory()} ()}
+     */
+    @Deprecated
+    public String getExecutionRootDirectory() {
         return request.getBaseDirectory();
     }
 
-    public MavenExecutionRequest getRequest()
-    {
+    /**
+     * @see MavenExecutionRequest#getTopDirectory()
+     * @since 4.0.0
+     */
+    public Path getTopDirectory() {
+        return request.getTopDirectory();
+    }
+
+    /**
+     * @see MavenExecutionRequest#getRootDirectory()
+     * @since 4.0.0
+     */
+    public Path getRootDirectory() {
+        return request.getRootDirectory();
+    }
+
+    public MavenExecutionRequest getRequest() {
         return request;
     }
 
-    public void setCurrentProject( MavenProject currentProject )
-    {
-        this.currentProject.set( currentProject );
+    public void setCurrentProject(MavenProject currentProject) {
+        this.currentProject.set(currentProject);
     }
 
-    public MavenProject getCurrentProject()
-    {
+    public MavenProject getCurrentProject() {
         return currentProject.get();
     }
 
-    public ProjectBuildingRequest getProjectBuildingRequest()
-    {
-        return request.getProjectBuildingRequest().setRepositorySession( getRepositorySession() );
+    public ProjectBuildingRequest getProjectBuildingRequest() {
+        return request.getProjectBuildingRequest().setRepositorySession(getRepositorySession());
     }
 
-    public List<String> getPluginGroups()
-    {
+    public List<String> getPluginGroups() {
         return request.getPluginGroups();
     }
 
-    public boolean isOffline()
-    {
+    public boolean isOffline() {
         return request.isOffline();
     }
 
-    public MavenProject getTopLevelProject()
-    {
+    public MavenProject getTopLevelProject() {
         return topLevelProject;
     }
 
-    public MavenExecutionResult getResult()
-    {
+    public MavenExecutionResult getResult() {
         return result;
     }
 
     // Backward compat
 
-
     /**
      * Returns the plugin context for given key ({@link PluginDescriptor#getPluginLookupKey()} and
      * {@link MavenProject}, never returns {@code null} as if context not present, creates it.
@@ -203,87 +209,72 @@
      * implements {@link ConcurrentMap} as well.
      *
      */
-    public Map<String, Object> getPluginContext( PluginDescriptor plugin, MavenProject project )
-    {
+    public Map<String, Object> getPluginContext(PluginDescriptor plugin, MavenProject project) {
         String projectKey = project.getId();
 
-        ConcurrentMap<String, ConcurrentMap<String, Object>> pluginContextsByKey = pluginContextsByProjectAndPluginKey
-                .computeIfAbsent( projectKey, k -> new ConcurrentHashMap<>() );
+        ConcurrentMap<String, ConcurrentMap<String, Object>> pluginContextsByKey =
+                pluginContextsByProjectAndPluginKey.computeIfAbsent(projectKey, k -> new ConcurrentHashMap<>());
 
         String pluginKey = plugin.getPluginLookupKey();
 
-        return pluginContextsByKey.computeIfAbsent( pluginKey, k -> new ConcurrentHashMap<>() );
+        return pluginContextsByKey.computeIfAbsent(pluginKey, k -> new ConcurrentHashMap<>());
     }
 
-    public ProjectDependencyGraph getProjectDependencyGraph()
-    {
+    public ProjectDependencyGraph getProjectDependencyGraph() {
         return projectDependencyGraph;
     }
 
-    public void setProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph )
-    {
+    public void setProjectDependencyGraph(ProjectDependencyGraph projectDependencyGraph) {
         this.projectDependencyGraph = projectDependencyGraph;
     }
 
-    public String getReactorFailureBehavior()
-    {
+    public String getReactorFailureBehavior() {
         return request.getReactorFailureBehavior();
     }
 
     @Override
-    public MavenSession clone()
-    {
-        try
-        {
+    public MavenSession clone() {
+        try {
             MavenSession clone = (MavenSession) super.clone();
             // the default must become the current project of the thread that clones this
             MavenProject current = getCurrentProject();
             // we replace the thread local of the clone to prevent write through and enforce the new default value
-            clone.currentProject = ThreadLocal.withInitial( () -> current );
+            clone.currentProject = ThreadLocal.withInitial(() -> current);
             return clone;
-        }
-        catch ( CloneNotSupportedException e )
-        {
-            throw new RuntimeException( "Bug", e );
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException("Bug", e);
         }
     }
 
-    public Date getStartTime()
-    {
+    public Date getStartTime() {
         return request.getStartTime();
     }
 
-    public boolean isParallel()
-    {
+    public boolean isParallel() {
         return parallel;
     }
 
-    public void setParallel( boolean parallel )
-    {
+    public void setParallel(boolean parallel) {
         this.parallel = parallel;
     }
 
-    public RepositorySystemSession getRepositorySession()
-    {
-        return repositorySession;
+    public RepositorySystemSession getRepositorySession() {
+        return repositorySystemSession;
     }
 
     private Map<String, MavenProject> projectMap;
 
-    public void setProjectMap( Map<String, MavenProject> projectMap )
-    {
+    public void setProjectMap(Map<String, MavenProject> projectMap) {
         this.projectMap = projectMap;
     }
 
     /** This is a provisional method and may be removed */
-    public List<MavenProject> getAllProjects()
-    {
+    public List<MavenProject> getAllProjects() {
         return allProjects;
     }
 
     /** This is a provisional method and may be removed */
-    public void setAllProjects( List<MavenProject> allProjects )
-    {
+    public void setAllProjects(List<MavenProject> allProjects) {
         this.allProjects = allProjects;
     }
 
@@ -293,77 +284,154 @@
     // Deprecated
     //
 
-    private PlexusContainer container;
+    private final PlexusContainer container;
 
     private final Settings settings;
 
+    private Session session;
+
     @Deprecated
     /** @deprecated This appears not to be used anywhere within Maven itself. */
-    public Map<String, MavenProject> getProjectMap()
-    {
+    public Map<String, MavenProject> getProjectMap() {
         return projectMap;
     }
 
+    public MavenSession(
+            RepositorySystemSession repositorySystemSession,
+            MavenExecutionRequest request,
+            MavenExecutionResult result) {
+        this.container = null;
+        this.request = requireNonNull(request);
+        this.result = requireNonNull(result);
+        this.settings = adaptSettings(request);
+        this.repositorySystemSession = requireNonNull(repositorySystemSession);
+        Properties executionProperties = new Properties();
+        executionProperties.putAll(request.getSystemProperties());
+        executionProperties.putAll(request.getUserProperties());
+        this.executionProperties = executionProperties;
+    }
+
     @Deprecated
-    public MavenSession( PlexusContainer container, RepositorySystemSession repositorySession,
-                         MavenExecutionRequest request, MavenExecutionResult result )
-    {
+    public MavenSession(
+            PlexusContainer container,
+            RepositorySystemSession repositorySession,
+            MavenExecutionRequest request,
+            MavenExecutionResult result) {
         this.container = container;
         this.request = request;
         this.result = result;
-        this.settings = new SettingsAdapter( request );
-        this.repositorySession = repositorySession;
+        this.settings = adaptSettings(request);
+        this.repositorySystemSession = repositorySession;
+        Properties executionProperties = new Properties();
+        executionProperties.putAll(request.getSystemProperties());
+        executionProperties.putAll(request.getUserProperties());
+        this.executionProperties = executionProperties;
     }
 
     @Deprecated
-    public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result,
-                         MavenProject project )
-    {
-        this( container, request, result, Arrays.asList( new MavenProject[]{project} ) );
+    public MavenSession(
+            PlexusContainer container,
+            MavenExecutionRequest request,
+            MavenExecutionResult result,
+            MavenProject project) {
+        this(container, request, result, Arrays.asList(new MavenProject[] {project}));
     }
 
     @Deprecated
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public MavenSession( PlexusContainer container, Settings settings, ArtifactRepository localRepository,
-                         EventDispatcher eventDispatcher, ReactorManager unused, List<String> goals,
-                         String executionRootDir, Properties executionProperties, Date startTime )
-    {
-        this( container, settings, localRepository, eventDispatcher, unused, goals, executionRootDir,
-              executionProperties, null, startTime );
+    @SuppressWarnings("checkstyle:parameternumber")
+    public MavenSession(
+            PlexusContainer container,
+            Settings settings,
+            ArtifactRepository localRepository,
+            EventDispatcher eventDispatcher,
+            ReactorManager unused,
+            List<String> goals,
+            String executionRootDir,
+            Properties executionProperties,
+            Date startTime) {
+        this(
+                container,
+                settings,
+                localRepository,
+                eventDispatcher,
+                unused,
+                goals,
+                executionRootDir,
+                executionProperties,
+                null,
+                startTime);
     }
 
     @Deprecated
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public MavenSession( PlexusContainer container, Settings settings, ArtifactRepository localRepository,
-                         EventDispatcher eventDispatcher, ReactorManager unused, List<String> goals,
-                         String executionRootDir, Properties executionProperties, Properties userProperties,
-                         Date startTime )
-    {
+    @SuppressWarnings("checkstyle:parameternumber")
+    public MavenSession(
+            PlexusContainer container,
+            Settings settings,
+            ArtifactRepository localRepository,
+            EventDispatcher eventDispatcher,
+            ReactorManager unused,
+            List<String> goals,
+            String executionRootDir,
+            Properties executionProperties,
+            Properties userProperties,
+            Date startTime) {
         this.container = container;
         this.settings = settings;
         this.executionProperties = executionProperties;
         this.request = new DefaultMavenExecutionRequest();
-        this.request.setUserProperties( userProperties );
-        this.request.setLocalRepository( localRepository );
-        this.request.setGoals( goals );
-        this.request.setBaseDirectory( ( executionRootDir != null ) ? new File( executionRootDir ) : null );
-        this.request.setStartTime( startTime );
+        this.request.setUserProperties(userProperties);
+        this.request.setLocalRepository(localRepository);
+        this.request.setGoals(goals);
+        this.request.setBaseDirectory((executionRootDir != null) ? new File(executionRootDir) : null);
+        this.request.setStartTime(startTime);
+        this.result = null;
+        this.repositorySystemSession = null;
     }
 
     @Deprecated
-    public MavenSession( PlexusContainer container, MavenExecutionRequest request, MavenExecutionResult result,
-                         List<MavenProject> projects )
-    {
+    public MavenSession(
+            PlexusContainer container,
+            MavenExecutionRequest request,
+            MavenExecutionResult result,
+            List<MavenProject> projects) {
         this.container = container;
         this.request = request;
         this.result = result;
-        this.settings = new SettingsAdapter( request );
-        setProjects( projects );
+        this.settings = adaptSettings(request);
+        Properties executionProperties = new Properties();
+        executionProperties.putAll(request.getSystemProperties());
+        executionProperties.putAll(request.getUserProperties());
+        this.executionProperties = executionProperties;
+        setProjects(projects);
+        this.repositorySystemSession = null;
+    }
+
+    /**
+     * Adapt a {@link MavenExecutionRequest} to a {@link Settings} object for use in the Maven core.
+     * We want to make sure that what is ask for in the execution request overrides what is in the settings.
+     * The CLI feeds into an execution request so if a particular value is present in the execution request
+     * then we will take that over the value coming from the user settings.
+     */
+    private static Settings adaptSettings(MavenExecutionRequest request) {
+        File localRepo = request.getLocalRepositoryPath();
+        return new Settings(org.apache.maven.api.settings.Settings.newBuilder()
+                .localRepository(localRepo != null ? localRepo.getAbsolutePath() : null)
+                .interactiveMode(request.isInteractiveMode())
+                .offline(request.isOffline())
+                .proxies(request.getProxies().stream().map(Proxy::getDelegate).collect(Collectors.toList()))
+                .servers(request.getServers().stream().map(Server::getDelegate).collect(Collectors.toList()))
+                .mirrors(request.getMirrors().stream().map(Mirror::getDelegate).collect(Collectors.toList()))
+                .profiles(request.getProfiles().stream()
+                        .map(Profile::getDelegate)
+                        .map(SettingsUtilsV4::convertToSettingsProfile)
+                        .collect(Collectors.toList()))
+                .activeProfiles(request.getActiveProfiles())
+                .pluginGroups(request.getPluginGroups())
+                .build());
     }
 
     @Deprecated
-    public List<MavenProject> getSortedProjects()
-    {
+    public List<MavenProject> getSortedProjects() {
         return getProjects();
     }
 
@@ -372,20 +440,17 @@
     // Used by Tycho and will break users and force them to upgrade to Maven 3.1 so we should really leave
     // this here, possibly indefinitely.
     //
-    public RepositoryCache getRepositoryCache()
-    {
+    public RepositoryCache getRepositoryCache() {
         return null;
     }
 
     @Deprecated
-    public EventDispatcher getEventDispatcher()
-    {
+    public EventDispatcher getEventDispatcher() {
         return null;
     }
 
     @Deprecated
-    public boolean isUsingPOMsFromFilesystem()
-    {
+    public boolean isUsingPOMsFromFilesystem() {
         return request.isProjectPresent();
     }
 
@@ -393,51 +458,41 @@
      * @deprecated Use either {@link #getUserProperties()} or {@link #getSystemProperties()}.
      */
     @Deprecated
-    public Properties getExecutionProperties()
-    {
-        if ( executionProperties == null )
-        {
-            executionProperties = new Properties();
-            executionProperties.putAll( request.getSystemProperties() );
-            executionProperties.putAll( request.getUserProperties() );
-        }
-
+    public Properties getExecutionProperties() {
         return executionProperties;
     }
 
     @Deprecated
-    public PlexusContainer getContainer()
-    {
+    public PlexusContainer getContainer() {
         return container;
     }
 
     @Deprecated
-    public Object lookup( String role )
-        throws ComponentLookupException
-    {
-        return container.lookup( role );
+    public Object lookup(String role) throws ComponentLookupException {
+        return container.lookup(role);
     }
 
     @Deprecated
-    public Object lookup( String role, String roleHint )
-        throws ComponentLookupException
-    {
-        return container.lookup( role, roleHint );
+    public Object lookup(String role, String roleHint) throws ComponentLookupException {
+        return container.lookup(role, roleHint);
     }
 
     @Deprecated
-    public List<Object> lookupList( String role )
-        throws ComponentLookupException
-    {
-        return container.lookupList( role );
+    public List<Object> lookupList(String role) throws ComponentLookupException {
+        return container.lookupList(role);
     }
 
     @Deprecated
-    public Map<String, Object> lookupMap( String role )
-        throws ComponentLookupException
-    {
-        return container.lookupMap( role );
+    public Map<String, Object> lookupMap(String role) throws ComponentLookupException {
+        return container.lookupMap(role);
     }
 
+    public Session getSession() {
+        return session;
+    }
+
+    public void setSession(Session session) {
+        this.session = session;
+    }
     /*end[MAVEN4]*/
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionEvent.java b/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionEvent.java
index 85a58cb..5022f0f 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionEvent.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionEvent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.plugin.Mojo;
 import org.apache.maven.plugin.MojoExecution;
@@ -34,8 +33,7 @@
  * @see org.apache.maven.execution.scope.WeakMojoExecutionListener
  * @since 3.1.2
  */
-public class MojoExecutionEvent
-{
+public class MojoExecutionEvent {
     private final MavenSession session;
 
     private final MavenProject project;
@@ -46,14 +44,12 @@
 
     private final Throwable cause;
 
-    public MojoExecutionEvent( MavenSession session, MavenProject project, MojoExecution mojoExecution, Mojo mojo )
-    {
-        this( session, project, mojoExecution, mojo, null );
+    public MojoExecutionEvent(MavenSession session, MavenProject project, MojoExecution mojoExecution, Mojo mojo) {
+        this(session, project, mojoExecution, mojo, null);
     }
 
-    public MojoExecutionEvent( MavenSession session, MavenProject project, MojoExecution mojoExecution, Mojo mojo,
-                               Throwable cause )
-    {
+    public MojoExecutionEvent(
+            MavenSession session, MavenProject project, MojoExecution mojoExecution, Mojo mojo, Throwable cause) {
         this.session = session;
         this.project = project;
         this.mojoExecution = mojoExecution;
@@ -61,28 +57,23 @@
         this.cause = cause;
     }
 
-    public MavenSession getSession()
-    {
+    public MavenSession getSession() {
         return session;
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public MojoExecution getExecution()
-    {
+    public MojoExecution getExecution() {
         return mojoExecution;
     }
 
-    public Mojo getMojo()
-    {
+    public Mojo getMojo() {
         return mojo;
     }
 
-    public Throwable getCause()
-    {
+    public Throwable getCause() {
         return cause;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java
index 97d6b03..b935fb8 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/MojoExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.plugin.MojoExecutionException;
 
@@ -30,13 +29,10 @@
  * @see org.apache.maven.execution.scope.WeakMojoExecutionListener
  * @since 3.1.2
  */
-public interface MojoExecutionListener
-{
-    void beforeMojoExecution( MojoExecutionEvent event )
-        throws MojoExecutionException;
+public interface MojoExecutionListener {
+    void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException;
 
-    void afterMojoExecutionSuccess( MojoExecutionEvent event )
-        throws MojoExecutionException;
+    void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException;
 
-    void afterExecutionFailure( MojoExecutionEvent event );
+    void afterExecutionFailure(MojoExecutionEvent event);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java b/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
index ad00a74..cc6aecb 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ProfileActivation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -33,8 +32,7 @@
  * Container for storing the request from the user to activate or de-activate certain profiles and optionally fail the
  * build if those profiles do not exist.
  */
-public class ProfileActivation
-{
+public class ProfileActivation {
     private final Map<String, ActivationSettings> activations = new HashMap<>();
 
     /**
@@ -42,9 +40,8 @@
      * @deprecated Use {@link #getRequiredActiveProfileIds()} and {@link #getOptionalActiveProfileIds()} instead.
      */
     @Deprecated
-    public List<String> getActiveProfiles()
-    {
-        return Collections.unmodifiableList( new ArrayList<>( getProfileIds( pa -> pa.active ) ) );
+    public List<String> getActiveProfiles() {
+        return Collections.unmodifiableList(new ArrayList<>(getProfileIds(pa -> pa.active)));
     }
 
     /**
@@ -52,9 +49,8 @@
      * @deprecated Use {@link #getRequiredInactiveProfileIds()} and {@link #getOptionalInactiveProfileIds()} instead.
      */
     @Deprecated
-    public List<String> getInactiveProfiles()
-    {
-        return Collections.unmodifiableList( new ArrayList<>( getProfileIds( pa -> !pa.active ) ) );
+    public List<String> getInactiveProfiles() {
+        return Collections.unmodifiableList(new ArrayList<>(getProfileIds(pa -> !pa.active)));
     }
 
     /**
@@ -63,10 +59,9 @@
      * @deprecated Use {@link #activateOptionalProfile(String)} or {@link #activateRequiredProfile(String)} instead.
      */
     @Deprecated
-    public void overwriteActiveProfiles( List<String> activeProfileIds )
-    {
-        getActiveProfiles().forEach( this.activations::remove );
-        activeProfileIds.forEach( this::activateOptionalProfile );
+    public void overwriteActiveProfiles(List<String> activeProfileIds) {
+        getActiveProfiles().forEach(this.activations::remove);
+        activeProfileIds.forEach(this::activateOptionalProfile);
     }
 
     /**
@@ -75,46 +70,41 @@
      * @deprecated Use {@link #deactivateOptionalProfile(String)} or {@link #deactivateRequiredProfile(String)} instead.
      */
     @Deprecated
-    public void overwriteInactiveProfiles( List<String> inactiveProfileIds )
-    {
-        getInactiveProfiles().forEach( this.activations::remove );
-        inactiveProfileIds.forEach( this::deactivateOptionalProfile );
+    public void overwriteInactiveProfiles(List<String> inactiveProfileIds) {
+        getInactiveProfiles().forEach(this.activations::remove);
+        inactiveProfileIds.forEach(this::deactivateOptionalProfile);
     }
 
     /**
      * Mark a profile as required and activated.
      * @param id The identifier of the profile.
      */
-    public void activateRequiredProfile( String id )
-    {
-        this.activations.put( id, ActivationSettings.ACTIVATION_REQUIRED );
+    public void activateRequiredProfile(String id) {
+        this.activations.put(id, ActivationSettings.ACTIVATION_REQUIRED);
     }
 
     /**
      * Mark a profile as optional and activated.
      * @param id The identifier of the profile.
      */
-    public void activateOptionalProfile( String id )
-    {
-        this.activations.put( id, ActivationSettings.ACTIVATION_OPTIONAL );
+    public void activateOptionalProfile(String id) {
+        this.activations.put(id, ActivationSettings.ACTIVATION_OPTIONAL);
     }
 
     /**
      * Mark a profile as required and deactivated.
      * @param id The identifier of the profile.
      */
-    public void deactivateRequiredProfile( String id )
-    {
-        this.activations.put( id, ActivationSettings.DEACTIVATION_REQUIRED );
+    public void deactivateRequiredProfile(String id) {
+        this.activations.put(id, ActivationSettings.DEACTIVATION_REQUIRED);
     }
 
     /**
      * Mark a profile as optional and deactivated.
      * @param id The identifier of the profile.
      */
-    public void deactivateOptionalProfile( String id )
-    {
-        this.activations.put( id, ActivationSettings.DEACTIVATION_OPTIONAL );
+    public void deactivateOptionalProfile(String id) {
+        this.activations.put(id, ActivationSettings.DEACTIVATION_OPTIONAL);
     }
 
     /**
@@ -123,49 +113,43 @@
      * @param active Should the profile be activated?
      * @param optional Can the build continue if the profile does not exist?
      */
-    public void addProfileActivation( String id, boolean active, boolean optional )
-    {
-        final ActivationSettings settings = ActivationSettings.of( active, optional );
-        this.activations.put( id, settings );
+    public void addProfileActivation(String id, boolean active, boolean optional) {
+        final ActivationSettings settings = ActivationSettings.of(active, optional);
+        this.activations.put(id, settings);
     }
 
-    private Set<String> getProfileIds( final Predicate<ActivationSettings> predicate )
-    {
+    private Set<String> getProfileIds(final Predicate<ActivationSettings> predicate) {
         return this.activations.entrySet().stream()
-                .filter( e -> predicate.test( e.getValue() ) )
-                .map( Map.Entry::getKey )
-                .collect( toSet() );
+                .filter(e -> predicate.test(e.getValue()))
+                .map(Map.Entry::getKey)
+                .collect(toSet());
     }
 
     /**
      * @return Required active profile identifiers, never {@code null}.
      */
-    public Set<String> getRequiredActiveProfileIds()
-    {
-        return getProfileIds( pa -> !pa.optional && pa.active );
+    public Set<String> getRequiredActiveProfileIds() {
+        return getProfileIds(pa -> !pa.optional && pa.active);
     }
 
     /**
      * @return Optional active profile identifiers, never {@code null}.
      */
-    public Set<String> getOptionalActiveProfileIds()
-    {
-        return getProfileIds( pa -> pa.optional && pa.active );
+    public Set<String> getOptionalActiveProfileIds() {
+        return getProfileIds(pa -> pa.optional && pa.active);
     }
 
     /**
      * @return Required inactive profile identifiers, never {@code null}.
      */
-    public Set<String> getRequiredInactiveProfileIds()
-    {
-        return getProfileIds( pa -> !pa.optional && !pa.active );
+    public Set<String> getRequiredInactiveProfileIds() {
+        return getProfileIds(pa -> !pa.optional && !pa.active);
     }
 
     /**
      * @return Optional inactive profile identifiers, never {@code null}.
      */
-    public Set<String> getOptionalInactiveProfileIds()
-    {
-        return getProfileIds( pa -> pa.optional && !pa.active );
+    public Set<String> getOptionalInactiveProfileIds() {
+        return getProfileIds(pa -> pa.optional && !pa.active);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java b/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java
index a1d366c..f5f91a4 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ProjectActivation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -33,10 +32,8 @@
  * Container for storing the request from the user to activate or deactivate certain projects and optionally fail the
  * build if those projects do not exist.
  */
-public class ProjectActivation
-{
-    private static class ProjectActivationSettings
-    {
+public class ProjectActivation {
+    private static class ProjectActivationSettings {
         /**
          * The selector of a project. This can be the project directory, [groupId]:[artifactId] or :[artifactId].
          */
@@ -47,8 +44,7 @@
          */
         final ActivationSettings activationSettings;
 
-        ProjectActivationSettings( String selector, ActivationSettings activationSettings )
-        {
+        ProjectActivationSettings(String selector, ActivationSettings activationSettings) {
             this.selector = selector;
             this.activationSettings = activationSettings;
         }
@@ -65,55 +61,45 @@
      * @param active Should the project be activated?
      * @param optional Can the build continue if the project does not exist?
      */
-    public void addProjectActivation( String selector, boolean active, boolean optional )
-    {
-        final ActivationSettings settings = ActivationSettings.of( active, optional );
-        this.activations.add( new ProjectActivationSettings( selector, settings ) );
+    public void addProjectActivation(String selector, boolean active, boolean optional) {
+        final ActivationSettings settings = ActivationSettings.of(active, optional);
+        this.activations.add(new ProjectActivationSettings(selector, settings));
     }
 
-    private Stream<ProjectActivationSettings> getProjects( final Predicate<ActivationSettings> predicate )
-    {
-        return this.activations.stream()
-                .filter( activation -> predicate.test( activation.activationSettings ) );
+    private Stream<ProjectActivationSettings> getProjects(final Predicate<ActivationSettings> predicate) {
+        return this.activations.stream().filter(activation -> predicate.test(activation.activationSettings));
     }
 
-    private Set<String> getProjectSelectors( final Predicate<ActivationSettings> predicate )
-    {
-        return getProjects( predicate )
-                .map( activation -> activation.selector )
-                .collect( toSet() );
+    private Set<String> getProjectSelectors(final Predicate<ActivationSettings> predicate) {
+        return getProjects(predicate).map(activation -> activation.selector).collect(toSet());
     }
 
     /**
      * @return Required active project selectors, never {@code null}.
      */
-    public Set<String> getRequiredActiveProjectSelectors()
-    {
-        return getProjectSelectors( pa -> !pa.optional && pa.active );
+    public Set<String> getRequiredActiveProjectSelectors() {
+        return getProjectSelectors(pa -> !pa.optional && pa.active);
     }
 
     /**
      * @return Optional active project selectors, never {@code null}.
      */
-    public Set<String> getOptionalActiveProjectSelectors()
-    {
-        return getProjectSelectors( pa -> pa.optional && pa.active );
+    public Set<String> getOptionalActiveProjectSelectors() {
+        return getProjectSelectors(pa -> pa.optional && pa.active);
     }
 
     /**
      * @return Required inactive project selectors, never {@code null}.
      */
-    public Set<String> getRequiredInactiveProjectSelectors()
-    {
-        return getProjectSelectors( pa -> !pa.optional && !pa.active );
+    public Set<String> getRequiredInactiveProjectSelectors() {
+        return getProjectSelectors(pa -> !pa.optional && !pa.active);
     }
 
     /**
      * @return Optional inactive project selectors, never {@code null}.
      */
-    public Set<String> getOptionalInactiveProjectSelectors()
-    {
-        return getProjectSelectors( pa -> pa.optional && !pa.active );
+    public Set<String> getOptionalInactiveProjectSelectors() {
+        return getProjectSelectors(pa -> pa.optional && !pa.active);
     }
 
     /**
@@ -122,9 +108,8 @@
      * instead.
      */
     @Deprecated
-    public List<String> getSelectedProjects()
-    {
-        return Collections.unmodifiableList( new ArrayList<>( getProjectSelectors( pa -> pa.active ) ) );
+    public List<String> getSelectedProjects() {
+        return Collections.unmodifiableList(new ArrayList<>(getProjectSelectors(pa -> pa.active)));
     }
 
     /**
@@ -133,9 +118,8 @@
      * instead.
      */
     @Deprecated
-    public List<String> getExcludedProjects()
-    {
-        return Collections.unmodifiableList( new ArrayList<>( getProjectSelectors( pa -> !pa.active ) ) );
+    public List<String> getExcludedProjects() {
+        return Collections.unmodifiableList(new ArrayList<>(getProjectSelectors(pa -> !pa.active)));
     }
 
     /**
@@ -144,11 +128,10 @@
      * @deprecated Use {@link #activateOptionalProject(String)} or {@link #activateRequiredProject(String)} instead.
      */
     @Deprecated
-    public void overwriteActiveProjects( List<String> activeProjectSelectors )
-    {
-        List<ProjectActivationSettings> projects = getProjects( pa -> pa.active ).collect( Collectors.toList() );
-        this.activations.removeAll( projects );
-        activeProjectSelectors.forEach( this::activateOptionalProject );
+    public void overwriteActiveProjects(List<String> activeProjectSelectors) {
+        List<ProjectActivationSettings> projects = getProjects(pa -> pa.active).collect(Collectors.toList());
+        this.activations.removeAll(projects);
+        activeProjectSelectors.forEach(this::activateOptionalProject);
     }
 
     /**
@@ -157,51 +140,45 @@
      * @deprecated Use {@link #deactivateOptionalProject(String)} or {@link #deactivateRequiredProject(String)} instead.
      */
     @Deprecated
-    public void overwriteInactiveProjects( List<String> inactiveProjectSelectors )
-    {
-        List<ProjectActivationSettings> projects = getProjects( pa -> !pa.active ).collect( Collectors.toList() );
-        this.activations.removeAll( projects );
-        inactiveProjectSelectors.forEach( this::deactivateOptionalProject );
+    public void overwriteInactiveProjects(List<String> inactiveProjectSelectors) {
+        List<ProjectActivationSettings> projects = getProjects(pa -> !pa.active).collect(Collectors.toList());
+        this.activations.removeAll(projects);
+        inactiveProjectSelectors.forEach(this::deactivateOptionalProject);
     }
 
     /**
      * Mark a project as required and activated.
      * @param selector The selector of the project.
      */
-    public void activateRequiredProject( String selector )
-    {
-        this.activations.add( new ProjectActivationSettings( selector, ActivationSettings.ACTIVATION_REQUIRED ) );
+    public void activateRequiredProject(String selector) {
+        this.activations.add(new ProjectActivationSettings(selector, ActivationSettings.ACTIVATION_REQUIRED));
     }
 
     /**
      * Mark a project as optional and activated.
      * @param selector The selector of the project.
      */
-    public void activateOptionalProject( String selector )
-    {
-        this.activations.add( new ProjectActivationSettings( selector, ActivationSettings.ACTIVATION_OPTIONAL ) );
+    public void activateOptionalProject(String selector) {
+        this.activations.add(new ProjectActivationSettings(selector, ActivationSettings.ACTIVATION_OPTIONAL));
     }
 
     /**
      * Mark a project as required and deactivated.
      * @param selector The selector of the project.
      */
-    public void deactivateRequiredProject( String selector )
-    {
-        this.activations.add( new ProjectActivationSettings( selector, ActivationSettings.DEACTIVATION_REQUIRED ) );
+    public void deactivateRequiredProject(String selector) {
+        this.activations.add(new ProjectActivationSettings(selector, ActivationSettings.DEACTIVATION_REQUIRED));
     }
 
     /**
      * Mark a project as optional and deactivated.
      * @param selector The selector of the project.
      */
-    public void deactivateOptionalProject( String selector )
-    {
-        this.activations.add( new ProjectActivationSettings( selector, ActivationSettings.DEACTIVATION_OPTIONAL ) );
+    public void deactivateOptionalProject(String selector) {
+        this.activations.add(new ProjectActivationSettings(selector, ActivationSettings.DEACTIVATION_OPTIONAL));
     }
 
-    public boolean isEmpty()
-    {
+    public boolean isEmpty() {
         return this.activations.isEmpty();
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/execution/ProjectDependencyGraph.java
index f28b502..39c43f1 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ProjectDependencyGraph.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ProjectDependencyGraph.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.List;
 
@@ -26,11 +25,9 @@
 /**
  * Describes the interdependencies between projects in the reactor.
  *
- * @author Benjamin Bentmann
  * @since 3.0-alpha
  */
-public interface ProjectDependencyGraph
-{
+public interface ProjectDependencyGraph {
 
     /**
      * Gets all collected projects.
@@ -58,7 +55,7 @@
      *            downstream projects.
      * @return The downstream projects in the build order, never {@code null}.
      */
-    List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive );
+    List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive);
 
     /**
      * Gets the upstream projects of the specified project. An upstream project is a project that directly or indirectly
@@ -69,6 +66,5 @@
      *            upstream projects.
      * @return The upstream projects in the build order, never {@code null}.
      */
-    List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive );
-
+    List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionEvent.java b/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionEvent.java
index 96cb226..257193d 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionEvent.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionEvent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import java.util.List;
 
@@ -34,8 +33,7 @@
  * @see ProjectExecutionListener
  * @since 3.1.2
  */
-public class ProjectExecutionEvent
-{
+public class ProjectExecutionEvent {
 
     private final MavenSession session;
 
@@ -45,48 +43,39 @@
 
     private final Throwable cause;
 
-    public ProjectExecutionEvent( MavenSession session, MavenProject project )
-    {
-        this( session, project, null, null );
+    public ProjectExecutionEvent(MavenSession session, MavenProject project) {
+        this(session, project, null, null);
     }
 
-    public ProjectExecutionEvent( MavenSession session, MavenProject project, List<MojoExecution> executionPlan )
-    {
-        this( session, project, executionPlan, null );
+    public ProjectExecutionEvent(MavenSession session, MavenProject project, List<MojoExecution> executionPlan) {
+        this(session, project, executionPlan, null);
     }
 
-    public ProjectExecutionEvent( MavenSession session, MavenProject project, Throwable cause )
-    {
-        this( session, project, null, cause );
+    public ProjectExecutionEvent(MavenSession session, MavenProject project, Throwable cause) {
+        this(session, project, null, cause);
     }
 
-    public ProjectExecutionEvent( MavenSession session, MavenProject project, List<MojoExecution> executionPlan,
-                                  Throwable cause )
-    {
+    public ProjectExecutionEvent(
+            MavenSession session, MavenProject project, List<MojoExecution> executionPlan, Throwable cause) {
         this.session = session;
         this.project = project;
         this.executionPlan = executionPlan;
         this.cause = cause;
     }
 
-    public MavenSession getSession()
-    {
+    public MavenSession getSession() {
         return session;
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public List<MojoExecution> getExecutionPlan()
-    {
+    public List<MojoExecution> getExecutionPlan() {
         return executionPlan;
     }
 
-    public Throwable getCause()
-    {
+    public Throwable getCause() {
         return cause;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java
index 2797425..da17ce3 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ProjectExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
 
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 
@@ -31,16 +30,12 @@
  * @see MojoExecutionListener
  * @since 3.1.2
  */
-public interface ProjectExecutionListener
-{
-    void beforeProjectExecution( ProjectExecutionEvent event )
-        throws LifecycleExecutionException;
+public interface ProjectExecutionListener {
+    void beforeProjectExecution(ProjectExecutionEvent event) throws LifecycleExecutionException;
 
-    void beforeProjectLifecycleExecution( ProjectExecutionEvent event )
-        throws LifecycleExecutionException;
+    void beforeProjectLifecycleExecution(ProjectExecutionEvent event) throws LifecycleExecutionException;
 
-    void afterProjectExecutionSuccess( ProjectExecutionEvent event )
-        throws LifecycleExecutionException;
+    void afterProjectExecutionSuccess(ProjectExecutionEvent event) throws LifecycleExecutionException;
 
-    void afterProjectExecutionFailure( ProjectExecutionEvent event );
+    void afterProjectExecutionFailure(ProjectExecutionEvent event);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java b/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
index 795ac34..2ac0643 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/ReactorManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,25 +16,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.project.DuplicateProjectException;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.ProjectSorter;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
+package org.apache.maven.execution;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.CycleDetectedException;
+import org.apache.maven.project.DuplicateProjectException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectSorter;
+
 /**
  * ReactorManager - unused
  */
 @Deprecated
-public class ReactorManager
-{
+public class ReactorManager {
     public static final String FAIL_FAST = "fail-fast";
 
     public static final String FAIL_AT_END = "fail-at-end";
@@ -62,129 +60,102 @@
 
     private Map<String, BuildSuccess> buildSuccessesByProject = new HashMap<>();
 
-    public ReactorManager( List<MavenProject> projects )
-        throws CycleDetectedException, DuplicateProjectException
-    {
-        this.sorter = new ProjectSorter( projects );
+    public ReactorManager(List<MavenProject> projects) throws CycleDetectedException, DuplicateProjectException {
+        this.sorter = new ProjectSorter(projects);
     }
 
-    public Map getPluginContext( PluginDescriptor plugin, MavenProject project )
-    {
+    public Map getPluginContext(PluginDescriptor plugin, MavenProject project) {
         Map<String, Map> pluginContextsByKey =
-            pluginContextsByProjectAndPluginKey.computeIfAbsent( project.getId(), k -> new HashMap<>() );
+                pluginContextsByProjectAndPluginKey.computeIfAbsent(project.getId(), k -> new HashMap<>());
 
-        return pluginContextsByKey.computeIfAbsent( plugin.getPluginLookupKey(), k -> new HashMap<>() );
+        return pluginContextsByKey.computeIfAbsent(plugin.getPluginLookupKey(), k -> new HashMap<>());
     }
 
-    public void setFailureBehavior( String failureBehavior )
-    {
-        if ( failureBehavior == null )
-        {
+    public void setFailureBehavior(String failureBehavior) {
+        if (failureBehavior == null) {
             this.failureBehavior = FAIL_FAST; // default
             return;
         }
-        if ( FAIL_FAST.equals( failureBehavior ) || FAIL_AT_END.equals( failureBehavior ) || FAIL_NEVER.equals(
-            failureBehavior ) )
-        {
+        if (FAIL_FAST.equals(failureBehavior)
+                || FAIL_AT_END.equals(failureBehavior)
+                || FAIL_NEVER.equals(failureBehavior)) {
             this.failureBehavior = failureBehavior;
-        }
-        else
-        {
-            throw new IllegalArgumentException(
-                    "Invalid failure behavior (must be one of: '" + FAIL_FAST + "', '" + FAIL_AT_END + "', '"
-                    + FAIL_NEVER + "')." );
+        } else {
+            throw new IllegalArgumentException("Invalid failure behavior (must be one of: '" + FAIL_FAST + "', '"
+                    + FAIL_AT_END + "', '" + FAIL_NEVER + "').");
         }
     }
 
-    public String getFailureBehavior()
-    {
+    public String getFailureBehavior() {
         return failureBehavior;
     }
 
-    public void blackList( MavenProject project )
-    {
-        blackList( getProjectKey( project ) );
+    public void blackList(MavenProject project) {
+        blackList(getProjectKey(project));
     }
 
-    private void blackList( String id )
-    {
-        if ( !blackList.contains( id ) )
-        {
-            blackList.add( id );
+    private void blackList(String id) {
+        if (!blackList.contains(id)) {
+            blackList.add(id);
 
-            List<String> dependents = sorter.getDependents( id );
+            List<String> dependents = sorter.getDependents(id);
 
-            if ( dependents != null && !dependents.isEmpty() )
-            {
-                for ( String dependentId : dependents )
-                {
-                    if ( !buildSuccessesByProject.containsKey( dependentId ) && !buildFailuresByProject.containsKey(
-                        dependentId ) )
-                    {
-                        blackList( dependentId );
+            if (dependents != null && !dependents.isEmpty()) {
+                for (String dependentId : dependents) {
+                    if (!buildSuccessesByProject.containsKey(dependentId)
+                            && !buildFailuresByProject.containsKey(dependentId)) {
+                        blackList(dependentId);
                     }
                 }
             }
         }
     }
 
-    public boolean isBlackListed( MavenProject project )
-    {
-        return blackList.contains( getProjectKey( project ) );
+    public boolean isBlackListed(MavenProject project) {
+        return blackList.contains(getProjectKey(project));
     }
 
-    private static String getProjectKey( MavenProject project )
-    {
-        return ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
+    private static String getProjectKey(MavenProject project) {
+        return ArtifactUtils.versionlessKey(project.getGroupId(), project.getArtifactId());
     }
 
-    public void registerBuildFailure( MavenProject project, Exception error, String task, long time )
-    {
-        buildFailuresByProject.put( getProjectKey( project ), new BuildFailure( project, time, error ) );
+    public void registerBuildFailure(MavenProject project, Exception error, String task, long time) {
+        buildFailuresByProject.put(getProjectKey(project), new BuildFailure(project, time, error));
     }
 
-    public boolean hasBuildFailures()
-    {
+    public boolean hasBuildFailures() {
         return !buildFailuresByProject.isEmpty();
     }
 
-    public boolean hasBuildFailure( MavenProject project )
-    {
-        return buildFailuresByProject.containsKey( getProjectKey( project ) );
+    public boolean hasBuildFailure(MavenProject project) {
+        return buildFailuresByProject.containsKey(getProjectKey(project));
     }
 
-    public boolean hasMultipleProjects()
-    {
+    public boolean hasMultipleProjects() {
         return sorter.hasMultipleProjects();
     }
 
-    public List<MavenProject> getSortedProjects()
-    {
+    public List<MavenProject> getSortedProjects() {
         return sorter.getSortedProjects();
     }
 
-    public boolean hasBuildSuccess( MavenProject project )
-    {
-        return buildSuccessesByProject.containsKey( getProjectKey( project ) );
+    public boolean hasBuildSuccess(MavenProject project) {
+        return buildSuccessesByProject.containsKey(getProjectKey(project));
     }
 
-    public void registerBuildSuccess( MavenProject project, long time )
-    {
-        buildSuccessesByProject.put( getProjectKey( project ), new BuildSuccess( project, time ) );
+    public void registerBuildSuccess(MavenProject project, long time) {
+        buildSuccessesByProject.put(getProjectKey(project), new BuildSuccess(project, time));
     }
 
-    public BuildFailure getBuildFailure( MavenProject project )
-    {
-        return buildFailuresByProject.get( getProjectKey( project ) );
+    public BuildFailure getBuildFailure(MavenProject project) {
+        return buildFailuresByProject.get(getProjectKey(project));
     }
 
-    public BuildSuccess getBuildSuccess( MavenProject project )
-    {
-        return buildSuccessesByProject.get( getProjectKey( project ) );
+    public BuildSuccess getBuildSuccess(MavenProject project) {
+        return buildSuccessesByProject.get(getProjectKey(project));
     }
 
-    public boolean executedMultipleProjects()
-    {
+    public boolean executedMultipleProjects() {
         return buildFailuresByProject.size() + buildSuccessesByProject.size() > 1;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/SettingsAdapter.java b/maven-core/src/main/java/org/apache/maven/execution/SettingsAdapter.java
deleted file mode 100644
index bf5d373..0000000
--- a/maven-core/src/main/java/org/apache/maven/execution/SettingsAdapter.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package org.apache.maven.execution;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.maven.settings.Mirror;
-import org.apache.maven.settings.Profile;
-import org.apache.maven.settings.Proxy;
-import org.apache.maven.settings.RuntimeInfo;
-import org.apache.maven.settings.Server;
-import org.apache.maven.settings.Settings;
-import org.apache.maven.settings.SettingsUtils;
-
-/**
- * Adapt a {@link MavenExecutionRequest} to a {@link Settings} object for use in the Maven core.
- * We want to make sure that what is ask for in the execution request overrides what is in the settings.
- * The CLI feeds into an execution request so if a particular value is present in the execution request
- * then we will take that over the value coming from the user settings.
- *
- * @author Jason van Zyl
- */
-class SettingsAdapter
-    extends Settings
-{
-
-    private MavenExecutionRequest request;
-
-    private RuntimeInfo runtimeInfo;
-
-    SettingsAdapter( MavenExecutionRequest request )
-    {
-        this.request = request;
-
-        /*
-         * NOTE: Plugins like maven-release-plugin query the path to the settings.xml to pass it into a forked Maven and
-         * the CLI will fail when called with a non-existing settings, so be sure to only point at actual files. Having
-         * a null file should be harmless as this case matches general Maven 2.x behavior...
-         */
-        File userSettings = request.getUserSettingsFile();
-        this.runtimeInfo = new RuntimeInfo( ( userSettings != null && userSettings.isFile() ) ? userSettings : null );
-    }
-
-    @Override
-    public String getLocalRepository()
-    {
-        if ( request.getLocalRepositoryPath() != null )
-        {
-            return request.getLocalRepositoryPath().getAbsolutePath();
-        }
-
-        return null;
-    }
-
-    @Override
-    public boolean isInteractiveMode()
-    {
-        return request.isInteractiveMode();
-    }
-
-    @Override
-    public boolean isOffline()
-    {
-        return request.isOffline();
-    }
-
-    @Override
-    public List<Proxy> getProxies()
-    {
-        return request.getProxies();
-    }
-
-    @Override
-    public List<Server> getServers()
-    {
-        return request.getServers();
-    }
-
-    @Override
-    public List<Mirror> getMirrors()
-    {
-        return request.getMirrors();
-    }
-
-    @Override
-    public List<Profile> getProfiles()
-    {
-        List<Profile> result = new ArrayList<>();
-        for ( org.apache.maven.model.Profile profile : request.getProfiles() )
-        {
-            result.add( SettingsUtils.convertToSettingsProfile( profile ) );
-        }
-        return result;
-    }
-
-    @Override
-    public List<String> getActiveProfiles()
-    {
-        return request.getActiveProfiles();
-    }
-
-    @Override
-    public List<String> getPluginGroups()
-    {
-        return request.getPluginGroups();
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/infoproviders/DefaultPluginsMetadataInfoProvider.java b/maven-core/src/main/java/org/apache/maven/execution/infoproviders/DefaultPluginsMetadataInfoProvider.java
deleted file mode 100644
index 616a3a8..0000000
--- a/maven-core/src/main/java/org/apache/maven/execution/infoproviders/DefaultPluginsMetadataInfoProvider.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package org.apache.maven.execution.infoproviders;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Objects;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.repository.metadata.Metadata;
-import org.apache.maven.artifact.repository.metadata.Plugin;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.repository.internal.PluginsMetadataInfoProvider;
-import org.apache.maven.repository.legacy.metadata.ArtifactMetadata;
-import org.eclipse.aether.artifact.Artifact;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * Default implementation of {@link PluginsMetadataInfoProvider}.
- */
-@Named
-@Singleton
-public class DefaultPluginsMetadataInfoProvider
-    implements PluginsMetadataInfoProvider
-{
-    private final Provider<MavenSession> mavenSessionProvider;
-
-    @Inject
-    public DefaultPluginsMetadataInfoProvider( final Provider<MavenSession> mavenSessionProvider )
-    {
-        this.mavenSessionProvider = requireNonNull( mavenSessionProvider );
-    }
-
-    @Override
-    public PluginInfo getPluginInfo( final Artifact artifact )
-    {
-        MavenSession mavenSession = mavenSessionProvider.get();
-        if ( mavenSession != null )
-        {
-            MavenProject mavenProject = searchForProject( mavenSession, artifact );
-            if ( mavenProject != null && "maven-plugin".equals( mavenProject.getPackaging() ) )
-            {
-                Plugin plugin = searchForPluginGroupLevelRepositoryMetadata( mavenProject );
-
-                if ( plugin != null )
-                {
-                    return new PluginInfo()
-                    {
-                        @Override
-                        public String getPluginGroupId()
-                        {
-                            return artifact.getGroupId();
-                        }
-
-                        @Override
-                        public String getPluginArtifactId()
-                        {
-                            return artifact.getArtifactId();
-                        }
-
-                        @Override
-                        public String getPluginPrefix()
-                        {
-                            return plugin.getPrefix();
-                        }
-
-                        @Override
-                        public String getPluginName()
-                        {
-                            return plugin.getName();
-                        }
-                    };
-                }
-            }
-        }
-
-        return null;
-    }
-
-    private MavenProject searchForProject( MavenSession mavenSession, Artifact artifact )
-    {
-        for ( MavenProject mavenProject : mavenSession.getProjects() )
-        {
-            if ( mavenProject.getArtifact() != null
-                && Objects.equals( mavenProject.getGroupId(), artifact.getGroupId() )
-                && Objects.equals( mavenProject.getArtifactId(), artifact.getArtifactId() ) )
-            {
-                return mavenProject;
-            }
-        }
-        return null;
-    }
-
-    private Plugin searchForPluginGroupLevelRepositoryMetadata( MavenProject mavenProject )
-    {
-        org.apache.maven.artifact.Artifact projectArtifact = mavenProject.getArtifact();
-        for ( ArtifactMetadata artifactMetadata : projectArtifact.getMetadataList() )
-        {
-            if ( artifactMetadata instanceof RepositoryMetadata )
-            {
-                RepositoryMetadata repositoryMetadata = (RepositoryMetadata) artifactMetadata;
-                Metadata metadata = repositoryMetadata.getMetadata();
-
-                for ( Plugin plugin : metadata.getPlugins() )
-                {
-                    if ( Objects.equals( plugin.getArtifactId(), mavenProject.getArtifactId() ) )
-                    {
-                        return plugin;
-                    }
-                }
-            }
-        }
-        return null;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionScoped.java b/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionScoped.java
index 0dcbd16..dc16433 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionScoped.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/scope/MojoExecutionScoped.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution.scope;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,25 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static java.lang.annotation.ElementType.TYPE;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
+package org.apache.maven.execution.scope;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
 
 import com.google.inject.ScopeAnnotation;
 
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
 /**
  * Indicates that annotated component should be instantiated before mojo execution starts and discarded after mojo
  * execution completes.
  *
- * @author igor
  * @since 3.1.2
  */
-@Target( { TYPE } )
-@Retention( RUNTIME )
+@Target({TYPE})
+@Retention(RUNTIME)
 @ScopeAnnotation
-public @interface MojoExecutionScoped
-{
-}
+public @interface MojoExecutionScoped {}
diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java b/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java
index da78de7..d064326 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/scope/WeakMojoExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution.scope;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution.scope;
 
 import org.apache.maven.execution.MojoExecutionEvent;
 import org.apache.maven.plugin.MojoExecutionException;
@@ -34,13 +33,10 @@
  * @see org.apache.maven.execution.MojoExecutionListener
  * @since 3.1.2
  */
-public interface WeakMojoExecutionListener
-{
-    void beforeMojoExecution( MojoExecutionEvent event )
-        throws MojoExecutionException;
+public interface WeakMojoExecutionListener {
+    void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException;
 
-    void afterMojoExecutionSuccess( MojoExecutionEvent event )
-        throws MojoExecutionException;
+    void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException;
 
-    void afterExecutionFailure( MojoExecutionEvent event );
+    void afterExecutionFailure(MojoExecutionEvent event);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java
index 86d7c73..b650912 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScope.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution.scope.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution.scope.internal;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -25,30 +24,25 @@
 import java.util.LinkedList;
 import java.util.Map;
 
-import org.apache.maven.execution.MojoExecutionEvent;
-import org.apache.maven.execution.MojoExecutionListener;
-import org.apache.maven.execution.scope.WeakMojoExecutionListener;
-import org.apache.maven.plugin.MojoExecutionException;
-
 import com.google.inject.Key;
 import com.google.inject.OutOfScopeException;
 import com.google.inject.Provider;
 import com.google.inject.Scope;
 import com.google.inject.util.Providers;
+import org.apache.maven.execution.MojoExecutionEvent;
+import org.apache.maven.execution.MojoExecutionListener;
+import org.apache.maven.execution.scope.WeakMojoExecutionListener;
+import org.apache.maven.plugin.MojoExecutionException;
 
 /**
  * MojoExecutionScope
  */
-public class MojoExecutionScope
-    implements Scope, MojoExecutionListener
-{
-    private static final Provider<Object> SEEDED_KEY_PROVIDER = () ->
-    {
+public class MojoExecutionScope implements Scope, MojoExecutionListener {
+    private static final Provider<Object> SEEDED_KEY_PROVIDER = () -> {
         throw new IllegalStateException();
     };
 
-    private static final class ScopeState
-    {
+    private static final class ScopeState {
         private final Map<Key<?>, Provider<?>> seeded = new HashMap<>();
 
         private final Map<Key<?>, Object> provided = new HashMap<>();
@@ -56,129 +50,99 @@
 
     private final ThreadLocal<LinkedList<ScopeState>> values = new ThreadLocal<>();
 
-    public MojoExecutionScope()
-    {
-    }
+    public MojoExecutionScope() {}
 
-    public void enter()
-    {
+    public void enter() {
         LinkedList<ScopeState> stack = values.get();
-        if ( stack == null )
-        {
+        if (stack == null) {
             stack = new LinkedList<>();
-            values.set( stack );
+            values.set(stack);
         }
-        stack.addFirst( new ScopeState() );
+        stack.addFirst(new ScopeState());
     }
 
-    private ScopeState getScopeState()
-    {
+    private ScopeState getScopeState() {
         LinkedList<ScopeState> stack = values.get();
-        if ( stack == null || stack.isEmpty() )
-        {
+        if (stack == null || stack.isEmpty()) {
             throw new IllegalStateException();
         }
         return stack.getFirst();
     }
 
-    public void exit()
-        throws MojoExecutionException
-    {
+    public void exit() throws MojoExecutionException {
         final LinkedList<ScopeState> stack = values.get();
-        if ( stack == null || stack.isEmpty() )
-        {
+        if (stack == null || stack.isEmpty()) {
             throw new IllegalStateException();
         }
         stack.removeFirst();
-        if ( stack.isEmpty() )
-        {
+        if (stack.isEmpty()) {
             values.remove();
         }
     }
 
-    public <T> void seed( Class<T> clazz, Provider<T> value )
-    {
-        getScopeState().seeded.put( Key.get( clazz ), value );
+    public <T> void seed(Class<T> clazz, Provider<T> value) {
+        getScopeState().seeded.put(Key.get(clazz), value);
     }
 
-    public <T> void seed( Class<T> clazz, final T value )
-    {
-        getScopeState().seeded.put( Key.get( clazz ), Providers.of( value ) );
+    public <T> void seed(Class<T> clazz, final T value) {
+        getScopeState().seeded.put(Key.get(clazz), Providers.of(value));
     }
 
-    public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
-    {
-        return () ->
-        {
+    public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
+        return () -> {
             LinkedList<ScopeState> stack = values.get();
-            if ( stack == null || stack.isEmpty() )
-            {
-                throw new OutOfScopeException( "Cannot access " + key + " outside of a scoping block" );
+            if (stack == null || stack.isEmpty()) {
+                throw new OutOfScopeException("Cannot access " + key + " outside of a scoping block");
             }
 
             ScopeState state = stack.getFirst();
 
-            Provider<?> seeded = state.seeded.get( key );
+            Provider<?> seeded = state.seeded.get(key);
 
-            if ( seeded != null )
-            {
+            if (seeded != null) {
                 return (T) seeded.get();
             }
 
-            T provided = (T) state.provided.get( key );
-            if ( provided == null && unscoped != null )
-            {
+            T provided = (T) state.provided.get(key);
+            if (provided == null && unscoped != null) {
                 provided = unscoped.get();
-                state.provided.put( key, provided );
+                state.provided.put(key, provided);
             }
 
             return provided;
         };
     }
 
-    @SuppressWarnings( { "unchecked" } )
-    public static <T> Provider<T> seededKeyProvider()
-    {
+    @SuppressWarnings({"unchecked"})
+    public static <T> Provider<T> seededKeyProvider() {
         return (Provider<T>) SEEDED_KEY_PROVIDER;
     }
 
-    public void beforeMojoExecution( MojoExecutionEvent event )
-        throws MojoExecutionException
-    {
-        for ( WeakMojoExecutionListener provided : getProvidedListeners() )
-        {
-            provided.beforeMojoExecution( event );
+    public void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException {
+        for (WeakMojoExecutionListener provided : getProvidedListeners()) {
+            provided.beforeMojoExecution(event);
         }
     }
 
-    public void afterMojoExecutionSuccess( MojoExecutionEvent event )
-        throws MojoExecutionException
-    {
-        for ( WeakMojoExecutionListener provided : getProvidedListeners() )
-        {
-            provided.afterMojoExecutionSuccess( event );
+    public void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException {
+        for (WeakMojoExecutionListener provided : getProvidedListeners()) {
+            provided.afterMojoExecutionSuccess(event);
         }
     }
 
-    public void afterExecutionFailure( MojoExecutionEvent event )
-    {
-        for ( WeakMojoExecutionListener provided : getProvidedListeners() )
-        {
-            provided.afterExecutionFailure( event );
+    public void afterExecutionFailure(MojoExecutionEvent event) {
+        for (WeakMojoExecutionListener provided : getProvidedListeners()) {
+            provided.afterExecutionFailure(event);
         }
     }
 
-    private Collection<WeakMojoExecutionListener> getProvidedListeners()
-    {
+    private Collection<WeakMojoExecutionListener> getProvidedListeners() {
         // the same instance can be provided multiple times under different Key's
         // deduplicate instances to avoid redundant beforeXXX/afterXXX callbacks
-        IdentityHashMap<WeakMojoExecutionListener, Object> listeners =
-            new IdentityHashMap<>();
-        for ( Object provided : getScopeState().provided.values() )
-        {
-            if ( provided instanceof WeakMojoExecutionListener )
-            {
-                listeners.put( (WeakMojoExecutionListener) provided, null );
+        IdentityHashMap<WeakMojoExecutionListener, Object> listeners = new IdentityHashMap<>();
+        for (Object provided : getScopeState().provided.values()) {
+            if (provided instanceof WeakMojoExecutionListener) {
+                listeners.put((WeakMojoExecutionListener) provided, null);
             }
         }
         return listeners.keySet();
diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeCoreModule.java b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeCoreModule.java
index 79a18bd..cc3fd7a 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeCoreModule.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeCoreModule.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution.scope.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution.scope.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -28,21 +27,16 @@
  * MojoExecutionScopeCoreModule
  */
 @Named
-public class MojoExecutionScopeCoreModule
-    extends MojoExecutionScopeModule
-{
+public class MojoExecutionScopeCoreModule extends MojoExecutionScopeModule {
 
     @Inject
-    public MojoExecutionScopeCoreModule()
-    {
-        super( new MojoExecutionScope() );
+    public MojoExecutionScopeCoreModule() {
+        super(new MojoExecutionScope());
     }
 
     @Override
-    protected void configure()
-    {
+    protected void configure() {
         super.configure();
-        bind( MojoExecutionListener.class ).toInstance( scope );
+        bind(MojoExecutionListener.class).toInstance(scope);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java
index 9b2617f..f574e43 100644
--- a/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java
+++ b/maven-core/src/main/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeModule.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution.scope.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,42 +16,47 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution.scope.internal;
 
+import com.google.inject.AbstractModule;
+import org.apache.maven.api.plugin.Log;
 import org.apache.maven.execution.scope.MojoExecutionScoped;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 
-import com.google.inject.AbstractModule;
-
 /**
  * MojoExecutionScopeModule
  */
-public class MojoExecutionScopeModule
-    extends AbstractModule
-{
+public class MojoExecutionScopeModule extends AbstractModule {
     protected final MojoExecutionScope scope;
 
-    public MojoExecutionScopeModule( PlexusContainer container )
-        throws ComponentLookupException
-    {
-        this( container.lookup( MojoExecutionScope.class ) );
+    public MojoExecutionScopeModule(PlexusContainer container) throws ComponentLookupException {
+        this(container.lookup(MojoExecutionScope.class));
     }
 
-    protected MojoExecutionScopeModule( MojoExecutionScope scope )
-    {
+    protected MojoExecutionScopeModule(MojoExecutionScope scope) {
         this.scope = scope;
     }
 
     @Override
-    protected void configure()
-    {
-        bindScope( MojoExecutionScoped.class, scope );
-        bind( MojoExecutionScope.class ).toInstance( scope );
-
-        bind( MavenProject.class ).toProvider( MojoExecutionScope.seededKeyProvider() ).in( scope );
-        bind( MojoExecution.class ).toProvider( MojoExecutionScope.seededKeyProvider() ).in( scope );
+    protected void configure() {
+        bindScope(MojoExecutionScoped.class, scope);
+        bindScope(org.apache.maven.api.di.MojoExecutionScoped.class, scope);
+        bind(MojoExecutionScope.class).toInstance(scope);
+        bind(MavenProject.class)
+                .toProvider(MojoExecutionScope.seededKeyProvider())
+                .in(scope);
+        bind(MojoExecution.class)
+                .toProvider(MojoExecutionScope.seededKeyProvider())
+                .in(scope);
+        bind(Log.class).toProvider(MojoExecutionScope.seededKeyProvider()).in(scope);
+        bind(org.apache.maven.api.Project.class)
+                .toProvider(MojoExecutionScope.seededKeyProvider())
+                .in(scope);
+        bind(org.apache.maven.api.MojoExecution.class)
+                .toProvider(MojoExecutionScope.seededKeyProvider())
+                .in(scope);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java
index 2d976ae..aec37e7 100644
--- a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java
+++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExports.java
@@ -1,5 +1,3 @@
-package org.apache.maven.extension.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.extension.internal;
 
 import java.util.Collections;
 import java.util.HashSet;
@@ -36,38 +35,33 @@
  *
  * @since 3.3.0
  */
-public class CoreExports
-{
+public class CoreExports {
     private final Set<String> artifacts;
 
     private final Map<String, ClassLoader> packages;
 
-    public CoreExports( CoreExtensionEntry entry )
-    {
-        this( entry.getClassRealm(), entry.getExportedArtifacts(), entry.getExportedPackages() );
+    public CoreExports(CoreExtensionEntry entry) {
+        this(entry.getClassRealm(), entry.getExportedArtifacts(), entry.getExportedPackages());
     }
 
-    public CoreExports( ClassRealm realm, Set<String> exportedArtifacts, Set<String> exportedPackages )
-    {
-        this.artifacts = Collections.unmodifiableSet( new HashSet<>( exportedArtifacts ) );
-        this.packages = exportedPackages.stream().collect(
-                collectingAndThen( toMap( identity(), v -> realm ), Collections::unmodifiableMap ) );
+    public CoreExports(ClassRealm realm, Set<String> exportedArtifacts, Set<String> exportedPackages) {
+        this.artifacts = Collections.unmodifiableSet(new HashSet<>(exportedArtifacts));
+        this.packages = exportedPackages.stream()
+                .collect(collectingAndThen(toMap(identity(), v -> realm), Collections::unmodifiableMap));
     }
 
     /**
      * Returns artifacts exported by Maven core and core extensions. Artifacts are identified by their
      * groupId:artifactId string key.
      */
-    public Set<String> getExportedArtifacts()
-    {
+    public Set<String> getExportedArtifacts() {
         return artifacts;
     }
 
     /**
      * Returns packages exported by Maven core and core extensions.
      */
-    public Map<String, ClassLoader> getExportedPackages()
-    {
+    public Map<String, ClassLoader> getExportedPackages() {
         return packages;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java
index b1a30fe..9c9d647 100644
--- a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExportsProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.extension.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.Objects;
+package org.apache.maven.extension.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 
+import java.util.Objects;
+
 import org.codehaus.plexus.PlexusContainer;
 
 /**
@@ -33,24 +32,20 @@
  */
 @Named
 @Singleton
-public class CoreExportsProvider implements Provider<CoreExports>
-{
+public class CoreExportsProvider implements Provider<CoreExports> {
 
     private final CoreExports exports;
 
     @Inject
-    public CoreExportsProvider( PlexusContainer container )
-    {
-        this( new CoreExports( CoreExtensionEntry.discoverFrom( container.getContainerRealm() ) ) );
+    public CoreExportsProvider(PlexusContainer container) {
+        this(new CoreExports(CoreExtensionEntry.discoverFrom(container.getContainerRealm())));
     }
 
-    public CoreExportsProvider( CoreExports exports )
-    {
-        this.exports = Objects.requireNonNull( exports );
+    public CoreExportsProvider(CoreExports exports) {
+        this.exports = Objects.requireNonNull(exports);
     }
 
-    public CoreExports get()
-    {
+    public CoreExports get() {
         return exports;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
index 50220f6..e482019 100644
--- a/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
+++ b/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
@@ -1,5 +1,3 @@
-package org.apache.maven.extension.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,10 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.project.ExtensionDescriptor;
-import org.apache.maven.project.ExtensionDescriptorBuilder;
-import org.codehaus.plexus.classworlds.realm.ClassRealm;
+package org.apache.maven.extension.internal;
 
 import java.io.File;
 import java.io.IOException;
@@ -34,103 +29,117 @@
 import java.util.LinkedHashSet;
 import java.util.Set;
 
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.project.ExtensionDescriptor;
+import org.apache.maven.project.ExtensionDescriptorBuilder;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+
 /**
  * Provides information about artifacts (identified by groupId:artifactId string key) and classpath elements exported by
  * Maven core itself or a Maven core extension.
  *
  * @since 3.3.0
  */
-public class CoreExtensionEntry
-{
+public class CoreExtensionEntry {
     private final ClassRealm realm;
 
     private final Set<String> artifacts;
 
     private final Set<String> packages;
 
-    public CoreExtensionEntry( ClassRealm realm, Collection<String> artifacts, Collection<String> packages )
-    {
+    private final String key;
+
+    private final XmlNode configuration;
+
+    public CoreExtensionEntry(
+            ClassRealm realm,
+            Collection<String> artifacts,
+            Collection<String> packages,
+            String key,
+            XmlNode configuration) {
         this.realm = realm;
-        this.artifacts = Collections.unmodifiableSet( new HashSet<>( artifacts ) );
-        this.packages = Collections.unmodifiableSet( new HashSet<>( packages ) );
+        this.artifacts = Collections.unmodifiableSet(new HashSet<>(artifacts));
+        this.packages = Collections.unmodifiableSet(new HashSet<>(packages));
+        this.key = key;
+        this.configuration = configuration;
     }
 
     /**
      * Returns ClassLoader used to load extension classes.
      */
-    public ClassRealm getClassRealm()
-    {
+    public ClassRealm getClassRealm() {
         return realm;
     }
 
     /**
      * Returns artifacts exported by the extension, identified by groupId:artifactId string key.
      */
-    public Set<String> getExportedArtifacts()
-    {
+    public Set<String> getExportedArtifacts() {
         return artifacts;
     }
 
     /**
      * Returns classpath elements exported by the extension.
      */
-    public Set<String> getExportedPackages()
-    {
+    public Set<String> getExportedPackages() {
         return packages;
     }
 
+    /**
+     * The key that can must used to identify the configuration using the
+     * {@link javax.inject.Named} annotation.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * Returns the configuration for this extension.
+     */
+    public XmlNode getConfiguration() {
+        return configuration;
+    }
+
     private static final ExtensionDescriptorBuilder BUILDER = new ExtensionDescriptorBuilder();
 
-    public static CoreExtensionEntry discoverFrom( ClassRealm loader )
-    {
+    public static CoreExtensionEntry discoverFrom(ClassRealm loader) {
         Set<String> artifacts = new LinkedHashSet<>();
         Set<String> packages = new LinkedHashSet<>();
 
-        try
-        {
-            Enumeration<URL> urls = loader.getResources( BUILDER.getExtensionDescriptorLocation() );
-            while ( urls.hasMoreElements() )
-            {
+        try {
+            Enumeration<URL> urls = loader.getResources(BUILDER.getExtensionDescriptorLocation());
+            while (urls.hasMoreElements()) {
 
-                try ( InputStream is = urls.nextElement().openStream() )
-                {
-                    ExtensionDescriptor descriptor = BUILDER.build( is );
-                    artifacts.addAll( descriptor.getExportedArtifacts() );
-                    packages.addAll( descriptor.getExportedPackages() );
+                try (InputStream is = urls.nextElement().openStream()) {
+                    ExtensionDescriptor descriptor = BUILDER.build(is);
+                    artifacts.addAll(descriptor.getExportedArtifacts());
+                    packages.addAll(descriptor.getExportedPackages());
                 }
             }
-        }
-        catch ( IOException ignored )
-        {
+        } catch (IOException ignored) {
             // exports descriptors are entirely optional
         }
 
-        return new CoreExtensionEntry( loader, artifacts, packages );
+        return new CoreExtensionEntry(loader, artifacts, packages, null, null);
     }
 
-    public static CoreExtensionEntry discoverFrom( ClassRealm loader, Collection<File> classpath )
-    {
+    public static CoreExtensionEntry discoverFrom(
+            ClassRealm loader, Collection<File> classpath, String key, XmlNode configuration) {
         Set<String> artifacts = new LinkedHashSet<>();
         Set<String> packages = new LinkedHashSet<>();
 
-        try
-        {
-            for ( File entry : classpath )
-            {
-                ExtensionDescriptor descriptor = BUILDER.build( entry );
-                if ( descriptor != null )
-                {
-                    artifacts.addAll( descriptor.getExportedArtifacts() );
-                    packages.addAll( descriptor.getExportedPackages() );
+        try {
+            for (File entry : classpath) {
+                ExtensionDescriptor descriptor = BUILDER.build(entry);
+                if (descriptor != null) {
+                    artifacts.addAll(descriptor.getExportedArtifacts());
+                    packages.addAll(descriptor.getExportedPackages());
                 }
             }
-        }
-        catch ( IOException ignored )
-        {
+        } catch (IOException ignored) {
             // exports descriptors are entirely optional
         }
 
-        return new CoreExtensionEntry( loader, artifacts, packages );
+        return new CoreExtensionEntry(loader, artifacts, packages, key, configuration);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
index 0d4f6ca..02d935d 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultGraphBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.graph;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.graph;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -29,10 +32,6 @@
 import java.util.Map;
 import java.util.Set;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.ProjectCycleException;
 import org.apache.maven.artifact.ArtifactUtils;
@@ -44,14 +43,13 @@
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.building.DefaultModelProblem;
 import org.apache.maven.model.building.Result;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingException;
 import org.apache.maven.project.collector.MultiModuleCollectionStrategy;
 import org.apache.maven.project.collector.PomlessCollectionStrategy;
 import org.apache.maven.project.collector.RequestPomCollectionStrategy;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,12 +58,10 @@
 /**
  * Builds the {@link ProjectDependencyGraph inter-dependencies graph} between projects in the reactor.
  */
-@Named( GraphBuilder.HINT )
+@Named(GraphBuilder.HINT)
 @Singleton
-public class DefaultGraphBuilder
-    implements GraphBuilder
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultGraphBuilder.class );
+public class DefaultGraphBuilder implements GraphBuilder {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultGraphBuilder.class);
 
     private final BuildResumptionDataRepository buildResumptionDataRepository;
     private final PomlessCollectionStrategy pomlessCollectionStrategy;
@@ -73,12 +69,21 @@
     private final RequestPomCollectionStrategy requestPomCollectionStrategy;
     private final ProjectSelector projectSelector;
 
+    /**
+     * @deprecated Use {@link #DefaultGraphBuilder(BuildResumptionDataRepository, PomlessCollectionStrategy,
+     * MultiModuleCollectionStrategy, RequestPomCollectionStrategy)} instead or rely on JSR 330
+     */
+    @Deprecated
+    public DefaultGraphBuilder() {
+        this(null, null, null, null);
+    }
+
     @Inject
-    public DefaultGraphBuilder( BuildResumptionDataRepository buildResumptionDataRepository,
-                                PomlessCollectionStrategy pomlessCollectionStrategy,
-                                MultiModuleCollectionStrategy multiModuleCollectionStrategy,
-                                RequestPomCollectionStrategy requestPomCollectionStrategy )
-    {
+    public DefaultGraphBuilder(
+            BuildResumptionDataRepository buildResumptionDataRepository,
+            PomlessCollectionStrategy pomlessCollectionStrategy,
+            MultiModuleCollectionStrategy multiModuleCollectionStrategy,
+            RequestPomCollectionStrategy requestPomCollectionStrategy) {
         this.buildResumptionDataRepository = buildResumptionDataRepository;
         this.pomlessCollectionStrategy = pomlessCollectionStrategy;
         this.multiModuleCollectionStrategy = multiModuleCollectionStrategy;
@@ -87,274 +92,244 @@
     }
 
     @Override
-    public Result<ProjectDependencyGraph> build( MavenSession session )
-    {
-        try
-        {
-            Result<ProjectDependencyGraph> result = sessionDependencyGraph( session );
+    public Result<ProjectDependencyGraph> build(MavenSession session) {
+        try {
+            Result<ProjectDependencyGraph> result = sessionDependencyGraph(session);
 
-            if ( result == null )
-            {
-                final List<MavenProject> projects = getProjectsForMavenReactor( session );
-                validateProjects( projects, session.getRequest() );
-                enrichRequestFromResumptionData( projects, session.getRequest() );
-                result = reactorDependencyGraph( session, projects );
+            if (result == null) {
+                final List<MavenProject> projects = getProjectsForMavenReactor(session);
+                validateProjects(projects, session.getRequest());
+                processPackagingAttribute(projects, session.getRequest());
+                enrichRequestFromResumptionData(projects, session.getRequest());
+                result = reactorDependencyGraph(session, projects);
             }
 
             return result;
-        }
-        catch ( final ProjectBuildingException | DuplicateProjectException | MavenExecutionException e )
-        {
-            return Result.error( Collections.singletonList
-                    ( new DefaultModelProblem ( null, null, null, null, 0, 0, e ) ) );
-        }
-        catch ( final CycleDetectedException e )
-        {
+        } catch (final ProjectBuildingException | DuplicateProjectException | MavenExecutionException e) {
+            return Result.error(Collections.singletonList(new DefaultModelProblem(null, null, null, null, 0, 0, e)));
+        } catch (final CycleDetectedException e) {
             String message = "The projects in the reactor contain a cyclic reference: " + e.getMessage();
-            ProjectCycleException error = new ProjectCycleException( message, e );
-            return Result.error( Collections.singletonList(
-                    new DefaultModelProblem( null, null, null, null, 0, 0, error ) ) );
+            ProjectCycleException error = new ProjectCycleException(message, e);
+            return Result.error(
+                    Collections.singletonList(new DefaultModelProblem(null, null, null, null, 0, 0, error)));
         }
     }
 
-    private Result<ProjectDependencyGraph> sessionDependencyGraph( final MavenSession session )
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    private Result<ProjectDependencyGraph> sessionDependencyGraph(final MavenSession session)
+            throws CycleDetectedException, DuplicateProjectException {
         Result<ProjectDependencyGraph> result = null;
 
-        if ( session.getProjectDependencyGraph() != null || session.getProjects() != null )
-        {
+        if (session.getProjectDependencyGraph() != null || session.getProjects() != null) {
             final ProjectDependencyGraph graph =
-                new DefaultProjectDependencyGraph( session.getAllProjects(), session.getProjects() );
+                    new DefaultProjectDependencyGraph(session.getAllProjects(), session.getProjects());
 
-            result = Result.success( graph );
+            result = Result.success(graph);
         }
 
         return result;
     }
 
-    private Result<ProjectDependencyGraph> reactorDependencyGraph( MavenSession session, List<MavenProject> projects )
-        throws CycleDetectedException, DuplicateProjectException, MavenExecutionException
-    {
-        ProjectDependencyGraph projectDependencyGraph = new DefaultProjectDependencyGraph( projects );
+    private Result<ProjectDependencyGraph> reactorDependencyGraph(MavenSession session, List<MavenProject> projects)
+            throws CycleDetectedException, DuplicateProjectException, MavenExecutionException {
+        ProjectDependencyGraph projectDependencyGraph = new DefaultProjectDependencyGraph(projects);
         List<MavenProject> activeProjects = projectDependencyGraph.getSortedProjects();
         List<MavenProject> allSortedProjects = projectDependencyGraph.getSortedProjects();
-        activeProjects = trimProjectsToRequest( activeProjects, projectDependencyGraph, session.getRequest() );
-        activeProjects = trimSelectedProjects(
-                activeProjects, allSortedProjects, projectDependencyGraph, session.getRequest() );
-        activeProjects = trimResumedProjects( activeProjects, projectDependencyGraph, session.getRequest() );
-        activeProjects = trimExcludedProjects( activeProjects, projectDependencyGraph, session.getRequest() );
+        activeProjects = trimProjectsToRequest(activeProjects, projectDependencyGraph, session.getRequest());
+        activeProjects =
+                trimSelectedProjects(activeProjects, allSortedProjects, projectDependencyGraph, session.getRequest());
+        activeProjects = trimResumedProjects(activeProjects, projectDependencyGraph, session.getRequest());
+        activeProjects = trimExcludedProjects(activeProjects, projectDependencyGraph, session.getRequest());
 
-        if ( activeProjects.size() != projectDependencyGraph.getSortedProjects().size() )
-        {
-            projectDependencyGraph = new FilteredProjectDependencyGraph( projectDependencyGraph, activeProjects );
+        if (activeProjects.size() != projectDependencyGraph.getSortedProjects().size()) {
+            projectDependencyGraph = new FilteredProjectDependencyGraph(projectDependencyGraph, activeProjects);
         }
 
-        return Result.success( projectDependencyGraph );
+        return Result.success(projectDependencyGraph);
     }
 
-    private List<MavenProject> trimProjectsToRequest( List<MavenProject> activeProjects,
-                                                      ProjectDependencyGraph graph,
-                                                      MavenExecutionRequest request )
-            throws MavenExecutionException
-    {
+    private List<MavenProject> trimProjectsToRequest(
+            List<MavenProject> activeProjects, ProjectDependencyGraph graph, MavenExecutionRequest request)
+            throws MavenExecutionException {
         List<MavenProject> result = activeProjects;
 
-        if ( request.getPom() != null )
-        {
-            result = getProjectsInRequestScope( request, activeProjects );
+        if (request.getPom() != null) {
+            result = getProjectsInRequestScope(request, activeProjects);
 
             List<MavenProject> sortedProjects = graph.getSortedProjects();
-            result.sort( comparing( sortedProjects::indexOf ) );
+            result.sort(comparing(sortedProjects::indexOf));
 
-            result = includeAlsoMakeTransitively( result, request, graph );
+            result = includeAlsoMakeTransitively(result, request, graph);
         }
 
         return result;
     }
 
-    private List<MavenProject> trimSelectedProjects( List<MavenProject> projects, List<MavenProject> allSortedProjects,
-                                                     ProjectDependencyGraph graph, MavenExecutionRequest request )
-        throws MavenExecutionException
-    {
+    private List<MavenProject> trimSelectedProjects(
+            List<MavenProject> projects,
+            List<MavenProject> allSortedProjects,
+            ProjectDependencyGraph graph,
+            MavenExecutionRequest request)
+            throws MavenExecutionException {
         List<MavenProject> result = projects;
 
         ProjectActivation projectActivation = request.getProjectActivation();
         Set<String> requiredSelectors = projectActivation.getRequiredActiveProjectSelectors();
         Set<String> optionalSelectors = projectActivation.getOptionalActiveProjectSelectors();
-        if ( !requiredSelectors.isEmpty() || !optionalSelectors.isEmpty() )
-        {
-            Set<MavenProject> selectedProjects = new HashSet<>( requiredSelectors.size() + optionalSelectors.size() );
+        if (!requiredSelectors.isEmpty() || !optionalSelectors.isEmpty()) {
+            Set<MavenProject> selectedProjects = new HashSet<>(requiredSelectors.size() + optionalSelectors.size());
             selectedProjects.addAll(
-                    projectSelector.getRequiredProjectsBySelectors( request, allSortedProjects, requiredSelectors ) );
+                    projectSelector.getRequiredProjectsBySelectors(request, allSortedProjects, requiredSelectors));
             selectedProjects.addAll(
-                    projectSelector.getOptionalProjectsBySelectors( request, allSortedProjects, optionalSelectors ) );
+                    projectSelector.getOptionalProjectsBySelectors(request, allSortedProjects, optionalSelectors));
 
             // it can be empty when an optional project is missing from the reactor, fallback to returning all projects
-            if ( !selectedProjects.isEmpty() )
-            {
-                result = new ArrayList<>( selectedProjects );
+            if (!selectedProjects.isEmpty()) {
+                result = new ArrayList<>(selectedProjects);
 
-                result = includeAlsoMakeTransitively( result, request, graph );
+                result = includeAlsoMakeTransitively(result, request, graph);
 
                 // Order the new list in the original order
                 List<MavenProject> sortedProjects = graph.getSortedProjects();
-                result.sort( comparing( sortedProjects::indexOf ) );
+                result.sort(comparing(sortedProjects::indexOf));
             }
         }
 
         return result;
     }
 
-    private List<MavenProject> trimResumedProjects( List<MavenProject> projects, ProjectDependencyGraph graph,
-                                                    MavenExecutionRequest request )
-            throws MavenExecutionException
-    {
+    private List<MavenProject> trimResumedProjects(
+            List<MavenProject> projects, ProjectDependencyGraph graph, MavenExecutionRequest request)
+            throws MavenExecutionException {
         List<MavenProject> result = projects;
 
-        if ( StringUtils.isNotEmpty( request.getResumeFrom() ) )
-        {
-            File reactorDirectory = projectSelector.getBaseDirectoryFromRequest( request );
+        if (request.getResumeFrom() != null && !request.getResumeFrom().isEmpty()) {
+            File reactorDirectory = projectSelector.getBaseDirectoryFromRequest(request);
 
             String selector = request.getResumeFrom();
 
             MavenProject resumingFromProject = projects.stream()
-                    .filter( project -> projectSelector.isMatchingProject( project, selector, reactorDirectory ) )
+                    .filter(project -> projectSelector.isMatchingProject(project, selector, reactorDirectory))
                     .findFirst()
-                    .orElseThrow( () -> new MavenExecutionException(
+                    .orElseThrow(() -> new MavenExecutionException(
                             "Could not find project to resume reactor build from: " + selector + " vs "
-                            + formatProjects( projects ), request.getPom() ) );
-            int resumeFromProjectIndex = projects.indexOf( resumingFromProject );
-            List<MavenProject> retainingProjects = result.subList( resumeFromProjectIndex, projects.size() );
+                                    + formatProjects(projects),
+                            request.getPom()));
+            int resumeFromProjectIndex = projects.indexOf(resumingFromProject);
+            List<MavenProject> retainingProjects = result.subList(resumeFromProjectIndex, projects.size());
 
-            result = includeAlsoMakeTransitively( retainingProjects, request, graph );
+            result = includeAlsoMakeTransitively(retainingProjects, request, graph);
         }
 
         return result;
     }
 
-    private List<MavenProject> trimExcludedProjects( List<MavenProject> projects, ProjectDependencyGraph graph,
-                                                     MavenExecutionRequest request )
-        throws MavenExecutionException
-    {
+    private List<MavenProject> trimExcludedProjects(
+            List<MavenProject> projects, ProjectDependencyGraph graph, MavenExecutionRequest request)
+            throws MavenExecutionException {
         List<MavenProject> result = projects;
 
         ProjectActivation projectActivation = request.getProjectActivation();
         Set<String> requiredSelectors = projectActivation.getRequiredInactiveProjectSelectors();
         Set<String> optionalSelectors = projectActivation.getOptionalInactiveProjectSelectors();
-        if ( !requiredSelectors.isEmpty() || !optionalSelectors.isEmpty() )
-        {
-            Set<MavenProject> excludedProjects = new HashSet<>( requiredSelectors.size() + optionalSelectors.size() );
+        if (!requiredSelectors.isEmpty() || !optionalSelectors.isEmpty()) {
+            Set<MavenProject> excludedProjects = new HashSet<>(requiredSelectors.size() + optionalSelectors.size());
             List<MavenProject> allProjects = graph.getAllProjects();
             excludedProjects.addAll(
-                    projectSelector.getRequiredProjectsBySelectors( request, allProjects, requiredSelectors ) );
+                    projectSelector.getRequiredProjectsBySelectors(request, allProjects, requiredSelectors));
             excludedProjects.addAll(
-                    projectSelector.getOptionalProjectsBySelectors( request, allProjects, optionalSelectors ) );
+                    projectSelector.getOptionalProjectsBySelectors(request, allProjects, optionalSelectors));
 
-            result = new ArrayList<>( projects );
-            result.removeAll( excludedProjects );
+            result = new ArrayList<>(projects);
+            result.removeAll(excludedProjects);
 
-            if ( result.isEmpty() )
-            {
+            if (result.isEmpty()) {
                 boolean isPlural = excludedProjects.size() > 1;
-                String message = String.format( "The project exclusion%s in --projects/-pl resulted in an "
-                        + "empty reactor, please correct %s.", isPlural ? "s" : "", isPlural ? "them" : "it" );
-                throw new MavenExecutionException( message, request.getPom() );
+                String message = String.format(
+                        "The project exclusion%s in --projects/-pl resulted in an "
+                                + "empty reactor, please correct %s.",
+                        isPlural ? "s" : "", isPlural ? "them" : "it");
+                throw new MavenExecutionException(message, request.getPom());
             }
         }
 
         return result;
     }
 
-    private List<MavenProject> includeAlsoMakeTransitively( List<MavenProject> projects, MavenExecutionRequest request,
-                                                            ProjectDependencyGraph graph )
-            throws MavenExecutionException
-    {
+    private List<MavenProject> includeAlsoMakeTransitively(
+            List<MavenProject> projects, MavenExecutionRequest request, ProjectDependencyGraph graph)
+            throws MavenExecutionException {
         List<MavenProject> result = projects;
 
         String makeBehavior = request.getMakeBehavior();
-        boolean makeBoth = MavenExecutionRequest.REACTOR_MAKE_BOTH.equals( makeBehavior );
+        boolean makeBoth = MavenExecutionRequest.REACTOR_MAKE_BOTH.equals(makeBehavior);
 
-        boolean makeUpstream = makeBoth || MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals( makeBehavior );
-        boolean makeDownstream = makeBoth || MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals( makeBehavior );
+        boolean makeUpstream = makeBoth || MavenExecutionRequest.REACTOR_MAKE_UPSTREAM.equals(makeBehavior);
+        boolean makeDownstream = makeBoth || MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM.equals(makeBehavior);
 
-        if ( StringUtils.isNotEmpty( makeBehavior ) && !makeUpstream && !makeDownstream )
-        {
-            throw new MavenExecutionException( "Invalid reactor make behavior: " + makeBehavior,
-                    request.getPom() );
+        if ((makeBehavior != null && !makeBehavior.isEmpty()) && !makeUpstream && !makeDownstream) {
+            throw new MavenExecutionException("Invalid reactor make behavior: " + makeBehavior, request.getPom());
         }
 
-        if ( makeUpstream || makeDownstream )
-        {
-            Set<MavenProject> projectsSet = new HashSet<>( projects );
+        if (makeUpstream || makeDownstream) {
+            Set<MavenProject> projectsSet = new HashSet<>(projects);
 
-            for ( MavenProject project : projects )
-            {
-                if ( makeUpstream )
-                {
-                    projectsSet.addAll( graph.getUpstreamProjects( project, true ) );
+            for (MavenProject project : projects) {
+                if (makeUpstream) {
+                    projectsSet.addAll(graph.getUpstreamProjects(project, true));
                 }
-                if ( makeDownstream )
-                {
-                    projectsSet.addAll( graph.getDownstreamProjects( project, true ) );
+                if (makeDownstream) {
+                    projectsSet.addAll(graph.getDownstreamProjects(project, true));
                 }
             }
 
-            result = new ArrayList<>( projectsSet );
+            result = new ArrayList<>(projectsSet);
 
             // Order the new list in the original order
             List<MavenProject> sortedProjects = graph.getSortedProjects();
-            result.sort( comparing( sortedProjects::indexOf ) );
+            result.sort(comparing(sortedProjects::indexOf));
         }
 
         return result;
     }
 
-    private void enrichRequestFromResumptionData( List<MavenProject> projects, MavenExecutionRequest request )
-    {
-        if ( request.isResume() )
-        {
+    private void enrichRequestFromResumptionData(List<MavenProject> projects, MavenExecutionRequest request) {
+        if (request.isResume()) {
             projects.stream()
-                    .filter( MavenProject::isExecutionRoot )
+                    .filter(MavenProject::isExecutionRoot)
                     .findFirst()
-                    .ifPresent( rootProject ->
-                            buildResumptionDataRepository.applyResumptionData( request, rootProject ) );
+                    .ifPresent(rootProject -> buildResumptionDataRepository.applyResumptionData(request, rootProject));
         }
     }
 
-    private List<MavenProject> getProjectsInRequestScope( MavenExecutionRequest request, List<MavenProject> projects )
-            throws MavenExecutionException
-    {
-        if ( request.getPom() == null )
-        {
+    private List<MavenProject> getProjectsInRequestScope(MavenExecutionRequest request, List<MavenProject> projects)
+            throws MavenExecutionException {
+        if (request.getPom() == null) {
             return projects;
         }
 
         MavenProject requestPomProject = projects.stream()
-                .filter( project -> request.getPom().equals( project.getFile() ) )
+                .filter(project -> request.getPom().equals(project.getFile()))
                 .findFirst()
-                .orElseThrow( () -> new MavenExecutionException(
-                        "Could not find a project in reactor matching the request POM", request.getPom() ) );
+                .orElseThrow(() -> new MavenExecutionException(
+                        "Could not find a project in reactor matching the request POM", request.getPom()));
 
         List<MavenProject> modules = requestPomProject.getCollectedProjects() != null
-                ? requestPomProject.getCollectedProjects() : Collections.emptyList();
+                ? requestPomProject.getCollectedProjects()
+                : Collections.emptyList();
 
-        List<MavenProject> result = new ArrayList<>( modules );
-        result.add( requestPomProject );
+        List<MavenProject> result = new ArrayList<>(modules);
+        result.add(requestPomProject);
         return result;
     }
 
-    private String formatProjects( List<MavenProject> projects )
-    {
+    private String formatProjects(List<MavenProject> projects) {
         StringBuilder projectNames = new StringBuilder();
         Iterator<MavenProject> iterator = projects.iterator();
-        while ( iterator.hasNext() )
-        {
+        while (iterator.hasNext()) {
             MavenProject project = iterator.next();
-            projectNames.append( project.getGroupId() ).append( ":" ).append( project.getArtifactId() );
-            if ( iterator.hasNext() )
-            {
-                projectNames.append( ", " );
+            projectNames.append(project.getGroupId()).append(":").append(project.getArtifactId());
+            if (iterator.hasNext()) {
+                projectNames.append(", ");
             }
         }
         return projectNames.toString();
@@ -366,60 +341,67 @@
     //
     // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private List<MavenProject> getProjectsForMavenReactor( MavenSession session )
-        throws ProjectBuildingException
-    {
+    private List<MavenProject> getProjectsForMavenReactor(MavenSession session) throws ProjectBuildingException {
         MavenExecutionRequest request = session.getRequest();
-        request.getProjectBuildingRequest().setRepositorySession( session.getRepositorySession() );
+        request.getProjectBuildingRequest().setRepositorySession(session.getRepositorySession());
 
         // 1. Collect project for invocation without a POM.
-        if ( request.getPom() == null )
-        {
-            return pomlessCollectionStrategy.collectProjects( request );
+        if (request.getPom() == null) {
+            return pomlessCollectionStrategy.collectProjects(request);
         }
 
         // 2. Collect projects for all modules in the multi-module project.
-        List<MavenProject> projects = multiModuleCollectionStrategy.collectProjects( request );
-        if ( !projects.isEmpty() )
-        {
-            return projects;
+        if (request.getMakeBehavior() != null || !request.getProjectActivation().isEmpty()) {
+            List<MavenProject> projects = multiModuleCollectionStrategy.collectProjects(request);
+            if (!projects.isEmpty()) {
+                return projects;
+            }
         }
 
         // 3. Collect projects for explicitly requested POM.
-        return requestPomCollectionStrategy.collectProjects( request );
+        return requestPomCollectionStrategy.collectProjects(request);
     }
 
-    private void validateProjects( List<MavenProject> projects, MavenExecutionRequest request )
-            throws MavenExecutionException
-    {
+    private void validateProjects(List<MavenProject> projects, MavenExecutionRequest request)
+            throws MavenExecutionException {
         Map<String, MavenProject> projectsMap = new HashMap<>();
 
-        List<MavenProject> projectsInRequestScope = getProjectsInRequestScope( request, projects );
-        for ( MavenProject p : projectsInRequestScope )
-        {
-            String projectKey = ArtifactUtils.key( p.getGroupId(), p.getArtifactId(), p.getVersion() );
+        List<MavenProject> projectsInRequestScope = getProjectsInRequestScope(request, projects);
+        for (MavenProject p : projectsInRequestScope) {
+            String projectKey = ArtifactUtils.key(p.getGroupId(), p.getArtifactId(), p.getVersion());
 
-            projectsMap.put( projectKey, p );
+            projectsMap.put(projectKey, p);
         }
 
-        for ( MavenProject project : projects )
-        {
+        for (MavenProject project : projects) {
             // MNG-1911 / MNG-5572: Building plugins with extensions cannot be part of reactor
-            for ( Plugin plugin : project.getBuildPlugins() )
-            {
-                if ( plugin.isExtensions() )
-                {
-                    String pluginKey = ArtifactUtils.key( plugin.getGroupId(), plugin.getArtifactId(),
-                                                          plugin.getVersion() );
+            for (Plugin plugin : project.getBuildPlugins()) {
+                if (plugin.isExtensions()) {
+                    String pluginKey =
+                            ArtifactUtils.key(plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion());
 
-                    if ( projectsMap.containsKey( pluginKey ) )
-                    {
-                        LOGGER.warn( "'{}' uses '{}' as extension which is not possible within the same reactor build. "
-                            + "This plugin was pulled from the local repository!", project.getName(), plugin.getKey() );
+                    if (projectsMap.containsKey(pluginKey)) {
+                        LOGGER.warn(
+                                "'{}' uses '{}' as extension which is not possible within the same reactor build. "
+                                        + "This plugin was pulled from the local repository!",
+                                project.getName(),
+                                plugin.getKey());
                     }
                 }
             }
         }
     }
 
+    private void processPackagingAttribute(List<MavenProject> projects, MavenExecutionRequest request)
+            throws MavenExecutionException {
+        List<MavenProject> projectsInRequestScope = getProjectsInRequestScope(request, projects);
+        for (MavenProject p : projectsInRequestScope) {
+            if ("bom".equals(p.getPackaging())) {
+                LOGGER.info(
+                        "The packaging attribute of the '{}' project is configured as 'bom' and changed to 'pom'",
+                        p.getName());
+                p.setPackaging("pom");
+            }
+        }
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
index c5553d9..d49670b 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/DefaultProjectDependencyGraph.java
@@ -1,5 +1,3 @@
-package org.apache.maven.graph;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.graph;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -32,19 +31,16 @@
 import java.util.stream.Collectors;
 
 import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectSorter;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 
 /**
  * Describes the interdependencies between projects in the reactor.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultProjectDependencyGraph
-        implements ProjectDependencyGraph
-{
+public class DefaultProjectDependencyGraph implements ProjectDependencyGraph {
 
     private final ProjectSorter sorter;
 
@@ -61,10 +57,9 @@
      * @throws DuplicateProjectException
      * @throws CycleDetectedException
      */
-    public DefaultProjectDependencyGraph( Collection<MavenProject> projects )
-            throws CycleDetectedException, DuplicateProjectException
-    {
-        this( projects, projects );
+    public DefaultProjectDependencyGraph(Collection<MavenProject> projects)
+            throws CycleDetectedException, DuplicateProjectException {
+        this(projects, projects);
     }
 
     /**
@@ -75,94 +70,94 @@
      * @throws DuplicateProjectException
      * @throws CycleDetectedException
      * @since 3.5.0
+     * @deprecated Use {@link #DefaultProjectDependencyGraph(Collection, Collection)} instead.
      */
-    public DefaultProjectDependencyGraph( Collection<MavenProject> allProjects,
-                                          Collection<MavenProject> projects )
-            throws CycleDetectedException, DuplicateProjectException
-    {
-        this.allProjects = Collections.unmodifiableList( new ArrayList<>( allProjects ) );
-        this.sorter = new ProjectSorter( projects );
+    @Deprecated
+    public DefaultProjectDependencyGraph(List<MavenProject> allProjects, Collection<MavenProject> projects)
+            throws CycleDetectedException, DuplicateProjectException {
+        this((Collection<MavenProject>) allProjects, projects);
+    }
+
+    /**
+     * Creates a new project dependency graph based on the specified projects.
+     *
+     * @param allProjects All collected projects.
+     * @param projects    The projects to create the dependency graph with.
+     * @throws DuplicateProjectException
+     * @throws CycleDetectedException
+     * @since 4.0.0
+     */
+    public DefaultProjectDependencyGraph(Collection<MavenProject> allProjects, Collection<MavenProject> projects)
+            throws CycleDetectedException, DuplicateProjectException {
+        this.allProjects = Collections.unmodifiableList(new ArrayList<>(allProjects));
+        this.sorter = new ProjectSorter(projects);
         this.order = new HashMap<>();
         this.projects = new HashMap<>();
         List<MavenProject> sorted = this.sorter.getSortedProjects();
-        for ( int index = 0; index < sorted.size(); index++ )
-        {
-            MavenProject project = sorted.get( index );
-            String id = ProjectSorter.getId( project );
-            this.projects.put( id, project );
-            this.order.put( project, index );
+        for (int index = 0; index < sorted.size(); index++) {
+            MavenProject project = sorted.get(index);
+            String id = ProjectSorter.getId(project);
+            this.projects.put(id, project);
+            this.order.put(project, index);
         }
     }
 
     /**
      * @since 3.5.0
      */
-    public List<MavenProject> getAllProjects()
-    {
+    public List<MavenProject> getAllProjects() {
         return this.allProjects;
     }
 
-    public List<MavenProject> getSortedProjects()
-    {
-        return new ArrayList<>( sorter.getSortedProjects() );
+    public List<MavenProject> getSortedProjects() {
+        return new ArrayList<>(sorter.getSortedProjects());
     }
 
-    public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive )
-    {
-        Objects.requireNonNull( project, "project cannot be null" );
+    public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
+        Objects.requireNonNull(project, "project cannot be null");
 
         Set<String> projectIds = new HashSet<>();
 
-        getDownstreamProjects( ProjectSorter.getId( project ), projectIds, transitive );
+        getDownstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
 
-        return getSortedProjects( projectIds );
+        return getSortedProjects(projectIds);
     }
 
-    private void getDownstreamProjects( String projectId, Set<String> projectIds, boolean transitive )
-    {
-        for ( String id : sorter.getDependents( projectId ) )
-        {
-            if ( projectIds.add( id ) && transitive )
-            {
-                getDownstreamProjects( id, projectIds, transitive );
+    private void getDownstreamProjects(String projectId, Set<String> projectIds, boolean transitive) {
+        for (String id : sorter.getDependents(projectId)) {
+            if (projectIds.add(id) && transitive) {
+                getDownstreamProjects(id, projectIds, transitive);
             }
         }
     }
 
-    public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive )
-    {
-        Objects.requireNonNull( project, "project cannot be null" );
+    public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
+        Objects.requireNonNull(project, "project cannot be null");
 
         Set<String> projectIds = new HashSet<>();
 
-        getUpstreamProjects( ProjectSorter.getId( project ), projectIds, transitive );
+        getUpstreamProjects(ProjectSorter.getId(project), projectIds, transitive);
 
-        return getSortedProjects( projectIds );
+        return getSortedProjects(projectIds);
     }
 
-    private void getUpstreamProjects( String projectId, Collection<String> projectIds, boolean transitive )
-    {
-        for ( String id : sorter.getDependencies( projectId ) )
-        {
-            if ( projectIds.add( id ) && transitive )
-            {
-                getUpstreamProjects( id, projectIds, transitive );
+    private void getUpstreamProjects(String projectId, Collection<String> projectIds, boolean transitive) {
+        for (String id : sorter.getDependencies(projectId)) {
+            if (projectIds.add(id) && transitive) {
+                getUpstreamProjects(id, projectIds, transitive);
             }
         }
     }
 
-    private List<MavenProject> getSortedProjects( Set<String> projectIds )
-    {
+    private List<MavenProject> getSortedProjects(Set<String> projectIds) {
         return projectIds.stream()
-                .map( projects::get )
-                .sorted( Comparator.comparingInt( order::get ) )
-                .collect( Collectors.toList() );
+                .map(projects::get)
+                .sorted(Comparator.comparingInt(order::get))
+                .collect(Collectors.toList());
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return sorter.getSortedProjects().toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java
index 97ba57e..2d6612e 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/FilteredProjectDependencyGraph.java
@@ -1,5 +1,3 @@
-package org.apache.maven.graph;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.graph;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -32,11 +31,8 @@
 /**
  * Provides a sub view of another dependency graph.
  *
- * @author Benjamin Bentmann
  */
-class FilteredProjectDependencyGraph
-    implements ProjectDependencyGraph
-{
+class FilteredProjectDependencyGraph implements ProjectDependencyGraph {
 
     private ProjectDependencyGraph projectDependencyGraph;
 
@@ -50,57 +46,47 @@
      * @param projectDependencyGraph The project dependency graph to create a sub view from, must not be {@code null}.
      * @param whiteList The projects on which the dependency view should focus, must not be {@code null}.
      */
-    FilteredProjectDependencyGraph( ProjectDependencyGraph projectDependencyGraph,
-                                    Collection<? extends MavenProject> whiteList )
-    {
+    FilteredProjectDependencyGraph(
+            ProjectDependencyGraph projectDependencyGraph, Collection<? extends MavenProject> whiteList) {
         this.projectDependencyGraph =
-                Objects.requireNonNull( projectDependencyGraph, "projectDependencyGraph cannot be null" );
+                Objects.requireNonNull(projectDependencyGraph, "projectDependencyGraph cannot be null");
 
         this.whiteList = new IdentityHashMap<>();
 
-        for ( MavenProject project : whiteList )
-        {
-            this.whiteList.put( project, null );
+        for (MavenProject project : whiteList) {
+            this.whiteList.put(project, null);
         }
     }
 
     /**
      * @since 3.5.0
      */
-    public List<MavenProject> getAllProjects()
-    {
+    public List<MavenProject> getAllProjects() {
         return this.projectDependencyGraph.getAllProjects();
     }
 
-    public List<MavenProject> getSortedProjects()
-    {
-        if ( sortedProjects == null )
-        {
-            sortedProjects = applyFilter( projectDependencyGraph.getSortedProjects() );
+    public List<MavenProject> getSortedProjects() {
+        if (sortedProjects == null) {
+            sortedProjects = applyFilter(projectDependencyGraph.getSortedProjects());
         }
 
-        return new ArrayList<>( sortedProjects );
+        return new ArrayList<>(sortedProjects);
     }
 
-    public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive )
-    {
-        return applyFilter( projectDependencyGraph.getDownstreamProjects( project, transitive ) );
+    public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
+        return applyFilter(projectDependencyGraph.getDownstreamProjects(project, transitive));
     }
 
-    public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive )
-    {
-        return applyFilter( projectDependencyGraph.getUpstreamProjects( project, transitive ) );
+    public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
+        return applyFilter(projectDependencyGraph.getUpstreamProjects(project, transitive));
     }
 
-    private List<MavenProject> applyFilter( Collection<? extends MavenProject> projects )
-    {
-        List<MavenProject> filtered = new ArrayList<>( projects.size() );
+    private List<MavenProject> applyFilter(Collection<? extends MavenProject> projects) {
+        List<MavenProject> filtered = new ArrayList<>(projects.size());
 
-        for ( MavenProject project : projects )
-        {
-            if ( whiteList.containsKey( project ) )
-            {
-                filtered.add( project );
+        for (MavenProject project : projects) {
+            if (whiteList.containsKey(project)) {
+                filtered.add(project);
             }
         }
 
@@ -108,9 +94,7 @@
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getSortedProjects().toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java b/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java
index 0f584d9..b860781 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/GraphBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.graph;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.graph;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
@@ -28,9 +27,8 @@
  *
  * @since 3.0-alpha
  */
-public interface GraphBuilder
-{
+public interface GraphBuilder {
     String HINT = "graphBuilder";
 
-    Result<? extends ProjectDependencyGraph> build( MavenSession session );
+    Result<? extends ProjectDependencyGraph> build(MavenSession session);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java b/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
index bc81abc..f2ee85f 100644
--- a/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
+++ b/maven-core/src/main/java/org/apache/maven/graph/ProjectSelector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.graph;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.MavenExecutionException;
-import org.apache.maven.execution.MavenExecutionRequest;
-import org.apache.maven.project.MavenProject;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+package org.apache.maven.graph;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -33,123 +26,107 @@
 import java.util.Optional;
 import java.util.Set;
 
+import org.apache.maven.MavenExecutionException;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.project.MavenProject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 /**
  * Utility class to extract {@link MavenProject} from the project graph during the execution phase based on optional or
  * required selectors.
  */
-public final class ProjectSelector
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( ProjectSelector.class );
+public final class ProjectSelector {
+    private static final Logger LOGGER = LoggerFactory.getLogger(ProjectSelector.class);
 
-    public Set<MavenProject> getRequiredProjectsBySelectors( MavenExecutionRequest request, List<MavenProject> projects,
-                                                             Set<String> projectSelectors )
-            throws MavenExecutionException
-    {
+    public Set<MavenProject> getRequiredProjectsBySelectors(
+            MavenExecutionRequest request, List<MavenProject> projects, Set<String> projectSelectors)
+            throws MavenExecutionException {
         Set<MavenProject> selectedProjects = new LinkedHashSet<>();
-        File baseDirectory = getBaseDirectoryFromRequest( request );
-        for ( String selector : projectSelectors )
-        {
+        File baseDirectory = getBaseDirectoryFromRequest(request);
+        for (String selector : projectSelectors) {
             Optional<MavenProject> optSelectedProject =
-                    findOptionalProjectBySelector( projects, baseDirectory, selector );
-            if ( !optSelectedProject.isPresent() )
-            {
+                    findOptionalProjectBySelector(projects, baseDirectory, selector);
+            if (!optSelectedProject.isPresent()) {
                 String message = "Could not find the selected project in the reactor: " + selector;
-                throw new MavenExecutionException( message, request.getPom() );
+                throw new MavenExecutionException(message, request.getPom());
             }
 
             MavenProject selectedProject = optSelectedProject.get();
 
-            selectedProjects.add( selectedProject );
-            selectedProjects.addAll( getChildProjects( selectedProject, request ) );
+            selectedProjects.add(selectedProject);
+            selectedProjects.addAll(getChildProjects(selectedProject, request));
         }
 
         return selectedProjects;
     }
 
-    public Set<MavenProject> getOptionalProjectsBySelectors( MavenExecutionRequest request, List<MavenProject> projects,
-                                                             Set<String> projectSelectors )
-    {
+    public Set<MavenProject> getOptionalProjectsBySelectors(
+            MavenExecutionRequest request, List<MavenProject> projects, Set<String> projectSelectors) {
         Set<MavenProject> resolvedOptionalProjects = new LinkedHashSet<>();
         Set<String> unresolvedOptionalSelectors = new HashSet<>();
-        File baseDirectory = getBaseDirectoryFromRequest( request );
-        for ( String selector : projectSelectors )
-        {
+        File baseDirectory = getBaseDirectoryFromRequest(request);
+        for (String selector : projectSelectors) {
             Optional<MavenProject> optSelectedProject =
-                    findOptionalProjectBySelector( projects, baseDirectory, selector );
-            if ( optSelectedProject.isPresent() )
-            {
-                resolvedOptionalProjects.add( optSelectedProject.get() );
-                resolvedOptionalProjects.addAll( getChildProjects( optSelectedProject.get(), request ) );
-            }
-            else
-            {
-                unresolvedOptionalSelectors.add( selector );
+                    findOptionalProjectBySelector(projects, baseDirectory, selector);
+            if (optSelectedProject.isPresent()) {
+                resolvedOptionalProjects.add(optSelectedProject.get());
+                resolvedOptionalProjects.addAll(getChildProjects(optSelectedProject.get(), request));
+            } else {
+                unresolvedOptionalSelectors.add(selector);
             }
         }
 
-        if ( !unresolvedOptionalSelectors.isEmpty() )
-        {
-            LOGGER.info( "The requested optional projects {} do not exist.", unresolvedOptionalSelectors );
+        if (!unresolvedOptionalSelectors.isEmpty()) {
+            LOGGER.info("The requested optional projects {} do not exist.", unresolvedOptionalSelectors);
         }
 
         return resolvedOptionalProjects;
     }
 
-    private List<MavenProject> getChildProjects( MavenProject parent, MavenExecutionRequest request )
-    {
+    private List<MavenProject> getChildProjects(MavenProject parent, MavenExecutionRequest request) {
         final List<MavenProject> children = parent.getCollectedProjects();
-        if ( children != null && request.isRecursive() )
-        {
+        if (children != null && request.isRecursive()) {
             return children;
-        }
-        else
-        {
+        } else {
             return new ArrayList<>();
         }
     }
 
-    private Optional<MavenProject> findOptionalProjectBySelector( List<MavenProject> projects, File reactorDirectory,
-                                                                  String selector )
-    {
+    private Optional<MavenProject> findOptionalProjectBySelector(
+            List<MavenProject> projects, File reactorDirectory, String selector) {
         return projects.stream()
-                .filter( project -> isMatchingProject( project, selector, reactorDirectory ) )
+                .filter(project -> isMatchingProject(project, selector, reactorDirectory))
                 .findFirst();
     }
 
-    File getBaseDirectoryFromRequest( MavenExecutionRequest request )
-    {
-        return request.getBaseDirectory() != null ? new File( request.getBaseDirectory() ) : null;
+    File getBaseDirectoryFromRequest(MavenExecutionRequest request) {
+        return request.getBaseDirectory() != null ? new File(request.getBaseDirectory()) : null;
     }
 
-    boolean isMatchingProject( MavenProject project, String selector, File reactorDirectory )
-    {
+    boolean isMatchingProject(MavenProject project, String selector, File reactorDirectory) {
         // [groupId]:artifactId
-        if ( selector.contains( ":" ) )
-        {
+        if (selector.contains(":")) {
             String id = ':' + project.getArtifactId();
 
-            if ( id.equals( selector ) )
-            {
+            if (id.equals(selector)) {
                 return true;
             }
 
             id = project.getGroupId() + id;
 
-            return id.equals( selector );
+            return id.equals(selector);
         }
 
         // relative path, e.g. "sub", "../sub" or "."
-        else if ( reactorDirectory != null )
-        {
-            File selectedProject = new File( new File( reactorDirectory, selector ).toURI().normalize() );
+        else if (reactorDirectory != null) {
+            File selectedProject =
+                    new File(new File(reactorDirectory, selector).toURI().normalize());
 
-            if ( selectedProject.isFile() )
-            {
-                return selectedProject.equals( project.getFile() );
-            }
-            else if ( selectedProject.isDirectory() )
-            {
-                return selectedProject.equals( project.getBasedir() );
+            if (selectedProject.isFile()) {
+                return selectedProject.equals(project.getFile());
+            } else if (selectedProject.isDirectory()) {
+                return selectedProject.equals(project.getBasedir());
             }
         }
 
diff --git a/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java b/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java
index da15829..9ff2d20 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/MultilineMessageHelper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,74 +16,68 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.internal;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * Helper class to format multiline messages to the console
  */
-public class MultilineMessageHelper
-{
+public class MultilineMessageHelper {
 
     private static final int DEFAULT_MAX_SIZE = 65;
     private static final char BOX_CHAR = '*';
 
-    public static String separatorLine()
-    {
-        StringBuilder sb = new StringBuilder( DEFAULT_MAX_SIZE );
-        repeat( sb, '*', DEFAULT_MAX_SIZE );
+    private static final Pattern S_FILTER = Pattern.compile("\\s+");
+
+    public static String separatorLine() {
+        StringBuilder sb = new StringBuilder(DEFAULT_MAX_SIZE);
+        repeat(sb, '*', DEFAULT_MAX_SIZE);
         return sb.toString();
     }
 
-    public static List<String> format( String... lines )
-    {
+    public static List<String> format(String... lines) {
         int size = DEFAULT_MAX_SIZE;
         int remainder = size - 4; // 4 chars = 2 box_char + 2 spaces
         List<String> result = new ArrayList<>();
-        StringBuilder sb = new StringBuilder( size );
+        StringBuilder sb = new StringBuilder(size);
         // first line
-        sb.setLength( 0 );
-        repeat( sb, BOX_CHAR, size );
-        result.add( sb.toString() );
+        sb.setLength(0);
+        repeat(sb, BOX_CHAR, size);
+        result.add(sb.toString());
         // lines
-        for ( String line : lines )
-        {
-            sb.setLength( 0 );
-            String[] words = line.split( "\\s+" );
-            for ( String word : words )
-            {
-                if ( sb.length() >= remainder - word.length() - ( sb.length() > 0 ? 1 : 0 ) )
-                {
-                    repeat( sb, ' ', remainder - sb.length() );
-                    result.add( BOX_CHAR + " " + sb + " " + BOX_CHAR );
-                    sb.setLength( 0 );
+        for (String line : lines) {
+            sb.setLength(0);
+            String[] words = S_FILTER.split(line);
+            for (String word : words) {
+                if (sb.length() >= remainder - word.length() - (sb.length() > 0 ? 1 : 0)) {
+                    repeat(sb, ' ', remainder - sb.length());
+                    result.add(BOX_CHAR + " " + sb + " " + BOX_CHAR);
+                    sb.setLength(0);
                 }
-                if ( sb.length() > 0 )
-                {
-                    sb.append( ' ' );
+                if (sb.length() > 0) {
+                    sb.append(' ');
                 }
-                sb.append( word );
+                sb.append(word);
             }
 
-            while ( sb.length() < remainder )
-            {
-                sb.append( ' ' );
+            while (sb.length() < remainder) {
+                sb.append(' ');
             }
-            result.add( BOX_CHAR + " " + sb + " " + BOX_CHAR );
+            result.add(BOX_CHAR + " " + sb + " " + BOX_CHAR);
         }
         // last line
-        sb.setLength( 0 );
-        repeat( sb, BOX_CHAR, size );
-        result.add( sb.toString() );
+        sb.setLength(0);
+        repeat(sb, BOX_CHAR, size);
+        result.add(sb.toString());
         return result;
     }
 
-    private static void repeat( StringBuilder sb, char c, int nb )
-    {
-        for ( int i = 0; i < nb; i++ )
-        {
-            sb.append( c );
+    private static void repeat(StringBuilder sb, char c, int nb) {
+        for (int i = 0; i < nb; i++) {
+            sb.append(c);
         }
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java b/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
deleted file mode 100644
index c1e1144..0000000
--- a/maven-core/src/main/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformer.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package org.apache.maven.internal.aether;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-
-import org.apache.maven.model.building.DefaultBuildPomXMLFilterFactory;
-import org.apache.maven.model.building.TransformerContext;
-import org.apache.maven.model.transform.RawToConsumerPomXMLFilterFactory;
-import org.apache.maven.model.transform.pull.XmlUtils;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.XmlStreamReader;
-import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
-import org.codehaus.plexus.util.xml.pull.MXParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-class ConsumerModelSourceTransformer
-{
-    public InputStream transform( Path pomFile, TransformerContext context )
-            throws IOException, XmlPullParserException
-    {
-        XmlStreamReader reader = ReaderFactory.newXmlReader( Files.newInputStream( pomFile ) );
-        XmlPullParser parser = new MXParser( EntityReplacementMap.defaultEntityReplacementMap );
-        parser.setInput( reader );
-        parser = new RawToConsumerPomXMLFilterFactory( new DefaultBuildPomXMLFilterFactory( context, true ) )
-                .get( parser, pomFile );
-
-        return XmlUtils.writeDocument( reader, parser );
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
index 4eacf7b..6dd44ab 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.internal.aether;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,26 +16,34 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
+package org.apache.maven.internal.aether;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
 import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.services.TypeRegistry;
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.Authentication;
 import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
 import org.apache.maven.execution.MavenExecutionRequest;
-import org.apache.maven.feature.Features;
-import org.apache.maven.model.building.TransformerContext;
+import org.apache.maven.internal.xml.XmlNodeImpl;
+import org.apache.maven.internal.xml.XmlPlexusConfiguration;
+import org.apache.maven.model.ModelBase;
 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
 import org.apache.maven.rtinfo.RuntimeInformation;
 import org.apache.maven.settings.Mirror;
@@ -47,26 +53,26 @@
 import org.apache.maven.settings.crypto.DefaultSettingsDecryptionRequest;
 import org.apache.maven.settings.crypto.SettingsDecrypter;
 import org.apache.maven.settings.crypto.SettingsDecryptionResult;
-import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
 import org.eclipse.aether.ConfigurationProperties;
-import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositoryListener;
 import org.eclipse.aether.RepositorySystem;
-import org.eclipse.aether.SessionData;
-import org.eclipse.aether.artifact.Artifact;
-import org.eclipse.aether.repository.LocalRepository;
-import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
+import org.eclipse.aether.repository.AuthenticationContext;
+import org.eclipse.aether.repository.AuthenticationSelector;
+import org.eclipse.aether.repository.ProxySelector;
+import org.eclipse.aether.repository.RemoteRepository;
 import org.eclipse.aether.repository.RepositoryPolicy;
 import org.eclipse.aether.repository.WorkspaceReader;
 import org.eclipse.aether.resolution.ResolutionErrorPolicy;
-import org.eclipse.aether.spi.localrepo.LocalRepositoryManagerFactory;
-import org.eclipse.aether.transform.FileTransformer;
-import org.eclipse.aether.transform.TransformException;
+import org.eclipse.aether.util.listener.ChainedRepositoryListener;
 import org.eclipse.aether.util.repository.AuthenticationBuilder;
+import org.eclipse.aether.util.repository.ChainedLocalRepositoryManager;
 import org.eclipse.aether.util.repository.DefaultAuthenticationSelector;
 import org.eclipse.aether.util.repository.DefaultMirrorSelector;
 import org.eclipse.aether.util.repository.DefaultProxySelector;
+import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
 import org.eclipse.aether.util.repository.SimpleResolutionErrorPolicy;
 import org.eclipse.sisu.Nullable;
 import org.slf4j.Logger;
@@ -76,297 +82,464 @@
  * @since 3.3.0
  */
 @Named
-public class DefaultRepositorySystemSessionFactory
-{
+public class DefaultRepositorySystemSessionFactory {
+    /**
+     * User property for chained LRM: list of "tail" local repository paths (separated by comma), to be used with
+     * {@link ChainedLocalRepositoryManager}.
+     * Default value: {@code null}, no chained LRM is used.
+     *
+     * @since 3.9.0
+     */
+    private static final String MAVEN_REPO_LOCAL_TAIL = "maven.repo.local.tail";
+
+    /**
+     * User property for chained LRM: should artifact availability be ignored in tail local repositories or not.
+     * Default: {@code true}, will ignore availability from tail local repositories.
+     *
+     * @since 3.9.0
+     * @deprecated Use {@link ChainedLocalRepositoryManager#IGNORE_TAIL_AVAILABILITY} instead.
+     */
+    @Deprecated
+    private static final String MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY = "maven.repo.local.tail.ignoreAvailability";
+
+    /**
+     * User property for reverse dependency tree. If enabled, Maven will record ".tracking" directory into local
+     * repository with "reverse dependency tree", essentially explaining WHY given artifact is present in local
+     * repository.
+     * Default: {@code false}, will not record anything.
+     *
+     * @since 3.9.0
+     */
+    private static final String MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE = "maven.repo.local.recordReverseTree";
+
     private static final String MAVEN_RESOLVER_TRANSPORT_KEY = "maven.resolver.transport";
 
     private static final String MAVEN_RESOLVER_TRANSPORT_DEFAULT = "default";
 
     private static final String MAVEN_RESOLVER_TRANSPORT_WAGON = "wagon";
 
+    private static final String MAVEN_RESOLVER_TRANSPORT_APACHE = "apache";
+
+    private static final String MAVEN_RESOLVER_TRANSPORT_JDK = "jdk";
+
+    /**
+     * This name for Apache HttpClient transport is deprecated.
+     *
+     * @deprecated Renamed to {@link #MAVEN_RESOLVER_TRANSPORT_APACHE}
+     */
+    @Deprecated
     private static final String MAVEN_RESOLVER_TRANSPORT_NATIVE = "native";
 
     private static final String MAVEN_RESOLVER_TRANSPORT_AUTO = "auto";
 
     private static final String WAGON_TRANSPORTER_PRIORITY_KEY = "aether.priority.WagonTransporterFactory";
 
-    private static final String NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.HttpTransporterFactory";
+    private static final String APACHE_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.HttpTransporterFactory";
 
-    private static final String NATIVE_FILE_TRANSPORTER_PRIORITY_KEY = "aether.priority.FileTransporterFactory";
+    private static final String JDK_HTTP_TRANSPORTER_PRIORITY_KEY = "aether.priority.JdkTransporterFactory";
 
-    private static final String RESOLVER_MAX_PRIORITY = String.valueOf( Float.MAX_VALUE );
+    private static final String FILE_TRANSPORTER_PRIORITY_KEY = "aether.priority.FileTransporterFactory";
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private static final String RESOLVER_MAX_PRIORITY = String.valueOf(Float.MAX_VALUE);
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final ArtifactHandlerManager artifactHandlerManager;
 
     private final RepositorySystem repoSystem;
 
-    private final LocalRepositoryManagerFactory simpleLocalRepoMgrFactory;
-
     private final WorkspaceReader workspaceRepository;
 
     private final SettingsDecrypter settingsDecrypter;
 
     private final EventSpyDispatcher eventSpyDispatcher;
 
-    private final MavenRepositorySystem mavenRepositorySystem;
-
     private final RuntimeInformation runtimeInformation;
 
+    private final TypeRegistry typeRegistry;
+
+    @SuppressWarnings("checkstyle:ParameterNumber")
     @Inject
     public DefaultRepositorySystemSessionFactory(
             ArtifactHandlerManager artifactHandlerManager,
             RepositorySystem repoSystem,
-            @Nullable @Named( "simple" ) LocalRepositoryManagerFactory simpleLocalRepoMgrFactory,
-            @Nullable @Named( "ide" ) WorkspaceReader workspaceRepository,
+            @Nullable @Named("ide") WorkspaceReader workspaceRepository,
             SettingsDecrypter settingsDecrypter,
             EventSpyDispatcher eventSpyDispatcher,
-            MavenRepositorySystem mavenRepositorySystem,
-            RuntimeInformation runtimeInformation )
-    {
+            RuntimeInformation runtimeInformation,
+            TypeRegistry typeRegistry) {
         this.artifactHandlerManager = artifactHandlerManager;
         this.repoSystem = repoSystem;
-        this.simpleLocalRepoMgrFactory = simpleLocalRepoMgrFactory;
         this.workspaceRepository = workspaceRepository;
         this.settingsDecrypter = settingsDecrypter;
         this.eventSpyDispatcher = eventSpyDispatcher;
-        this.mavenRepositorySystem = mavenRepositorySystem;
         this.runtimeInformation = runtimeInformation;
+        this.typeRegistry = typeRegistry;
     }
 
-    public DefaultRepositorySystemSession newRepositorySession( MavenExecutionRequest request )
-    {
-        DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
-        session.setCache( request.getRepositoryCache() );
+    @Deprecated
+    public RepositorySystemSession newRepositorySession(MavenExecutionRequest request) {
+        return newRepositorySessionBuilder(request).build();
+    }
+
+    @SuppressWarnings("checkstyle:methodLength")
+    public SessionBuilder newRepositorySessionBuilder(MavenExecutionRequest request) {
+        SessionBuilder session = MavenRepositorySystemUtils.newSession(
+                repoSystem.createSessionBuilder(), new TypeRegistryAdapter(typeRegistry));
+        session.setCache(request.getRepositoryCache());
 
         Map<Object, Object> configProps = new LinkedHashMap<>();
-        configProps.put( ConfigurationProperties.USER_AGENT, getUserAgent() );
-        configProps.put( ConfigurationProperties.INTERACTIVE, request.isInteractiveMode() );
-        configProps.put( "maven.startTime", request.getStartTime() );
-        configProps.putAll( request.getSystemProperties() );
-        configProps.putAll( request.getUserProperties() );
+        configProps.put(ConfigurationProperties.USER_AGENT, getUserAgent());
+        configProps.put(ConfigurationProperties.INTERACTIVE, request.isInteractiveMode());
+        configProps.put("maven.startTime", request.getStartTime());
+        // First add properties populated from settings.xml
+        configProps.putAll(getPropertiesFromRequestedProfiles(request));
+        // Resolver's ConfigUtils solely rely on config properties, that is why we need to add both here as well.
+        configProps.putAll(request.getSystemProperties());
+        configProps.putAll(request.getUserProperties());
 
-        session.setOffline( request.isOffline() );
-        session.setChecksumPolicy( request.getGlobalChecksumPolicy() );
-        if ( request.isNoSnapshotUpdates() )
-        {
-            session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_NEVER );
+        // we need to "translate" this
+        if (configProps.containsKey(MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY)) {
+            logger.warn(
+                    "User property {} is DEPRECATED, switch to {}",
+                    MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY,
+                    ChainedLocalRepositoryManager.IGNORE_TAIL_AVAILABILITY);
+            configProps.put(
+                    ChainedLocalRepositoryManager.IGNORE_TAIL_AVAILABILITY,
+                    configProps.get(MAVEN_REPO_LOCAL_TAIL_IGNORE_AVAILABILITY));
         }
-        else if ( request.isUpdateSnapshots() )
-        {
-            session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS );
+
+        // HACK: Resolver 2.0.0-alpha-2 carries a bad change:
+        // https://github.com/apache/maven-resolver/commit/178cfba9f3889f7e942a6a0d74716355b01a78f5
+        // that is fixed in later versions by MRESOLVER-437 https://github.com/apache/maven-resolver/pull/373
+        // TODO: remove this hack below once Resolver PR above is applied
+        if (!configProps.containsKey(ConfigurationProperties.HTTP_EXPECT_CONTINUE)) {
+            configProps.put(ConfigurationProperties.HTTP_EXPECT_CONTINUE, Boolean.FALSE.toString());
         }
-        else
-        {
-            session.setUpdatePolicy( null );
-        }
+
+        session.setOffline(request.isOffline());
+        session.setChecksumPolicy(request.getGlobalChecksumPolicy());
+        session.setUpdatePolicy(
+                request.isNoSnapshotUpdates()
+                        ? RepositoryPolicy.UPDATE_POLICY_NEVER
+                        : request.isUpdateSnapshots() ? RepositoryPolicy.UPDATE_POLICY_ALWAYS : null);
 
         int errorPolicy = 0;
-        errorPolicy |= request.isCacheNotFound() ? ResolutionErrorPolicy.CACHE_NOT_FOUND
-            : ResolutionErrorPolicy.CACHE_DISABLED;
-        errorPolicy |= request.isCacheTransferError() ? ResolutionErrorPolicy.CACHE_TRANSFER_ERROR
-            : ResolutionErrorPolicy.CACHE_DISABLED;
+        errorPolicy |= request.isCacheNotFound()
+                ? ResolutionErrorPolicy.CACHE_NOT_FOUND
+                : ResolutionErrorPolicy.CACHE_DISABLED;
+        errorPolicy |= request.isCacheTransferError()
+                ? ResolutionErrorPolicy.CACHE_TRANSFER_ERROR
+                : ResolutionErrorPolicy.CACHE_DISABLED;
         session.setResolutionErrorPolicy(
-            new SimpleResolutionErrorPolicy( errorPolicy, errorPolicy | ResolutionErrorPolicy.CACHE_NOT_FOUND ) );
+                new SimpleResolutionErrorPolicy(errorPolicy, errorPolicy | ResolutionErrorPolicy.CACHE_NOT_FOUND));
 
-        session.setArtifactTypeRegistry( RepositoryUtils.newArtifactTypeRegistry( artifactHandlerManager ) );
+        session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(
+                request.isIgnoreMissingArtifactDescriptor(), request.isIgnoreInvalidArtifactDescriptor()));
 
-        LocalRepository localRepo = new LocalRepository( request.getLocalRepository().getBasedir() );
+        session.setArtifactTypeRegistry(RepositoryUtils.newArtifactTypeRegistry(artifactHandlerManager));
 
-        if ( request.isUseLegacyLocalRepository() )
-        {
-            try
-            {
-                session.setLocalRepositoryManager( simpleLocalRepoMgrFactory.newInstance( session, localRepo ) );
-                logger.info( "Disabling enhanced local repository: using legacy is strongly discouraged to ensure"
-                                 + " build reproducibility." );
-            }
-            catch ( NoLocalRepositoryManagerException e )
-            {
-                logger.error( "Failed to configure legacy local repository: falling back to default" );
-                session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( session, localRepo ) );
-            }
-        }
-        else
-        {
-            session.setLocalRepositoryManager( repoSystem.newLocalRepositoryManager( session, localRepo ) );
-        }
-
-        if ( request.getWorkspaceReader() != null )
-        {
-            session.setWorkspaceReader( request.getWorkspaceReader() );
-        }
-        else
-        {
-            session.setWorkspaceReader( workspaceRepository );
-        }
+        session.setWorkspaceReader(
+                request.getWorkspaceReader() != null ? request.getWorkspaceReader() : workspaceRepository);
 
         DefaultSettingsDecryptionRequest decrypt = new DefaultSettingsDecryptionRequest();
-        decrypt.setProxies( request.getProxies() );
-        decrypt.setServers( request.getServers() );
-        SettingsDecryptionResult decrypted = settingsDecrypter.decrypt( decrypt );
+        decrypt.setProxies(request.getProxies());
+        decrypt.setServers(request.getServers());
+        SettingsDecryptionResult decrypted = settingsDecrypter.decrypt(decrypt);
 
-        if ( logger.isDebugEnabled() )
-        {
-            for ( SettingsProblem problem : decrypted.getProblems() )
-            {
-                logger.debug( problem.getMessage(), problem.getException() );
+        if (logger.isDebugEnabled()) {
+            for (SettingsProblem problem : decrypted.getProblems()) {
+                logger.debug(problem.getMessage(), problem.getException());
             }
         }
 
         DefaultMirrorSelector mirrorSelector = new DefaultMirrorSelector();
-        for ( Mirror mirror : request.getMirrors() )
-        {
-            mirrorSelector.add( mirror.getId(), mirror.getUrl(), mirror.getLayout(), false, mirror.isBlocked(),
-                                mirror.getMirrorOf(), mirror.getMirrorOfLayouts() );
+        for (Mirror mirror : request.getMirrors()) {
+            mirrorSelector.add(
+                    mirror.getId(),
+                    mirror.getUrl(),
+                    mirror.getLayout(),
+                    false,
+                    mirror.isBlocked(),
+                    mirror.getMirrorOf(),
+                    mirror.getMirrorOfLayouts());
         }
-        session.setMirrorSelector( mirrorSelector );
+        session.setMirrorSelector(mirrorSelector);
 
         DefaultProxySelector proxySelector = new DefaultProxySelector();
-        for ( Proxy proxy : decrypted.getProxies() )
-        {
+        for (Proxy proxy : decrypted.getProxies()) {
             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
-            authBuilder.addUsername( proxy.getUsername() ).addPassword( proxy.getPassword() );
+            authBuilder.addUsername(proxy.getUsername()).addPassword(proxy.getPassword());
             proxySelector.add(
-                new org.eclipse.aether.repository.Proxy( proxy.getProtocol(), proxy.getHost(), proxy.getPort(),
-                                                         authBuilder.build() ), proxy.getNonProxyHosts() );
+                    new org.eclipse.aether.repository.Proxy(
+                            proxy.getProtocol(), proxy.getHost(), proxy.getPort(), authBuilder.build()),
+                    proxy.getNonProxyHosts());
         }
-        session.setProxySelector( proxySelector );
+        session.setProxySelector(proxySelector);
 
         DefaultAuthenticationSelector authSelector = new DefaultAuthenticationSelector();
-        for ( Server server : decrypted.getServers() )
-        {
+        for (Server server : decrypted.getServers()) {
             AuthenticationBuilder authBuilder = new AuthenticationBuilder();
-            authBuilder.addUsername( server.getUsername() ).addPassword( server.getPassword() );
-            authBuilder.addPrivateKey( server.getPrivateKey(), server.getPassphrase() );
-            authSelector.add( server.getId(), authBuilder.build() );
+            authBuilder.addUsername(server.getUsername()).addPassword(server.getPassword());
+            authBuilder.addPrivateKey(server.getPrivateKey(), server.getPassphrase());
+            authSelector.add(server.getId(), authBuilder.build());
 
-            if ( server.getConfiguration() != null )
-            {
-                Xpp3Dom dom = (Xpp3Dom) server.getConfiguration();
-                for ( int i = dom.getChildCount() - 1; i >= 0; i-- )
-                {
-                    Xpp3Dom child = dom.getChild( i );
-                    if ( "wagonProvider".equals( child.getName() ) )
-                    {
-                        dom.removeChild( i );
+            if (server.getConfiguration() != null) {
+                XmlNode dom = server.getDelegate().getConfiguration();
+                List<XmlNode> children = dom.getChildren().stream()
+                        .filter(c -> !"wagonProvider".equals(c.getName()))
+                        .collect(Collectors.toList());
+                dom = new XmlNodeImpl(dom.getName(), null, null, children, null);
+                PlexusConfiguration config = XmlPlexusConfiguration.toPlexusConfiguration(dom);
+                configProps.put("aether.connector.wagon.config." + server.getId(), config);
+
+                // Translate to proper resolver configuration properties as well (as Plexus XML above is Wagon specific
+                // only) but support only configuration/httpConfiguration/all, see
+                // https://maven.apache.org/guides/mini/guide-http-settings.html
+                Map<String, String> headers = null;
+                Integer connectTimeout = null;
+                Integer requestTimeout = null;
+
+                PlexusConfiguration httpHeaders = config.getChild("httpHeaders", false);
+                if (httpHeaders != null) {
+                    PlexusConfiguration[] properties = httpHeaders.getChildren("property");
+                    if (properties != null && properties.length > 0) {
+                        headers = new HashMap<>();
+                        for (PlexusConfiguration property : properties) {
+                            headers.put(
+                                    property.getChild("name").getValue(),
+                                    property.getChild("value").getValue());
+                        }
                     }
                 }
 
-                XmlPlexusConfiguration config = new XmlPlexusConfiguration( dom );
-                configProps.put( "aether.connector.wagon.config." + server.getId(), config );
+                PlexusConfiguration connectTimeoutXml = config.getChild("connectTimeout", false);
+                if (connectTimeoutXml != null) {
+                    connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
+                } else {
+                    // fallback configuration name
+                    PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
+                    if (httpConfiguration != null) {
+                        PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
+                        if (httpConfigurationAll != null) {
+                            connectTimeoutXml = httpConfigurationAll.getChild("connectionTimeout", false);
+                            if (connectTimeoutXml != null) {
+                                connectTimeout = Integer.parseInt(connectTimeoutXml.getValue());
+                                logger.warn("Settings for server {} uses legacy format", server.getId());
+                            }
+                        }
+                    }
+                }
+
+                PlexusConfiguration requestTimeoutXml = config.getChild("requestTimeout", false);
+                if (requestTimeoutXml != null) {
+                    requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
+                } else {
+                    // fallback configuration name
+                    PlexusConfiguration httpConfiguration = config.getChild("httpConfiguration", false);
+                    if (httpConfiguration != null) {
+                        PlexusConfiguration httpConfigurationAll = httpConfiguration.getChild("all", false);
+                        if (httpConfigurationAll != null) {
+                            requestTimeoutXml = httpConfigurationAll.getChild("readTimeout", false);
+                            if (requestTimeoutXml != null) {
+                                requestTimeout = Integer.parseInt(requestTimeoutXml.getValue());
+                                logger.warn("Settings for server {} uses legacy format", server.getId());
+                            }
+                        }
+                    }
+                }
+
+                // org.eclipse.aether.ConfigurationProperties.HTTP_HEADERS => Map<String, String>
+                if (headers != null) {
+                    configProps.put(ConfigurationProperties.HTTP_HEADERS + "." + server.getId(), headers);
+                }
+                // org.eclipse.aether.ConfigurationProperties.CONNECT_TIMEOUT => int
+                if (connectTimeout != null) {
+                    configProps.put(ConfigurationProperties.CONNECT_TIMEOUT + "." + server.getId(), connectTimeout);
+                }
+                // org.eclipse.aether.ConfigurationProperties.REQUEST_TIMEOUT => int
+                if (requestTimeout != null) {
+                    configProps.put(ConfigurationProperties.REQUEST_TIMEOUT + "." + server.getId(), requestTimeout);
+                }
             }
 
-            configProps.put( "aether.connector.perms.fileMode." + server.getId(), server.getFilePermissions() );
-            configProps.put( "aether.connector.perms.dirMode." + server.getId(), server.getDirectoryPermissions() );
+            configProps.put("aether.connector.perms.fileMode." + server.getId(), server.getFilePermissions());
+            configProps.put("aether.connector.perms.dirMode." + server.getId(), server.getDirectoryPermissions());
         }
-        session.setAuthenticationSelector( authSelector );
+        session.setAuthenticationSelector(authSelector);
 
-        Object transport = configProps.getOrDefault( MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT );
-        if ( MAVEN_RESOLVER_TRANSPORT_DEFAULT.equals( transport ) )
-        {
-            // The "default" mode (user did not set anything) needs to tweak resolver default priorities
-            // that are coded like this (default values):
-            //
-            // org.eclipse.aether.transport.http.HttpTransporterFactory.priority = 5.0f;
-            // org.eclipse.aether.transport.wagon.WagonTransporterFactory.priority = -1.0f;
-            //
-            // Hence, as both are present on classpath, HttpTransport would be selected, while
-            // we want to retain "default" behaviour of Maven and use Wagon. To achieve that,
-            // we set explicitly priority of WagonTransport to 6.0f (just above of HttpTransport),
-            // to make it "win" over HttpTransport. We do this to NOT interfere with possibly
-            // installed OTHER transports and their priorities, as unlike "wagon" or "native"
-            // transport setting, that sets priorities to MAX, hence prevents any 3rd party
-            // transport to get into play (inhibits them), in default mode we want to retain
-            // old behavior. Also, this "default" mode is different from "auto" setting,
-            // as it does not alter resolver priorities at all, and uses priorities as is.
-
-            configProps.put( WAGON_TRANSPORTER_PRIORITY_KEY, "6" );
-        }
-        else if ( MAVEN_RESOLVER_TRANSPORT_NATIVE.equals( transport ) )
-        {
-            // Make sure (whatever extra priority is set) that resolver native is selected
-            configProps.put( NATIVE_FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY );
-            configProps.put( NATIVE_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY );
-        }
-        else if ( MAVEN_RESOLVER_TRANSPORT_WAGON.equals( transport ) )
-        {
+        Object transport = configProps.getOrDefault(MAVEN_RESOLVER_TRANSPORT_KEY, MAVEN_RESOLVER_TRANSPORT_DEFAULT);
+        if (MAVEN_RESOLVER_TRANSPORT_DEFAULT.equals(transport)) {
+            // The "default" mode (user did not set anything) from now on defaults to AUTO
+        } else if (MAVEN_RESOLVER_TRANSPORT_JDK.equals(transport)) {
+            // Make sure (whatever extra priority is set) that resolver file/jdk is selected
+            configProps.put(FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
+            configProps.put(JDK_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
+        } else if (MAVEN_RESOLVER_TRANSPORT_APACHE.equals(transport)
+                || MAVEN_RESOLVER_TRANSPORT_NATIVE.equals(transport)) {
+            if (MAVEN_RESOLVER_TRANSPORT_NATIVE.equals(transport)) {
+                logger.warn(
+                        "Transport name '{}' is DEPRECATED/RENAMED, use '{}' instead",
+                        MAVEN_RESOLVER_TRANSPORT_NATIVE,
+                        MAVEN_RESOLVER_TRANSPORT_APACHE);
+            }
+            // Make sure (whatever extra priority is set) that resolver file/apache is selected
+            configProps.put(FILE_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
+            configProps.put(APACHE_HTTP_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
+        } else if (MAVEN_RESOLVER_TRANSPORT_WAGON.equals(transport)) {
             // Make sure (whatever extra priority is set) that wagon is selected
-            configProps.put( WAGON_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY );
-        }
-        else if ( !MAVEN_RESOLVER_TRANSPORT_AUTO.equals( transport ) )
-        {
-            throw new IllegalArgumentException( "Unknown resolver transport '" + transport
+            configProps.put(WAGON_TRANSPORTER_PRIORITY_KEY, RESOLVER_MAX_PRIORITY);
+        } else if (!MAVEN_RESOLVER_TRANSPORT_AUTO.equals(transport)) {
+            throw new IllegalArgumentException("Unknown resolver transport '" + transport
                     + "'. Supported transports are: " + MAVEN_RESOLVER_TRANSPORT_WAGON + ", "
-                    + MAVEN_RESOLVER_TRANSPORT_NATIVE + ", " + MAVEN_RESOLVER_TRANSPORT_AUTO );
+                    + MAVEN_RESOLVER_TRANSPORT_APACHE + ", " + MAVEN_RESOLVER_TRANSPORT_JDK + ", "
+                    + MAVEN_RESOLVER_TRANSPORT_AUTO);
         }
 
-        session.setTransferListener( request.getTransferListener() );
+        session.setUserProperties(request.getUserProperties());
+        session.setSystemProperties(request.getSystemProperties());
+        session.setConfigProperties(configProps);
 
-        session.setRepositoryListener( eventSpyDispatcher.chainListener( new LoggingRepositoryListener( logger ) ) );
+        session.setTransferListener(request.getTransferListener());
 
-        session.setUserProperties( request.getUserProperties() );
-        session.setSystemProperties( request.getSystemProperties() );
-        session.setConfigProperties( configProps );
+        RepositoryListener repositoryListener = eventSpyDispatcher.chainListener(new LoggingRepositoryListener(logger));
 
-        mavenRepositorySystem.injectMirror( request.getRemoteRepositories(), request.getMirrors() );
-        mavenRepositorySystem.injectProxy( session, request.getRemoteRepositories() );
-        mavenRepositorySystem.injectAuthentication( session, request.getRemoteRepositories() );
-
-        mavenRepositorySystem.injectMirror( request.getPluginArtifactRepositories(), request.getMirrors() );
-        mavenRepositorySystem.injectProxy( session, request.getPluginArtifactRepositories() );
-        mavenRepositorySystem.injectAuthentication( session, request.getPluginArtifactRepositories() );
-
-        if ( Features.buildConsumer( request.getUserProperties() ).isActive() )
-        {
-            session.setFileTransformerManager( a -> getTransformersForArtifact( a, session.getData() ) );
+        boolean recordReverseTree = configProps.containsKey(MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE)
+                && Boolean.parseBoolean((String) configProps.get(MAVEN_REPO_LOCAL_RECORD_REVERSE_TREE));
+        if (recordReverseTree) {
+            repositoryListener = new ChainedRepositoryListener(repositoryListener, new ReverseTreeRepositoryListener());
         }
+        session.setRepositoryListener(repositoryListener);
+
+        injectMirror(request.getRemoteRepositories(), request.getMirrors());
+        injectProxy(proxySelector, request.getRemoteRepositories());
+        injectAuthentication(authSelector, request.getRemoteRepositories());
+
+        injectMirror(request.getPluginArtifactRepositories(), request.getMirrors());
+        injectProxy(proxySelector, request.getPluginArtifactRepositories());
+        injectAuthentication(authSelector, request.getPluginArtifactRepositories());
+
+        ArrayList<File> paths = new ArrayList<>();
+        paths.add(new File(request.getLocalRepository().getBasedir()));
+        String localRepoTail = (String) configProps.get(MAVEN_REPO_LOCAL_TAIL);
+        if (localRepoTail != null) {
+            Arrays.stream(localRepoTail.split(","))
+                    .filter(p -> p != null && !p.trim().isEmpty())
+                    .map(File::new)
+                    .forEach(paths::add);
+        }
+        session.withLocalRepositoryBaseDirectories(paths);
 
         return session;
     }
 
-    private String getUserAgent()
-    {
+    private Map<?, ?> getPropertiesFromRequestedProfiles(MavenExecutionRequest request) {
+        HashSet<String> activeProfileId =
+                new HashSet<>(request.getProfileActivation().getRequiredActiveProfileIds());
+        activeProfileId.addAll(request.getProfileActivation().getOptionalActiveProfileIds());
+
+        return request.getProfiles().stream()
+                .filter(profile -> activeProfileId.contains(profile.getId()))
+                .map(ModelBase::getProperties)
+                .flatMap(properties -> properties.entrySet().stream())
+                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k1, k2) -> k2));
+    }
+
+    private String getUserAgent() {
         String version = runtimeInformation.getMavenVersion();
         version = version.isEmpty() ? version : "/" + version;
-        return "Apache-Maven" + version + " (Java " + System.getProperty( "java.version" ) + "; "
-            + System.getProperty( "os.name" ) + " " + System.getProperty( "os.version" ) + ")";
+        return "Apache-Maven" + version + " (Java " + System.getProperty("java.version") + "; "
+                + System.getProperty("os.name") + " " + System.getProperty("os.version") + ")";
     }
 
-    private Collection<FileTransformer> getTransformersForArtifact( final Artifact artifact,
-                                                                    final SessionData sessionData )
-    {
-        TransformerContext context = (TransformerContext) sessionData.get( TransformerContext.KEY );
-        Collection<FileTransformer> transformers = new ArrayList<>();
-
-        // In case of install:install-file there's no transformer context, as the goal is unrelated to the lifecycle.
-        if ( "pom".equals( artifact.getExtension() ) && context != null )
-        {
-            transformers.add( new FileTransformer()
-            {
-                @Override
-                public InputStream transformData( File pomFile )
-                    throws IOException, TransformException
-                {
-                    try
-                    {
-                        return new ConsumerModelSourceTransformer().transform( pomFile.toPath(), context );
-                    }
-                    catch ( XmlPullParserException e )
-                    {
-                        throw new TransformException( e );
-                    }
-                }
-
-                @Override
-                public Artifact transformArtifact( Artifact artifact )
-                {
-                    return artifact;
-                }
-            } );
+    private void injectMirror(List<ArtifactRepository> repositories, List<Mirror> mirrors) {
+        if (repositories != null && mirrors != null) {
+            for (ArtifactRepository repository : repositories) {
+                Mirror mirror = MavenRepositorySystem.getMirror(repository, mirrors);
+                injectMirror(repository, mirror);
+            }
         }
-        return Collections.unmodifiableCollection( transformers );
     }
 
+    private void injectMirror(ArtifactRepository repository, Mirror mirror) {
+        if (mirror != null) {
+            ArtifactRepository original = MavenRepositorySystem.createArtifactRepository(
+                    repository.getId(),
+                    repository.getUrl(),
+                    repository.getLayout(),
+                    repository.getSnapshots(),
+                    repository.getReleases());
+
+            repository.setMirroredRepositories(Collections.singletonList(original));
+
+            repository.setId(mirror.getId());
+            repository.setUrl(mirror.getUrl());
+
+            if (mirror.getLayout() != null && !mirror.getLayout().isEmpty()) {
+                repository.setLayout(original.getLayout());
+            }
+
+            repository.setBlocked(mirror.isBlocked());
+        }
+    }
+
+    private void injectProxy(ProxySelector selector, List<ArtifactRepository> repositories) {
+        if (repositories != null && selector != null) {
+            for (ArtifactRepository repository : repositories) {
+                repository.setProxy(getProxy(selector, repository));
+            }
+        }
+    }
+
+    private org.apache.maven.repository.Proxy getProxy(ProxySelector selector, ArtifactRepository repository) {
+        if (selector != null) {
+            RemoteRepository repo = RepositoryUtils.toRepo(repository);
+            org.eclipse.aether.repository.Proxy proxy = selector.getProxy(repo);
+            if (proxy != null) {
+                org.apache.maven.repository.Proxy p = new org.apache.maven.repository.Proxy();
+                p.setHost(proxy.getHost());
+                p.setProtocol(proxy.getType());
+                p.setPort(proxy.getPort());
+                if (proxy.getAuthentication() != null) {
+                    repo = new RemoteRepository.Builder(repo).setProxy(proxy).build();
+                    AuthenticationContext authCtx = AuthenticationContext.forProxy(null, repo);
+                    p.setUserName(authCtx.get(AuthenticationContext.USERNAME));
+                    p.setPassword(authCtx.get(AuthenticationContext.PASSWORD));
+                    p.setNtlmDomain(authCtx.get(AuthenticationContext.NTLM_DOMAIN));
+                    p.setNtlmHost(authCtx.get(AuthenticationContext.NTLM_WORKSTATION));
+                    authCtx.close();
+                }
+                return p;
+            }
+        }
+        return null;
+    }
+
+    public void injectAuthentication(AuthenticationSelector selector, List<ArtifactRepository> repositories) {
+        if (repositories != null && selector != null) {
+            for (ArtifactRepository repository : repositories) {
+                repository.setAuthentication(getAuthentication(selector, repository));
+            }
+        }
+    }
+
+    private Authentication getAuthentication(AuthenticationSelector selector, ArtifactRepository repository) {
+        if (selector != null) {
+            RemoteRepository repo = RepositoryUtils.toRepo(repository);
+            org.eclipse.aether.repository.Authentication auth = selector.getAuthentication(repo);
+            if (auth != null) {
+                repo = new RemoteRepository.Builder(repo)
+                        .setAuthentication(auth)
+                        .build();
+                AuthenticationContext authCtx = AuthenticationContext.forRepository(null, repo);
+                Authentication result = new Authentication(
+                        authCtx.get(AuthenticationContext.USERNAME), authCtx.get(AuthenticationContext.PASSWORD));
+                result.setPrivateKey(authCtx.get(AuthenticationContext.PRIVATE_KEY_PATH));
+                result.setPassphrase(authCtx.get(AuthenticationContext.PRIVATE_KEY_PASSPHRASE));
+                authCtx.close();
+                return result;
+            }
+        }
+        return null;
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/LoggingRepositoryListener.java b/maven-core/src/main/java/org/apache/maven/internal/aether/LoggingRepositoryListener.java
index 340a3b6..fe9c074 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/aether/LoggingRepositoryListener.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/LoggingRepositoryListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.internal.aether;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.internal.aether;
 
 import java.io.FileNotFoundException;
 
@@ -27,115 +26,82 @@
 import org.slf4j.Logger;
 
 /**
- * @author Benjamin Bentmann
  */
-class LoggingRepositoryListener
-    extends AbstractRepositoryListener
-{
+class LoggingRepositoryListener extends AbstractRepositoryListener {
 
     private final Logger logger;
 
-    LoggingRepositoryListener( Logger logger )
-    {
+    LoggingRepositoryListener(Logger logger) {
         this.logger = logger;
     }
 
     @Override
-    public void artifactInstalling( RepositoryEvent event )
-    {
-        logger.info( "Installing " + event.getArtifact().getFile() + " to " + event.getFile() );
+    public void artifactInstalling(RepositoryEvent event) {
+        logger.info("Installing {} to {}", event.getArtifact().getFile(), event.getFile());
     }
 
     @Override
-    public void metadataInstalling( RepositoryEvent event )
-    {
-        logger.debug( "Installing " + event.getMetadata() + " to " + event.getFile() );
+    public void metadataInstalling(RepositoryEvent event) {
+        logger.debug("Installing {} to {}", event.getMetadata(), event.getFile());
     }
 
     @Override
-    public void metadataResolved( RepositoryEvent event )
-    {
+    public void metadataResolved(RepositoryEvent event) {
         Exception e = event.getException();
-        if ( e != null )
-        {
-            if ( e instanceof MetadataNotFoundException )
-            {
-                logger.debug( e.getMessage() );
-            }
-            else if ( logger.isDebugEnabled() )
-            {
-                logger.warn( e.getMessage(), e );
-            }
-            else
-            {
-                logger.warn( e.getMessage() );
+        if (e != null) {
+            if (e instanceof MetadataNotFoundException) {
+                logger.debug(e.getMessage());
+            } else if (logger.isDebugEnabled()) {
+                logger.warn(e.getMessage(), e);
+            } else {
+                logger.warn(e.getMessage());
             }
         }
     }
 
     @Override
-    public void metadataInvalid( RepositoryEvent event )
-    {
+    public void metadataInvalid(RepositoryEvent event) {
         Exception exception = event.getException();
 
-        StringBuilder buffer = new StringBuilder( 256 );
-        buffer.append( "The metadata " );
-        if ( event.getMetadata().getFile() != null )
-        {
-            buffer.append( event.getMetadata().getFile() );
-        }
-        else
-        {
-            buffer.append( event.getMetadata() );
+        Object metadata;
+        if (event.getMetadata().getFile() != null) {
+            metadata = event.getMetadata().getFile();
+        } else {
+            metadata = event.getMetadata();
         }
 
-        if ( exception instanceof FileNotFoundException )
-        {
-            buffer.append( " is inaccessible" );
-        }
-        else
-        {
-            buffer.append( " is invalid" );
+        String errorType = " is invalid";
+        if (exception instanceof FileNotFoundException) {
+            errorType = " is inaccessible";
         }
 
-        if ( exception != null )
-        {
-            buffer.append( ": " );
-            buffer.append( exception.getMessage() );
+        String msg = "";
+        if (exception != null) {
+            msg = ": " + exception.getMessage();
         }
 
-        if ( logger.isDebugEnabled() )
-        {
-            logger.warn( buffer.toString(), exception );
-        }
-        else
-        {
-            logger.warn( buffer.toString() );
+        if (logger.isDebugEnabled()) {
+            logger.warn("The metadata {} {}{}", metadata, errorType, msg, exception);
+        } else {
+            logger.warn("The metadata {} {}{}", metadata, errorType, msg);
         }
     }
 
     @Override
-    public void artifactDescriptorInvalid( RepositoryEvent event )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-        buffer.append( "The POM for " );
-        buffer.append( event.getArtifact() );
-        buffer.append( " is invalid, transitive dependencies (if any) will not be available" );
-
-        if ( logger.isDebugEnabled() )
-        {
-            logger.warn( buffer + ": " + event.getException().getMessage() );
-        }
-        else
-        {
-            logger.warn( buffer + ", enable verbose output (-X) for more details" );
+    public void artifactDescriptorInvalid(RepositoryEvent event) {
+        // The exception stack trace is not really interesting here
+        // but the message itself may be quite details and span multiple
+        // lines with errors in it, so only display it at debug level.
+        String msg = "The POM for {} is invalid, transitive dependencies (if any) will not be available: {}";
+        if (logger.isDebugEnabled()) {
+            logger.warn(msg, event.getArtifact(), event.getException().getMessage());
+        } else {
+            logger.warn(msg, event.getArtifact(), "enable verbose output (-X) for more details");
         }
     }
 
     @Override
-    public void artifactDescriptorMissing( RepositoryEvent event )
-    {
-        logger.warn( "The POM for " + event.getArtifact() + " is missing, no dependency information available" );
+    public void artifactDescriptorMissing(RepositoryEvent event) {
+        logger.warn("The POM for {} is missing, no dependency information available", event.getArtifact());
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/MavenChainedWorkspaceReader.java b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenChainedWorkspaceReader.java
index 4bc16a9..f23a3db 100644
--- a/maven-core/src/main/java/org/apache/maven/internal/aether/MavenChainedWorkspaceReader.java
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenChainedWorkspaceReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.internal.aether;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,73 +16,125 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.internal.aether;
 
 import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.repository.internal.MavenWorkspaceReader;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.repository.WorkspaceReader;
 import org.eclipse.aether.repository.WorkspaceRepository;
-import org.eclipse.aether.util.repository.ChainedWorkspaceReader;
+
+import static java.util.Objects.requireNonNull;
 
 /**
  * A maven workspace reader that delegates to a chain of other readers, effectively aggregating their contents.
  */
-public final class MavenChainedWorkspaceReader
-    implements MavenWorkspaceReader
-{
+public class MavenChainedWorkspaceReader implements MavenWorkspaceReader {
 
-    private ChainedWorkspaceReader delegate;
-
-    private WorkspaceReader[] readers;
+    protected List<WorkspaceReader> readers;
+    protected WorkspaceRepository repository;
 
     /**
      * Creates a new workspace reader by chaining the specified readers.
-     * 
+     *
      * @param readers The readers to chain must not be {@code null}.
      */
-    private MavenChainedWorkspaceReader( WorkspaceReader... readers )
-    {
-        this.delegate = new ChainedWorkspaceReader( readers );
-        this.readers = readers;
+    public MavenChainedWorkspaceReader(WorkspaceReader... readers) {
+        setReaders(Arrays.asList(readers));
     }
 
     @Override
-    public Model findModel( Artifact artifact )
-    {
-        for ( WorkspaceReader workspaceReader : readers )
-        {
-            if ( workspaceReader instanceof MavenWorkspaceReader )
-            {
-                Model model = ( (MavenWorkspaceReader) workspaceReader ).findModel( artifact );
-                if ( model != null )
-                {
-                    return model;
+    public WorkspaceRepository getRepository() {
+        return this.repository;
+    }
+
+    @Override
+    public Model findModel(Artifact artifact) {
+        requireNonNull(artifact, "artifact cannot be null");
+        Model model = null;
+
+        for (WorkspaceReader workspaceReader : readers) {
+            if (workspaceReader instanceof MavenWorkspaceReader) {
+                model = ((MavenWorkspaceReader) workspaceReader).findModel(artifact);
+                if (model != null) {
+                    break;
                 }
             }
         }
-        return null;
+
+        return model;
     }
 
     @Override
-    public WorkspaceRepository getRepository()
-    {
-        return delegate.getRepository();
+    public File findArtifact(Artifact artifact) {
+        requireNonNull(artifact, "artifact cannot be null");
+        File file = null;
+
+        for (WorkspaceReader reader : readers) {
+            file = reader.findArtifact(artifact);
+            if (file != null) {
+                break;
+            }
+        }
+
+        return file;
     }
 
     @Override
-    public File findArtifact( Artifact artifact )
-    {
-        return delegate.findArtifact( artifact );
+    public List<String> findVersions(Artifact artifact) {
+        requireNonNull(artifact, "artifact cannot be null");
+        Collection<String> versions = new LinkedHashSet<>();
+
+        for (WorkspaceReader reader : readers) {
+            versions.addAll(reader.findVersions(artifact));
+        }
+
+        return Collections.unmodifiableList(new ArrayList<>(versions));
     }
 
-    @Override
-    public List<String> findVersions( Artifact artifact )
-    {
-        return delegate.findVersions( artifact );
+    public void setReaders(Collection<WorkspaceReader> readers) {
+        this.readers = Collections.unmodifiableList(new ArrayList<>(readers));
+        Key key = new Key(this.readers);
+        this.repository = new WorkspaceRepository(key.getContentType(), key);
+    }
+
+    public List<WorkspaceReader> getReaders() {
+        return readers;
+    }
+
+    private static class Key {
+        private final List<Object> keys;
+        private final String type;
+
+        Key(Collection<WorkspaceReader> readers) {
+            keys = readers.stream().map(r -> r.getRepository().getKey()).collect(Collectors.toList());
+            type = readers.stream().map(r -> r.getRepository().getContentType()).collect(Collectors.joining("+"));
+        }
+
+        public String getContentType() {
+            return type;
+        }
+
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            } else {
+                return obj != null && this.getClass().equals(obj.getClass()) && this.keys.equals(((Key) obj).keys);
+            }
+        }
+
+        public int hashCode() {
+            return this.keys.hashCode();
+        }
     }
 
     /**
@@ -93,14 +143,11 @@
      * @return if the collection contains only one item returns the single item, otherwise creates a new
      *         {@link MavenChainedWorkspaceReader} chaining all readers in the order of the given collection.
      */
-    public static WorkspaceReader of( Collection<WorkspaceReader> workspaceReaderCollection )
-    {
-        WorkspaceReader[] readers = workspaceReaderCollection.toArray( new WorkspaceReader[0] );
-        if ( readers.length == 1 )
-        {
+    public static WorkspaceReader of(Collection<WorkspaceReader> workspaceReaderCollection) {
+        WorkspaceReader[] readers = workspaceReaderCollection.toArray(new WorkspaceReader[0]);
+        if (readers.length == 1) {
             return readers[0];
         }
-        return new MavenChainedWorkspaceReader( readers );
+        return new MavenChainedWorkspaceReader(readers);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/MavenDeployer.java b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenDeployer.java
new file mode 100644
index 0000000..93aa844
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenDeployer.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.aether;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.internal.transformation.ConsumerPomArtifactTransformer;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.deployment.DeployRequest;
+import org.eclipse.aether.deployment.DeployResult;
+import org.eclipse.aether.deployment.DeploymentException;
+import org.eclipse.aether.impl.Deployer;
+import org.eclipse.aether.internal.impl.DefaultDeployer;
+import org.eclipse.sisu.Priority;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Maven specific deployer.
+ */
+@Singleton
+@Named
+@Priority(100)
+final class MavenDeployer implements Deployer {
+
+    private final DefaultDeployer deployer;
+
+    private final ConsumerPomArtifactTransformer consumerPomArtifactTransformer;
+
+    @Inject
+    MavenDeployer(DefaultDeployer deployer, ConsumerPomArtifactTransformer consumerPomArtifactTransformer) {
+        this.deployer = requireNonNull(deployer);
+        this.consumerPomArtifactTransformer = requireNonNull(consumerPomArtifactTransformer);
+    }
+
+    @Override
+    public DeployResult deploy(RepositorySystemSession session, DeployRequest request) throws DeploymentException {
+        return deployer.deploy(session, consumerPomArtifactTransformer.remapDeployArtifacts(session, request));
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/MavenInstaller.java b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenInstaller.java
new file mode 100644
index 0000000..d7f2f95
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/MavenInstaller.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.aether;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.internal.transformation.ConsumerPomArtifactTransformer;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.impl.Installer;
+import org.eclipse.aether.installation.InstallRequest;
+import org.eclipse.aether.installation.InstallResult;
+import org.eclipse.aether.installation.InstallationException;
+import org.eclipse.aether.internal.impl.DefaultInstaller;
+import org.eclipse.sisu.Priority;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Maven specific installer.
+ */
+@Singleton
+@Named
+@Priority(100)
+final class MavenInstaller implements Installer {
+
+    private final DefaultInstaller installer;
+
+    private final ConsumerPomArtifactTransformer consumerPomArtifactTransformer;
+
+    @Inject
+    MavenInstaller(DefaultInstaller installer, ConsumerPomArtifactTransformer consumerPomArtifactTransformer) {
+        this.installer = requireNonNull(installer);
+        this.consumerPomArtifactTransformer = requireNonNull(consumerPomArtifactTransformer);
+    }
+
+    @Override
+    public InstallResult install(RepositorySystemSession session, InstallRequest request) throws InstallationException {
+        return installer.install(session, consumerPomArtifactTransformer.remapInstallArtifacts(session, request));
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/ResolverLifecycle.java b/maven-core/src/main/java/org/apache/maven/internal/aether/ResolverLifecycle.java
new file mode 100644
index 0000000..11b6da6
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/ResolverLifecycle.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.aether;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.sisu.EagerSingleton;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Maven internal component that bridges container "shut down" to {@link RepositorySystem#shutdown()}.
+ *
+ * @since 3.9.0
+ */
+@Named
+@EagerSingleton
+final class ResolverLifecycle {
+    private final Provider<RepositorySystem> repositorySystemProvider;
+
+    @Inject
+    ResolverLifecycle(Provider<RepositorySystem> repositorySystemProvider) {
+        this.repositorySystemProvider = requireNonNull(repositorySystemProvider);
+    }
+
+    @PreDestroy
+    public void shutdown() {
+        repositorySystemProvider.get().shutdown();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java b/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java
new file mode 100644
index 0000000..14f7378
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListener.java
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.aether;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Objects;
+
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.Plugin;
+import org.eclipse.aether.AbstractRepositoryListener;
+import org.eclipse.aether.RepositoryEvent;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.collection.CollectStepData;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactDescriptorRequest;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.util.artifact.ArtifactIdUtils;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A class building reverse tree using {@link CollectStepData} trace data provided in {@link RepositoryEvent}
+ * events fired during collection.
+ *
+ * @since 3.9.0
+ */
+class ReverseTreeRepositoryListener extends AbstractRepositoryListener {
+    @Override
+    public void artifactResolved(RepositoryEvent event) {
+        requireNonNull(event, "event cannot be null");
+
+        if (!isLocalRepositoryArtifactOrMissing(event.getSession(), event.getArtifact())) {
+            return;
+        }
+
+        RequestTrace trace = event.getTrace();
+
+        CollectStepData collectStepTrace = null;
+        ArtifactRequest artifactRequest = null;
+        ArtifactDescriptorRequest artifactDescriptorRequest = null;
+        Plugin plugin = null;
+
+        while (trace != null) {
+            Object data = trace.getData();
+            if (data instanceof CollectStepData) {
+                collectStepTrace = (CollectStepData) data;
+            } else if (data instanceof ArtifactDescriptorRequest) {
+                artifactDescriptorRequest = (ArtifactDescriptorRequest) data;
+            } else if (data instanceof ArtifactRequest) {
+                artifactRequest = (ArtifactRequest) data;
+            } else if (data instanceof Plugin) {
+                plugin = (Plugin) data;
+            }
+            trace = trace.getParent();
+        }
+
+        Path trackingDir;
+        boolean missing = event.getFile() == null;
+        if (missing) {
+            // missing artifact - let's track the path anyway
+            File dir = event.getSession().getLocalRepository().getBasedir();
+            dir = new File(
+                    dir, event.getSession().getLocalRepositoryManager().getPathForLocalArtifact(event.getArtifact()));
+            trackingDir = dir.getParentFile().toPath().resolve(".tracking");
+        } else {
+            trackingDir = event.getFile().getParentFile().toPath().resolve(".tracking");
+        }
+
+        String baseName;
+        String ext = missing ? ".miss" : ".dep";
+        Path trackingFile = null;
+
+        String indent = "";
+        ArrayList<String> trackingData = new ArrayList<>();
+
+        if (collectStepTrace == null && plugin != null) {
+            ext = ".plugin";
+            baseName = plugin.getGroupId() + "_" + plugin.getArtifactId() + "_" + plugin.getVersion();
+            trackingFile = trackingDir.resolve(baseName + ext);
+            if (Files.exists(trackingFile)) {
+                return;
+            }
+
+            if (event.getArtifact() != null) {
+                trackingData.add(indent + event.getArtifact());
+                indent += "  ";
+            }
+            trackingData.add(indent + plugin.getGroupId() + ":" + plugin.getArtifactId() + ":" + plugin.getVersion());
+            indent += "  ";
+
+            InputLocation location = plugin.getLocation("");
+            if (location != null && location.getSource() != null) {
+                trackingData.add(indent + location.getSource().getModelId() + " (implicit)");
+                indent += "  ";
+            }
+        } else if (collectStepTrace != null) {
+            if (collectStepTrace.getPath().get(0).getArtifact() == null) {
+                return;
+            }
+            baseName = ArtifactIdUtils.toId(collectStepTrace.getPath().get(0).getArtifact())
+                    .replace(":", "_");
+            trackingFile = trackingDir.resolve(baseName + ext);
+            if (Files.exists(trackingFile)) {
+                return;
+            }
+
+            Artifact resolvedArtifact = event.getArtifact();
+            Artifact nodeArtifact = collectStepTrace.getNode().getArtifact();
+
+            if (isInScope(resolvedArtifact, nodeArtifact) || "pom".equals(resolvedArtifact.getExtension())) {
+                Dependency node = collectStepTrace.getNode();
+                trackingData.add(resolvedArtifact.toString());
+                indent += "  ";
+                trackingData.add(indent + node + " (" + collectStepTrace.getContext() + ")");
+                ListIterator<DependencyNode> iter = collectStepTrace
+                        .getPath()
+                        .listIterator(collectStepTrace.getPath().size());
+                while (iter.hasPrevious()) {
+                    DependencyNode curr = iter.previous();
+                    indent += "  ";
+                    trackingData.add(indent + curr + " (" + collectStepTrace.getContext() + ")");
+                }
+            }
+        }
+
+        if (trackingFile == null) {
+            return;
+        }
+        try {
+            Files.createDirectories(trackingDir);
+
+            trackingData.add("");
+            if (!missing) {
+                if (event.getRepository() != null) {
+                    trackingData.add("Repository: " + event.getRepository());
+                }
+            } else {
+                List<RemoteRepository> repositories = new ArrayList<>();
+                if (artifactRequest != null && artifactRequest.getRepositories() != null) {
+                    repositories.addAll(artifactRequest.getRepositories());
+                } else if (artifactDescriptorRequest != null && artifactDescriptorRequest.getRepositories() != null) {
+                    repositories.addAll(artifactDescriptorRequest.getRepositories());
+                }
+                if (!repositories.isEmpty()) {
+                    trackingData.add("Configured repositories:");
+                    for (RemoteRepository r : repositories) {
+                        trackingData.add(" - " + r.getId() + " : " + r.getUrl());
+                    }
+                } else {
+                    trackingData.add("No repositories configured");
+                }
+            }
+
+            Files.write(trackingFile, trackingData, StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    /**
+     * Returns {@code true} if passed in artifact is originating from local repository. In other words, we want
+     * to process and store tracking information ONLY into local repository, not to any other place. This method
+     * filters out currently built artifacts, as events are fired for them as well, but their resolved artifact
+     * file would point to checked out source-tree, not the local repository.
+     * <p>
+     * Visible for testing.
+     */
+    static boolean isLocalRepositoryArtifactOrMissing(RepositorySystemSession session, Artifact artifact) {
+        return artifact.getFile() == null
+                || artifact.getFile()
+                        .getPath()
+                        .startsWith(session.getLocalRepository().getBasedir().getPath());
+    }
+
+    /**
+     * Unravels trace tree (going upwards from current node), looking for {@link CollectStepData} trace data.
+     * This method may return {@code null} if no collect step data found in passed trace data or it's parents.
+     * <p>
+     * Visible for testing.
+     */
+    static CollectStepData lookupCollectStepData(RequestTrace trace) {
+        CollectStepData collectStepTrace = null;
+        while (trace != null) {
+            if (trace.getData() instanceof CollectStepData) {
+                collectStepTrace = (CollectStepData) trace.getData();
+                break;
+            }
+            trace = trace.getParent();
+        }
+        return collectStepTrace;
+    }
+
+    /**
+     * The event "artifact resolved" if fired WHENEVER an artifact is resolved, BUT it happens also when an artifact
+     * descriptor (model, the POM) is being built, and parent (and parent of parent...) is being asked for. Hence, this
+     * method "filters" out in WHICH artifact are we interested in, but it intentionally neglects extension as
+     * ArtifactDescriptorReader modifies extension to "pom" during collect. So all we have to rely on is GAV only.
+     */
+    static boolean isInScope(Artifact artifact, Artifact nodeArtifact) {
+        return Objects.equals(artifact.getGroupId(), nodeArtifact.getGroupId())
+                && Objects.equals(artifact.getArtifactId(), nodeArtifact.getArtifactId())
+                && Objects.equals(artifact.getVersion(), nodeArtifact.getVersion());
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java
new file mode 100644
index 0000000..c090218
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/aether/TypeRegistryAdapter.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.aether;
+
+import org.apache.maven.api.Type;
+import org.apache.maven.api.services.TypeRegistry;
+import org.apache.maven.internal.impl.DefaultType;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+
+import static java.util.Objects.requireNonNull;
+
+public class TypeRegistryAdapter implements ArtifactTypeRegistry {
+    private final TypeRegistry typeRegistry;
+
+    public TypeRegistryAdapter(TypeRegistry typeRegistry) {
+        this.typeRegistry = requireNonNull(typeRegistry, "null typeRegistry");
+    }
+
+    @Override
+    public ArtifactType get(String typeId) {
+        Type type = typeRegistry.getType(typeId);
+        if (type instanceof ArtifactType) {
+            return (ArtifactType) type;
+        }
+        if (type != null) {
+            return new DefaultType(
+                    type.getId(), type.getExtension(), type.getClassifier(), type.getDependencyProperties());
+        }
+        return null;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractNode.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractNode.java
new file mode 100644
index 0000000..f3e8987
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractNode.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.Node;
+import org.apache.maven.api.NodeVisitor;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.graph.DependencyNode;
+
+public abstract class AbstractNode implements Node {
+
+    abstract org.eclipse.aether.graph.DependencyNode getDependencyNode();
+
+    @Override
+    public boolean accept(NodeVisitor visitor) {
+        if (visitor.enter(this)) {
+            for (Node child : getChildren()) {
+                if (!child.accept(visitor)) {
+                    break;
+                }
+            }
+        }
+        return visitor.leave(this);
+    }
+
+    @Override
+    public Node filter(Predicate<Node> filter) {
+        List<Node> children =
+                getChildren().stream().filter(filter).map(n -> n.filter(filter)).collect(Collectors.toList());
+        return new WrapperNode(this, Collections.unmodifiableList(children));
+    }
+
+    @Override
+    public String asString() {
+        StringBuilder sb = new StringBuilder();
+
+        DependencyNode node = getDependencyNode();
+        Artifact artifact = node.getArtifact();
+        sb.append(artifact);
+
+        Dependency dependency = node.getDependency();
+        if (dependency != null) {
+            sb.append(":").append(dependency.getScope());
+        }
+
+        return sb.toString();
+    }
+
+    @Override
+    public String toString() {
+        return getDependencyNode().toString();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java
new file mode 100644
index 0000000..62b0bfe
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/AbstractSession.java
@@ -0,0 +1,511 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.WeakHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Listener;
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Version;
+import org.apache.maven.api.VersionRange;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.api.services.ArtifactCoordinateFactory;
+import org.apache.maven.api.services.ArtifactDeployer;
+import org.apache.maven.api.services.ArtifactDeployerException;
+import org.apache.maven.api.services.ArtifactFactory;
+import org.apache.maven.api.services.ArtifactInstaller;
+import org.apache.maven.api.services.ArtifactInstallerException;
+import org.apache.maven.api.services.ArtifactManager;
+import org.apache.maven.api.services.ArtifactResolver;
+import org.apache.maven.api.services.ArtifactResolverException;
+import org.apache.maven.api.services.DependencyCollector;
+import org.apache.maven.api.services.DependencyCollectorException;
+import org.apache.maven.api.services.DependencyCoordinateFactory;
+import org.apache.maven.api.services.LocalRepositoryManager;
+import org.apache.maven.api.services.RepositoryFactory;
+import org.apache.maven.api.services.VersionParser;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.project.MavenProject;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+public abstract class AbstractSession implements InternalSession {
+
+    private final List<Listener> listeners = new CopyOnWriteArrayList<>();
+    private final Map<org.eclipse.aether.graph.DependencyNode, Node> allNodes =
+            Collections.synchronizedMap(new WeakHashMap<>());
+    private final Map<org.eclipse.aether.artifact.Artifact, Artifact> allArtifacts =
+            Collections.synchronizedMap(new WeakHashMap<>());
+    private final Map<org.eclipse.aether.repository.RemoteRepository, RemoteRepository> allRepositories =
+            Collections.synchronizedMap(new WeakHashMap<>());
+    private final Map<String, Project> allProjects = Collections.synchronizedMap(new WeakHashMap<>());
+    private final Map<org.eclipse.aether.graph.Dependency, Dependency> allDependencies =
+            Collections.synchronizedMap(new WeakHashMap<>());
+
+    public RemoteRepository getRemoteRepository(org.eclipse.aether.repository.RemoteRepository repository) {
+        return allRepositories.computeIfAbsent(repository, DefaultRemoteRepository::new);
+    }
+
+    public Node getNode(org.eclipse.aether.graph.DependencyNode node) {
+        return getNode(node, false);
+    }
+
+    public Node getNode(org.eclipse.aether.graph.DependencyNode node, boolean verbose) {
+        return allNodes.computeIfAbsent(node, n -> new DefaultNode(this, n, verbose));
+    }
+
+    @Nonnull
+    public Artifact getArtifact(@Nonnull org.eclipse.aether.artifact.Artifact artifact) {
+        return allArtifacts.computeIfAbsent(artifact, a -> new DefaultArtifact(this, a));
+    }
+
+    @Nonnull
+    public Dependency getDependency(@Nonnull org.eclipse.aether.graph.Dependency dependency) {
+        return allDependencies.computeIfAbsent(dependency, d -> new DefaultDependency(this, d));
+    }
+
+    public List<Project> getProjects(List<MavenProject> projects) {
+        return projects == null ? null : projects.stream().map(this::getProject).collect(Collectors.toList());
+    }
+
+    public Project getProject(MavenProject project) {
+        return allProjects.computeIfAbsent(project.getId(), id -> new DefaultProject(this, project));
+    }
+
+    public List<org.eclipse.aether.repository.RemoteRepository> toRepositories(List<RemoteRepository> repositories) {
+        return repositories == null
+                ? null
+                : repositories.stream().map(this::toRepository).collect(Collectors.toList());
+    }
+
+    public org.eclipse.aether.repository.RemoteRepository toRepository(RemoteRepository repository) {
+        if (repository instanceof DefaultRemoteRepository) {
+            return ((DefaultRemoteRepository) repository).getRepository();
+        } else {
+            // TODO
+            throw new UnsupportedOperationException("Not implemented yet");
+        }
+    }
+
+    public org.eclipse.aether.repository.LocalRepository toRepository(LocalRepository repository) {
+        if (repository instanceof DefaultLocalRepository) {
+            return ((DefaultLocalRepository) repository).getRepository();
+        } else {
+            // TODO
+            throw new UnsupportedOperationException("Not implemented yet");
+        }
+    }
+
+    public List<ArtifactRepository> toArtifactRepositories(List<RemoteRepository> repositories) {
+        return repositories == null
+                ? null
+                : repositories.stream().map(this::toArtifactRepository).collect(Collectors.toList());
+    }
+
+    public abstract ArtifactRepository toArtifactRepository(RemoteRepository repository);
+
+    public List<org.eclipse.aether.graph.Dependency> toDependencies(Collection<DependencyCoordinate> dependencies) {
+        return dependencies == null
+                ? null
+                : dependencies.stream().map(this::toDependency).collect(Collectors.toList());
+    }
+
+    public abstract org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency);
+
+    public List<org.eclipse.aether.artifact.Artifact> toArtifacts(Collection<Artifact> artifacts) {
+        return artifacts == null
+                ? null
+                : artifacts.stream().map(this::toArtifact).collect(Collectors.toList());
+    }
+
+    public org.eclipse.aether.artifact.Artifact toArtifact(Artifact artifact) {
+        File file = getService(ArtifactManager.class)
+                .getPath(artifact)
+                .map(Path::toFile)
+                .orElse(null);
+        if (artifact instanceof DefaultArtifact) {
+            org.eclipse.aether.artifact.Artifact a = ((DefaultArtifact) artifact).getArtifact();
+            if (Objects.equals(file, a.getFile())) {
+                return a;
+            }
+        }
+        return new org.eclipse.aether.artifact.DefaultArtifact(
+                artifact.getGroupId(),
+                artifact.getArtifactId(),
+                artifact.getClassifier(),
+                artifact.getExtension(),
+                artifact.getVersion().toString(),
+                null,
+                file);
+    }
+
+    public org.eclipse.aether.artifact.Artifact toArtifact(ArtifactCoordinate coord) {
+        if (coord instanceof DefaultArtifactCoordinate) {
+            return ((DefaultArtifactCoordinate) coord).getCoordinate();
+        }
+        return new org.eclipse.aether.artifact.DefaultArtifact(
+                coord.getGroupId(),
+                coord.getArtifactId(),
+                coord.getClassifier(),
+                coord.getExtension(),
+                coord.getVersion().toString(),
+                null,
+                (File) null);
+    }
+
+    @Override
+    public void registerListener(@Nonnull Listener listener) {
+        listeners.add(nonNull(listener));
+    }
+
+    @Override
+    public void unregisterListener(@Nonnull Listener listener) {
+        listeners.remove(nonNull(listener));
+    }
+
+    @Nonnull
+    @Override
+    public Collection<Listener> getListeners() {
+        return Collections.unmodifiableCollection(listeners);
+    }
+
+    //
+    // Shortcut implementations
+    //
+
+    /**
+     * Shortcut for <code>getService(RepositoryFactory.class).createLocal(...)</code>
+     *
+     * @see RepositoryFactory#createLocal(Path)
+     */
+    @Override
+    public LocalRepository createLocalRepository(Path path) {
+        return getService(RepositoryFactory.class).createLocal(path);
+    }
+
+    /**
+     * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
+     *
+     * @see RepositoryFactory#createRemote(String, String)
+     */
+    @Nonnull
+    @Override
+    public RemoteRepository createRemoteRepository(@Nonnull String id, @Nonnull String url) {
+        return getService(RepositoryFactory.class).createRemote(id, url);
+    }
+
+    /**
+     * Shortcut for <code>getService(RepositoryFactory.class).createRemote(...)</code>
+     *
+     * @see RepositoryFactory#createRemote(Repository)
+     */
+    @Nonnull
+    @Override
+    public RemoteRepository createRemoteRepository(@Nonnull Repository repository) {
+        return getService(RepositoryFactory.class).createRemote(repository);
+    }
+
+    /**
+     * Shortcut for <code>getService(CoordinateFactory.class).create(...)</code>
+     *
+     * @see ArtifactFactory#create(Session, String, String, String, String)
+     */
+    @Override
+    public ArtifactCoordinate createArtifactCoordinate(
+            String groupId, String artifactId, String version, String extension) {
+        return getService(ArtifactCoordinateFactory.class).create(this, groupId, artifactId, version, extension);
+    }
+
+    /**
+     * Shortcut for <code>getService(CoordinateFactory.class).create(...)</code>
+     *
+     * @see ArtifactCoordinateFactory#create(Session, String, String, String, String, String, String)
+     */
+    @Override
+    public ArtifactCoordinate createArtifactCoordinate(
+            String groupId, String artifactId, String version, String classifier, String extension, String type) {
+        return getService(ArtifactCoordinateFactory.class)
+                .create(this, groupId, artifactId, version, classifier, extension, type);
+    }
+
+    /**
+     * Shortcut for <code>getService(CoordinateFactory.class).create(...)</code>
+     *
+     * @see ArtifactCoordinateFactory#create(Session, String, String, String, String, String, String)
+     */
+    @Override
+    public ArtifactCoordinate createArtifactCoordinate(Artifact artifact) {
+        return getService(ArtifactCoordinateFactory.class)
+                .create(
+                        this,
+                        artifact.getGroupId(),
+                        artifact.getArtifactId(),
+                        artifact.getVersion().asString(),
+                        artifact.getClassifier(),
+                        artifact.getExtension(),
+                        null);
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
+     *
+     * @see ArtifactFactory#create(Session, String, String, String, String)
+     */
+    @Override
+    public Artifact createArtifact(String groupId, String artifactId, String version, String extension) {
+        return getService(ArtifactFactory.class).create(this, groupId, artifactId, version, extension);
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactFactory.class).create(...)</code>
+     *
+     * @see ArtifactFactory#create(Session, String, String, String, String, String, String)
+     */
+    @Override
+    public Artifact createArtifact(
+            String groupId, String artifactId, String version, String classifier, String extension, String type) {
+        return getService(ArtifactFactory.class)
+                .create(this, groupId, artifactId, version, classifier, extension, type);
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     *
+     * @throws ArtifactResolverException if the artifact resolution failed
+     * @see ArtifactResolver#resolve(Session, Collection)
+     */
+    @Override
+    public Artifact resolveArtifact(ArtifactCoordinate coordinate) {
+        return getService(ArtifactResolver.class)
+                .resolve(this, Collections.singletonList(coordinate))
+                .getArtifacts()
+                .keySet()
+                .iterator()
+                .next();
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     *
+     * @throws ArtifactResolverException if the artifact resolution failed
+     * @see ArtifactResolver#resolve(Session, Collection)
+     */
+    @Override
+    public Collection<Artifact> resolveArtifacts(ArtifactCoordinate... coordinates) {
+        return resolveArtifacts(Arrays.asList(coordinates));
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     *
+     * @throws ArtifactResolverException if the artifact resolution failed
+     * @see ArtifactResolver#resolve(Session, Collection)
+     */
+    @Override
+    public Collection<Artifact> resolveArtifacts(Collection<? extends ArtifactCoordinate> coordinates) {
+        return getService(ArtifactResolver.class)
+                .resolve(this, coordinates)
+                .getArtifacts()
+                .keySet();
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactResolver.class).resolve(...)</code>
+     *
+     * @throws ArtifactResolverException if the artifact resolution failed
+     * @see ArtifactResolver#resolve(Session, Collection)
+     */
+    @Override
+    public Artifact resolveArtifact(Artifact artifact) {
+        ArtifactCoordinate coordinate =
+                getService(ArtifactCoordinateFactory.class).create(this, artifact);
+        return resolveArtifact(coordinate);
+    }
+
+    @Override
+    public Collection<Artifact> resolveArtifacts(Artifact... artifacts) {
+        ArtifactCoordinateFactory acf = getService(ArtifactCoordinateFactory.class);
+        ArtifactCoordinate[] coords =
+                Stream.of(artifacts).map(a -> acf.create(this, a)).toArray(ArtifactCoordinate[]::new);
+        return resolveArtifacts(coords);
+    }
+
+    /**
+     * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
+     *
+     * @throws ArtifactInstallerException if the artifacts installation failed
+     * @see ArtifactInstaller#install(Session, Collection)
+     */
+    @Override
+    public void installArtifacts(Artifact... artifacts) {
+        installArtifacts(Arrays.asList(artifacts));
+    }
+
+    /**
+     * Shortcut for {@code getService(ArtifactInstaller.class).install(...)}
+     *
+     * @throws ArtifactInstallerException if the artifacts installation failed
+     * @see ArtifactInstaller#install(Session, Collection)
+     */
+    @Override
+    public void installArtifacts(Collection<Artifact> artifacts) {
+        getService(ArtifactInstaller.class).install(this, artifacts);
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactDeployer.class).deploy(...)</code>
+     *
+     * @throws ArtifactDeployerException if the artifacts deployment failed
+     * @see ArtifactDeployer#deploy(Session, RemoteRepository, Collection)
+     */
+    @Override
+    public void deployArtifact(RemoteRepository repository, Artifact... artifacts) {
+        getService(ArtifactDeployer.class).deploy(this, repository, Arrays.asList(artifacts));
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactManager.class).setPath(...)</code>
+     *
+     * @see ArtifactManager#setPath(Artifact, Path)
+     */
+    @Override
+    public void setArtifactPath(@Nonnull Artifact artifact, @Nonnull Path path) {
+        getService(ArtifactManager.class).setPath(artifact, path);
+    }
+
+    /**
+     * Shortcut for <code>getService(ArtifactManager.class).getPath(...)</code>
+     *
+     * @see ArtifactManager#getPath(Artifact)
+     */
+    @Nonnull
+    @Override
+    public Optional<Path> getArtifactPath(@Nonnull Artifact artifact) {
+        return getService(ArtifactManager.class).getPath(artifact);
+    }
+
+    /**
+     * Shortcut for <code>getService(VersionParser.class).isSnapshot(...)</code>
+     *
+     * @see VersionParser#isSnapshot(String)
+     */
+    @Override
+    public boolean isVersionSnapshot(@Nonnull String version) {
+        return getService(VersionParser.class).isSnapshot(version);
+    }
+
+    /**
+     * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
+     *
+     * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate)
+     */
+    @Nonnull
+    @Override
+    public DependencyCoordinate createDependencyCoordinate(@Nonnull ArtifactCoordinate coordinate) {
+        return getService(DependencyCoordinateFactory.class).create(this, coordinate);
+    }
+
+    /**
+     * Shortcut for <code>getService(DependencyFactory.class).create(...)</code>
+     *
+     * @see DependencyCoordinateFactory#create(Session, ArtifactCoordinate)
+     */
+    @Nonnull
+    public DependencyCoordinate createDependencyCoordinate(@Nonnull Dependency dependency) {
+        return getService(DependencyCoordinateFactory.class).create(this, dependency);
+    }
+
+    /**
+     * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
+     *
+     * @throws DependencyCollectorException if the dependency collection failed
+     * @see DependencyCollector#collect(Session, Artifact)
+     */
+    @Nonnull
+    @Override
+    public Node collectDependencies(@Nonnull Artifact artifact) {
+        return getService(DependencyCollector.class).collect(this, artifact).getRoot();
+    }
+
+    /**
+     * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
+     *
+     * @throws DependencyCollectorException if the dependency collection failed
+     * @see DependencyCollector#collect(Session, Project)
+     */
+    @Nonnull
+    @Override
+    public Node collectDependencies(@Nonnull Project project) {
+        return getService(DependencyCollector.class).collect(this, project).getRoot();
+    }
+
+    /**
+     * Shortcut for <code>getService(DependencyCollector.class).collect(...)</code>
+     *
+     * @throws DependencyCollectorException if the dependency collection failed
+     * @see DependencyCollector#collect(Session, DependencyCoordinate)
+     */
+    @Nonnull
+    @Override
+    public Node collectDependencies(@Nonnull DependencyCoordinate dependency) {
+        return getService(DependencyCollector.class).collect(this, dependency).getRoot();
+    }
+
+    @Override
+    public Path getPathForLocalArtifact(@Nonnull Artifact artifact) {
+        return getService(LocalRepositoryManager.class).getPathForLocalArtifact(this, getLocalRepository(), artifact);
+    }
+
+    @Override
+    public Path getPathForRemoteArtifact(RemoteRepository remote, Artifact artifact) {
+        return getService(LocalRepositoryManager.class)
+                .getPathForRemoteArtifact(this, getLocalRepository(), remote, artifact);
+    }
+
+    @Override
+    public Version parseVersion(String version) {
+        return getService(VersionParser.class).parseVersion(version);
+    }
+
+    @Override
+    public VersionRange parseVersionRange(String versionRange) {
+        return getService(VersionParser.class).parseVersionRange(versionRange);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java
new file mode 100644
index 0000000..b12ef94
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifact.java
@@ -0,0 +1,115 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Objects;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Version;
+import org.apache.maven.api.annotations.Nonnull;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+/**
+ * A wrapper class around a maven resolver artifact.
+ */
+public class DefaultArtifact implements Artifact {
+    private final @Nonnull InternalSession session;
+    private final @Nonnull org.eclipse.aether.artifact.Artifact artifact;
+    private final String id;
+
+    public DefaultArtifact(@Nonnull InternalSession session, @Nonnull org.eclipse.aether.artifact.Artifact artifact) {
+        this.session = nonNull(session, "session can not be null");
+        this.artifact = nonNull(artifact, "artifact can not be null");
+        this.id = getGroupId()
+                + ':'
+                + getArtifactId()
+                + ':'
+                + getExtension()
+                + (getClassifier().isEmpty() ? "" : ":" + getClassifier())
+                + ':'
+                + getVersion();
+    }
+
+    public org.eclipse.aether.artifact.Artifact getArtifact() {
+        return artifact;
+    }
+
+    @Override
+    public String key() {
+        return id;
+    }
+
+    @Nonnull
+    @Override
+    public String getGroupId() {
+        return artifact.getGroupId();
+    }
+
+    @Nonnull
+    @Override
+    public String getArtifactId() {
+        return artifact.getArtifactId();
+    }
+
+    @Nonnull
+    @Override
+    public Version getVersion() {
+        return session.parseVersion(artifact.getVersion());
+    }
+
+    @Nonnull
+    @Override
+    public String getExtension() {
+        return artifact.getExtension();
+    }
+
+    @Nonnull
+    @Override
+    public String getClassifier() {
+        return artifact.getClassifier();
+    }
+
+    @Override
+    public boolean isSnapshot() {
+        return DefaultVersionParser.checkSnapshot(artifact.getVersion());
+    }
+
+    @Nonnull
+    @Override
+    public ArtifactCoordinate toCoordinate() {
+        return session.createArtifactCoordinate(this);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof DefaultArtifact && Objects.equals(id, ((DefaultArtifact) o).id);
+    }
+
+    @Override
+    public int hashCode() {
+        return id.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return artifact.toString();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java
new file mode 100644
index 0000000..18bc1b0
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinate.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Objects;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.VersionRange;
+import org.apache.maven.api.annotations.Nonnull;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+/**
+ * A wrapper class around a maven resolver artifact.
+ */
+public class DefaultArtifactCoordinate implements ArtifactCoordinate {
+    private final @Nonnull InternalSession session;
+    private final @Nonnull org.eclipse.aether.artifact.Artifact coordinate;
+
+    public DefaultArtifactCoordinate(
+            @Nonnull InternalSession session, @Nonnull org.eclipse.aether.artifact.Artifact coordinate) {
+        this.session = nonNull(session, "session can not be null");
+        this.coordinate = nonNull(coordinate, "coordinate can not be null");
+    }
+
+    public org.eclipse.aether.artifact.Artifact getCoordinate() {
+        return coordinate;
+    }
+
+    @Nonnull
+    @Override
+    public String getGroupId() {
+        return coordinate.getGroupId();
+    }
+
+    @Nonnull
+    @Override
+    public String getArtifactId() {
+        return coordinate.getArtifactId();
+    }
+
+    @Nonnull
+    @Override
+    public VersionRange getVersion() {
+        return session.parseVersionRange(coordinate.getVersion());
+    }
+
+    @Override
+    public String getExtension() {
+        return coordinate.getExtension();
+    }
+
+    @Nonnull
+    @Override
+    public String getClassifier() {
+        return coordinate.getClassifier();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        DefaultArtifactCoordinate that = (DefaultArtifactCoordinate) o;
+        return Objects.equals(this.getGroupId(), that.getGroupId())
+                && Objects.equals(this.getArtifactId(), that.getArtifactId())
+                && Objects.equals(this.getVersion(), that.getVersion())
+                && Objects.equals(this.getClassifier(), that.getClassifier());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(getGroupId(), getArtifactId(), getVersion(), getClassifier());
+    }
+
+    @Override
+    public String toString() {
+        return coordinate.toString();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java
new file mode 100644
index 0000000..161afb8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactCoordinateFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.ArtifactCoordinateFactory;
+import org.apache.maven.api.services.ArtifactCoordinateFactoryRequest;
+import org.eclipse.aether.artifact.ArtifactType;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultArtifactCoordinateFactory implements ArtifactCoordinateFactory {
+    @Override
+    public ArtifactCoordinate create(@Nonnull ArtifactCoordinateFactoryRequest request) {
+        nonNull(request, "request can not be null");
+        InternalSession session = InternalSession.from(request.getSession());
+        ArtifactType type = null;
+        if (request.getType() != null) {
+            type = session.getSession().getArtifactTypeRegistry().get(request.getType());
+        }
+        String str1 = request.getClassifier();
+        String classifier =
+                str1 != null && !str1.isEmpty() ? request.getClassifier() : type != null ? type.getClassifier() : "";
+        String str = request.getExtension();
+        String extension =
+                str != null && !str.isEmpty() ? request.getExtension() : type != null ? type.getExtension() : "";
+        return new DefaultArtifactCoordinate(
+                session,
+                new org.eclipse.aether.artifact.DefaultArtifact(
+                        request.getGroupId(),
+                        request.getArtifactId(),
+                        classifier,
+                        extension,
+                        request.getVersion(),
+                        type));
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java
new file mode 100644
index 0000000..b2afdc4
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactDeployer.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Collection;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.ArtifactDeployer;
+import org.apache.maven.api.services.ArtifactDeployerException;
+import org.apache.maven.api.services.ArtifactDeployerRequest;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.deployment.DeployRequest;
+import org.eclipse.aether.deployment.DeployResult;
+import org.eclipse.aether.deployment.DeploymentException;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+/**
+ * Implementation of {@link ArtifactDeployer} service.
+ */
+@Named
+@Singleton
+public class DefaultArtifactDeployer implements ArtifactDeployer {
+    private final @Nonnull RepositorySystem repositorySystem;
+
+    @Inject
+    DefaultArtifactDeployer(@Nonnull RepositorySystem repositorySystem) {
+        this.repositorySystem = nonNull(repositorySystem, "repositorySystem can not be null");
+    }
+
+    @Override
+    public void deploy(@Nonnull ArtifactDeployerRequest request) {
+        nonNull(request, "request can not be null");
+        InternalSession session = InternalSession.from(request.getSession());
+        Collection<Artifact> artifacts = nonNull(request.getArtifacts(), "request.artifacts can not be null");
+        RemoteRepository repository = nonNull(request.getRepository(), "request.repository can not be null");
+        try {
+            DeployRequest deployRequest = new DeployRequest()
+                    .setRepository(session.toRepository(repository))
+                    .setArtifacts(session.toArtifacts(artifacts));
+
+            DeployResult result = repositorySystem.deploy(session.getSession(), deployRequest);
+        } catch (DeploymentException e) {
+            throw new ArtifactDeployerException("Unable to deploy artifacts", e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java
new file mode 100644
index 0000000..26a4b60
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.ArtifactFactory;
+import org.apache.maven.api.services.ArtifactFactoryRequest;
+import org.eclipse.aether.artifact.ArtifactType;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultArtifactFactory implements ArtifactFactory {
+    @Override
+    public Artifact create(@Nonnull ArtifactFactoryRequest request) {
+        nonNull(request, "request can not be null");
+        InternalSession session = InternalSession.from(request.getSession());
+        ArtifactType type = null;
+        if (request.getType() != null) {
+            type = session.getSession().getArtifactTypeRegistry().get(request.getType());
+        }
+        String str1 = request.getClassifier();
+        String classifier =
+                str1 != null && !str1.isEmpty() ? request.getClassifier() : type != null ? type.getClassifier() : null;
+        String str = request.getExtension();
+        String extension =
+                str != null && !str.isEmpty() ? request.getExtension() : type != null ? type.getExtension() : null;
+        return new DefaultArtifact(
+                session,
+                new org.eclipse.aether.artifact.DefaultArtifact(
+                        request.getGroupId(),
+                        request.getArtifactId(),
+                        classifier,
+                        extension,
+                        request.getVersion(),
+                        type));
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java
new file mode 100644
index 0000000..6107d78
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactInstaller.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.ArtifactInstaller;
+import org.apache.maven.api.services.ArtifactInstallerException;
+import org.apache.maven.api.services.ArtifactInstallerRequest;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.installation.InstallRequest;
+import org.eclipse.aether.installation.InstallResult;
+import org.eclipse.aether.installation.InstallationException;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultArtifactInstaller implements ArtifactInstaller {
+
+    private final RepositorySystem repositorySystem;
+
+    @Inject
+    DefaultArtifactInstaller(@Nonnull RepositorySystem repositorySystem) {
+        this.repositorySystem = nonNull(repositorySystem);
+    }
+
+    @Override
+    public void install(ArtifactInstallerRequest request) throws ArtifactInstallerException, IllegalArgumentException {
+        nonNull(request, "request can not be null");
+        InternalSession session = InternalSession.from(request.getSession());
+        try {
+            InstallRequest installRequest =
+                    new InstallRequest().setArtifacts(session.toArtifacts(request.getArtifacts()));
+
+            InstallResult result = repositorySystem.install(session.getSession(), installRequest);
+        } catch (InstallationException e) {
+            throw new ArtifactInstallerException(e.getMessage(), e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactManager.java
new file mode 100644
index 0000000..f0d521b
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactManager.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Stream;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.di.SessionScoped;
+import org.apache.maven.api.services.ArtifactManager;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.sisu.Typed;
+
+@Named
+@Typed
+@SessionScoped
+public class DefaultArtifactManager implements ArtifactManager {
+
+    @Nonnull
+    private final InternalSession session;
+
+    private final Map<String, Path> paths = new ConcurrentHashMap<>();
+
+    @Inject
+    public DefaultArtifactManager(@Nonnull InternalSession session) {
+        this.session = session;
+    }
+
+    @Nonnull
+    @Override
+    public Optional<Path> getPath(@Nonnull Artifact artifact) {
+        String id = id(artifact);
+        if (session.getMavenSession().getAllProjects() != null) {
+            for (MavenProject project : session.getMavenSession().getAllProjects()) {
+                if (id.equals(id(project.getArtifact()))
+                        && project.getArtifact().getFile() != null) {
+                    return Optional.of(project.getArtifact().getFile().toPath());
+                }
+            }
+        }
+        Path path = paths.get(id);
+        if (path == null && artifact instanceof DefaultArtifact) {
+            File file = ((DefaultArtifact) artifact).getArtifact().getFile();
+            if (file != null) {
+                path = file.toPath();
+            }
+        }
+        return Optional.ofNullable(path);
+    }
+
+    @Override
+    public void setPath(@Nonnull Artifact artifact, Path path) {
+        String id = id(artifact);
+        if (session.getMavenSession().getAllProjects() != null) {
+            session.getMavenSession().getAllProjects().stream()
+                    .flatMap(this::getProjectArtifacts)
+                    .filter(a -> Objects.equals(id, id(a)))
+                    .forEach(a -> a.setFile(path != null ? path.toFile() : null));
+        }
+        if (path == null) {
+            paths.remove(id);
+        } else {
+            paths.put(id, path);
+        }
+    }
+
+    /**
+     * Retrieve a stream of the project's artifacts.
+     * Do not include the POM artifact as the file can't be set anyway.
+     */
+    private Stream<org.apache.maven.artifact.Artifact> getProjectArtifacts(MavenProject project) {
+        return Stream.concat(Stream.of(project.getArtifact()), project.getAttachedArtifacts().stream());
+    }
+
+    private String id(org.apache.maven.artifact.Artifact artifact) {
+        return artifact.getGroupId()
+                + ":" + artifact.getArtifactId()
+                + ":" + artifact.getArtifactHandler().getExtension()
+                + (artifact.getClassifier() == null || artifact.getClassifier().isEmpty()
+                        ? ""
+                        : ":" + artifact.getClassifier())
+                + ":" + artifact.getVersion();
+    }
+
+    private String id(Artifact artifact) {
+        return artifact.key();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java
new file mode 100644
index 0000000..6d02991
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultArtifactResolver.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.ArtifactManager;
+import org.apache.maven.api.services.ArtifactResolver;
+import org.apache.maven.api.services.ArtifactResolverException;
+import org.apache.maven.api.services.ArtifactResolverRequest;
+import org.apache.maven.api.services.ArtifactResolverResult;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.resolution.ArtifactRequest;
+import org.eclipse.aether.resolution.ArtifactResolutionException;
+import org.eclipse.aether.resolution.ArtifactResult;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultArtifactResolver implements ArtifactResolver {
+    private final RepositorySystem repositorySystem;
+
+    @Inject
+    DefaultArtifactResolver(@Nonnull RepositorySystem repositorySystem) {
+        this.repositorySystem = nonNull(repositorySystem, "repositorySystem can not be null");
+    }
+
+    @Override
+    public ArtifactResolverResult resolve(ArtifactResolverRequest request)
+            throws ArtifactResolverException, IllegalArgumentException {
+        nonNull(request, "request can not be null");
+        InternalSession session = InternalSession.from(request.getSession());
+        try {
+            Map<Artifact, Path> paths = new HashMap<>();
+            ArtifactManager artifactManager = session.getService(ArtifactManager.class);
+            List<RemoteRepository> repositories = session.toRepositories(session.getRemoteRepositories());
+            List<ArtifactRequest> requests = new ArrayList<>();
+            for (ArtifactCoordinate coord : request.getCoordinates()) {
+                org.eclipse.aether.artifact.Artifact aetherArtifact = session.toArtifact(coord);
+                Artifact artifact = session.getArtifact(aetherArtifact);
+                Path path = artifactManager.getPath(artifact).orElse(null);
+                if (path != null) {
+                    paths.put(artifact, path);
+                } else {
+                    requests.add(new ArtifactRequest(aetherArtifact, repositories, null));
+                }
+            }
+            if (!requests.isEmpty()) {
+                List<ArtifactResult> results = repositorySystem.resolveArtifacts(session.getSession(), requests);
+                for (ArtifactResult result : results) {
+                    Artifact artifact = session.getArtifact(result.getArtifact());
+                    Path path = result.getArtifact().getFile().toPath();
+                    artifactManager.setPath(artifact, path);
+                    paths.put(artifact, path);
+                }
+            }
+            return () -> paths;
+        } catch (ArtifactResolutionException e) {
+            throw new ArtifactResolverException("Unable to resolve artifact", e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java
new file mode 100644
index 0000000..1e5ee23
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependency.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Objects;
+
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Scope;
+import org.apache.maven.api.Type;
+import org.apache.maven.api.Version;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.services.TypeRegistry;
+import org.eclipse.aether.artifact.ArtifactProperties;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+public class DefaultDependency implements Dependency {
+    private final InternalSession session;
+    private final org.eclipse.aether.graph.Dependency dependency;
+    private final DependencyProperties dependencyProperties;
+    private final String key;
+
+    public DefaultDependency(
+            @Nonnull InternalSession session, @Nonnull org.eclipse.aether.graph.Dependency dependency) {
+        this.session = nonNull(session, "session");
+        this.dependency = nonNull(dependency, "dependency");
+        this.dependencyProperties =
+                new DefaultDependencyProperties(dependency.getArtifact().getProperties());
+        this.key = getGroupId()
+                + ':'
+                + getArtifactId()
+                + ':'
+                + getExtension()
+                + (!getClassifier().isEmpty() ? ":" + getClassifier() : "")
+                + ':'
+                + getVersion();
+    }
+
+    @Override
+    public String key() {
+        return key;
+    }
+
+    @Nonnull
+    public org.eclipse.aether.graph.Dependency getDependency() {
+        return dependency;
+    }
+
+    @Override
+    public String getGroupId() {
+        return dependency.getArtifact().getGroupId();
+    }
+
+    @Override
+    public String getArtifactId() {
+        return dependency.getArtifact().getArtifactId();
+    }
+
+    @Override
+    public String getClassifier() {
+        return dependency.getArtifact().getClassifier();
+    }
+
+    @Override
+    public Version getVersion() {
+        return session.parseVersion(dependency.getArtifact().getVersion());
+    }
+
+    @Override
+    public String getExtension() {
+        return dependency.getArtifact().getExtension();
+    }
+
+    @Override
+    public Type getType() {
+        String type = dependency
+                .getArtifact()
+                .getProperty(ArtifactProperties.TYPE, dependency.getArtifact().getExtension());
+        return session.getService(TypeRegistry.class).getType(type);
+    }
+
+    @Override
+    public DependencyProperties getDependencyProperties() {
+        return dependencyProperties;
+    }
+
+    @Override
+    public boolean isSnapshot() {
+        return DefaultVersionParser.checkSnapshot(dependency.getArtifact().getVersion());
+    }
+
+    @Nonnull
+    @Override
+    public Scope getScope() {
+        return Scope.get(dependency.getScope());
+    }
+
+    @Nullable
+    @Override
+    public boolean isOptional() {
+        return dependency.isOptional();
+    }
+
+    @Nonnull
+    @Override
+    public DependencyCoordinate toCoordinate() {
+        return session.createDependencyCoordinate(this);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        return o instanceof DefaultDependency && Objects.equals(key, ((DefaultDependency) o).key);
+    }
+
+    @Override
+    public int hashCode() {
+        return key.hashCode();
+    }
+
+    @Override
+    public String toString() {
+        return dependency.toString();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java
new file mode 100644
index 0000000..d40bc72
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCollector.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.List;
+
+import org.apache.maven.api.Node;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.DependencyCollector;
+import org.apache.maven.api.services.DependencyCollectorException;
+import org.apache.maven.api.services.DependencyCollectorRequest;
+import org.apache.maven.api.services.DependencyCollectorResult;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.collection.CollectRequest;
+import org.eclipse.aether.collection.CollectResult;
+import org.eclipse.aether.collection.DependencyCollectionException;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
+import org.eclipse.aether.util.graph.transformer.ConflictResolver;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultDependencyCollector implements DependencyCollector {
+
+    private final RepositorySystem repositorySystem;
+
+    @Inject
+    DefaultDependencyCollector(@Nonnull RepositorySystem repositorySystem) {
+        this.repositorySystem = repositorySystem;
+    }
+
+    @Nonnull
+    @Override
+    public DependencyCollectorResult collect(@Nonnull DependencyCollectorRequest request)
+            throws DependencyCollectorException, IllegalArgumentException {
+        nonNull(request, "request can not be null");
+        InternalSession session = InternalSession.from(request.getSession());
+
+        Artifact rootArtifact =
+                request.getRootArtifact().map(session::toArtifact).orElse(null);
+        Dependency root = request.getRoot().map(session::toDependency).orElse(null);
+        CollectRequest collectRequest = new CollectRequest()
+                .setRootArtifact(rootArtifact)
+                .setRoot(root)
+                .setDependencies(session.toDependencies(request.getDependencies()))
+                .setManagedDependencies(session.toDependencies(request.getManagedDependencies()))
+                .setRepositories(session.toRepositories(session.getRemoteRepositories()));
+
+        RepositorySystemSession systemSession = session.getSession();
+        if (request.getVerbose()) {
+            systemSession = new DefaultRepositorySystemSession(systemSession)
+                    .setConfigProperty(ConflictResolver.CONFIG_PROP_VERBOSE, true)
+                    .setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, true);
+        }
+
+        try {
+            final CollectResult result = repositorySystem.collectDependencies(systemSession, collectRequest);
+            return new DependencyCollectorResult() {
+                @Override
+                public List<Exception> getExceptions() {
+                    return result.getExceptions();
+                }
+
+                @Override
+                public Node getRoot() {
+                    return session.getNode(result.getRoot(), request.getVerbose());
+                }
+            };
+        } catch (DependencyCollectionException e) {
+            throw new DependencyCollectorException("Unable to collect dependencies", e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java
new file mode 100644
index 0000000..64c2939
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinate.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Collection;
+
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Exclusion;
+import org.apache.maven.api.Scope;
+import org.apache.maven.api.Type;
+import org.apache.maven.api.VersionRange;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.services.TypeRegistry;
+import org.eclipse.aether.artifact.ArtifactProperties;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+public class DefaultDependencyCoordinate implements DependencyCoordinate {
+    private final InternalSession session;
+    private final org.eclipse.aether.graph.Dependency dependency;
+
+    public DefaultDependencyCoordinate(
+            @Nonnull InternalSession session, @Nonnull org.eclipse.aether.graph.Dependency dependency) {
+        this.session = nonNull(session, "session");
+        this.dependency = nonNull(dependency, "dependency");
+    }
+
+    @Nonnull
+    public org.eclipse.aether.graph.Dependency getDependency() {
+        return dependency;
+    }
+
+    @Override
+    public String getGroupId() {
+        return dependency.getArtifact().getGroupId();
+    }
+
+    @Override
+    public String getArtifactId() {
+        return dependency.getArtifact().getArtifactId();
+    }
+
+    @Override
+    public String getClassifier() {
+        return dependency.getArtifact().getClassifier();
+    }
+
+    @Override
+    public VersionRange getVersion() {
+        return session.parseVersionRange(dependency.getArtifact().getVersion());
+    }
+
+    @Override
+    public String getExtension() {
+        return dependency.getArtifact().getExtension();
+    }
+
+    @Override
+    public Type getType() {
+        String type = dependency
+                .getArtifact()
+                .getProperty(ArtifactProperties.TYPE, dependency.getArtifact().getExtension());
+        return session.getService(TypeRegistry.class).getType(type);
+    }
+
+    @Nonnull
+    @Override
+    public Scope getScope() {
+        return Scope.get(dependency.getScope());
+    }
+
+    @Nullable
+    @Override
+    public Boolean getOptional() {
+        return dependency.getOptional();
+    }
+
+    @Nonnull
+    @Override
+    public Collection<Exclusion> getExclusions() {
+        return new MappedCollection<>(dependency.getExclusions(), this::toExclusion);
+    }
+
+    private Exclusion toExclusion(org.eclipse.aether.graph.Exclusion exclusion) {
+        return new Exclusion() {
+            @Nullable
+            @Override
+            public String getGroupId() {
+                return exclusion.getGroupId();
+            }
+
+            @Nullable
+            @Override
+            public String getArtifactId() {
+                return exclusion.getArtifactId();
+            }
+        };
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java
new file mode 100644
index 0000000..eb8d346
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyCoordinateFactory.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Exclusion;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.DependencyCoordinateFactory;
+import org.apache.maven.api.services.DependencyCoordinateFactoryRequest;
+import org.eclipse.aether.artifact.ArtifactType;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultDependencyCoordinateFactory implements DependencyCoordinateFactory {
+
+    @Nonnull
+    @Override
+    public DependencyCoordinate create(@Nonnull DependencyCoordinateFactoryRequest request) {
+        nonNull(request, "request can not be null");
+        InternalSession session = InternalSession.from(request.getSession());
+
+        ArtifactType type = null;
+        if (request.getType() != null) {
+            type = session.getSession().getArtifactTypeRegistry().get(request.getType());
+        }
+        return new DefaultDependencyCoordinate(
+                session,
+                new org.eclipse.aether.graph.Dependency(
+                        new org.eclipse.aether.artifact.DefaultArtifact(
+                                request.getGroupId(),
+                                request.getArtifactId(),
+                                request.getClassifier(),
+                                request.getExtension(),
+                                request.getVersion(),
+                                type),
+                        request.getScope(),
+                        request.isOptional(),
+                        request.getExclusions().stream().map(this::toExclusion).collect(Collectors.toList())));
+    }
+
+    private org.eclipse.aether.graph.Exclusion toExclusion(Exclusion exclusion) {
+        return new org.eclipse.aether.graph.Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*");
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java
new file mode 100644
index 0000000..fc77c87
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultDependencyProperties.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.annotations.Nonnull;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+/**
+ * Default implementation of artifact properties.
+ */
+public class DefaultDependencyProperties implements DependencyProperties {
+    private final Map<String, String> properties;
+
+    public DefaultDependencyProperties(String... flags) {
+        this(Arrays.asList(flags));
+    }
+
+    public DefaultDependencyProperties(@Nonnull Collection<String> flags) {
+        nonNull(flags, "null flags");
+        HashMap<String, String> map = new HashMap<>();
+        for (String flag : flags) {
+            map.put(flag, Boolean.TRUE.toString());
+        }
+        this.properties = Collections.unmodifiableMap(map);
+    }
+
+    public DefaultDependencyProperties(@Nonnull Map<String, String> properties) {
+        this.properties = Collections.unmodifiableMap(nonNull(properties, "null properties"));
+    }
+
+    @Nonnull
+    @Override
+    public Map<String, String> asMap() {
+        return properties;
+    }
+
+    @Override
+    public boolean checkFlag(@Nonnull String flag) {
+        nonNull(flag, "null flag");
+        return Boolean.parseBoolean(properties.getOrDefault(flag, ""));
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java
new file mode 100644
index 0000000..86ec498
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultEvent.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Optional;
+
+import org.apache.maven.api.Event;
+import org.apache.maven.api.EventType;
+import org.apache.maven.api.MojoExecution;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.Session;
+import org.apache.maven.execution.ExecutionEvent;
+
+public class DefaultEvent implements Event {
+    private final InternalSession session;
+    private final ExecutionEvent delegate;
+
+    public DefaultEvent(InternalSession session, ExecutionEvent delegate) {
+        this.session = session;
+        this.delegate = delegate;
+    }
+
+    @Override
+    public EventType getType() {
+        return EventType.valueOf(delegate.getType().name());
+    }
+
+    @Override
+    public Session getSession() {
+        return session;
+    }
+
+    @Override
+    public Optional<Project> getProject() {
+        return Optional.ofNullable(delegate.getProject()).map(session::getProject);
+    }
+
+    @Override
+    public Optional<MojoExecution> getMojoExecution() {
+        return Optional.ofNullable(delegate.getMojoExecution()).map(me -> new DefaultMojoExecution(session, me));
+    }
+
+    @Override
+    public Optional<Exception> getException() {
+        return Optional.ofNullable(delegate.getException());
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java
new file mode 100644
index 0000000..dd1db21
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepository.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.annotations.Nonnull;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+public class DefaultLocalRepository implements LocalRepository {
+
+    private final @Nonnull org.eclipse.aether.repository.LocalRepository repository;
+
+    @Inject
+    public DefaultLocalRepository(@Nonnull org.eclipse.aether.repository.LocalRepository repository) {
+        this.repository = nonNull(repository, "repository can not be null");
+    }
+
+    @Nonnull
+    public org.eclipse.aether.repository.LocalRepository getRepository() {
+        return repository;
+    }
+
+    @Nonnull
+    @Override
+    public String getId() {
+        return repository.getId();
+    }
+
+    @Nonnull
+    @Override
+    public String getType() {
+        return repository.getContentType();
+    }
+
+    @Nonnull
+    @Override
+    public Path getPath() {
+        return repository.getBasedir().toPath();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java
new file mode 100644
index 0000000..43ba786
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLocalRepositoryManager.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.services.LocalRepositoryManager;
+
+@Named
+@Singleton
+public class DefaultLocalRepositoryManager implements LocalRepositoryManager {
+
+    @Override
+    public Path getPathForLocalArtifact(Session session, LocalRepository local, Artifact artifact) {
+        InternalSession s = InternalSession.from(session);
+        String path = getManager(s, local).getPathForLocalArtifact(s.toArtifact(artifact));
+        return local.getPath().resolve(path);
+    }
+
+    @Override
+    public Path getPathForRemoteArtifact(
+            Session session, LocalRepository local, RemoteRepository remote, Artifact artifact) {
+        InternalSession s = InternalSession.from(session);
+        String path =
+                getManager(s, local).getPathForRemoteArtifact(s.toArtifact(artifact), s.toRepository(remote), null);
+        return local.getPath().resolve(path);
+    }
+
+    private org.eclipse.aether.repository.LocalRepositoryManager getManager(
+            InternalSession session, LocalRepository local) {
+        org.eclipse.aether.repository.LocalRepository repository = session.toRepository(local);
+        if ("enhanced".equals(repository.getContentType())) {
+            repository = new org.eclipse.aether.repository.LocalRepository(repository.getBasedir(), "");
+        }
+        return session.getRepositorySystem().newLocalRepositoryManager(session.getSession(), repository);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLog.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLog.java
new file mode 100644
index 0000000..fa26a10
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLog.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.function.Supplier;
+
+import org.apache.maven.api.plugin.Log;
+import org.slf4j.Logger;
+
+import static java.util.Objects.requireNonNull;
+
+public class DefaultLog implements Log {
+    private final Logger logger;
+
+    public DefaultLog(Logger logger) {
+        this.logger = requireNonNull(logger);
+    }
+
+    public void debug(CharSequence content) {
+        if (isDebugEnabled()) {
+            logger.debug(toString(content));
+        }
+    }
+
+    @Override
+    public void debug(CharSequence content, Throwable error) {
+        if (isDebugEnabled()) {
+            logger.debug(toString(content), error);
+        }
+    }
+
+    @Override
+    public void debug(Throwable error) {
+        logger.debug("", error);
+    }
+
+    @Override
+    public void debug(Supplier<String> content) {
+        if (isDebugEnabled()) {
+            logger.debug(content.get());
+        }
+    }
+
+    @Override
+    public void debug(Supplier<String> content, Throwable error) {
+        if (isDebugEnabled()) {
+            logger.debug(content.get(), error);
+        }
+    }
+
+    @Override
+    public void info(CharSequence content) {
+        if (isInfoEnabled()) {
+            logger.info(toString(content));
+        }
+    }
+
+    @Override
+    public void info(CharSequence content, Throwable error) {
+        if (isInfoEnabled()) {
+            logger.info(toString(content), error);
+        }
+    }
+
+    @Override
+    public void info(Throwable error) {
+        logger.info("", error);
+    }
+
+    @Override
+    public void info(Supplier<String> content) {
+        if (isInfoEnabled()) {
+            logger.info(content.get());
+        }
+    }
+
+    @Override
+    public void info(Supplier<String> content, Throwable error) {
+        if (isInfoEnabled()) {
+            logger.info(content.get(), error);
+        }
+    }
+
+    @Override
+    public void warn(CharSequence content) {
+        if (isWarnEnabled()) {
+            logger.warn(toString(content));
+        }
+    }
+
+    @Override
+    public void warn(CharSequence content, Throwable error) {
+        if (isWarnEnabled()) {
+            logger.warn(toString(content), error);
+        }
+    }
+
+    @Override
+    public void warn(Throwable error) {
+        logger.warn("", error);
+    }
+
+    @Override
+    public void warn(Supplier<String> content) {
+        if (isWarnEnabled()) {
+            logger.warn(content.get());
+        }
+    }
+
+    @Override
+    public void warn(Supplier<String> content, Throwable error) {
+        if (isWarnEnabled()) {
+            logger.info(content.get(), error);
+        }
+    }
+
+    @Override
+    public void error(CharSequence content) {
+        if (isErrorEnabled()) {
+            logger.error(toString(content));
+        }
+    }
+
+    @Override
+    public void error(CharSequence content, Throwable error) {
+        if (isErrorEnabled()) {
+            logger.error(toString(content), error);
+        }
+    }
+
+    @Override
+    public void error(Throwable error) {
+        logger.error("", error);
+    }
+
+    @Override
+    public void error(Supplier<String> content) {
+        if (isErrorEnabled()) {
+            logger.error(content.get());
+        }
+    }
+
+    @Override
+    public void error(Supplier<String> content, Throwable error) {
+        if (isErrorEnabled()) {
+            logger.error(content.get(), error);
+        }
+    }
+
+    @Override
+    public boolean isDebugEnabled() {
+        return logger.isDebugEnabled();
+    }
+
+    @Override
+    public boolean isInfoEnabled() {
+        return logger.isInfoEnabled();
+    }
+
+    @Override
+    public boolean isWarnEnabled() {
+        return logger.isWarnEnabled();
+    }
+
+    @Override
+    public boolean isErrorEnabled() {
+        return logger.isErrorEnabled();
+    }
+
+    private String toString(CharSequence content) {
+        return content != null ? content.toString() : "";
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLookup.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLookup.java
new file mode 100644
index 0000000..8acf1f0
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultLookup.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.services.Lookup;
+import org.apache.maven.api.services.LookupException;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
+@Named
+@Singleton
+public class DefaultLookup implements Lookup {
+
+    private final PlexusContainer container;
+
+    @Inject
+    public DefaultLookup(PlexusContainer container) {
+        this.container = container;
+    }
+
+    @Override
+    public <T> T lookup(Class<T> type) {
+        try {
+            return container.lookup(type);
+        } catch (ComponentLookupException e) {
+            throw new LookupException(e);
+        }
+    }
+
+    @Override
+    public <T> T lookup(Class<T> type, String name) {
+        try {
+            return container.lookup(type, name);
+        } catch (ComponentLookupException e) {
+            throw new LookupException(e);
+        }
+    }
+
+    @Override
+    public <T> List<T> lookupList(Class<T> type) {
+        try {
+            return container.lookupList(type);
+        } catch (ComponentLookupException e) {
+            throw new LookupException(e);
+        }
+    }
+
+    @Override
+    public <T> Map<String, T> lookupMap(Class<T> type) {
+        try {
+            return container.lookupMap(type);
+        } catch (ComponentLookupException e) {
+            throw new LookupException(e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java
new file mode 100644
index 0000000..08f28d9
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilder.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.MessageBuilder;
+
+@Experimental
+public class DefaultMessageBuilder implements MessageBuilder {
+
+    private final StringBuilder buffer;
+
+    public DefaultMessageBuilder() {
+        this(new StringBuilder());
+    }
+
+    public DefaultMessageBuilder(StringBuilder buffer) {
+        this.buffer = buffer;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder trace(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder debug(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder info(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder warning(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder error(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder success(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder failure(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder strong(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder mojo(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder project(Object o) {
+        return a(o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(char[] chars, int i, int i1) {
+        buffer.append(chars, i, i1);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(char[] chars) {
+        buffer.append(chars);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(CharSequence charSequence, int i, int i1) {
+        buffer.append(charSequence, i, i1);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(CharSequence charSequence) {
+        buffer.append(charSequence);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(Object o) {
+        buffer.append(o);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder newline() {
+        buffer.append(System.getProperty("line.separator"));
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder format(String s, Object... objects) {
+        buffer.append(String.format(s, objects));
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public String build() {
+        return buffer.toString();
+    }
+
+    @Override
+    public String toString() {
+        return build();
+    }
+
+    @Override
+    public void setLength(int length) {
+        buffer.setLength(length);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java
new file mode 100644
index 0000000..196af16
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMessageBuilderFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Objects;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.MessageBuilder;
+import org.apache.maven.api.services.MessageBuilderFactory;
+
+@Experimental
+@Named
+@Singleton
+@Priority(-1)
+public class DefaultMessageBuilderFactory implements MessageBuilderFactory {
+
+    @Inject
+    public DefaultMessageBuilderFactory() {}
+
+    @Override
+    public boolean isColorEnabled() {
+        return false;
+    }
+
+    @Override
+    public int getTerminalWidth() {
+        return -1;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder builder() {
+        return new DefaultMessageBuilder();
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder builder(@Nonnull StringBuilder stringBuilder) {
+        return new DefaultMessageBuilder(Objects.requireNonNull(stringBuilder));
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java
new file mode 100644
index 0000000..a3acaa6
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultModelXmlFactory.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.InputSource;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.services.xml.ModelXmlFactory;
+import org.apache.maven.api.services.xml.XmlReaderException;
+import org.apache.maven.api.services.xml.XmlReaderRequest;
+import org.apache.maven.api.services.xml.XmlWriterException;
+import org.apache.maven.api.services.xml.XmlWriterRequest;
+import org.apache.maven.model.v4.MavenStaxReader;
+import org.apache.maven.model.v4.MavenStaxWriter;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultModelXmlFactory implements ModelXmlFactory {
+    @Override
+    public Model read(@Nonnull XmlReaderRequest request) throws XmlReaderException {
+        nonNull(request, "request can not be null");
+        Path path = request.getPath();
+        URL url = request.getURL();
+        Reader reader = request.getReader();
+        InputStream inputStream = request.getInputStream();
+        if (path == null && url == null && reader == null && inputStream == null) {
+            throw new IllegalArgumentException("path, url, reader or inputStream must be non null");
+        }
+        try {
+            InputSource source = null;
+            if (request.getModelId() != null || request.getLocation() != null) {
+                source = new InputSource(request.getModelId(), request.getLocation());
+            }
+            MavenStaxReader xml = new MavenStaxReader();
+            xml.setAddDefaultEntities(request.isAddDefaultEntities());
+            if (inputStream != null) {
+                return xml.read(inputStream, request.isStrict(), source);
+            } else if (reader != null) {
+                return xml.read(reader, request.isStrict(), source);
+            } else if (path != null) {
+                try (InputStream is = Files.newInputStream(path)) {
+                    return xml.read(is, request.isStrict(), source);
+                }
+            } else {
+                try (InputStream is = url.openStream()) {
+                    return xml.read(is, request.isStrict(), source);
+                }
+            }
+        } catch (Exception e) {
+            throw new XmlReaderException("Unable to read model", e);
+        }
+    }
+
+    @Override
+    public void write(XmlWriterRequest<Model> request) throws XmlWriterException {
+        nonNull(request, "request can not be null");
+        Model content = nonNull(request.getContent(), "content can not be null");
+        Path path = request.getPath();
+        OutputStream outputStream = request.getOutputStream();
+        Writer writer = request.getWriter();
+        if (writer == null && outputStream == null && path == null) {
+            throw new IllegalArgumentException("writer, outputStream or path must be non null");
+        }
+        try {
+            if (writer != null) {
+                new MavenStaxWriter().write(writer, content);
+            } else if (outputStream != null) {
+                new MavenStaxWriter().write(outputStream, content);
+            } else {
+                try (OutputStream os = Files.newOutputStream(path)) {
+                    new MavenStaxWriter().write(outputStream, content);
+                }
+            }
+        } catch (Exception e) {
+            throw new XmlWriterException("Unable to write model", e);
+        }
+    }
+
+    /**
+     * Simply parse the given xml string.
+     *
+     * @param xml the input xml string
+     * @return the parsed object
+     * @throws XmlReaderException if an error occurs during the parsing
+     * @see #toXmlString(Object)
+     */
+    public static Model fromXml(@Nonnull String xml) throws XmlReaderException {
+        return new DefaultModelXmlFactory().fromXmlString(xml);
+    }
+
+    /**
+     * Simply converts the given content to an xml string.
+     *
+     * @param content the object to convert
+     * @return the xml string representation
+     * @throws XmlWriterException if an error occurs during the transformation
+     * @see #fromXmlString(String)
+     */
+    public static String toXml(@Nonnull Model content) throws XmlWriterException {
+        return new DefaultModelXmlFactory().toXmlString(content);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMojoExecution.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMojoExecution.java
new file mode 100644
index 0000000..f6f86c3
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultMojoExecution.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.MojoExecution;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Plugin;
+import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.api.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.api.plugin.descriptor.lifecycle.Lifecycle;
+import org.apache.maven.api.xml.XmlNode;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.eclipse.aether.graph.DependencyNode;
+
+public class DefaultMojoExecution implements MojoExecution {
+    private final InternalSession session;
+    private final org.apache.maven.plugin.MojoExecution delegate;
+
+    public DefaultMojoExecution(InternalSession session, org.apache.maven.plugin.MojoExecution delegate) {
+        this.session = session;
+        this.delegate = delegate;
+    }
+
+    public org.apache.maven.plugin.MojoExecution getDelegate() {
+        return delegate;
+    }
+
+    @Override
+    public Plugin getPlugin() {
+        return new Plugin() {
+            @Override
+            public org.apache.maven.api.model.Plugin getModel() {
+                return delegate.getPlugin().getDelegate();
+            }
+
+            @Override
+            public PluginDescriptor getDescriptor() {
+                return delegate.getMojoDescriptor().getPluginDescriptor().getPluginDescriptorV4();
+            }
+
+            @Override
+            public List<Lifecycle> getLifecycles() {
+                try {
+                    return Collections.unmodifiableList(new ArrayList<>(delegate.getMojoDescriptor()
+                            .getPluginDescriptor()
+                            .getLifecycleMappings()
+                            .values()));
+                } catch (Exception e) {
+                    throw new RuntimeException("Unable to load plugin lifecycles", e);
+                }
+            }
+
+            @Override
+            public ClassLoader getClassLoader() {
+                return delegate.getMojoDescriptor().getRealm();
+            }
+
+            @Override
+            public Artifact getArtifact() {
+                org.apache.maven.artifact.Artifact artifact =
+                        delegate.getMojoDescriptor().getPluginDescriptor().getPluginArtifact();
+                org.eclipse.aether.artifact.Artifact resolverArtifact = RepositoryUtils.toArtifact(artifact);
+                return resolverArtifact != null ? session.getArtifact(resolverArtifact) : null;
+            }
+
+            @Override
+            public Map<String, Dependency> getDependenciesMap() {
+                DependencyNode resolverNode =
+                        delegate.getMojoDescriptor().getPluginDescriptor().getDependencyNode();
+                DefaultNode node = new DefaultNode(session, resolverNode, false);
+                return Collections.unmodifiableMap(node.stream()
+                        .map(Node::getDependency)
+                        .collect(Collectors.toMap(d -> d.getGroupId() + ":" + d.getArtifactId(), d -> d)));
+            }
+        };
+    }
+
+    @Override
+    public PluginExecution getModel() {
+        return delegate.getPlugin().getExecutions().stream()
+                .filter(pe -> Objects.equals(pe.getId(), getExecutionId()))
+                .findFirst()
+                .map(org.apache.maven.model.PluginExecution::getDelegate)
+                .orElse(null);
+    }
+
+    @Override
+    public MojoDescriptor getDescriptor() {
+        return delegate.getMojoDescriptor().getMojoDescriptorV4();
+    }
+
+    @Override
+    public String getLifecyclePhase() {
+        return delegate.getLifecyclePhase();
+    }
+
+    @Override
+    public String getExecutionId() {
+        return delegate.getExecutionId();
+    }
+
+    @Override
+    public String getGoal() {
+        return delegate.getGoal();
+    }
+
+    @Override
+    public Optional<XmlNode> getConfiguration() {
+        return Optional.of(delegate.getConfiguration()).map(Xpp3Dom::getDom);
+    }
+
+    @Override
+    public String toString() {
+        return delegate.toString();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultNode.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultNode.java
new file mode 100644
index 0000000..2efc4c0
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultNode.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.annotations.Nonnull;
+import org.eclipse.aether.graph.DependencyNode;
+import org.eclipse.aether.util.graph.manager.DependencyManagerUtils;
+import org.eclipse.aether.util.graph.transformer.ConflictResolver;
+
+public class DefaultNode extends AbstractNode {
+
+    protected final @Nonnull InternalSession session;
+    protected final @Nonnull org.eclipse.aether.graph.DependencyNode node;
+    protected final boolean verbose;
+
+    public DefaultNode(
+            @Nonnull InternalSession session, @Nonnull org.eclipse.aether.graph.DependencyNode node, boolean verbose) {
+        this.session = session;
+        this.node = node;
+        this.verbose = verbose;
+    }
+
+    @Override
+    DependencyNode getDependencyNode() {
+        return node;
+    }
+
+    @Override
+    public Dependency getDependency() {
+        return node.getDependency() != null ? session.getDependency(node.getDependency()) : null;
+    }
+
+    @Override
+    public List<Node> getChildren() {
+        return new MappedList<>(node.getChildren(), n -> session.getNode(n, verbose));
+    }
+
+    @Override
+    public List<RemoteRepository> getRemoteRepositories() {
+        return new MappedList<>(node.getRepositories(), session::getRemoteRepository);
+    }
+
+    @Override
+    public Optional<RemoteRepository> getRepository() {
+        // TODO: v4: implement
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public String asString() {
+        String nodeString = super.asString();
+
+        if (!verbose) {
+            return nodeString;
+        }
+
+        org.eclipse.aether.graph.DependencyNode node = getDependencyNode();
+
+        List<String> details = new ArrayList<>();
+
+        org.eclipse.aether.graph.DependencyNode winner =
+                (org.eclipse.aether.graph.DependencyNode) node.getData().get(ConflictResolver.NODE_DATA_WINNER);
+        String winnerVersion = winner != null ? winner.getArtifact().getBaseVersion() : null;
+        boolean included = (winnerVersion == null);
+
+        String preManagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
+        if (preManagedVersion != null) {
+            details.add("version managed from " + preManagedVersion);
+        }
+
+        String preManagedScope = DependencyManagerUtils.getPremanagedScope(node);
+        if (preManagedScope != null) {
+            details.add("scope managed from " + preManagedScope);
+        }
+
+        String originalScope = (String) node.getData().get(ConflictResolver.NODE_DATA_ORIGINAL_SCOPE);
+        if (originalScope != null && !originalScope.equals(node.getDependency().getScope())) {
+            details.add("scope updated from " + originalScope);
+        }
+
+        if (!included) {
+            if (Objects.equals(winnerVersion, node.getArtifact().getVersion())) {
+                details.add("omitted for duplicate");
+            } else {
+                details.add("omitted for conflict with " + winnerVersion);
+            }
+        }
+
+        StringBuilder buffer = new StringBuilder();
+        if (included) {
+            buffer.append(nodeString);
+            if (!details.isEmpty()) {
+                buffer.append(" (");
+                join(buffer, details, "; ");
+                buffer.append(")");
+            }
+        } else {
+            buffer.append("(");
+            buffer.append(nodeString);
+            if (!details.isEmpty()) {
+                buffer.append(" - ");
+                join(buffer, details, "; ");
+            }
+            buffer.append(")");
+        }
+        return buffer.toString();
+    }
+
+    private static void join(StringBuilder buffer, List<String> details, String separator) {
+        boolean first = true;
+        for (String detail : details) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(detail);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java
new file mode 100644
index 0000000..c92b060
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProject.java
@@ -0,0 +1,232 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.Exclusion;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Scope;
+import org.apache.maven.api.Type;
+import org.apache.maven.api.VersionRange;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.services.ArtifactManager;
+import org.apache.maven.api.services.TypeRegistry;
+import org.apache.maven.project.MavenProject;
+
+public class DefaultProject implements Project {
+
+    private final InternalSession session;
+    private final MavenProject project;
+
+    public DefaultProject(InternalSession session, MavenProject project) {
+        this.session = session;
+        this.project = project;
+    }
+
+    public InternalSession getSession() {
+        return session;
+    }
+
+    public MavenProject getProject() {
+        return project;
+    }
+
+    @Nonnull
+    @Override
+    public String getGroupId() {
+        return project.getGroupId();
+    }
+
+    @Nonnull
+    @Override
+    public String getArtifactId() {
+        return project.getArtifactId();
+    }
+
+    @Nonnull
+    @Override
+    public String getVersion() {
+        return project.getVersion();
+    }
+
+    @Nonnull
+    @Override
+    public Artifact getArtifact() {
+        org.eclipse.aether.artifact.Artifact resolverArtifact = RepositoryUtils.toArtifact(project.getArtifact());
+        Artifact artifact = session.getArtifact(resolverArtifact);
+        Path path =
+                resolverArtifact.getFile() != null ? resolverArtifact.getFile().toPath() : null;
+        session.getService(ArtifactManager.class).setPath(artifact, path);
+        return artifact;
+    }
+
+    @Nonnull
+    @Override
+    public String getPackaging() {
+        return project.getPackaging();
+    }
+
+    @Nonnull
+    @Override
+    public Model getModel() {
+        return project.getModel().getDelegate();
+    }
+
+    @Nonnull
+    @Override
+    public Optional<Path> getPomPath() {
+        File file = project.getFile();
+        return Optional.ofNullable(file).map(File::toPath);
+    }
+
+    @Nonnull
+    @Override
+    public List<DependencyCoordinate> getDependencies() {
+        return new MappedList<>(getModel().getDependencies(), this::toDependency);
+    }
+
+    @Nonnull
+    @Override
+    public List<DependencyCoordinate> getManagedDependencies() {
+        DependencyManagement dependencyManagement = getModel().getDependencyManagement();
+        if (dependencyManagement != null) {
+            return new MappedList<>(dependencyManagement.getDependencies(), this::toDependency);
+        }
+        return Collections.emptyList();
+    }
+
+    @Override
+    public boolean isExecutionRoot() {
+        return project.isExecutionRoot();
+    }
+
+    @Override
+    public boolean isTopProject() {
+        return getBasedir().isPresent()
+                && getBasedir().get().equals(getSession().getTopDirectory());
+    }
+
+    @Override
+    public boolean isRootProject() {
+        return getBasedir().isPresent() && getBasedir().get().equals(getRootDirectory());
+    }
+
+    @Override
+    public Path getRootDirectory() {
+        return project.getRootDirectory();
+    }
+
+    @Override
+    public Optional<Project> getParent() {
+        MavenProject parent = project.getParent();
+        return parent != null ? Optional.of(session.getProject(parent)) : Optional.empty();
+    }
+
+    @Override
+    public List<RemoteRepository> getRemoteProjectRepositories() {
+        return new MappedList<>(project.getRemoteProjectRepositories(), session::getRemoteRepository);
+    }
+
+    @Override
+    public List<RemoteRepository> getRemotePluginRepositories() {
+        return new MappedList<>(project.getRemotePluginRepositories(), session::getRemoteRepository);
+    }
+
+    @Nonnull
+    private DependencyCoordinate toDependency(org.apache.maven.api.model.Dependency dependency) {
+        return new DependencyCoordinate() {
+            @Override
+            public String getGroupId() {
+                return dependency.getGroupId();
+            }
+
+            @Override
+            public String getArtifactId() {
+                return dependency.getArtifactId();
+            }
+
+            @Override
+            public String getClassifier() {
+                return dependency.getClassifier();
+            }
+
+            @Override
+            public VersionRange getVersion() {
+                return session.parseVersionRange(dependency.getVersion());
+            }
+
+            @Override
+            public String getExtension() {
+                return getType().getExtension();
+            }
+
+            @Override
+            public Type getType() {
+                String type = dependency.getType();
+                return session.getService(TypeRegistry.class).getType(type);
+            }
+
+            @Nonnull
+            @Override
+            public Scope getScope() {
+                return Scope.get(dependency.getScope());
+            }
+
+            @Override
+            public Boolean getOptional() {
+                return dependency.isOptional();
+            }
+
+            @Nonnull
+            @Override
+            public Collection<Exclusion> getExclusions() {
+                return new MappedCollection<>(dependency.getExclusions(), this::toExclusion);
+            }
+
+            private Exclusion toExclusion(org.apache.maven.api.model.Exclusion exclusion) {
+                return new Exclusion() {
+                    @Nullable
+                    @Override
+                    public String getGroupId() {
+                        return exclusion.getGroupId();
+                    }
+
+                    @Nullable
+                    @Override
+                    public String getArtifactId() {
+                        return exclusion.getArtifactId();
+                    }
+                };
+            }
+        };
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
new file mode 100644
index 0000000..d291c24
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectBuilder.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.BuilderProblem;
+import org.apache.maven.api.services.DependencyCollectorResult;
+import org.apache.maven.api.services.ProjectBuilder;
+import org.apache.maven.api.services.ProjectBuilderException;
+import org.apache.maven.api.services.ProjectBuilderRequest;
+import org.apache.maven.api.services.ProjectBuilderResult;
+import org.apache.maven.api.services.Source;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.model.building.ModelProblem;
+import org.apache.maven.model.building.ModelSource2;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingException;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuildingResult;
+
+@Named
+@Singleton
+public class DefaultProjectBuilder implements ProjectBuilder {
+
+    private final org.apache.maven.project.ProjectBuilder builder;
+
+    @Inject
+    public DefaultProjectBuilder(org.apache.maven.project.ProjectBuilder builder) {
+        this.builder = builder;
+    }
+
+    @SuppressWarnings("MethodLength")
+    @Nonnull
+    @Override
+    public ProjectBuilderResult build(ProjectBuilderRequest request)
+            throws ProjectBuilderException, IllegalArgumentException {
+        InternalSession session = InternalSession.from(request.getSession());
+        try {
+            List<ArtifactRepository> repositories = session.toArtifactRepositories(session.getRemoteRepositories());
+            ProjectBuildingRequest req = new DefaultProjectBuildingRequest()
+                    .setRepositorySession(session.getSession())
+                    .setRemoteRepositories(repositories)
+                    .setPluginArtifactRepositories(repositories)
+                    .setProcessPlugins(request.isProcessPlugins());
+            ProjectBuildingResult res;
+            if (request.getPath().isPresent()) {
+                Path path = request.getPath().get();
+                res = builder.build(path.toFile(), req);
+            } else if (request.getSource().isPresent()) {
+                Source source = request.getSource().get();
+                ModelSource2 modelSource = new SourceWrapper(source);
+                res = builder.build(modelSource, req);
+            } else if (request.getArtifact().isPresent()) {
+                Artifact a = request.getArtifact().get();
+                org.eclipse.aether.artifact.Artifact aetherArtifact = session.toArtifact(a);
+                org.apache.maven.artifact.Artifact artifact = RepositoryUtils.toArtifact(aetherArtifact);
+                res = builder.build(artifact, request.isAllowStubModel(), req);
+            } else if (request.getCoordinate().isPresent()) {
+                ArtifactCoordinate c = request.getCoordinate().get();
+                org.apache.maven.artifact.Artifact artifact = new DefaultArtifact(
+                        c.getGroupId(),
+                        c.getArtifactId(),
+                        c.getVersion().asString(),
+                        null,
+                        c.getExtension(),
+                        c.getClassifier(),
+                        null);
+                res = builder.build(artifact, request.isAllowStubModel(), req);
+            } else {
+                throw new IllegalArgumentException("Invalid request");
+            }
+            return new ProjectBuilderResult() {
+                @Nonnull
+                @Override
+                public String getProjectId() {
+                    return res.getProjectId();
+                }
+
+                @Nonnull
+                @Override
+                public Optional<Path> getPomFile() {
+                    return Optional.ofNullable(res.getPomFile()).map(File::toPath);
+                }
+
+                @Nonnull
+                @Override
+                public Optional<Project> getProject() {
+                    return Optional.ofNullable(res.getProject()).map(session::getProject);
+                }
+
+                @Nonnull
+                @Override
+                public Collection<BuilderProblem> getProblems() {
+                    return new MappedCollection<>(res.getProblems(), this::toProblem);
+                }
+
+                private BuilderProblem toProblem(ModelProblem problem) {
+                    return new BuilderProblem() {
+                        @Override
+                        public String getSource() {
+                            return problem.getSource();
+                        }
+
+                        @Override
+                        public int getLineNumber() {
+                            return problem.getLineNumber();
+                        }
+
+                        @Override
+                        public int getColumnNumber() {
+                            return problem.getColumnNumber();
+                        }
+
+                        @Override
+                        public String getLocation() {
+                            StringBuilder buffer = new StringBuilder(256);
+
+                            if (!getSource().isEmpty()) {
+                                buffer.append(getSource());
+                            }
+
+                            if (getLineNumber() > 0) {
+                                if (buffer.length() > 0) {
+                                    buffer.append(", ");
+                                }
+                                buffer.append("line ").append(getLineNumber());
+                            }
+
+                            if (getColumnNumber() > 0) {
+                                if (buffer.length() > 0) {
+                                    buffer.append(", ");
+                                }
+                                buffer.append("column ").append(getColumnNumber());
+                            }
+
+                            return buffer.toString();
+                        }
+
+                        @Override
+                        public Exception getException() {
+                            return problem.getException();
+                        }
+
+                        @Override
+                        public String getMessage() {
+                            return problem.getMessage();
+                        }
+
+                        @Override
+                        public Severity getSeverity() {
+                            return Severity.valueOf(problem.getSeverity().name());
+                        }
+                    };
+                }
+
+                @Nonnull
+                @Override
+                public Optional<DependencyCollectorResult> getDependencyResolverResult() {
+                    return Optional.ofNullable(res.getDependencyResolutionResult())
+                            .map(r -> new DependencyCollectorResult() {
+                                @Override
+                                public List<Exception> getExceptions() {
+                                    return r.getCollectionErrors();
+                                }
+
+                                @Override
+                                public Node getRoot() {
+                                    return session.getNode(r.getDependencyGraph());
+                                }
+                            });
+                }
+            };
+        } catch (ProjectBuildingException e) {
+            throw new ProjectBuilderException("Unable to build project", e);
+        }
+    }
+
+    private static class SourceWrapper implements ModelSource2 {
+        private final Source source;
+
+        SourceWrapper(Source source) {
+            this.source = source;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return source.openStream();
+        }
+
+        @Override
+        public String getLocation() {
+            return source.getLocation();
+        }
+
+        @Override
+        public ModelSource2 getRelatedSource(String relPath) {
+            Source rel = source.resolve(relPath);
+            return rel != null ? new SourceWrapper(rel) : null;
+        }
+
+        @Override
+        public URI getLocationURI() {
+            Path path = source.getPath();
+            return path != null ? path.toUri() : URI.create(source.getLocation());
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java
new file mode 100644
index 0000000..a08d3a2
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.nio.file.Path;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.ResolutionScope;
+import org.apache.maven.api.Scope;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.di.SessionScoped;
+import org.apache.maven.api.services.ArtifactManager;
+import org.apache.maven.api.services.MavenException;
+import org.apache.maven.api.services.ProjectManager;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.sisu.Typed;
+
+@Named
+@Typed
+@SessionScoped
+public class DefaultProjectManager implements ProjectManager {
+
+    private final Session session;
+    private final ArtifactManager artifactManager;
+    private final PlexusContainer container;
+
+    @Inject
+    public DefaultProjectManager(Session session, ArtifactManager artifactManager, PlexusContainer container) {
+        this.session = session;
+        this.artifactManager = artifactManager;
+        this.container = container;
+    }
+
+    @Nonnull
+    @Override
+    public Optional<Path> getPath(Project project) {
+        // TODO: apiv4
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Nonnull
+    @Override
+    public Collection<Artifact> getAttachedArtifacts(Project project) {
+        InternalSession session = ((DefaultProject) project).getSession();
+        Collection<Artifact> attached = getMavenProject(project).getAttachedArtifacts().stream()
+                .map(RepositoryUtils::toArtifact)
+                .map(session::getArtifact)
+                .collect(Collectors.toList());
+        return Collections.unmodifiableCollection(attached);
+    }
+
+    @Override
+    public void attachArtifact(Project project, Artifact artifact, Path path) {
+        getMavenProject(project)
+                .addAttachedArtifact(RepositoryUtils.toArtifact(
+                        ((DefaultProject) project).getSession().toArtifact(artifact)));
+        artifactManager.setPath(artifact, path);
+    }
+
+    @Override
+    public List<String> getCompileSourceRoots(Project project) {
+        List<String> roots = getMavenProject(project).getCompileSourceRoots();
+        return Collections.unmodifiableList(roots);
+    }
+
+    @Override
+    public void addCompileSourceRoot(Project project, String sourceRoot) {
+        List<String> roots = getMavenProject(project).getCompileSourceRoots();
+        roots.add(sourceRoot);
+    }
+
+    @Override
+    public List<String> getTestCompileSourceRoots(Project project) {
+        List<String> roots = getMavenProject(project).getTestCompileSourceRoots();
+        return Collections.unmodifiableList(roots);
+    }
+
+    @Override
+    public void addTestCompileSourceRoot(Project project, String sourceRoot) {
+        List<String> roots = getMavenProject(project).getTestCompileSourceRoots();
+        roots.add(sourceRoot);
+    }
+
+    @Override
+    public List<RemoteRepository> getRepositories(Project project) {
+        // TODO: apiv4
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public List<Artifact> getResolvedDependencies(Project project, ResolutionScope scope) {
+        Collection<String> toResolve = toScopes(scope);
+        try {
+            LifecycleDependencyResolver lifecycleDependencyResolver =
+                    container.lookup(LifecycleDependencyResolver.class);
+            Set<org.apache.maven.artifact.Artifact> artifacts = lifecycleDependencyResolver.resolveProjectArtifacts(
+                    getMavenProject(project),
+                    toResolve,
+                    toResolve,
+                    InternalSession.from(session).getMavenSession(),
+                    false,
+                    Collections.emptySet());
+            return artifacts.stream()
+                    .map(RepositoryUtils::toArtifact)
+                    .map(InternalSession.from(session)::getArtifact)
+                    .collect(Collectors.toList());
+        } catch (LifecycleExecutionException | ComponentLookupException e) {
+            throw new MavenException("Unable to resolve project dependencies", e);
+        }
+    }
+
+    @Override
+    public Node getCollectedDependencies(Project project, ResolutionScope scope) {
+        // TODO: apiv4
+        throw new UnsupportedOperationException("Not implemented yet");
+    }
+
+    @Override
+    public void setProperty(Project project, String key, String value) {
+        getMavenProject(project).getProperties().setProperty(key, value);
+    }
+
+    private MavenProject getMavenProject(Project project) {
+        return ((DefaultProject) project).getProject();
+    }
+
+    private Collection<String> toScopes(ResolutionScope scope) {
+        return scope.scopes().stream().map(Scope::id).collect(Collectors.toList());
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPrompter.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPrompter.java
new file mode 100644
index 0000000..dc44da8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultPrompter.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.maven.api.services.Prompter;
+import org.apache.maven.api.services.PrompterException;
+import org.codehaus.plexus.PlexusContainer;
+
+@Named
+@Singleton
+public class DefaultPrompter implements Prompter {
+
+    private static final String PROMPTER_CLASS = "org.codehaus.plexus.components.interactivity.Prompter";
+    private final PlexusContainer container;
+
+    @Inject
+    public DefaultPrompter(PlexusContainer container) {
+        this.container = container;
+    }
+
+    @Override
+    public String prompt(String message, List<String> possibleValues, String defaultReply) throws PrompterException {
+        try {
+            Class<?> clazz = container.getContainerRealm().loadClass(PROMPTER_CLASS);
+            Object instance = container.lookup(clazz);
+            Method method = clazz.getMethod("prompt", String.class, List.class, String.class);
+            return (String) method.invoke(instance, message, possibleValues, defaultReply);
+        } catch (Exception e) {
+            throw new PrompterException("Unable to call prompter", e);
+        }
+    }
+
+    @Override
+    public String promptForPassword(String message) throws PrompterException {
+        try {
+            Class<?> clazz = container.getContainerRealm().loadClass(PROMPTER_CLASS);
+            Object instance = container.lookup(clazz);
+            Method method = clazz.getMethod("promptForPassword", String.class);
+            return (String) method.invoke(instance, message);
+        } catch (Exception e) {
+            throw new PrompterException("Unable to call prompter", e);
+        }
+    }
+
+    @Override
+    public void showMessage(String message) throws PrompterException {
+        try {
+            Class<?> clazz = container.getContainerRealm().loadClass(PROMPTER_CLASS);
+            Object instance = container.lookup(clazz);
+            Method method = clazz.getMethod("showMessage", String.class);
+            method.invoke(instance, message);
+        } catch (Exception e) {
+            throw new PrompterException("Unable to call prompter", e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java
new file mode 100644
index 0000000..6a279f6
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRemoteRepository.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.annotations.Nonnull;
+
+public class DefaultRemoteRepository implements RemoteRepository {
+    private final org.eclipse.aether.repository.RemoteRepository repository;
+
+    public DefaultRemoteRepository(org.eclipse.aether.repository.RemoteRepository repository) {
+        this.repository = repository;
+    }
+
+    public org.eclipse.aether.repository.RemoteRepository getRepository() {
+        return repository;
+    }
+
+    @Nonnull
+    @Override
+    public String getId() {
+        return repository.getId();
+    }
+
+    @Nonnull
+    @Override
+    public String getType() {
+        return repository.getContentType();
+    }
+
+    @Nonnull
+    @Override
+    public String getUrl() {
+        return repository.getUrl();
+    }
+
+    @Nonnull
+    @Override
+    public String getProtocol() {
+        return repository.getProtocol();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java
new file mode 100644
index 0000000..9e6da63
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultRepositoryFactory.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.api.services.RepositoryFactory;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.repository.RepositoryPolicy;
+
+@Named
+@Singleton
+public class DefaultRepositoryFactory implements RepositoryFactory {
+
+    private final RepositorySystem repositorySystem;
+
+    @Inject
+    public DefaultRepositoryFactory(RepositorySystem repositorySystem) {
+        this.repositorySystem = repositorySystem;
+    }
+
+    @Override
+    public LocalRepository createLocal(Path path) {
+        return new DefaultLocalRepository(new org.eclipse.aether.repository.LocalRepository(path.toFile()));
+    }
+
+    @Override
+    public RemoteRepository createRemote(String id, String url) {
+        return new DefaultRemoteRepository(
+                new org.eclipse.aether.repository.RemoteRepository.Builder(id, "default", url).build());
+    }
+
+    @Override
+    public RemoteRepository createRemote(Repository repository) throws IllegalArgumentException {
+        return new DefaultRemoteRepository(new org.eclipse.aether.repository.RemoteRepository.Builder(
+                        repository.getId(), repository.getLayout(), repository.getUrl())
+                .setReleasePolicy(buildRepositoryPolicy(repository.getReleases()))
+                .setSnapshotPolicy(buildRepositoryPolicy(repository.getSnapshots()))
+                .build());
+    }
+
+    public static org.eclipse.aether.repository.RepositoryPolicy buildRepositoryPolicy(
+            org.apache.maven.api.model.RepositoryPolicy policy) {
+        boolean enabled = true;
+        String updatePolicy = RepositoryPolicy.UPDATE_POLICY_DAILY;
+        String checksumPolicy = RepositoryPolicy.CHECKSUM_POLICY_FAIL;
+        if (policy != null) {
+            enabled = policy.isEnabled();
+            if (policy.getUpdatePolicy() != null) {
+                updatePolicy = policy.getUpdatePolicy();
+            }
+            if (policy.getChecksumPolicy() != null) {
+                checksumPolicy = policy.getChecksumPolicy();
+            }
+        }
+        return new org.eclipse.aether.repository.RepositoryPolicy(enabled, updatePolicy, checksumPolicy);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java
new file mode 100644
index 0000000..4b38176
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSession.java
@@ -0,0 +1,297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.nio.file.Path;
+import java.time.Instant;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Service;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.SessionData;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.api.services.MavenException;
+import org.apache.maven.api.settings.Settings;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.MojoExecution;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.rtinfo.RuntimeInformation;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+public class DefaultSession extends AbstractSession {
+
+    private final MavenSession mavenSession;
+    private final RepositorySystemSession session;
+    private final RepositorySystem repositorySystem;
+    private final List<RemoteRepository> repositories;
+    private final MavenRepositorySystem mavenRepositorySystem;
+    private final PlexusContainer container;
+    private final RuntimeInformation runtimeInformation;
+    private final Map<Class<? extends Service>, Service> services = new ConcurrentHashMap<>();
+
+    @SuppressWarnings("checkstyle:ParameterNumber")
+    public DefaultSession(
+            @Nonnull MavenSession session,
+            @Nonnull RepositorySystem repositorySystem,
+            @Nullable List<RemoteRepository> repositories,
+            @Nonnull MavenRepositorySystem mavenRepositorySystem,
+            @Nonnull PlexusContainer container,
+            @Nonnull RuntimeInformation runtimeInformation) {
+        this.mavenSession = nonNull(session);
+        this.session = mavenSession.getRepositorySession();
+        this.repositorySystem = nonNull(repositorySystem);
+        this.repositories = repositories != null
+                ? repositories
+                : mavenSession.getRequest().getRemoteRepositories().stream()
+                        .map(RepositoryUtils::toRepo)
+                        .map(this::getRemoteRepository)
+                        .collect(Collectors.toList());
+        this.mavenRepositorySystem = mavenRepositorySystem;
+        this.container = container;
+        this.runtimeInformation = runtimeInformation;
+    }
+
+    public MavenSession getMavenSession() {
+        return mavenSession;
+    }
+
+    @Nonnull
+    @Override
+    public LocalRepository getLocalRepository() {
+        return new DefaultLocalRepository(session.getLocalRepository());
+    }
+
+    @Nonnull
+    @Override
+    public List<RemoteRepository> getRemoteRepositories() {
+        return Collections.unmodifiableList(repositories);
+    }
+
+    @Nonnull
+    @Override
+    public Settings getSettings() {
+        return mavenSession.getSettings().getDelegate();
+    }
+
+    @Nonnull
+    @Override
+    public Map<String, String> getUserProperties() {
+        return new PropertiesAsMap(mavenSession.getUserProperties());
+    }
+
+    @Nonnull
+    @Override
+    public Map<String, String> getSystemProperties() {
+        return new PropertiesAsMap(mavenSession.getSystemProperties());
+    }
+
+    @Nonnull
+    @Override
+    public String getMavenVersion() {
+        return runtimeInformation.getMavenVersion();
+    }
+
+    @Override
+    public int getDegreeOfConcurrency() {
+        return mavenSession.getRequest().getDegreeOfConcurrency();
+    }
+
+    @Nonnull
+    @Override
+    public Instant getStartTime() {
+        return mavenSession.getStartTime().toInstant();
+    }
+
+    @Override
+    public Path getRootDirectory() {
+        return mavenSession.getRequest().getRootDirectory();
+    }
+
+    @Override
+    public Path getTopDirectory() {
+        return mavenSession.getRequest().getTopDirectory();
+    }
+
+    @Nonnull
+    @Override
+    public List<Project> getProjects() {
+        return getProjects(mavenSession.getProjects());
+    }
+
+    @Nonnull
+    @Override
+    public Map<String, Object> getPluginContext(Project project) {
+        nonNull(project, "project");
+        try {
+            MojoExecution mojoExecution = container.lookup(MojoExecution.class);
+            MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
+            PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
+            return mavenSession.getPluginContext(pluginDescriptor, ((DefaultProject) project).getProject());
+        } catch (ComponentLookupException e) {
+            throw new MavenException("The PluginContext is only available during a mojo execution", e);
+        }
+    }
+
+    @Nonnull
+    @Override
+    public SessionData getData() {
+        org.eclipse.aether.SessionData data = session.getData();
+        return new SessionData() {
+            @Override
+            public void set(@Nonnull Object key, @Nullable Object value) {
+                data.set(key, value);
+            }
+
+            @Override
+            public boolean set(@Nonnull Object key, @Nullable Object oldValue, @Nullable Object newValue) {
+                return data.set(key, oldValue, newValue);
+            }
+
+            @Nullable
+            @Override
+            public Object get(@Nonnull Object key) {
+                return data.get(key);
+            }
+
+            @Nullable
+            @Override
+            public Object computeIfAbsent(@Nonnull Object key, @Nonnull Supplier<Object> supplier) {
+                return data.computeIfAbsent(key, supplier);
+            }
+        };
+    }
+
+    @Nonnull
+    @Override
+    public Session withLocalRepository(@Nonnull LocalRepository localRepository) {
+        nonNull(localRepository, "localRepository");
+        if (session.getLocalRepository() != null
+                && Objects.equals(session.getLocalRepository().getBasedir().toPath(), localRepository.getPath())) {
+            return this;
+        }
+        org.eclipse.aether.repository.LocalRepository repository = toRepository(localRepository);
+        org.eclipse.aether.repository.LocalRepositoryManager localRepositoryManager =
+                repositorySystem.newLocalRepositoryManager(session, repository);
+
+        RepositorySystemSession repoSession =
+                new DefaultRepositorySystemSession(session).setLocalRepositoryManager(localRepositoryManager);
+        MavenSession newSession = new MavenSession(repoSession, mavenSession.getRequest(), mavenSession.getResult());
+        return new DefaultSession(
+                newSession, repositorySystem, repositories, mavenRepositorySystem, container, runtimeInformation);
+    }
+
+    @Nonnull
+    @Override
+    public Session withRemoteRepositories(@Nonnull List<RemoteRepository> repositories) {
+        return new DefaultSession(
+                mavenSession, repositorySystem, repositories, mavenRepositorySystem, container, runtimeInformation);
+    }
+
+    @Nonnull
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends Service> T getService(Class<T> clazz) throws NoSuchElementException {
+        T t = (T) services.computeIfAbsent(clazz, this::lookup);
+        if (t == null) {
+            throw new NoSuchElementException(clazz.getName());
+        }
+        return t;
+    }
+
+    private Service lookup(Class<? extends Service> c) {
+        try {
+            return container.lookup(c);
+        } catch (ComponentLookupException e) {
+            NoSuchElementException nsee = new NoSuchElementException(c.getName());
+            e.initCause(e);
+            throw nsee;
+        }
+    }
+
+    @Nonnull
+    public RepositorySystemSession getSession() {
+        return session;
+    }
+
+    @Nonnull
+    public RepositorySystem getRepositorySystem() {
+        return repositorySystem;
+    }
+
+    public ArtifactRepository toArtifactRepository(RemoteRepository repository) {
+        if (repository instanceof DefaultRemoteRepository) {
+            org.eclipse.aether.repository.RemoteRepository rr = ((DefaultRemoteRepository) repository).getRepository();
+
+            try {
+                return mavenRepositorySystem.createRepository(
+                        rr.getUrl(),
+                        rr.getId(),
+                        rr.getPolicy(false).isEnabled(),
+                        rr.getPolicy(false).getUpdatePolicy(),
+                        rr.getPolicy(true).isEnabled(),
+                        rr.getPolicy(true).getUpdatePolicy(),
+                        rr.getPolicy(false).getChecksumPolicy());
+
+            } catch (Exception e) {
+                throw new RuntimeException("Unable to create repository", e);
+            }
+        } else {
+            // TODO
+            throw new UnsupportedOperationException("Not yet implemented");
+        }
+    }
+
+    public org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency) {
+        if (dependency instanceof DefaultDependencyCoordinate) {
+            return ((DefaultDependencyCoordinate) dependency).getDependency();
+        } else {
+            return new org.eclipse.aether.graph.Dependency(
+                    new org.eclipse.aether.artifact.DefaultArtifact(
+                            dependency.getGroupId(),
+                            dependency.getArtifactId(),
+                            dependency.getClassifier(),
+                            dependency.getType().getExtension(),
+                            dependency.getVersion().toString(),
+                            null),
+                    dependency.getScope().id());
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSessionFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSessionFactory.java
new file mode 100644
index 0000000..e727a34
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSessionFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.rtinfo.RuntimeInformation;
+import org.codehaus.plexus.PlexusContainer;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.SessionData;
+
+@Singleton
+@Named
+public class DefaultSessionFactory {
+    private final RepositorySystem repositorySystem;
+    private final MavenRepositorySystem mavenRepositorySystem;
+    private final PlexusContainer plexusContainer;
+    private final RuntimeInformation runtimeInformation;
+
+    @Inject
+    @SuppressWarnings("checkstyle:ParameterNumber")
+    public DefaultSessionFactory(
+            RepositorySystem repositorySystem,
+            MavenRepositorySystem mavenRepositorySystem,
+            PlexusContainer plexusContainer,
+            RuntimeInformation runtimeInformation) {
+        this.repositorySystem = repositorySystem;
+        this.mavenRepositorySystem = mavenRepositorySystem;
+        this.plexusContainer = plexusContainer;
+        this.runtimeInformation = runtimeInformation;
+    }
+
+    public Session getSession(MavenSession mavenSession) {
+        SessionData data = mavenSession.getRepositorySession().getData();
+        return (Session) data.computeIfAbsent(InternalSession.class, () -> newSession(mavenSession));
+    }
+
+    private Session newSession(MavenSession mavenSession) {
+        return new DefaultSession(
+                mavenSession, repositorySystem, null, mavenRepositorySystem, plexusContainer, runtimeInformation);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
new file mode 100644
index 0000000..39d1961
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsBuilder.java
@@ -0,0 +1,162 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.BuilderProblem;
+import org.apache.maven.api.services.SettingsBuilder;
+import org.apache.maven.api.services.SettingsBuilderException;
+import org.apache.maven.api.services.SettingsBuilderRequest;
+import org.apache.maven.api.services.SettingsBuilderResult;
+import org.apache.maven.api.services.Source;
+import org.apache.maven.api.settings.Settings;
+import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
+import org.apache.maven.settings.building.SettingsBuildingException;
+import org.apache.maven.settings.building.SettingsBuildingResult;
+import org.apache.maven.settings.building.SettingsProblem;
+import org.apache.maven.settings.building.SettingsSource;
+
+@Named
+@Singleton
+public class DefaultSettingsBuilder implements SettingsBuilder {
+
+    private final org.apache.maven.settings.building.SettingsBuilder builder;
+
+    @Inject
+    public DefaultSettingsBuilder(org.apache.maven.settings.building.SettingsBuilder builder) {
+        this.builder = builder;
+    }
+
+    @Nonnull
+    @Override
+    public SettingsBuilderResult build(SettingsBuilderRequest request)
+            throws SettingsBuilderException, IllegalArgumentException {
+        InternalSession session = InternalSession.from(request.getSession());
+        try {
+            DefaultSettingsBuildingRequest req = new DefaultSettingsBuildingRequest();
+            req.setUserProperties(toProperties(session.getUserProperties()));
+            req.setSystemProperties(toProperties(session.getSystemProperties()));
+            if (request.getGlobalSettingsSource().isPresent()) {
+                req.setGlobalSettingsSource(new MappedSettingsSource(
+                        request.getGlobalSettingsSource().get()));
+            }
+            if (request.getGlobalSettingsPath().isPresent()) {
+                req.setGlobalSettingsFile(request.getGlobalSettingsPath().get().toFile());
+            }
+            if (request.getUserSettingsSource().isPresent()) {
+                req.setUserSettingsSource(
+                        new MappedSettingsSource(request.getUserSettingsSource().get()));
+            }
+            if (request.getUserSettingsPath().isPresent()) {
+                req.setUserSettingsFile(request.getUserSettingsPath().get().toFile());
+            }
+            SettingsBuildingResult result = builder.build(req);
+            return new SettingsBuilderResult() {
+                @Override
+                public Settings getEffectiveSettings() {
+                    return result.getEffectiveSettings().getDelegate();
+                }
+
+                @Override
+                public List<BuilderProblem> getProblems() {
+                    return new MappedList<>(result.getProblems(), MappedBuilderProblem::new);
+                }
+            };
+        } catch (SettingsBuildingException e) {
+            throw new SettingsBuilderException("Unable to build settings", e);
+        }
+    }
+
+    private Properties toProperties(Map<String, String> map) {
+        Properties properties = new Properties();
+        properties.putAll(map);
+        return properties;
+    }
+
+    private static class MappedSettingsSource implements SettingsSource {
+        private final Source source;
+
+        MappedSettingsSource(Source source) {
+            this.source = source;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return source.openStream();
+        }
+
+        @Override
+        public String getLocation() {
+            return source.getLocation();
+        }
+    }
+
+    private static class MappedBuilderProblem implements BuilderProblem {
+        private final SettingsProblem problem;
+
+        MappedBuilderProblem(SettingsProblem problem) {
+            this.problem = problem;
+        }
+
+        @Override
+        public String getSource() {
+            return problem.getSource();
+        }
+
+        @Override
+        public int getLineNumber() {
+            return problem.getLineNumber();
+        }
+
+        @Override
+        public int getColumnNumber() {
+            return problem.getColumnNumber();
+        }
+
+        @Override
+        public String getLocation() {
+            return problem.getLocation();
+        }
+
+        @Override
+        public Exception getException() {
+            return problem.getException();
+        }
+
+        @Override
+        public String getMessage() {
+            return problem.getMessage();
+        }
+
+        @Override
+        public Severity getSeverity() {
+            return Severity.valueOf(problem.getSeverity().name());
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java
new file mode 100644
index 0000000..cb75d64
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSettingsXmlFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Objects;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.xml.SettingsXmlFactory;
+import org.apache.maven.api.services.xml.XmlReaderException;
+import org.apache.maven.api.services.xml.XmlReaderRequest;
+import org.apache.maven.api.services.xml.XmlWriterException;
+import org.apache.maven.api.services.xml.XmlWriterRequest;
+import org.apache.maven.api.settings.InputSource;
+import org.apache.maven.api.settings.Settings;
+import org.apache.maven.settings.v4.SettingsStaxReader;
+import org.apache.maven.settings.v4.SettingsStaxWriter;
+
+@Named
+@Singleton
+public class DefaultSettingsXmlFactory implements SettingsXmlFactory {
+    @Override
+    public Settings read(@Nonnull XmlReaderRequest request) throws XmlReaderException {
+        Objects.requireNonNull(request, "request can not be null");
+        Reader reader = request.getReader();
+        InputStream inputStream = request.getInputStream();
+        if (reader == null && inputStream == null) {
+            throw new IllegalArgumentException("reader or inputStream must be non null");
+        }
+        try {
+            InputSource source = null;
+            if (request.getModelId() != null || request.getLocation() != null) {
+                source = new InputSource(request.getLocation());
+            }
+            SettingsStaxReader xml = new SettingsStaxReader();
+            xml.setAddDefaultEntities(request.isAddDefaultEntities());
+            if (reader != null) {
+                return xml.read(reader, request.isStrict(), source);
+            } else {
+                return xml.read(inputStream, request.isStrict(), source);
+            }
+        } catch (Exception e) {
+            throw new XmlReaderException("Unable to read settings", e);
+        }
+    }
+
+    @Override
+    public void write(XmlWriterRequest<Settings> request) throws XmlWriterException {
+        Objects.requireNonNull(request, "request can not be null");
+        Settings content = Objects.requireNonNull(request.getContent(), "content can not be null");
+        OutputStream outputStream = request.getOutputStream();
+        Writer writer = request.getWriter();
+        if (writer == null && outputStream == null) {
+            throw new IllegalArgumentException("writer or outputStream must be non null");
+        }
+        try {
+            if (writer != null) {
+                new SettingsStaxWriter().write(writer, content);
+            } else {
+                new SettingsStaxWriter().write(outputStream, content);
+            }
+        } catch (Exception e) {
+            throw new XmlWriterException("Unable to write settings", e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSuperPomProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSuperPomProvider.java
new file mode 100644
index 0000000..51fd3a4
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultSuperPomProvider.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.services.SuperPomProvider;
+import org.apache.maven.api.services.SuperPomProviderException;
+
+@Named
+@Singleton
+public class DefaultSuperPomProvider implements SuperPomProvider {
+
+    private final org.apache.maven.model.superpom.SuperPomProvider provider;
+
+    @Inject
+    public DefaultSuperPomProvider(org.apache.maven.model.superpom.SuperPomProvider provider) {
+        this.provider = provider;
+    }
+
+    @Override
+    public Model getSuperPom(String version) {
+        try {
+            return provider.getSuperModel(version).getDelegate();
+        } catch (IllegalStateException e) {
+            throw new SuperPomProviderException("Could not retrieve super pom " + version, e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainManager.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainManager.java
new file mode 100644
index 0000000..b22f813
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainManager.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+import org.apache.maven.api.Session;
+import org.apache.maven.api.Toolchain;
+import org.apache.maven.api.services.ToolchainManager;
+import org.apache.maven.api.services.ToolchainManagerException;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.toolchain.DefaultToolchainManagerPrivate;
+import org.apache.maven.toolchain.MisconfiguredToolchainException;
+import org.apache.maven.toolchain.ToolchainPrivate;
+
+@Named
+@Singleton
+public class DefaultToolchainManager implements ToolchainManager {
+    private final DefaultToolchainManagerPrivate toolchainManagerPrivate;
+
+    @Inject
+    public DefaultToolchainManager(DefaultToolchainManagerPrivate toolchainManagerPrivate) {
+        this.toolchainManagerPrivate = toolchainManagerPrivate;
+    }
+
+    @Override
+    public List<Toolchain> getToolchains(Session session, String type, Map<String, String> requirements)
+            throws ToolchainManagerException {
+        MavenSession s = InternalSession.from(session).getMavenSession();
+        List<org.apache.maven.toolchain.Toolchain> toolchains =
+                toolchainManagerPrivate.getToolchains(s, type, requirements);
+        return new MappedList<>(toolchains, this::toToolchain);
+    }
+
+    @Override
+    public Optional<Toolchain> getToolchainFromBuildContext(Session session, String type)
+            throws ToolchainManagerException {
+        MavenSession s = InternalSession.from(session).getMavenSession();
+        return Optional.ofNullable(toolchainManagerPrivate.getToolchainFromBuildContext(type, s))
+                .map(this::toToolchain);
+    }
+
+    @Override
+    public List<Toolchain> getToolchainsForType(Session session, String type) throws ToolchainManagerException {
+        try {
+            MavenSession s = InternalSession.from(session).getMavenSession();
+            ToolchainPrivate[] toolchains = toolchainManagerPrivate.getToolchainsForType(type, s);
+            return new MappedList<>(Arrays.asList(toolchains), this::toToolchain);
+        } catch (MisconfiguredToolchainException e) {
+            throw new ToolchainManagerException("Unable to get toochains for type " + type, e);
+        }
+    }
+
+    @Override
+    public void storeToolchainToBuildContext(Session session, Toolchain toolchain) throws ToolchainManagerException {
+        MavenSession s = InternalSession.from(session).getMavenSession();
+        org.apache.maven.toolchain.ToolchainPrivate tc =
+                (org.apache.maven.toolchain.ToolchainPrivate) ((ToolchainWrapper) toolchain).toolchain;
+        toolchainManagerPrivate.storeToolchainToBuildContext(tc, s);
+    }
+
+    private Toolchain toToolchain(org.apache.maven.toolchain.Toolchain toolchain) {
+        return new ToolchainWrapper(toolchain);
+    }
+
+    private static class ToolchainWrapper implements Toolchain {
+        private final org.apache.maven.toolchain.Toolchain toolchain;
+
+        ToolchainWrapper(org.apache.maven.toolchain.Toolchain toolchain) {
+            this.toolchain = toolchain;
+        }
+
+        @Override
+        public String getType() {
+            return toolchain.getType();
+        }
+
+        @Override
+        public String findTool(String toolName) {
+            return toolchain.findTool(toolName);
+        }
+
+        @Override
+        public boolean matchesRequirements(Map<String, String> requirements) {
+            return ((ToolchainPrivate) toolchain).matchesRequirements(requirements);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java
new file mode 100644
index 0000000..cff334d
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsBuilder.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.List;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.BuilderProblem;
+import org.apache.maven.api.services.Source;
+import org.apache.maven.api.services.ToolchainsBuilder;
+import org.apache.maven.api.services.ToolchainsBuilderException;
+import org.apache.maven.api.services.ToolchainsBuilderRequest;
+import org.apache.maven.api.services.ToolchainsBuilderResult;
+import org.apache.maven.api.toolchain.PersistedToolchains;
+import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
+import org.apache.maven.toolchain.building.ToolchainsBuildingException;
+import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
+
+@Named
+@Singleton
+public class DefaultToolchainsBuilder implements ToolchainsBuilder {
+
+    private final org.apache.maven.toolchain.building.ToolchainsBuilder builder;
+
+    @Inject
+    public DefaultToolchainsBuilder(org.apache.maven.toolchain.building.ToolchainsBuilder builder) {
+        this.builder = builder;
+    }
+
+    @Nonnull
+    @Override
+    public ToolchainsBuilderResult build(ToolchainsBuilderRequest request)
+            throws ToolchainsBuilderException, IllegalArgumentException {
+        try {
+            DefaultToolchainsBuildingRequest req = new DefaultToolchainsBuildingRequest();
+            if (request.getGlobalToolchainsSource().isPresent()) {
+                req.setGlobalToolchainsSource(new MappedToolchainsSource(
+                        request.getGlobalToolchainsSource().get()));
+            } else if (request.getGlobalToolchainsPath().isPresent()) {
+                req.setGlobalToolchainsSource(new org.apache.maven.building.FileSource(
+                        request.getGlobalToolchainsPath().get().toFile()));
+            }
+            if (request.getUserToolchainsSource().isPresent()) {
+                req.setUserToolchainsSource(new MappedToolchainsSource(
+                        request.getUserToolchainsSource().get()));
+            } else if (request.getUserToolchainsPath().isPresent()) {
+                req.setUserToolchainsSource(new org.apache.maven.building.FileSource(
+                        request.getUserToolchainsPath().get().toFile()));
+            }
+            ToolchainsBuildingResult result = builder.build(req);
+            return new ToolchainsBuilderResult() {
+                @Override
+                public PersistedToolchains getEffectiveToolchains() {
+                    return result.getEffectiveToolchains().getDelegate();
+                }
+
+                @Override
+                public List<BuilderProblem> getProblems() {
+                    return new MappedList<>(result.getProblems(), MappedBuilderProblem::new);
+                }
+            };
+        } catch (ToolchainsBuildingException e) {
+            throw new ToolchainsBuilderException("Unable to build Toolchains", e);
+        }
+    }
+
+    private static class MappedToolchainsSource implements org.apache.maven.building.Source {
+        private final Source source;
+
+        MappedToolchainsSource(Source source) {
+            this.source = source;
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return source.openStream();
+        }
+
+        @Override
+        public String getLocation() {
+            return source.getLocation();
+        }
+    }
+
+    private static class MappedBuilderProblem implements BuilderProblem {
+        private final org.apache.maven.building.Problem problem;
+
+        MappedBuilderProblem(org.apache.maven.building.Problem problem) {
+            this.problem = problem;
+        }
+
+        @Override
+        public String getSource() {
+            return problem.getSource();
+        }
+
+        @Override
+        public int getLineNumber() {
+            return problem.getLineNumber();
+        }
+
+        @Override
+        public int getColumnNumber() {
+            return problem.getColumnNumber();
+        }
+
+        @Override
+        public String getLocation() {
+            return problem.getLocation();
+        }
+
+        @Override
+        public Exception getException() {
+            return problem.getException();
+        }
+
+        @Override
+        public String getMessage() {
+            return problem.getMessage();
+        }
+
+        @Override
+        public Severity getSeverity() {
+            return Severity.valueOf(problem.getSeverity().name());
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java
new file mode 100644
index 0000000..a39bacc
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultToolchainsXmlFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Objects;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.model.InputSource;
+import org.apache.maven.api.services.xml.ToolchainsXmlFactory;
+import org.apache.maven.api.services.xml.XmlReaderException;
+import org.apache.maven.api.services.xml.XmlReaderRequest;
+import org.apache.maven.api.services.xml.XmlWriterException;
+import org.apache.maven.api.services.xml.XmlWriterRequest;
+import org.apache.maven.api.toolchain.PersistedToolchains;
+import org.apache.maven.toolchain.v4.MavenToolchainsStaxReader;
+import org.apache.maven.toolchain.v4.MavenToolchainsStaxWriter;
+
+@Named
+@Singleton
+public class DefaultToolchainsXmlFactory implements ToolchainsXmlFactory {
+    @Override
+    public PersistedToolchains read(@Nonnull XmlReaderRequest request) throws XmlReaderException {
+        Objects.requireNonNull(request, "request can not be null");
+        Reader reader = request.getReader();
+        InputStream inputStream = request.getInputStream();
+        if (reader == null && inputStream == null) {
+            throw new IllegalArgumentException("reader or inputStream must be non null");
+        }
+        try {
+            InputSource source = null;
+            if (request.getModelId() != null || request.getLocation() != null) {
+                source = new InputSource(request.getModelId(), request.getLocation());
+            }
+            MavenToolchainsStaxReader xml = new MavenToolchainsStaxReader();
+            xml.setAddDefaultEntities(request.isAddDefaultEntities());
+            if (reader != null) {
+                return xml.read(reader, request.isStrict());
+            } else {
+                return xml.read(inputStream, request.isStrict());
+            }
+        } catch (Exception e) {
+            throw new XmlReaderException("Unable to read toolchains", e);
+        }
+    }
+
+    @Override
+    public void write(XmlWriterRequest<PersistedToolchains> request) throws XmlWriterException {
+        Objects.requireNonNull(request, "request can not be null");
+        PersistedToolchains content = Objects.requireNonNull(request.getContent(), "content can not be null");
+        OutputStream outputStream = request.getOutputStream();
+        Writer writer = request.getWriter();
+        if (writer == null && outputStream == null) {
+            throw new IllegalArgumentException("writer or outputStream must be non null");
+        }
+        try {
+            if (writer != null) {
+                new MavenToolchainsStaxWriter().write(writer, content);
+            } else {
+                new MavenToolchainsStaxWriter().write(outputStream, content);
+            }
+        } catch (Exception e) {
+            throw new XmlWriterException("Unable to write toolchains", e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java
new file mode 100644
index 0000000..c8e692c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransport.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Optional;
+
+import org.apache.maven.api.services.Transport;
+import org.eclipse.aether.spi.connector.transport.GetTask;
+import org.eclipse.aether.spi.connector.transport.PutTask;
+import org.eclipse.aether.spi.connector.transport.Transporter;
+
+import static java.util.Objects.requireNonNull;
+
+@Named
+@Singleton
+public class DefaultTransport implements Transport {
+    private final URI baseURI;
+    private final Transporter transporter;
+
+    public DefaultTransport(URI baseURI, Transporter transporter) {
+        this.baseURI = requireNonNull(baseURI);
+        this.transporter = requireNonNull(transporter);
+    }
+
+    @Override
+    public boolean get(URI relativeSource, Path target) {
+        requireNonNull(relativeSource, "relativeSource is null");
+        requireNonNull(target, "target is null");
+        if (relativeSource.isAbsolute()) {
+            throw new IllegalArgumentException("Supplied URI is not relative");
+        }
+        URI source = baseURI.resolve(relativeSource);
+        if (!source.toASCIIString().startsWith(baseURI.toASCIIString())) {
+            throw new IllegalArgumentException("Supplied relative URI escapes baseUrl");
+        }
+        GetTask getTask = new GetTask(source);
+        getTask.setDataFile(target.toFile());
+        try {
+            transporter.get(getTask);
+            return true;
+        } catch (Exception e) {
+            if (Transporter.ERROR_NOT_FOUND != transporter.classify(e)) {
+                throw new RuntimeException(e);
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public Optional<byte[]> getBytes(URI relativeSource) {
+        try {
+            Path tempPath = null;
+            try {
+                tempPath = Files.createTempFile("transport-get", "tmp");
+                if (get(relativeSource, tempPath)) {
+                    // TODO: check file size and prevent OOM?
+                    return Optional.of(Files.readAllBytes(tempPath));
+                }
+                return Optional.empty();
+            } finally {
+                if (tempPath != null) {
+                    Files.deleteIfExists(tempPath);
+                }
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    @Override
+    public Optional<String> getString(URI relativeSource, Charset charset) {
+        requireNonNull(charset, "charset is null");
+        Optional<byte[]> data = getBytes(relativeSource);
+        return data.map(bytes -> new String(bytes, charset));
+    }
+
+    @Override
+    public void put(Path source, URI relativeTarget) {
+        requireNonNull(source, "source is null");
+        requireNonNull(relativeTarget, "relativeTarget is null");
+        if (Files.isRegularFile(source)) {
+            throw new IllegalArgumentException("source file does not exist or is not a file");
+        }
+        if (relativeTarget.isAbsolute()) {
+            throw new IllegalArgumentException("Supplied URI is not relative");
+        }
+        URI target = baseURI.resolve(relativeTarget);
+        if (!target.toASCIIString().startsWith(baseURI.toASCIIString())) {
+            throw new IllegalArgumentException("Supplied relative URI escapes baseUrl");
+        }
+
+        PutTask putTask = new PutTask(target);
+        putTask.setDataFile(source.toFile());
+        try {
+            transporter.put(putTask);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void putBytes(byte[] source, URI relativeTarget) {
+        requireNonNull(source, "source is null");
+        try {
+            Path tempPath = null;
+            try {
+                tempPath = Files.createTempFile("transport-get", "tmp");
+                Files.write(tempPath, source);
+                put(tempPath, relativeTarget);
+            } finally {
+                if (tempPath != null) {
+                    Files.deleteIfExists(tempPath);
+                }
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    @Override
+    public void putString(String source, Charset charset, URI relativeTarget) {
+        requireNonNull(source, "source string is null");
+        requireNonNull(charset, "charset is null");
+        putBytes(source.getBytes(charset), relativeTarget);
+    }
+
+    @Override
+    public void close() {
+        transporter.close();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java
new file mode 100644
index 0000000..e3ba885
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTransportProvider.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.services.Transport;
+import org.apache.maven.api.services.TransportProvider;
+import org.apache.maven.api.services.TransportProviderException;
+import org.eclipse.aether.spi.connector.transport.TransporterProvider;
+import org.eclipse.aether.transfer.NoTransporterException;
+
+import static java.util.Objects.requireNonNull;
+
+@Named
+@Singleton
+public class DefaultTransportProvider implements TransportProvider {
+    private final org.eclipse.aether.spi.connector.transport.TransporterProvider transporterProvider;
+
+    @Inject
+    public DefaultTransportProvider(TransporterProvider transporterProvider) {
+        this.transporterProvider = requireNonNull(transporterProvider);
+    }
+
+    @Override
+    public Transport transport(Session session, RemoteRepository repository) {
+        try {
+            URI baseURI = new URI(repository.getUrl());
+            return new DefaultTransport(
+                    baseURI,
+                    transporterProvider.newTransporter(
+                            InternalSession.from(session).getSession(),
+                            ((DefaultRemoteRepository) repository).getRepository()));
+        } catch (URISyntaxException e) {
+            throw new TransportProviderException("Remote repository URL invalid", e);
+        } catch (NoTransporterException e) {
+            throw new TransportProviderException("Unsupported remote repository", e);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java
new file mode 100644
index 0000000..8a319de
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultType.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.eclipse.aether.artifact.ArtifactProperties;
+import org.eclipse.aether.artifact.ArtifactType;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+public class DefaultType implements Type, ArtifactType {
+    private final String extension;
+
+    private final String classifier;
+
+    private final DependencyProperties dependencyProperties;
+
+    public DefaultType(String id, String extension, String classifier, DependencyProperties dependencyProperties) {
+        nonNull(id, "null id");
+        this.extension = nonNull(extension, "null extension");
+        this.classifier = classifier;
+        nonNull(dependencyProperties, "null dependencyProperties");
+        HashMap<String, String> props = new HashMap<>(dependencyProperties.asMap());
+        props.put(ArtifactProperties.TYPE, id);
+        this.dependencyProperties = new DefaultDependencyProperties(props);
+    }
+
+    @Override
+    public String getId() {
+        return dependencyProperties.asMap().get(ArtifactProperties.TYPE);
+    }
+
+    @Override
+    public String getExtension() {
+        return extension;
+    }
+
+    @Override
+    public String getClassifier() {
+        return classifier;
+    }
+
+    @Override
+    public DependencyProperties getDependencyProperties() {
+        return dependencyProperties;
+    }
+
+    @Override
+    public Map<String, String> getProperties() {
+        return getDependencyProperties().asMap();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java
new file mode 100644
index 0000000..19e98fd
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultTypeRegistry.java
@@ -0,0 +1,98 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.TypeRegistry;
+import org.apache.maven.artifact.handler.ArtifactHandler;
+import org.apache.maven.artifact.handler.manager.LegacyArtifactHandlerManager;
+import org.apache.maven.eventspy.AbstractEventSpy;
+import org.apache.maven.execution.ExecutionEvent;
+
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultTypeRegistry extends AbstractEventSpy implements TypeRegistry {
+    private final Map<String, Type> types;
+
+    private final ConcurrentHashMap<String, Type> usedTypes;
+
+    private final ConcurrentHashMap<String, Type> legacyTypes;
+
+    private final LegacyArtifactHandlerManager manager;
+
+    @Inject
+    public DefaultTypeRegistry(Map<String, Type> types, LegacyArtifactHandlerManager manager) {
+        this.types = nonNull(types, "types");
+        this.usedTypes = new ConcurrentHashMap<>();
+        this.legacyTypes = new ConcurrentHashMap<>();
+        this.manager = nonNull(manager, "artifactHandlerManager");
+    }
+
+    @Override
+    public void onEvent(Object event) {
+        if (event instanceof ExecutionEvent) {
+            ExecutionEvent executionEvent = (ExecutionEvent) event;
+            if (executionEvent.getType() == ExecutionEvent.Type.SessionEnded) {
+                usedTypes.clear();
+                legacyTypes.clear();
+            }
+        }
+    }
+
+    @Override
+    @Nonnull
+    public Type getType(String id) {
+        nonNull(id, "null id");
+        return usedTypes.computeIfAbsent(id, i -> {
+            Type type = types.get(id);
+            if (type == null) {
+                // legacy types ALWAYS return type (AHM never returns null)
+                type = legacyTypes.computeIfAbsent(id, k -> {
+                    // Copy data as the ArtifactHandler is not immutable, but Type should be.
+                    ArtifactHandler handler = manager.getArtifactHandler(id);
+                    ArrayList<String> flags = new ArrayList<>();
+                    if (handler.isAddedToClasspath()) {
+                        flags.add(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT);
+                    }
+                    if (handler.isIncludesDependencies()) {
+                        flags.add(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES);
+                    }
+                    return new DefaultType(
+                            id,
+                            handler.getExtension(),
+                            handler.getClassifier(),
+                            new DefaultDependencyProperties(flags));
+                });
+            }
+            return type;
+        });
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java
new file mode 100644
index 0000000..28d6ca1
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultVersionParser.java
@@ -0,0 +1,137 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Objects;
+import java.util.regex.Pattern;
+
+import org.apache.maven.api.Version;
+import org.apache.maven.api.VersionRange;
+import org.apache.maven.api.services.VersionParser;
+import org.apache.maven.api.services.VersionParserException;
+import org.apache.maven.artifact.versioning.ArtifactVersion;
+import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+
+import static org.apache.maven.artifact.versioning.VersionRange.createFromVersionSpec;
+import static org.apache.maven.internal.impl.Utils.nonNull;
+
+@Named
+@Singleton
+public class DefaultVersionParser implements VersionParser {
+    private static final String SNAPSHOT = "SNAPSHOT";
+    private static final Pattern SNAPSHOT_TIMESTAMP = Pattern.compile("^(.*-)?([0-9]{8}\\.[0-9]{6}-[0-9]+)$");
+
+    @Override
+    public Version parseVersion(String version) {
+        return new DefaultVersion(new DefaultArtifactVersion(nonNull(version, "version")));
+    }
+
+    @Override
+    public VersionRange parseVersionRange(String range) {
+        try {
+            return new DefaultVersionRange(createFromVersionSpec(nonNull(range, "version")));
+        } catch (InvalidVersionSpecificationException e) {
+            throw new VersionParserException("Unable to parse version range: " + range, e);
+        }
+    }
+
+    @Override
+    public boolean isSnapshot(String version) {
+        return checkSnapshot(version);
+    }
+
+    static boolean checkSnapshot(String version) {
+        return version.endsWith(SNAPSHOT) || SNAPSHOT_TIMESTAMP.matcher(version).matches();
+    }
+
+    static class DefaultVersion implements Version {
+        private final ArtifactVersion delegate;
+
+        DefaultVersion(ArtifactVersion delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public int compareTo(Version o) {
+            if (o instanceof DefaultVersion) {
+                return delegate.compareTo(((DefaultVersion) o).delegate);
+            } else {
+                return delegate.compareTo(new DefaultArtifactVersion(o.toString()));
+            }
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+            DefaultVersion that = (DefaultVersion) o;
+            return delegate.equals(that.delegate);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(delegate);
+        }
+
+        @Override
+        public String asString() {
+            return delegate.toString();
+        }
+
+        @Override
+        public String toString() {
+            return asString();
+        }
+    }
+
+    static class DefaultVersionRange implements VersionRange {
+        private final org.apache.maven.artifact.versioning.VersionRange delegate;
+
+        DefaultVersionRange(org.apache.maven.artifact.versioning.VersionRange delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        public boolean contains(Version version) {
+            if (version instanceof DefaultVersion) {
+                return delegate.containsVersion(((DefaultVersion) version).delegate);
+            } else {
+                return delegate.containsVersion(new DefaultArtifactVersion(version.toString()));
+            }
+        }
+
+        @Override
+        public String asString() {
+            return delegate.toString();
+        }
+
+        @Override
+        public String toString() {
+            return asString();
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/EventSpyImpl.java b/maven-core/src/main/java/org/apache/maven/internal/impl/EventSpyImpl.java
new file mode 100644
index 0000000..6d1dd78
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/EventSpyImpl.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Collection;
+
+import org.apache.maven.api.Event;
+import org.apache.maven.api.Listener;
+import org.apache.maven.eventspy.EventSpy;
+import org.apache.maven.execution.ExecutionEvent;
+
+@Named
+@Singleton
+public class EventSpyImpl implements EventSpy {
+
+    private DefaultSessionFactory sessionFactory;
+
+    @Inject
+    EventSpyImpl(DefaultSessionFactory sessionFactory) {
+        this.sessionFactory = sessionFactory;
+    }
+
+    @Override
+    public void init(Context context) throws Exception {}
+
+    @Override
+    public void onEvent(Object arg) throws Exception {
+        if (arg instanceof ExecutionEvent) {
+            ExecutionEvent ee = (ExecutionEvent) arg;
+            InternalSession session = InternalSession.from(sessionFactory.getSession(ee.getSession()));
+            Collection<Listener> listeners = session.getListeners();
+            if (!listeners.isEmpty()) {
+                Event event = new DefaultEvent(session, ee);
+                for (Listener listener : listeners) {
+                    listener.onEvent(event);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void close() throws Exception {}
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/InternalSession.java b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalSession.java
new file mode 100644
index 0000000..d13acfb
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/InternalSession.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.DependencyCoordinate;
+import org.apache.maven.api.LocalRepository;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.execution.MavenSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+
+import static org.apache.maven.internal.impl.Utils.cast;
+
+public interface InternalSession extends Session {
+
+    static InternalSession from(Session session) {
+        return cast(InternalSession.class, session, "session should be an " + InternalSession.class);
+    }
+
+    RemoteRepository getRemoteRepository(org.eclipse.aether.repository.RemoteRepository repository);
+
+    Node getNode(org.eclipse.aether.graph.DependencyNode node);
+
+    Node getNode(org.eclipse.aether.graph.DependencyNode node, boolean verbose);
+
+    @Nonnull
+    Artifact getArtifact(@Nonnull org.eclipse.aether.artifact.Artifact artifact);
+
+    @Nonnull
+    Dependency getDependency(@Nonnull org.eclipse.aether.graph.Dependency dependency);
+
+    List<Project> getProjects(List<org.apache.maven.project.MavenProject> projects);
+
+    Project getProject(org.apache.maven.project.MavenProject project);
+
+    List<org.eclipse.aether.repository.RemoteRepository> toRepositories(List<RemoteRepository> repositories);
+
+    org.eclipse.aether.repository.RemoteRepository toRepository(RemoteRepository repository);
+
+    org.eclipse.aether.repository.LocalRepository toRepository(LocalRepository repository);
+
+    List<org.apache.maven.artifact.repository.ArtifactRepository> toArtifactRepositories(
+            List<RemoteRepository> repositories);
+
+    org.apache.maven.artifact.repository.ArtifactRepository toArtifactRepository(RemoteRepository repository);
+
+    List<org.eclipse.aether.graph.Dependency> toDependencies(Collection<DependencyCoordinate> dependencies);
+
+    org.eclipse.aether.graph.Dependency toDependency(DependencyCoordinate dependency);
+
+    List<org.eclipse.aether.artifact.Artifact> toArtifacts(Collection<Artifact> artifacts);
+
+    org.eclipse.aether.artifact.Artifact toArtifact(Artifact artifact);
+
+    org.eclipse.aether.artifact.Artifact toArtifact(ArtifactCoordinate coord);
+
+    MavenSession getMavenSession();
+
+    RepositorySystemSession getSession();
+
+    RepositorySystem getRepositorySystem();
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/MappedCollection.java b/maven-core/src/main/java/org/apache/maven/internal/impl/MappedCollection.java
new file mode 100644
index 0000000..3492e9c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/MappedCollection.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.AbstractCollection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.function.Function;
+
+public class MappedCollection<U, V> extends AbstractCollection<U> {
+    private final Collection<V> list;
+    private final Function<V, U> mapper;
+
+    public MappedCollection(Collection<V> list, Function<V, U> mapper) {
+        this.list = list;
+        this.mapper = mapper;
+    }
+
+    @Override
+    public Iterator<U> iterator() {
+        Iterator<V> it = list.iterator();
+        return new Iterator<U>() {
+            @Override
+            public boolean hasNext() {
+                return it.hasNext();
+            }
+
+            @Override
+            public U next() {
+                return mapper.apply(it.next());
+            }
+        };
+    }
+
+    @Override
+    public int size() {
+        return list.size();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/MappedList.java b/maven-core/src/main/java/org/apache/maven/internal/impl/MappedList.java
new file mode 100644
index 0000000..78e5903
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/MappedList.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.AbstractList;
+import java.util.List;
+import java.util.function.Function;
+
+public class MappedList<U, V> extends AbstractList<U> {
+    private final List<V> list;
+    private final Function<V, U> mapper;
+
+    public MappedList(List<V> list, Function<V, U> mapper) {
+        this.list = list;
+        this.mapper = mapper;
+    }
+
+    @Override
+    public U get(int index) {
+        return mapper.apply(list.get(index));
+    }
+
+    @Override
+    public int size() {
+        return list.size();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java b/maven-core/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java
new file mode 100644
index 0000000..dbb3835
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/PropertiesAsMap.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+class PropertiesAsMap extends AbstractMap<String, String> {
+
+    private final Map<Object, Object> properties;
+
+    PropertiesAsMap(Map<Object, Object> properties) {
+        this.properties = properties;
+    }
+
+    @Override
+    public Set<Entry<String, String>> entrySet() {
+        return new AbstractSet<Entry<String, String>>() {
+            @Override
+            public Iterator<Entry<String, String>> iterator() {
+                Iterator<Entry<Object, Object>> iterator = properties.entrySet().iterator();
+                return new Iterator<Entry<String, String>>() {
+                    Entry<String, String> next;
+
+                    {
+                        advance();
+                    }
+
+                    private void advance() {
+                        next = null;
+                        while (iterator.hasNext()) {
+                            Entry<Object, Object> e = iterator.next();
+                            if (PropertiesAsMap.matches(e)) {
+                                next = new Entry<String, String>() {
+                                    @Override
+                                    public String getKey() {
+                                        return (String) e.getKey();
+                                    }
+
+                                    @Override
+                                    public String getValue() {
+                                        return (String) e.getValue();
+                                    }
+
+                                    @Override
+                                    public String setValue(String value) {
+                                        return (String) e.setValue(value);
+                                    }
+                                };
+                                break;
+                            }
+                        }
+                    }
+
+                    @Override
+                    public boolean hasNext() {
+                        return next != null;
+                    }
+
+                    @Override
+                    public Entry<String, String> next() {
+                        Entry<String, String> item = next;
+                        if (item == null) {
+                            throw new NoSuchElementException();
+                        }
+                        advance();
+                        return item;
+                    }
+                };
+            }
+
+            @Override
+            public int size() {
+                return (int) properties.entrySet().stream()
+                        .filter(PropertiesAsMap::matches)
+                        .count();
+            }
+        };
+    }
+
+    private static boolean matches(Entry<Object, Object> entry) {
+        return entry.getKey() instanceof String && entry.getValue() instanceof String;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/Utils.java b/maven-core/src/main/java/org/apache/maven/internal/impl/Utils.java
new file mode 100644
index 0000000..e96a807
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/Utils.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+class Utils {
+    static <T> T nonNull(T t) {
+        if (t == null) {
+            throw new IllegalArgumentException();
+        }
+        return t;
+    }
+
+    static <T> T nonNull(T t, String message) {
+        if (t == null) {
+            throw new IllegalArgumentException(message);
+        }
+        return t;
+    }
+
+    static <T> T cast(Class<T> clazz, Object o, String message) {
+        if (!clazz.isInstance(o)) {
+            throw new IllegalArgumentException(message);
+        }
+        return clazz.cast(o);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/WrapperNode.java b/maven-core/src/main/java/org/apache/maven/internal/impl/WrapperNode.java
new file mode 100644
index 0000000..66ead7d
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/WrapperNode.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.apache.maven.api.Dependency;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.RemoteRepository;
+import org.apache.maven.api.annotations.Nonnull;
+import org.eclipse.aether.graph.DependencyNode;
+
+class WrapperNode extends AbstractNode {
+    protected final Node delegate;
+    protected final List<Node> children;
+
+    WrapperNode(Node delegate, List<Node> children) {
+        this.delegate = delegate;
+        this.children = children;
+    }
+
+    @Override
+    DependencyNode getDependencyNode() {
+        return Utils.cast(AbstractNode.class, delegate, "delegate is not an instance of AbstractNode")
+                .getDependencyNode();
+    }
+
+    @Override
+    public List<Node> getChildren() {
+        return children;
+    }
+
+    @Override
+    public Dependency getDependency() {
+        return delegate.getDependency();
+    }
+
+    @Override
+    @Nonnull
+    public List<RemoteRepository> getRemoteRepositories() {
+        return delegate.getRemoteRepositories();
+    }
+
+    @Override
+    @Nonnull
+    public Optional<RemoteRepository> getRepository() {
+        return delegate.getRepository();
+    }
+
+    @Override
+    @Nonnull
+    public String asString() {
+        return delegate.asString();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java
new file mode 100644
index 0000000..29d87cc
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/BomTypeProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(BomTypeProvider.NAME)
+@Singleton
+public class BomTypeProvider implements Provider<Type> {
+    public static final String NAME = "bom";
+
+    private final Type type;
+
+    public BomTypeProvider() {
+        this.type = new DefaultType(NAME, "pom", null, new DefaultDependencyProperties());
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java
new file mode 100644
index 0000000..2ceb095
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EarTypeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(EarTypeProvider.NAME)
+@Singleton
+public class EarTypeProvider implements Provider<Type> {
+    public static final String NAME = "ear";
+
+    private final Type type;
+
+    public EarTypeProvider() {
+        this.type = new DefaultType(
+                NAME, "ear", null, new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java
new file mode 100644
index 0000000..39c8483
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbClientTypeProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(EjbClientTypeProvider.NAME)
+@Singleton
+public class EjbClientTypeProvider implements Provider<Type> {
+    public static final String NAME = "ejb-client";
+
+    private final Type type;
+
+    public EjbClientTypeProvider() {
+        this.type = new DefaultType(
+                NAME,
+                "jar",
+                "client",
+                new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java
new file mode 100644
index 0000000..5eb237d
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/EjbTypeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(EjbTypeProvider.NAME)
+@Singleton
+public class EjbTypeProvider implements Provider<Type> {
+    public static final String NAME = "ejb";
+
+    private final Type type;
+
+    public EjbTypeProvider() {
+        this.type = new DefaultType(
+                NAME, "jar", null, new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java
new file mode 100644
index 0000000..4e4cc36
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JarTypeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(JarTypeProvider.NAME)
+@Singleton
+public class JarTypeProvider implements Provider<Type> {
+    public static final String NAME = "jar";
+
+    private final Type type;
+
+    public JarTypeProvider() {
+        this.type = new DefaultType(
+                NAME, "jar", null, new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java
new file mode 100644
index 0000000..7a0d982
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavaSourceTypeProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(JavaSourceTypeProvider.NAME)
+@Singleton
+public class JavaSourceTypeProvider implements Provider<Type> {
+    public static final String NAME = "java-source";
+
+    private final Type type;
+
+    public JavaSourceTypeProvider() {
+        this.type = new DefaultType(NAME, "jar", "sources", new DefaultDependencyProperties());
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java
new file mode 100644
index 0000000..d4401cc
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/JavadocTypeProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(JavadocTypeProvider.NAME)
+@Singleton
+public class JavadocTypeProvider implements Provider<Type> {
+    public static final String NAME = "javadoc";
+
+    private final Type type;
+
+    public JavadocTypeProvider() {
+        this.type = new DefaultType(
+                NAME,
+                "jar",
+                "javadoc",
+                new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java
new file mode 100644
index 0000000..4fd2990
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/MavenPluginTypeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(MavenPluginTypeProvider.NAME)
+@Singleton
+public class MavenPluginTypeProvider implements Provider<Type> {
+    public static final String NAME = "maven-plugin";
+
+    private final Type type;
+
+    public MavenPluginTypeProvider() {
+        this.type = new DefaultType(
+                NAME, "jar", null, new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java
new file mode 100644
index 0000000..64b8ad7
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/ParTypeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(ParTypeProvider.NAME)
+@Singleton
+public class ParTypeProvider implements Provider<Type> {
+    public static final String NAME = "par";
+
+    private final Type type;
+
+    public ParTypeProvider() {
+        this.type = new DefaultType(
+                NAME, "par", null, new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java
new file mode 100644
index 0000000..4b1afe6
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/PomTypeProvider.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(PomTypeProvider.NAME)
+@Singleton
+public class PomTypeProvider implements Provider<Type> {
+    public static final String NAME = "pom";
+
+    private final Type type;
+
+    public PomTypeProvider() {
+        this.type = new DefaultType(NAME, "pom", null, new DefaultDependencyProperties());
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java
new file mode 100644
index 0000000..51267a5
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/RarTypeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(RarTypeProvider.NAME)
+@Singleton
+public class RarTypeProvider implements Provider<Type> {
+    public static final String NAME = "rar";
+
+    private final Type type;
+
+    public RarTypeProvider() {
+        this.type = new DefaultType(
+                NAME, "rar", null, new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java
new file mode 100644
index 0000000..14ccf92
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/TestJarTypeProvider.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(TestJarTypeProvider.NAME)
+@Singleton
+public class TestJarTypeProvider implements Provider<Type> {
+    public static final String NAME = "test-jar";
+
+    private final Type type;
+
+    public TestJarTypeProvider() {
+        this.type = new DefaultType(
+                NAME,
+                "jar",
+                "tests",
+                new DefaultDependencyProperties(DependencyProperties.FLAG_CLASS_PATH_CONSTITUENT));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java
new file mode 100644
index 0000000..c382f08
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/impl/types/WarTypeProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl.types;
+
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.DependencyProperties;
+import org.apache.maven.api.Type;
+import org.apache.maven.internal.impl.DefaultDependencyProperties;
+import org.apache.maven.internal.impl.DefaultType;
+
+@Named(WarTypeProvider.NAME)
+@Singleton
+public class WarTypeProvider implements Provider<Type> {
+    public static final String NAME = "war";
+
+    private final Type type;
+
+    public WarTypeProvider() {
+        this.type = new DefaultType(
+                NAME, "war", null, new DefaultDependencyProperties(DependencyProperties.FLAG_INCLUDES_DEPENDENCIES));
+    }
+
+    @Override
+    public Type get() {
+        return type;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformer.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformer.java
new file mode 100644
index 0000000..ef2901a
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/ConsumerPomArtifactTransformer.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation;
+
+import java.io.IOException;
+
+import org.apache.maven.project.MavenProject;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.deployment.DeployRequest;
+import org.eclipse.aether.installation.InstallRequest;
+
+/**
+ * Consumer POM transformer.
+ *
+ * @since TBD
+ */
+public interface ConsumerPomArtifactTransformer {
+
+    InstallRequest remapInstallArtifacts(RepositorySystemSession session, InstallRequest request);
+
+    DeployRequest remapDeployArtifacts(RepositorySystemSession session, DeployRequest request);
+
+    void injectTransformedArtifacts(RepositorySystemSession repositorySession, MavenProject currentProject)
+            throws IOException;
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/TransformationFailedException.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/TransformationFailedException.java
new file mode 100644
index 0000000..c45dd75
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/TransformationFailedException.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation;
+
+/**
+ * Exception that may be thrown by the {@link org.apache.maven.artifact.Artifact#getFile()}
+ * implementation.
+ */
+public class TransformationFailedException extends RuntimeException {
+
+    public TransformationFailedException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilder.java
new file mode 100644
index 0000000..f001fdd
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilder.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation.impl;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.nio.file.Path;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * This interface is not public and the purpose is to allow easy unit testing
+ * of {@link DefaultConsumerPomArtifactTransformer}.
+ */
+interface ConsumerPomBuilder {
+
+    Model build(RepositorySystemSession session, MavenProject project, Path src)
+            throws ModelBuildingException, ComponentLookupException, IOException, XMLStreamException;
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomArtifactTransformer.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomArtifactTransformer.java
new file mode 100644
index 0000000..569ce22
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomArtifactTransformer.java
@@ -0,0 +1,207 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation.impl;
+
+import javax.annotation.PreDestroy;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+import org.apache.maven.api.feature.Features;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.internal.transformation.ConsumerPomArtifactTransformer;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.model.v4.MavenStaxWriter;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.artifact.ProjectArtifact;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.artifact.DefaultArtifact;
+import org.eclipse.aether.deployment.DeployRequest;
+import org.eclipse.aether.installation.InstallRequest;
+
+/**
+ * Consumer POM transformer.
+ *
+ * @since TBD
+ */
+@Singleton
+@Named("consumer-pom")
+class DefaultConsumerPomArtifactTransformer implements ConsumerPomArtifactTransformer {
+
+    private static final String CONSUMER_POM_CLASSIFIER = "consumer";
+
+    private static final String BUILD_POM_CLASSIFIER = "build";
+
+    private static final String NAMESPACE_FORMAT = "http://maven.apache.org/POM/%s";
+
+    private static final String SCHEMA_LOCATION_FORMAT = "https://maven.apache.org/xsd/maven-%s.xsd";
+
+    private final Set<Path> toDelete = new CopyOnWriteArraySet<>();
+
+    private final ConsumerPomBuilder builder;
+
+    @Inject
+    DefaultConsumerPomArtifactTransformer(ConsumerPomBuilder builder) {
+        this.builder = builder;
+    }
+
+    @SuppressWarnings("deprecation")
+    public void injectTransformedArtifacts(RepositorySystemSession session, MavenProject project) throws IOException {
+        if (project.getFile() == null) {
+            // If there is no build POM there is no reason to inject artifacts for the consumer POM.
+            return;
+        }
+        if (Features.buildConsumer(session.getUserProperties())) {
+            Path buildDir =
+                    project.getBuild() != null ? Paths.get(project.getBuild().getDirectory()) : null;
+            if (buildDir != null) {
+                Files.createDirectories(buildDir);
+            }
+            Path consumer = buildDir != null
+                    ? Files.createTempFile(buildDir, CONSUMER_POM_CLASSIFIER + "-", ".pom")
+                    : Files.createTempFile(CONSUMER_POM_CLASSIFIER + "-", ".pom");
+            deferDeleteFile(consumer);
+
+            project.addAttachedArtifact(createConsumerPomArtifact(project, consumer, session));
+        } else if (project.getModel().getDelegate().isRoot()) {
+            throw new IllegalStateException(
+                    "The use of the root attribute on the model requires the buildconsumer feature to be active");
+        }
+    }
+
+    TransformedArtifact createConsumerPomArtifact(
+            MavenProject project, Path consumer, RepositorySystemSession session) {
+        return new TransformedArtifact(
+                this,
+                project,
+                consumer,
+                session,
+                new ProjectArtifact(project),
+                () -> project.getFile().toPath(),
+                CONSUMER_POM_CLASSIFIER,
+                "pom");
+    }
+
+    void transform(MavenProject project, RepositorySystemSession session, Path src, Path tgt)
+            throws ModelBuildingException, ComponentLookupException, XMLStreamException, IOException {
+        Model model = builder.build(session, project, src);
+        write(model, tgt);
+    }
+
+    private void deferDeleteFile(Path generatedFile) {
+        toDelete.add(generatedFile.toAbsolutePath());
+    }
+
+    @PreDestroy
+    private void doDeleteFiles() {
+        for (Path file : toDelete) {
+            try {
+                Files.delete(file);
+            } catch (IOException e) {
+                // ignore, we did our best...
+            }
+        }
+    }
+
+    public InstallRequest remapInstallArtifacts(RepositorySystemSession session, InstallRequest request) {
+        if (Features.buildConsumer(session.getUserProperties()) && consumerPomPresent(request.getArtifacts())) {
+            request.setArtifacts(replacePom(request.getArtifacts()));
+        }
+        return request;
+    }
+
+    public DeployRequest remapDeployArtifacts(RepositorySystemSession session, DeployRequest request) {
+        if (Features.buildConsumer(session.getUserProperties()) && consumerPomPresent(request.getArtifacts())) {
+            request.setArtifacts(replacePom(request.getArtifacts()));
+        }
+        return request;
+    }
+
+    private boolean consumerPomPresent(Collection<Artifact> artifacts) {
+        return artifacts.stream()
+                .anyMatch(a -> "pom".equals(a.getExtension()) && CONSUMER_POM_CLASSIFIER.equals(a.getClassifier()));
+    }
+
+    private Collection<Artifact> replacePom(Collection<Artifact> artifacts) {
+        List<Artifact> consumers = new ArrayList<>();
+        List<Artifact> mains = new ArrayList<>();
+        for (Artifact artifact : artifacts) {
+            if ("pom".equals(artifact.getExtension()) || artifact.getExtension().startsWith("pom.")) {
+                if (CONSUMER_POM_CLASSIFIER.equals(artifact.getClassifier())) {
+                    consumers.add(artifact);
+                } else if ("".equals(artifact.getClassifier())) {
+                    mains.add(artifact);
+                }
+            }
+        }
+        if (!mains.isEmpty() && !consumers.isEmpty()) {
+            ArrayList<Artifact> result = new ArrayList<>(artifacts);
+            for (Artifact main : mains) {
+                result.remove(main);
+                result.add(new DefaultArtifact(
+                        main.getGroupId(),
+                        main.getArtifactId(),
+                        BUILD_POM_CLASSIFIER,
+                        main.getExtension(),
+                        main.getVersion(),
+                        main.getProperties(),
+                        main.getFile()));
+            }
+            for (Artifact consumer : consumers) {
+                result.remove(consumer);
+                result.add(new DefaultArtifact(
+                        consumer.getGroupId(),
+                        consumer.getArtifactId(),
+                        "",
+                        consumer.getExtension(),
+                        consumer.getVersion(),
+                        consumer.getProperties(),
+                        consumer.getFile()));
+            }
+            artifacts = result;
+        }
+        return artifacts;
+    }
+
+    void write(Model model, Path dest) throws IOException, XMLStreamException {
+        String version = model.getModelVersion();
+        Files.createDirectories(dest.getParent());
+        try (Writer w = Files.newBufferedWriter(dest)) {
+            MavenStaxWriter writer = new MavenStaxWriter();
+            writer.setNamespace(String.format(NAMESPACE_FORMAT, version));
+            writer.setSchemaLocation(String.format(SCHEMA_LOCATION_FORMAT, version));
+            writer.setAddLocationInformation(false);
+            writer.write(w, model);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
new file mode 100644
index 0000000..f825cd1
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
@@ -0,0 +1,257 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation.impl;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.DistributionManagement;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.ModelBase;
+import org.apache.maven.api.model.Profile;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.model.building.DefaultModelBuilder;
+import org.apache.maven.model.building.DefaultModelBuilderFactory;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.ModelBuildingResult;
+import org.apache.maven.model.building.ModelProblemCollector;
+import org.apache.maven.model.building.ModelProcessor;
+import org.apache.maven.model.composition.DependencyManagementImporter;
+import org.apache.maven.model.inheritance.InheritanceAssembler;
+import org.apache.maven.model.interpolation.ModelInterpolator;
+import org.apache.maven.model.management.DependencyManagementInjector;
+import org.apache.maven.model.management.PluginManagementInjector;
+import org.apache.maven.model.normalization.ModelNormalizer;
+import org.apache.maven.model.path.ModelPathTranslator;
+import org.apache.maven.model.path.ModelUrlNormalizer;
+import org.apache.maven.model.plugin.LifecycleBindingsInjector;
+import org.apache.maven.model.plugin.PluginConfigurationExpander;
+import org.apache.maven.model.plugin.ReportConfigurationExpander;
+import org.apache.maven.model.profile.DefaultProfileSelector;
+import org.apache.maven.model.profile.ProfileActivationContext;
+import org.apache.maven.model.profile.ProfileInjector;
+import org.apache.maven.model.profile.ProfileSelector;
+import org.apache.maven.model.superpom.SuperPomProvider;
+import org.apache.maven.model.v4.MavenModelVersion;
+import org.apache.maven.model.validation.ModelValidator;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.project.ProjectBuildingRequest;
+import org.apache.maven.project.ProjectModelResolver;
+import org.apache.maven.repository.internal.ModelCacheFactory;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.impl.RemoteRepositoryManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Named
+class DefaultConsumerPomBuilder implements ConsumerPomBuilder {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultConsumerPomBuilder.class);
+
+    private static final String BOM_PACKAGING = "bom";
+
+    public static final String POM_PACKAGING = "pom";
+
+    @Inject
+    PlexusContainer container;
+
+    @Inject
+    ModelCacheFactory modelCacheFactory;
+
+    public Model build(RepositorySystemSession session, MavenProject project, Path src)
+            throws ModelBuildingException, ComponentLookupException {
+        Model model = project.getModel().getDelegate();
+        String packaging = model.getPackaging();
+        String originalPackaging = project.getOriginalModel().getPackaging();
+        if (POM_PACKAGING.equals(packaging) && !BOM_PACKAGING.equals(originalPackaging)) {
+            return buildPom(session, project, src);
+        } else {
+            return buildNonPom(session, project, src);
+        }
+    }
+
+    protected Model buildPom(RepositorySystemSession session, MavenProject project, Path src)
+            throws ModelBuildingException, ComponentLookupException {
+        ModelBuildingResult result = buildModel(session, project, src);
+        Model model = result.getRawModel().getDelegate();
+        return transform(model, project);
+    }
+
+    protected Model buildNonPom(RepositorySystemSession session, MavenProject project, Path src)
+            throws ModelBuildingException, ComponentLookupException {
+        ModelBuildingResult result = buildModel(session, project, src);
+        Model model = result.getEffectiveModel().getDelegate();
+        return transform(model, project);
+    }
+
+    private ModelBuildingResult buildModel(RepositorySystemSession session, MavenProject project, Path src)
+            throws ModelBuildingException, ComponentLookupException {
+        ProfileSelector customSelector = new DefaultProfileSelector() {
+            @Override
+            public List<Profile> getActiveProfilesV4(
+                    Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems) {
+                return new ArrayList<>();
+            }
+        };
+        DefaultModelBuilder modelBuilder = new DefaultModelBuilderFactory()
+                .setProfileSelector(customSelector)
+                // apply currently active ModelProcessor etc. to support extensions like jgitver
+                .setProfileInjector(lookup(ProfileInjector.class))
+                .setInheritanceAssembler(lookup(InheritanceAssembler.class))
+                .setDependencyManagementImporter(lookup(DependencyManagementImporter.class))
+                .setDependencyManagementInjector(lookup(DependencyManagementInjector.class))
+                .setLifecycleBindingsInjector(lookup(LifecycleBindingsInjector.class))
+                .setModelInterpolator(lookup(ModelInterpolator.class))
+                .setModelNormalizer(lookup(ModelNormalizer.class))
+                .setModelPathTranslator(lookup(ModelPathTranslator.class))
+                .setModelProcessor(lookup(ModelProcessor.class))
+                .setModelUrlNormalizer(lookup(ModelUrlNormalizer.class))
+                .setModelValidator(lookup(ModelValidator.class))
+                .setPluginConfigurationExpander(lookup(PluginConfigurationExpander.class))
+                .setPluginManagementInjector(lookup(PluginManagementInjector.class))
+                .setReportConfigurationExpander(lookup(ReportConfigurationExpander.class))
+                .setSuperPomProvider(lookup(SuperPomProvider.class))
+                .newInstance();
+        DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
+        try {
+            request.setRootDirectory(project.getRootDirectory());
+        } catch (IllegalStateException e) {
+            // ignore if we don't have a root directory
+        }
+        request.setPomFile(src.toFile());
+        request.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+        request.setLocationTracking(false);
+        request.setModelResolver(new ProjectModelResolver(
+                session,
+                new RequestTrace(null),
+                lookup(RepositorySystem.class),
+                lookup(RemoteRepositoryManager.class),
+                project.getRemoteProjectRepositories(),
+                ProjectBuildingRequest.RepositoryMerging.POM_DOMINANT,
+                null));
+        request.setTransformerContextBuilder(modelBuilder.newTransformerContextBuilder());
+        request.setSystemProperties(toProperties(session.getSystemProperties()));
+        request.setUserProperties(toProperties(session.getUserProperties()));
+        request.setModelCache(modelCacheFactory.createCache(session));
+        return modelBuilder.build(request);
+    }
+
+    private Properties toProperties(Map<String, String> map) {
+        Properties props = new Properties();
+        props.putAll(map);
+        return props;
+    }
+
+    private <T> T lookup(Class<T> clazz) throws ComponentLookupException {
+        return container.lookup(clazz);
+    }
+
+    static Model transform(Model model, MavenProject project) {
+        String packaging = model.getPackaging();
+        if (POM_PACKAGING.equals(packaging)) {
+            // raw to consumer transform
+            model = model.withRoot(false).withModules(null);
+            if (model.getParent() != null) {
+                model = model.withParent(model.getParent().withRelativePath(null));
+            }
+
+            if (!model.isPreserveModelVersion()) {
+                model = model.withPreserveModelVersion(false);
+                String modelVersion = new MavenModelVersion().getModelVersion(model);
+                model = model.withModelVersion(modelVersion);
+            }
+        } else if (BOM_PACKAGING.equals(packaging)) {
+            DependencyManagement dependencyManagement =
+                    project.getOriginalModel().getDependencyManagement().getDelegate();
+            List<Dependency> dependencies = new ArrayList<>();
+            String version = model.getVersion();
+
+            dependencyManagement
+                    .getDependencies()
+                    .forEach((dependency) -> dependencies.add(dependency.withVersion(version)));
+            Model.Builder builder = prune(
+                    Model.newBuilder(model, true)
+                            .preserveModelVersion(false)
+                            .root(false)
+                            .parent(null)
+                            .dependencyManagement(dependencyManagement.withDependencies(dependencies))
+                            .build(null),
+                    model);
+            builder.packaging(POM_PACKAGING);
+            builder.profiles(model.getProfiles().stream()
+                    .map(p -> prune(Profile.newBuilder(p, true), p).build())
+                    .collect(Collectors.toList()));
+
+            model = builder.build();
+            String modelVersion = new MavenModelVersion().getModelVersion(model);
+            model = model.withModelVersion(modelVersion);
+        } else {
+            Model.Builder builder = prune(
+                    Model.newBuilder(model, true)
+                            .preserveModelVersion(false)
+                            .root(false)
+                            .parent(null)
+                            .build(null),
+                    model);
+            builder.profiles(model.getProfiles().stream()
+                    .map(p -> prune(Profile.newBuilder(p, true), p).build())
+                    .collect(Collectors.toList()));
+            model = builder.build();
+            String modelVersion = new MavenModelVersion().getModelVersion(model);
+            model = model.withModelVersion(modelVersion);
+        }
+        return model;
+    }
+
+    private static <T extends ModelBase.Builder> T prune(T builder, ModelBase model) {
+        builder.properties(null).reporting(null);
+        if (model.getDistributionManagement() != null
+                && model.getDistributionManagement().getRelocation() != null) {
+            // keep relocation only
+            builder.distributionManagement(DistributionManagement.newBuilder()
+                    .relocation(model.getDistributionManagement().getRelocation())
+                    .build());
+        }
+        // only keep repositories other than 'central'
+        builder.pluginRepositories(pruneRepositories(model.getPluginRepositories()));
+        builder.repositories(pruneRepositories(model.getRepositories()));
+        return builder;
+    }
+
+    private static List<Repository> pruneRepositories(List<Repository> repositories) {
+        return repositories.stream()
+                .filter(r -> !org.apache.maven.api.Repository.CENTRAL_ID.equals(r.getId()))
+                .collect(Collectors.toList());
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifact.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifact.java
new file mode 100644
index 0000000..5800048
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifact.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation.impl;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Objects;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.internal.transformation.TransformationFailedException;
+import org.apache.maven.model.building.ModelBuildingException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.eclipse.aether.RepositorySystemSession;
+
+/**
+ * Transformed artifact is derived with some transformation from source artifact.
+ *
+ * @since TBD
+ */
+class TransformedArtifact extends DefaultArtifact {
+
+    private static final int SHA1_BUFFER_SIZE = 8192;
+    private final DefaultConsumerPomArtifactTransformer defaultConsumerPomArtifactTransformer;
+    private final MavenProject project;
+    private final Supplier<Path> sourcePathProvider;
+    private final Path target;
+    private final RepositorySystemSession session;
+    private final AtomicReference<String> sourceState;
+
+    TransformedArtifact(
+            DefaultConsumerPomArtifactTransformer defaultConsumerPomArtifactTransformer,
+            MavenProject project,
+            Path target,
+            RepositorySystemSession session,
+            org.apache.maven.artifact.Artifact source,
+            Supplier<Path> sourcePathProvider,
+            String classifier,
+            String extension) {
+        super(
+                source.getGroupId(),
+                source.getArtifactId(),
+                source.getVersionRange(),
+                source.getScope(),
+                extension,
+                classifier,
+                new TransformedArtifactHandler(
+                        classifier, extension, source.getArtifactHandler().getPackaging()));
+        this.defaultConsumerPomArtifactTransformer = defaultConsumerPomArtifactTransformer;
+        this.project = project;
+        this.target = target;
+        this.session = session;
+        this.sourcePathProvider = sourcePathProvider;
+        this.sourceState = new AtomicReference<>(null);
+    }
+
+    @Override
+    public boolean isResolved() {
+        return getFile() != null;
+    }
+
+    @Override
+    public void setFile(File file) {
+        throw new UnsupportedOperationException("transformed artifact file cannot be set");
+    }
+
+    @Override
+    public synchronized File getFile() {
+        try {
+            String state = mayUpdate();
+            if (state == null) {
+                return null;
+            }
+            return target.toFile();
+        } catch (IOException
+                | NoSuchAlgorithmException
+                | XMLStreamException
+                | ModelBuildingException
+                | ComponentLookupException e) {
+            throw new TransformationFailedException(e);
+        }
+    }
+
+    private String mayUpdate()
+            throws IOException, NoSuchAlgorithmException, XMLStreamException, ModelBuildingException,
+                    ComponentLookupException {
+        String result;
+        Path src = sourcePathProvider.get();
+        if (src == null) {
+            Files.deleteIfExists(target);
+            result = null;
+        } else if (!Files.exists(src)) {
+            Files.deleteIfExists(target);
+            result = "";
+        } else {
+            String current = sha1(src);
+            String existing = sourceState.get();
+            if (!Objects.equals(current, existing)) {
+                defaultConsumerPomArtifactTransformer.transform(project, session, src, target);
+                Files.setLastModifiedTime(target, Files.getLastModifiedTime(src));
+            }
+            result = current;
+        }
+        sourceState.set(result);
+        return result;
+    }
+
+    static String sha1(Path path) throws NoSuchAlgorithmException, IOException {
+        MessageDigest md = MessageDigest.getInstance("SHA-1");
+        try (InputStream fis = Files.newInputStream(path)) {
+            byte[] buffer = new byte[SHA1_BUFFER_SIZE];
+            int read;
+            while ((read = fis.read(buffer)) != -1) {
+                md.update(buffer, 0, read);
+            }
+        }
+        StringBuilder result = new StringBuilder();
+        for (byte b : md.digest()) {
+            result.append(String.format("%02x", b));
+        }
+        return result.toString();
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java
new file mode 100644
index 0000000..80ba4e7
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/TransformedArtifactHandler.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation.impl;
+
+import org.apache.maven.artifact.handler.ArtifactHandler;
+
+import static java.util.Objects.requireNonNull;
+
+class TransformedArtifactHandler implements ArtifactHandler {
+
+    private final String classifier;
+
+    private final String extension;
+
+    private final String packaging;
+
+    TransformedArtifactHandler(String classifier, String extension, String packaging) {
+        this.classifier = classifier;
+        this.extension = requireNonNull(extension);
+        this.packaging = requireNonNull(packaging);
+    }
+
+    public String getClassifier() {
+        return classifier;
+    }
+
+    public String getDirectory() {
+        return null;
+    }
+
+    public String getExtension() {
+        return extension;
+    }
+
+    public String getLanguage() {
+        return "none";
+    }
+
+    public String getPackaging() {
+        return packaging;
+    }
+
+    public boolean isAddedToClasspath() {
+        return false;
+    }
+
+    public boolean isIncludesDependencies() {
+        return false;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java
index c8b4c2d..8361ad6 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycleExecutor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
+package org.apache.maven.lifecycle;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.internal.LifecycleExecutionPlanCalculator;
 import org.apache.maven.lifecycle.internal.LifecycleStarter;
@@ -52,15 +52,10 @@
  *
  * Note that this component is not normally used from within core itself.
  *
- * @author Jason van Zyl
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold
  */
 @Named
 @Singleton
-public class DefaultLifecycleExecutor
-    implements LifecycleExecutor
-{
+public class DefaultLifecycleExecutor implements LifecycleExecutor {
 
     private final LifeCyclePluginAnalyzer lifeCyclePluginAnalyzer;
     private final DefaultLifecycles defaultLifeCycles;
@@ -78,8 +73,7 @@
             LifecycleExecutionPlanCalculator lifecycleExecutionPlanCalculator,
             MojoExecutor mojoExecutor,
             LifecycleStarter lifecycleStarter,
-            MojoDescriptorCreator mojoDescriptorCreator )
-    {
+            MojoDescriptorCreator mojoDescriptorCreator) {
         this.lifeCyclePluginAnalyzer = lifeCyclePluginAnalyzer;
         this.defaultLifeCycles = defaultLifeCycles;
         this.lifecycleTaskSegmentCalculator = lifecycleTaskSegmentCalculator;
@@ -89,9 +83,8 @@
         this.mojoDescriptorCreator = mojoDescriptorCreator;
     }
 
-    public void execute( MavenSession session )
-    {
-        lifecycleStarter.execute( session );
+    public void execute(MavenSession session) {
+        lifecycleStarter.execute(session);
     }
 
     // These methods deal with construction intact Plugin object that look like they come from a standard
@@ -106,58 +99,57 @@
     // TODO This whole method could probably removed by injecting lifeCyclePluginAnalyzer straight into client site.
     // TODO But for some reason the whole plexus appcontext refuses to start when I try this.
 
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
-        return lifeCyclePluginAnalyzer.getPluginsBoundByDefaultToAllLifecycles( packaging );
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
+        return lifeCyclePluginAnalyzer.getPluginsBoundByDefaultToAllLifecycles(packaging);
+    }
+
+    // USED BY MAVEN HELP PLUGIN
+
+    @Deprecated
+    public Map<String, Lifecycle> getPhaseToLifecycleMap() {
+        return defaultLifeCycles.getPhaseToLifecycleMap();
     }
 
     // Used by m2eclipse
 
-    @SuppressWarnings( { "UnusedDeclaration" } )
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, boolean setup, String... tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
-        PluginVersionResolutionException
-    {
+    @SuppressWarnings({"UnusedDeclaration"})
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, boolean setup, String... tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
+                    PluginVersionResolutionException {
         List<TaskSegment> taskSegments =
-            lifecycleTaskSegmentCalculator.calculateTaskSegments( session, Arrays.asList( tasks ) );
+                lifecycleTaskSegmentCalculator.calculateTaskSegments(session, Arrays.asList(tasks));
 
-        TaskSegment mergedSegment = new TaskSegment( false );
+        TaskSegment mergedSegment = new TaskSegment(false);
 
-        for ( TaskSegment taskSegment : taskSegments )
-        {
-            mergedSegment.getTasks().addAll( taskSegment.getTasks() );
+        for (TaskSegment taskSegment : taskSegments) {
+            mergedSegment.getTasks().addAll(taskSegment.getTasks());
         }
 
-        return lifecycleExecutionPlanCalculator.calculateExecutionPlan( session, session.getCurrentProject(),
-                                                                        mergedSegment.getTasks(), setup );
+        return lifecycleExecutionPlanCalculator.calculateExecutionPlan(
+                session, session.getCurrentProject(), mergedSegment.getTasks(), setup);
     }
 
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
-        PluginVersionResolutionException
-    {
-        return calculateExecutionPlan( session, true, tasks );
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, String... tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
+                    PluginVersionResolutionException {
+        return calculateExecutionPlan(session, true, tasks);
     }
 
     // Site 3.x
-    public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        lifecycleExecutionPlanCalculator.calculateForkedExecutions( mojoExecution, session );
+    public void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
+        lifecycleExecutionPlanCalculator.calculateForkedExecutions(mojoExecution, session);
     }
 
     // Site 3.x
-    public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws LifecycleExecutionException
-    {
-        return mojoExecutor.executeForkedExecutions( mojoExecution, session,
-                                                     new ProjectIndex( session.getProjects() ) );
+    public List<MavenProject> executeForkedExecutions(MojoExecution mojoExecution, MavenSession session)
+            throws LifecycleExecutionException {
+        return mojoExecutor.executeForkedExecutions(mojoExecution, session, new ProjectIndex(session.getProjects()));
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java
index 9849fff..76cb5a0 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/DefaultLifecycles.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Arrays;
 import java.util.Comparator;
@@ -27,44 +30,45 @@
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * @since 3.0
- * @author Jason van Zyl
- * @author Kristian Rosenvold
  */
 // TODO The configuration for the lifecycle needs to be externalized so that I can use the annotations properly for the
 // wiring and reference and external source for the lifecycle configuration.
 @Named
 @Singleton
-public class DefaultLifecycles
-{
-    public static final String[] STANDARD_LIFECYCLES = { "clean", "default", "site", "wrapper" };
+public class DefaultLifecycles {
+    public static final String[] STANDARD_LIFECYCLES = {"clean", "default", "site", "wrapper"};
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     // @Configuration(source="org/apache/maven/lifecycle/lifecycles.xml")
 
-    private final Map<String, Lifecycle> lifecyclesMap;
+    private final PlexusContainer plexusContainer;
 
-    public DefaultLifecycles()
-    {
-        this.lifecyclesMap = null;
+    private Map<String, Lifecycle> customLifecycles;
+
+    public DefaultLifecycles() {
+        this.plexusContainer = null;
+    }
+
+    /**
+     * @deprecated Rely on {@link #DefaultLifecycles(PlexusContainer)} instead
+     */
+    @Deprecated
+    public DefaultLifecycles(Map<String, Lifecycle> lifecycles, org.codehaus.plexus.logging.Logger logger) {
+        this.customLifecycles = lifecycles;
+        this.plexusContainer = null;
     }
 
     @Inject
-    public DefaultLifecycles( Map<String, Lifecycle> lifecyclesMap )
-    {
-        // Must keep the lifecyclesMap as is.
-        // During initialization it only contains the default lifecycles.
-        // However, extensions might add custom lifecycles later on.
-        this.lifecyclesMap = lifecyclesMap;
+    public DefaultLifecycles(PlexusContainer plexusContainer) {
+        this.plexusContainer = plexusContainer;
     }
 
     /**
@@ -73,9 +77,8 @@
      * @param phase
      * @return
      */
-    public Lifecycle get( String phase )
-    {
-        return getPhaseToLifecycleMap().get( phase );
+    public Lifecycle get(String phase) {
+        return getPhaseToLifecycleMap().get(phase);
     }
 
     /**
@@ -84,32 +87,26 @@
      *
      * @return A map of lifecycles, indexed on id
      */
-    public Map<String, Lifecycle> getPhaseToLifecycleMap()
-    {
+    public Map<String, Lifecycle> getPhaseToLifecycleMap() {
         // If people are going to make their own lifecycles then we need to tell people how to namespace them correctly
         // so that they don't interfere with internally defined lifecycles.
 
         Map<String, Lifecycle> phaseToLifecycleMap = new HashMap<>();
 
-        for ( Lifecycle lifecycle : getLifeCycles() )
-        {
-            if ( logger.isDebugEnabled() )
-            {
-                logger.debug( "Lifecycle " + lifecycle );
-            }
+        for (Lifecycle lifecycle : getLifeCycles()) {
+            logger.debug("Lifecycle {}", lifecycle);
 
-            for ( String phase : lifecycle.getPhases() )
-            {
+            for (String phase : lifecycle.getPhases()) {
                 // The first definition wins.
-                if ( !phaseToLifecycleMap.containsKey( phase ) )
-                {
-                    phaseToLifecycleMap.put( phase, lifecycle );
-                }
-                else
-                {
-                    Lifecycle original = phaseToLifecycleMap.get( phase );
-                    logger.warn( "Duplicated lifecycle phase " + phase + ". Defined in " + original.getId()
-                        + " but also in " + lifecycle.getId() );
+                if (!phaseToLifecycleMap.containsKey(phase)) {
+                    phaseToLifecycleMap.put(phase, lifecycle);
+                } else if (logger.isWarnEnabled()) {
+                    Lifecycle original = phaseToLifecycleMap.get(phase);
+                    logger.warn(
+                            "Duplicated lifecycle phase {}. Defined in {} but also in {}",
+                            phase,
+                            original.getId(),
+                            lifecycle.getId());
                 }
             }
         }
@@ -120,37 +117,45 @@
     /**
      * Returns an ordered list of lifecycles
      */
-    public List<Lifecycle> getLifeCycles()
-    {
-        List<String> lifecycleIds = Arrays.asList( STANDARD_LIFECYCLES );
+    public List<Lifecycle> getLifeCycles() {
+        List<String> lifecycleIds = Arrays.asList(STANDARD_LIFECYCLES);
 
-        Comparator<String> comparator = ( l, r ) ->
-        {
-            int lx = lifecycleIds.indexOf( l );
-            int rx = lifecycleIds.indexOf( r );
+        Comparator<String> comparator = (l, r) -> {
+            int lx = lifecycleIds.indexOf(l);
+            int rx = lifecycleIds.indexOf(r);
 
-            if ( lx < 0 || rx < 0 )
-            {
+            if (lx < 0 || rx < 0) {
                 return rx - lx;
-            }
-            else
-            {
+            } else {
                 return lx - rx;
             }
         };
 
+        Map<String, Lifecycle> lifecyclesMap = lookupLifecycles();
+
         // ensure canonical order of standard lifecycles
         return lifecyclesMap.values().stream()
-                                .peek( l -> Objects.requireNonNull( l.getId(), "A lifecycle must have an id." ) )
-                                .sorted( Comparator.comparing( Lifecycle::getId, comparator ) )
-                                .collect( Collectors.toList() );
+                .peek(l -> Objects.requireNonNull(l.getId(), "A lifecycle must have an id."))
+                .sorted(Comparator.comparing(Lifecycle::getId, comparator))
+                .collect(Collectors.toList());
     }
 
-    public String getLifecyclePhaseList()
-    {
-        return getLifeCycles().stream()
-                        .flatMap( l -> l.getPhases().stream() )
-                        .collect( Collectors.joining( ", " ) );
+    private Map<String, Lifecycle> lookupLifecycles() {
+        // TODO: Remove the following code when maven-compat is gone
+        // This code is here to ensure maven-compat's EmptyLifecycleExecutor keeps on working.
+        if (plexusContainer == null) {
+            return customLifecycles != null ? customLifecycles : new HashMap<>();
+        }
+
+        // Lifecycles cannot be cached as extensions might add custom lifecycles later in the execution.
+        try {
+            return plexusContainer.lookupMap(Lifecycle.class);
+        } catch (ComponentLookupException e) {
+            throw new IllegalStateException("Unable to lookup lifecycles from the plexus container", e);
+        }
     }
 
+    public String getLifecyclePhaseList() {
+        return getLifeCycles().stream().flatMap(l -> l.getPhases().stream()).collect(Collectors.joining(", "));
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java
index ed07c1d..34cafe9 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifeCyclePluginAnalyzer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 import java.util.Set;
+
 import org.apache.maven.model.Plugin;
 
 /**
  * @since 3.0
- * @author Kristian Rosenvold
  */
-public interface LifeCyclePluginAnalyzer
-{
-    Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging );
+public interface LifeCyclePluginAnalyzer {
+    Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java b/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
index 43a674e..b3b63cb 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/Lifecycle.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 import java.util.List;
 import java.util.Map;
@@ -27,14 +26,10 @@
 /**
  * Lifecycle definition, with eventual plugin bindings (when they are not packaging-specific).
  */
-public class Lifecycle
-{
-    public Lifecycle()
-    {
-    }
+public class Lifecycle {
+    public Lifecycle() {}
 
-    public Lifecycle( String id, List<String> phases, Map<String, LifecyclePhase> defaultPhases )
-    {
+    public Lifecycle(String id, List<String> phases, Map<String, LifecyclePhase> defaultPhases) {
         this.id = id;
         this.phases = phases;
         this.defaultPhases = defaultPhases;
@@ -58,31 +53,25 @@
 
     private Map<String, LifecyclePhase> defaultPhases;
 
-    public String getId()
-    {
+    public String getId() {
         return this.id;
     }
 
-    public List<String> getPhases()
-    {
+    public List<String> getPhases() {
         return this.phases;
     }
 
-    public Map<String, LifecyclePhase> getDefaultLifecyclePhases()
-    {
+    public Map<String, LifecyclePhase> getDefaultLifecyclePhases() {
         return defaultPhases;
     }
 
     @Deprecated
-    public Map<String, String> getDefaultPhases()
-    {
-        return LifecyclePhase.toLegacyMap( getDefaultLifecyclePhases() );
+    public Map<String, String> getDefaultPhases() {
+        return LifecyclePhase.toLegacyMap(getDefaultLifecyclePhases());
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return id + " -> " + phases;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
index 0831a4f..783ab15 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,90 +16,92 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
-
+import org.apache.maven.api.services.MessageBuilder;
+import org.apache.maven.api.services.MessageBuilderFactory;
+import org.apache.maven.internal.impl.DefaultMessageBuilderFactory;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
 
 /**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
  */
-public class LifecycleExecutionException
-    extends Exception
-{
+public class LifecycleExecutionException extends Exception {
     private MavenProject project;
 
-    public LifecycleExecutionException( String message )
-    {
-        super( message );
+    public LifecycleExecutionException(String message) {
+        super(message);
     }
 
-    public LifecycleExecutionException( Throwable cause )
-    {
-        super( cause );
+    public LifecycleExecutionException(Throwable cause) {
+        super(cause);
     }
 
-    public LifecycleExecutionException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public LifecycleExecutionException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public LifecycleExecutionException( String message, MavenProject project )
-    {
-        super( message );
+    public LifecycleExecutionException(String message, MavenProject project) {
+        super(message);
         this.project = project;
     }
 
-    public LifecycleExecutionException( String message, MojoExecution execution, MavenProject project )
-    {
-        super( message );
+    public LifecycleExecutionException(String message, MojoExecution execution, MavenProject project) {
+        super(message);
         this.project = project;
     }
 
-    public LifecycleExecutionException( String message, MojoExecution execution, MavenProject project, Throwable cause )
-    {
-        super( message, cause );
+    public LifecycleExecutionException(String message, MojoExecution execution, MavenProject project, Throwable cause) {
+        super(message, cause);
         this.project = project;
     }
 
-    public LifecycleExecutionException( MojoExecution execution, MavenProject project, Throwable cause )
-    {
-        this( createMessage( execution, project, cause ), execution, project, cause );
+    public LifecycleExecutionException(MojoExecution execution, MavenProject project, Throwable cause) {
+        this(new DefaultMessageBuilderFactory(), execution, project, cause);
     }
 
-    public MavenProject getProject()
-    {
+    public LifecycleExecutionException(
+            MessageBuilderFactory messageBuilderFactory,
+            MojoExecution execution,
+            MavenProject project,
+            Throwable cause) {
+        this(createMessage(messageBuilderFactory, execution, project, cause), execution, project, cause);
+    }
+
+    public MavenProject getProject() {
         return project;
     }
 
-    private static String createMessage( MojoExecution execution, MavenProject project, Throwable cause )
-    {
-        MessageBuilder buffer = buffer( 256 );
+    private static String createMessage(
+            MessageBuilderFactory messageBuilderFactory,
+            MojoExecution execution,
+            MavenProject project,
+            Throwable cause) {
+        MessageBuilder buffer = messageBuilderFactory.builder(256);
 
-        buffer.a( "Failed to execute goal" );
+        buffer.a("Failed to execute goal");
 
-        if ( execution != null )
-        {
-            buffer.a( ' ' );
-            buffer.mojo( execution.getGroupId() + ':' + execution.getArtifactId() + ':' + execution.getVersion() + ':'
-                + execution.getGoal() );
-            buffer.a( ' ' ).strong( '(' + execution.getExecutionId() + ')' );
+        if (execution != null) {
+            buffer.a(' ');
+            buffer.mojo(execution.getGroupId()
+                    + ':'
+                    + execution.getArtifactId()
+                    + ':'
+                    + execution.getVersion()
+                    + ':'
+                    + execution.getGoal());
+            buffer.a(' ').strong('(' + execution.getExecutionId() + ')');
         }
 
-        if ( project != null )
-        {
-            buffer.a( " on project " );
-            buffer.project( project.getArtifactId() );
+        if (project != null) {
+            buffer.a(" on project ");
+            buffer.project(project.getArtifactId());
         }
 
-        if ( cause != null )
-        {
-            buffer.a( ": " ).failure( cause.getMessage() );
+        if (cause != null) {
+            buffer.a(": ").failure(cause.getMessage());
         }
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java
index 26156db..d1af78c 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
+
+import java.util.List;
+import java.util.Set;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.Plugin;
@@ -32,16 +34,11 @@
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.apache.maven.project.MavenProject;
 
-import java.util.List;
-import java.util.Set;
-
 /**
  * A facade that provides lifecycle services to components outside Maven core.
  *
- * @author Jason van  Zyl
  */
-public interface LifecycleExecutor
-{
+public interface LifecycleExecutor {
 
     // USED BY MAVEN HELP PLUGIN
     @Deprecated
@@ -61,29 +58,29 @@
      * @return The plugins bound to the lifecycles of the specified packaging or {@code null} if the packaging is
      *         unknown.
      */
-    Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging );
+    Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging);
 
-    MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
-        PluginVersionResolutionException;
+    MavenExecutionPlan calculateExecutionPlan(MavenSession session, String... tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
+                    PluginVersionResolutionException;
 
-    MavenExecutionPlan calculateExecutionPlan( MavenSession session, boolean setup, String... tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
-        PluginVersionResolutionException;
+    MavenExecutionPlan calculateExecutionPlan(MavenSession session, boolean setup, String... tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginManagerException, LifecyclePhaseNotFoundException, LifecycleNotFoundException,
+                    PluginVersionResolutionException;
 
-    void execute( MavenSession session );
+    void execute(MavenSession session);
 
     // used by the site plugin 3.x
-    void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException;
+    void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException;
 
     // used by the site plugin 3.x
-    List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws LifecycleExecutionException;
+    List<MavenProject> executeForkedExecutions(MojoExecution mojoExecution, MavenSession session)
+            throws LifecycleExecutionException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingDelegate.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingDelegate.java
index f070198..39c10c8 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingDelegate.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleMappingDelegate.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 import java.util.List;
 import java.util.Map;
@@ -41,12 +40,10 @@
  *
  * @since 3.2.0
  * @see org.apache.maven.lifecycle.internal.DefaultLifecycleMappingDelegate
- * @author ifedorenko
  */
-public interface LifecycleMappingDelegate
-{
-    Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
-                                                                 Lifecycle lifecycle, String lifecyclePhase )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException;
+public interface LifecycleMappingDelegate {
+    Map<String, List<MojoExecution>> calculateLifecycleMappings(
+            MavenSession session, MavenProject project, Lifecycle lifecycle, String lifecyclePhase)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleNotFoundException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleNotFoundException.java
index e9ff0c2..923a390 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleNotFoundException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 /**
  * Signals a failure to locate a lifecycle.
  *
- * @author Benjamin Bentmann
  */
-public class LifecycleNotFoundException
-    extends Exception
-{
+public class LifecycleNotFoundException extends Exception {
 
     private final String lifecycleId;
 
@@ -35,10 +31,9 @@
      *
      * @param lifecycleId The identifier of the lifecycle that could not be located, may be {@code null}.
      */
-    public LifecycleNotFoundException( String lifecycleId )
-    {
-        super( "Unknown lifecycle " + lifecycleId );
-        this.lifecycleId = ( lifecycleId != null ) ? lifecycleId : "";
+    public LifecycleNotFoundException(String lifecycleId) {
+        super("Unknown lifecycle " + lifecycleId);
+        this.lifecycleId = (lifecycleId != null) ? lifecycleId : "";
     }
 
     /**
@@ -46,9 +41,7 @@
      *
      * @return The identifier of the lifecycle that was not found, never {@code null}.
      */
-    public String getLifecycleId()
-    {
+    public String getLifecycleId() {
         return lifecycleId;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecyclePhaseNotFoundException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecyclePhaseNotFoundException.java
index fab1d2f..cf2a311 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecyclePhaseNotFoundException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecyclePhaseNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 /**
  * Signals a failure to locate the lifecycle for some phase.
  *
- * @author Benjamin Bentmann
  */
-public class LifecyclePhaseNotFoundException
-    extends Exception
-{
+public class LifecyclePhaseNotFoundException extends Exception {
 
     private final String lifecyclePhase;
 
@@ -36,10 +32,9 @@
      * @param message The detail message, may be {@code null}.
      * @param lifecyclePhase The name of the lifecycle phase that could not be located, may be {@code null}.
      */
-    public LifecyclePhaseNotFoundException( String message, String lifecyclePhase )
-    {
-        super( message );
-        this.lifecyclePhase = ( lifecyclePhase != null ) ? lifecyclePhase : "";
+    public LifecyclePhaseNotFoundException(String message, String lifecyclePhase) {
+        super(message);
+        this.lifecyclePhase = (lifecyclePhase != null) ? lifecyclePhase : "";
     }
 
     /**
@@ -47,9 +42,7 @@
      *
      * @return The lifecycle phase that was not found, never {@code null}.
      */
-    public String getLifecyclePhase()
-    {
+    public String getLifecyclePhase() {
         return lifecyclePhase;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java b/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java
index aecf264..e3d1497 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/MavenExecutionPlan.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -34,29 +33,27 @@
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 
-//TODO lifecycles being executed
-//TODO what runs in each phase
-//TODO plugins that need downloading
-//TODO project dependencies that need downloading
-//TODO unfortunately the plugins need to be downloaded in order to get the plugin.xml file. need to externalize this
+// TODO lifecycles being executed
+// TODO what runs in each phase
+// TODO plugins that need downloading
+// TODO project dependencies that need downloading
+// TODO unfortunately the plugins need to be downloaded in order to get the plugin.xml file. need to externalize this
 //      from the plugin archive.
-//TODO this will be the class that people get in IDEs to modify
+// TODO this will be the class that people get in IDEs to modify
 
 /**
  * MavenExecutionPlan
  */
-public class MavenExecutionPlan
-    implements Iterable<ExecutionPlanItem>
-{
+public class MavenExecutionPlan implements Iterable<ExecutionPlanItem> {
 
     /*
-       At the moment, this class is totally immutable, and this is in line with thoughts about the
-       pre-calculated execution plan that stays the same during the execution.
+      At the moment, this class is totally immutable, and this is in line with thoughts about the
+      pre-calculated execution plan that stays the same during the execution.
 
-       If deciding to add mutable state to this class, it should be at least considered to
-       separate this into a separate mutable structure.
+      If deciding to add mutable state to this class, it should be at least considered to
+      separate this into a separate mutable structure.
 
-     */
+    */
 
     private final List<ExecutionPlanItem> planItem;
 
@@ -64,48 +61,40 @@
 
     final List<String> phasesInExecutionPlan;
 
-    public MavenExecutionPlan( List<ExecutionPlanItem> planItem, DefaultLifecycles defaultLifecycles )
-    {
+    public MavenExecutionPlan(List<ExecutionPlanItem> planItem, DefaultLifecycles defaultLifecycles) {
         this.planItem = planItem;
 
         lastMojoExecutionForAllPhases = new LinkedHashMap<>();
 
         LinkedHashSet<String> totalPhaseSet = new LinkedHashSet<>();
-        if ( defaultLifecycles != null )
-        {
-            for ( String phase : getDistinctPhasesInOrderOfExecutionPlanAppearance( planItem ) )
-            {
-                final Lifecycle lifecycle = defaultLifecycles.get( phase );
-                if ( lifecycle != null )
-                {
-                    totalPhaseSet.addAll( lifecycle.getPhases() );
+        if (defaultLifecycles != null) {
+            for (String phase : getDistinctPhasesInOrderOfExecutionPlanAppearance(planItem)) {
+                final Lifecycle lifecycle = defaultLifecycles.get(phase);
+                if (lifecycle != null) {
+                    totalPhaseSet.addAll(lifecycle.getPhases());
                 }
             }
         }
-        this.phasesInExecutionPlan = new ArrayList<>( totalPhaseSet );
+        this.phasesInExecutionPlan = new ArrayList<>(totalPhaseSet);
 
         Map<String, ExecutionPlanItem> lastInExistingPhases = new HashMap<>();
-        for ( ExecutionPlanItem executionPlanItem : getExecutionPlanItems() )
-        {
-            lastInExistingPhases.put( executionPlanItem.getLifecyclePhase(), executionPlanItem );
+        for (ExecutionPlanItem executionPlanItem : getExecutionPlanItems()) {
+            lastInExistingPhases.put(executionPlanItem.getLifecyclePhase(), executionPlanItem);
         }
 
         ExecutionPlanItem lastSeenExecutionPlanItem = null;
 
-        for ( String phase : totalPhaseSet )
-        {
-            ExecutionPlanItem forThisPhase = lastInExistingPhases.get( phase );
-            if ( forThisPhase != null )
-            {
+        for (String phase : totalPhaseSet) {
+            ExecutionPlanItem forThisPhase = lastInExistingPhases.get(phase);
+            if (forThisPhase != null) {
                 lastSeenExecutionPlanItem = forThisPhase;
             }
 
-            lastMojoExecutionForAllPhases.put( phase, lastSeenExecutionPlanItem );
+            lastMojoExecutionForAllPhases.put(phase, lastSeenExecutionPlanItem);
         }
     }
 
-    public Iterator<ExecutionPlanItem> iterator()
-    {
+    public Iterator<ExecutionPlanItem> iterator() {
         return getExecutionPlanItems().iterator();
     }
 
@@ -117,37 +106,30 @@
      *                       The execution plan item
      * @return The ExecutionPlanItem or null if none can be found
      */
-    public ExecutionPlanItem findLastInPhase( String requestedPhase )
-    {
-        return lastMojoExecutionForAllPhases.get( requestedPhase );
+    public ExecutionPlanItem findLastInPhase(String requestedPhase) {
+        return lastMojoExecutionForAllPhases.get(requestedPhase);
     }
 
-    private List<ExecutionPlanItem> getExecutionPlanItems()
-    {
+    private List<ExecutionPlanItem> getExecutionPlanItems() {
         return planItem;
     }
 
     private static Iterable<String> getDistinctPhasesInOrderOfExecutionPlanAppearance(
-        List<ExecutionPlanItem> planItems )
-    {
+            List<ExecutionPlanItem> planItems) {
         LinkedHashSet<String> result = new LinkedHashSet<>();
-        for ( ExecutionPlanItem executionPlanItem : planItems )
-        {
+        for (ExecutionPlanItem executionPlanItem : planItems) {
             final String phase = executionPlanItem.getLifecyclePhase();
-            if ( !result.contains( phase ) )
-            {
-                result.add( phase );
+            if (!result.contains(phase)) {
+                result.add(phase);
             }
         }
         return result;
     }
 
-    public List<MojoExecution> getMojoExecutions()
-    {
+    public List<MojoExecution> getMojoExecutions() {
         List<MojoExecution> result = new ArrayList<>();
-        for ( ExecutionPlanItem executionPlanItem : planItem )
-        {
-            result.add( executionPlanItem.getMojoExecution() );
+        for (ExecutionPlanItem executionPlanItem : planItem) {
+            result.add(executionPlanItem.getMojoExecution());
         }
         return result;
     }
@@ -157,15 +139,12 @@
      *
      * @return the set of plugins (without info on which goal is concerned)
      */
-    public Set<Plugin> getNonThreadSafePlugins()
-    {
+    public Set<Plugin> getNonThreadSafePlugins() {
         Set<Plugin> plugins = new HashSet<>();
-        for ( ExecutionPlanItem executionPlanItem : planItem )
-        {
+        for (ExecutionPlanItem executionPlanItem : planItem) {
             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
-            if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
-            {
-                plugins.add( mojoExecution.getPlugin() );
+            if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
+                plugins.add(mojoExecution.getPlugin());
             }
         }
         return plugins;
@@ -176,15 +155,12 @@
      *
      * @return the set of mojo descriptors
      */
-    public Set<MojoDescriptor> getNonThreadSafeMojos()
-    {
+    public Set<MojoDescriptor> getNonThreadSafeMojos() {
         Set<MojoDescriptor> mojos = new HashSet<>();
-        for ( ExecutionPlanItem executionPlanItem : planItem )
-        {
+        for (ExecutionPlanItem executionPlanItem : planItem) {
             final MojoExecution mojoExecution = executionPlanItem.getMojoExecution();
-            if ( !mojoExecution.getMojoDescriptor().isThreadSafe() )
-            {
-                mojos.add( mojoExecution.getMojoDescriptor() );
+            if (!mojoExecution.getMojoDescriptor().isThreadSafe()) {
+                mojos.add(mojoExecution.getMojoDescriptor());
             }
         }
         return mojos;
@@ -192,14 +168,11 @@
 
     // Used by m2e but will be removed, really.
     @Deprecated
-    public List<MojoExecution> getExecutions()
-    {
+    public List<MojoExecution> getExecutions() {
         return getMojoExecutions();
     }
 
-    public int size()
-    {
+    public int size() {
         return planItem.size();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/MissingProjectException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/MissingProjectException.java
index 571e1d2..414672f 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/MissingProjectException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/MissingProjectException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,24 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 /**
  * Signals a failure to execute a lifecycle phase or mojo because a project is required but not present.
  *
- * @author Benjamin Bentmann
  */
-public class MissingProjectException
-    extends Exception
-{
+public class MissingProjectException extends Exception {
 
     /**
      * Creates a new exception.
      *
      * @param message The detail message, may be {@code null}.
      */
-    public MissingProjectException( String message )
-    {
-        super( message );
+    public MissingProjectException(String message) {
+        super(message);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/MojoExecutionConfigurator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/MojoExecutionConfigurator.java
index 07219b2..efb1f7b 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/MojoExecutionConfigurator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/MojoExecutionConfigurator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.project.MavenProject;
@@ -28,11 +27,9 @@
  * in the MavenProject and the default configuration for the Mojo from the containing plugin's plugin.xml descriptor.
  * </p>
  * <strong>Note:</strong> This interface is part of work in progress and can be changed or removed without notice.
- * @author Jason van Zyl
  * @since 3.3.1, MNG-5753
  */
-public interface MojoExecutionConfigurator
-{
+public interface MojoExecutionConfigurator {
     /**
      * Create the MojoExecution configuration based on configuration for a Mojo in the MavenProject and the
      * default configuration for the Mojo from the containing plugin's plugin.xml descriptor.
@@ -41,5 +38,5 @@
      * @param mojoExecution
      * @param allowPluginLevelConfig
      */
-    void configure( MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig );
+    void configure(MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/NoGoalSpecifiedException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/NoGoalSpecifiedException.java
index 2ac9638..ba8709a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/NoGoalSpecifiedException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/NoGoalSpecifiedException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,24 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 /**
  * Signals a failure to build because no goal was specified.
  *
- * @author Benjamin Bentmann
  */
-public class NoGoalSpecifiedException
-    extends Exception
-{
+public class NoGoalSpecifiedException extends Exception {
 
     /**
      * Creates a new exception.
      *
      * @param message The detail message, may be {@code null}.
      */
-    public NoGoalSpecifiedException( String message )
-    {
-        super( message );
+    public NoGoalSpecifiedException(String message) {
+        super(message);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java
index b30b560..7a86e62 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildListCalculator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
 import org.apache.maven.project.MavenProject;
@@ -34,47 +33,36 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Kristian Rosenvold
  */
 @Named
 @Singleton
-public class BuildListCalculator
-{
-    public ProjectBuildList calculateProjectBuilds( MavenSession session, List<TaskSegment> taskSegments )
-    {
+public class BuildListCalculator {
+    public ProjectBuildList calculateProjectBuilds(MavenSession session, List<TaskSegment> taskSegments) {
         List<ProjectSegment> projectBuilds = new ArrayList<>();
 
         MavenProject rootProject = session.getTopLevelProject();
 
-        for ( TaskSegment taskSegment : taskSegments )
-        {
+        for (TaskSegment taskSegment : taskSegments) {
             List<MavenProject> projects;
 
-            if ( taskSegment.isAggregating() )
-            {
-                projects = Collections.singletonList( rootProject );
-            }
-            else
-            {
+            if (taskSegment.isAggregating()) {
+                projects = Collections.singletonList(rootProject);
+            } else {
                 projects = session.getProjects();
             }
-            for ( MavenProject project : projects )
-            {
+            for (MavenProject project : projects) {
                 ClassLoader tccl = Thread.currentThread().getContextClassLoader();
                 MavenProject currentProject = session.getCurrentProject();
-                try
-                {
-                    BuilderCommon.attachToThread( project ); // Not totally sure if this is needed for anything
-                    session.setCurrentProject( project );
-                    projectBuilds.add( new ProjectSegment( project, taskSegment, session ) );
-                }
-                finally
-                {
-                    session.setCurrentProject( currentProject );
-                    Thread.currentThread().setContextClassLoader( tccl );
+                try {
+                    BuilderCommon.attachToThread(project); // Not totally sure if this is needed for anything
+                    session.setCurrentProject(project);
+                    projectBuilds.add(new ProjectSegment(project, taskSegment, session));
+                } finally {
+                    session.setCurrentProject(currentProject);
+                    Thread.currentThread().setContextClassLoader(tccl);
                 }
             }
         }
-        return new ProjectBuildList( projectBuilds );
+        return new ProjectBuildList(projectBuilds);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildThreadFactory.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildThreadFactory.java
index bf6e637..f0886b6 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildThreadFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/BuildThreadFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -25,15 +24,12 @@
 /**
  * Simple {@link ThreadFactory} implementation that ensures the corresponding threads have a meaningful name.
  */
-public class BuildThreadFactory
-    implements ThreadFactory
-{
+public class BuildThreadFactory implements ThreadFactory {
     private final AtomicInteger id = new AtomicInteger();
 
     private static final String PREFIX = "BuilderThread";
 
-    public Thread newThread( Runnable r )
-    {
-        return new Thread( r, String.format( "%s-%d", PREFIX, id.getAndIncrement() ) );
+    public Thread newThread(Runnable r) {
+        return new Thread(r, String.format("%s-%d", PREFIX, id.getAndIncrement()));
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java
index 48474e6..515c53e 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/CompoundProjectExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.Collection;
 
@@ -25,48 +24,34 @@
 import org.apache.maven.execution.ProjectExecutionListener;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 
-class CompoundProjectExecutionListener
-    implements ProjectExecutionListener
-{
+class CompoundProjectExecutionListener implements ProjectExecutionListener {
     private final Collection<ProjectExecutionListener> listeners;
 
-    CompoundProjectExecutionListener( Collection<ProjectExecutionListener> listeners )
-    {
+    CompoundProjectExecutionListener(Collection<ProjectExecutionListener> listeners) {
         this.listeners = listeners; // NB this is live injected collection
     }
 
-    public void beforeProjectExecution( ProjectExecutionEvent event )
-        throws LifecycleExecutionException
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.beforeProjectExecution( event );
+    public void beforeProjectExecution(ProjectExecutionEvent event) throws LifecycleExecutionException {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.beforeProjectExecution(event);
         }
     }
 
-    public void beforeProjectLifecycleExecution( ProjectExecutionEvent event )
-        throws LifecycleExecutionException
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.beforeProjectLifecycleExecution( event );
+    public void beforeProjectLifecycleExecution(ProjectExecutionEvent event) throws LifecycleExecutionException {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.beforeProjectLifecycleExecution(event);
         }
     }
 
-    public void afterProjectExecutionSuccess( ProjectExecutionEvent event )
-        throws LifecycleExecutionException
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.afterProjectExecutionSuccess( event );
+    public void afterProjectExecutionSuccess(ProjectExecutionEvent event) throws LifecycleExecutionException {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.afterProjectExecutionSuccess(event);
         }
     }
 
-    public void afterProjectExecutionFailure( ProjectExecutionEvent event )
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.afterProjectExecutionFailure( event );
+    public void afterProjectExecutionFailure(ProjectExecutionEvent event) {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.afterProjectExecutionFailure(event);
         }
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEvent.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEvent.java
index 1090871..a657e63 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEvent.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEvent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenSession;
@@ -27,11 +26,8 @@
 /**
  * Holds data relevant for an execution event.
  *
- * @author Benjamin Bentmann
  */
-class DefaultExecutionEvent
-    implements ExecutionEvent
-{
+class DefaultExecutionEvent implements ExecutionEvent {
 
     private final Type type;
 
@@ -41,37 +37,30 @@
 
     private final Exception exception;
 
-    DefaultExecutionEvent( Type type, MavenSession session, MojoExecution mojoExecution, Exception exception )
-    {
+    DefaultExecutionEvent(Type type, MavenSession session, MojoExecution mojoExecution, Exception exception) {
         this.type = type;
         this.session = session;
         this.mojoExecution = mojoExecution;
         this.exception = exception;
     }
 
-    public Type getType()
-    {
+    public Type getType() {
         return type;
     }
 
-    public MavenSession getSession()
-    {
+    public MavenSession getSession() {
         return session;
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return session.getCurrentProject();
     }
 
-    public MojoExecution getMojoExecution()
-    {
+    public MojoExecution getMojoExecution() {
         return mojoExecution;
     }
 
-    public Exception getException()
-    {
+    public Exception getException() {
         return exception;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult.java
index 94948bc..505119a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultExecutionEventCatapult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -32,91 +31,83 @@
  * for technical reasons, it is not part of the public API. In particular, this class can be changed or deleted without
  * prior notice.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultExecutionEventCatapult
-    implements ExecutionEventCatapult
-{
+public class DefaultExecutionEventCatapult implements ExecutionEventCatapult {
 
-    public void fire( ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution )
-    {
-        fire( eventType, session, mojoExecution, null );
+    public void fire(ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution) {
+        fire(eventType, session, mojoExecution, null);
     }
 
-    public void fire( ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution,
-                      Exception exception )
-    {
+    public void fire(
+            ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution, Exception exception) {
         ExecutionListener listener = session.getRequest().getExecutionListener();
 
-        if ( listener != null )
-        {
-            ExecutionEvent event = new DefaultExecutionEvent( eventType, session, mojoExecution, exception );
+        if (listener != null) {
+            ExecutionEvent event = new DefaultExecutionEvent(eventType, session, mojoExecution, exception);
 
-            switch ( eventType )
-            {
+            switch (eventType) {
                 case ProjectDiscoveryStarted:
-                    listener.projectDiscoveryStarted( event );
+                    listener.projectDiscoveryStarted(event);
                     break;
 
                 case SessionStarted:
-                    listener.sessionStarted( event );
+                    listener.sessionStarted(event);
                     break;
                 case SessionEnded:
-                    listener.sessionEnded( event );
+                    listener.sessionEnded(event);
                     break;
 
                 case ProjectSkipped:
-                    listener.projectSkipped( event );
+                    listener.projectSkipped(event);
                     break;
                 case ProjectStarted:
-                    listener.projectStarted( event );
+                    listener.projectStarted(event);
                     break;
                 case ProjectSucceeded:
-                    listener.projectSucceeded( event );
+                    listener.projectSucceeded(event);
                     break;
                 case ProjectFailed:
-                    listener.projectFailed( event );
+                    listener.projectFailed(event);
                     break;
 
                 case MojoSkipped:
-                    listener.mojoSkipped( event );
+                    listener.mojoSkipped(event);
                     break;
                 case MojoStarted:
-                    listener.mojoStarted( event );
+                    listener.mojoStarted(event);
                     break;
                 case MojoSucceeded:
-                    listener.mojoSucceeded( event );
+                    listener.mojoSucceeded(event);
                     break;
                 case MojoFailed:
-                    listener.mojoFailed( event );
+                    listener.mojoFailed(event);
                     break;
 
                 case ForkStarted:
-                    listener.forkStarted( event );
+                    listener.forkStarted(event);
                     break;
                 case ForkSucceeded:
-                    listener.forkSucceeded( event );
+                    listener.forkSucceeded(event);
                     break;
                 case ForkFailed:
-                    listener.forkFailed( event );
+                    listener.forkFailed(event);
                     break;
 
                 case ForkedProjectStarted:
-                    listener.forkedProjectStarted( event );
+                    listener.forkedProjectStarted(event);
                     break;
                 case ForkedProjectSucceeded:
-                    listener.forkedProjectSucceeded( event );
+                    listener.forkedProjectSucceeded(event);
                     break;
                 case ForkedProjectFailed:
-                    listener.forkedProjectFailed( event );
+                    listener.forkedProjectFailed(event);
                     break;
 
                 default:
-                    throw new IllegalStateException( "Unknown execution event type " + eventType );
+                    throw new IllegalStateException("Unknown execution event type " + eventType);
             }
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java
index 036b940..71355f3 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleExecutionPlanCalculator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
 
+import java.io.IOException;
+import java.util.*;
+
+import org.apache.maven.api.plugin.descriptor.lifecycle.Execution;
+import org.apache.maven.api.plugin.descriptor.lifecycle.Phase;
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.xml.XmlNodeImpl;
 import org.apache.maven.lifecycle.DefaultLifecycles;
 import org.apache.maven.lifecycle.Lifecycle;
 import org.apache.maven.lifecycle.LifecycleMappingDelegate;
@@ -52,28 +49,18 @@
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.lifecycle.Execution;
-import org.apache.maven.plugin.lifecycle.Phase;
 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
 
 /**
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold (Extract class)
  */
 @Named
 @Singleton
-public class DefaultLifecycleExecutionPlanCalculator
-    implements LifecycleExecutionPlanCalculator
-{
+public class DefaultLifecycleExecutionPlanCalculator implements LifecycleExecutionPlanCalculator {
 
     private final BuildPluginManager pluginManager;
 
@@ -95,10 +82,9 @@
             DefaultLifecycles defaultLifecycles,
             MojoDescriptorCreator mojoDescriptorCreator,
             LifecyclePluginResolver lifecyclePluginResolver,
-            @Named( DefaultLifecycleMappingDelegate.HINT ) LifecycleMappingDelegate standardDelegate,
+            @Named(DefaultLifecycleMappingDelegate.HINT) LifecycleMappingDelegate standardDelegate,
             Map<String, LifecycleMappingDelegate> delegates,
-            Map<String, MojoExecutionConfigurator> mojoExecutionConfigurators )
-    {
+            Map<String, MojoExecutionConfigurator> mojoExecutionConfigurators) {
         this.pluginManager = pluginManager;
         this.defaultLifecycles = defaultLifecycles;
         this.mojoDescriptorCreator = mojoDescriptorCreator;
@@ -109,198 +95,178 @@
     }
 
     // Only used for testing
-    public DefaultLifecycleExecutionPlanCalculator( BuildPluginManager pluginManager,
-                                                    DefaultLifecycles defaultLifecycles,
-                                                    MojoDescriptorCreator mojoDescriptorCreator,
-                                                    LifecyclePluginResolver lifecyclePluginResolver )
-    {
+    public DefaultLifecycleExecutionPlanCalculator(
+            BuildPluginManager pluginManager,
+            DefaultLifecycles defaultLifecycles,
+            MojoDescriptorCreator mojoDescriptorCreator,
+            LifecyclePluginResolver lifecyclePluginResolver) {
         this.pluginManager = pluginManager;
         this.defaultLifecycles = defaultLifecycles;
         this.mojoDescriptorCreator = mojoDescriptorCreator;
         this.lifecyclePluginResolver = lifecyclePluginResolver;
         this.standardDelegate = null;
         this.delegates = null;
-        this.mojoExecutionConfigurators = Collections.singletonMap(
-             "default", (MojoExecutionConfigurator) new DefaultMojoExecutionConfigurator() );
+        this.mojoExecutionConfigurators =
+                Collections.singletonMap("default", (MojoExecutionConfigurator) new DefaultMojoExecutionConfigurator());
     }
 
     @Override
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks,
-                                                      boolean setup )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        lifecyclePluginResolver.resolveMissingPluginVersions( project, session );
+    public MavenExecutionPlan calculateExecutionPlan(
+            MavenSession session, MavenProject project, List<Object> tasks, boolean setup)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        lifecyclePluginResolver.resolveMissingPluginVersions(project, session);
 
-        final List<MojoExecution> executions = calculateMojoExecutions( session, project, tasks );
+        final List<MojoExecution> executions = calculateMojoExecutions(session, project, tasks);
 
-        if ( setup )
-        {
-            setupMojoExecutions( session, project, executions );
+        if (setup) {
+            setupMojoExecutions(session, project, executions);
         }
 
-        final List<ExecutionPlanItem> planItem = ExecutionPlanItem.createExecutionPlanItems( project, executions );
+        final List<ExecutionPlanItem> planItem = ExecutionPlanItem.createExecutionPlanItems(project, executions);
 
-        return new MavenExecutionPlan( planItem, defaultLifecycles );
+        return new MavenExecutionPlan(planItem, defaultLifecycles);
     }
 
     @Override
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        return calculateExecutionPlan( session, project, tasks, true );
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, MavenProject project, List<Object> tasks)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        return calculateExecutionPlan(session, project, tasks, true);
     }
 
-    private void setupMojoExecutions( MavenSession session, MavenProject project, List<MojoExecution> mojoExecutions )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        Set<MojoDescriptor> alreadyPlannedExecutions = fillMojoDescriptors( session, project, mojoExecutions );
+    private void setupMojoExecutions(MavenSession session, MavenProject project, List<MojoExecution> mojoExecutions)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
+        Set<MojoDescriptor> alreadyPlannedExecutions = fillMojoDescriptors(session, project, mojoExecutions);
 
-        for ( MojoExecution mojoExecution : mojoExecutions )
-        {
-            setupMojoExecution( session, project, mojoExecution, alreadyPlannedExecutions );
+        for (MojoExecution mojoExecution : mojoExecutions) {
+            setupMojoExecution(session, project, mojoExecution, alreadyPlannedExecutions);
         }
     }
 
-    private Set<MojoDescriptor> fillMojoDescriptors( MavenSession session, MavenProject project,
-                                                    List<MojoExecution> mojoExecutions )
+    private Set<MojoDescriptor> fillMojoDescriptors(
+            MavenSession session, MavenProject project, List<MojoExecution> mojoExecutions)
             throws InvalidPluginDescriptorException, MojoNotFoundException, PluginResolutionException,
-            PluginDescriptorParsingException, PluginNotFoundException
-    {
-        Set<MojoDescriptor> descriptors = new HashSet<>( mojoExecutions.size() );
+                    PluginDescriptorParsingException, PluginNotFoundException {
+        Set<MojoDescriptor> descriptors = new HashSet<>(mojoExecutions.size());
 
-        for ( MojoExecution execution : mojoExecutions )
-        {
-            MojoDescriptor mojoDescriptor = fillMojoDescriptor( session, project, execution );
-            descriptors.add( mojoDescriptor );
+        for (MojoExecution execution : mojoExecutions) {
+            MojoDescriptor mojoDescriptor = fillMojoDescriptor(session, project, execution);
+            descriptors.add(mojoDescriptor);
         }
 
         return descriptors;
     }
 
-    private MojoDescriptor fillMojoDescriptor( MavenSession session, MavenProject project, MojoExecution execution )
+    private MojoDescriptor fillMojoDescriptor(MavenSession session, MavenProject project, MojoExecution execution)
             throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-            MojoNotFoundException, InvalidPluginDescriptorException
-    {
+                    MojoNotFoundException, InvalidPluginDescriptorException {
         MojoDescriptor mojoDescriptor = execution.getMojoDescriptor();
 
-        if ( mojoDescriptor == null )
-        {
-            mojoDescriptor =
-                    pluginManager.getMojoDescriptor( execution.getPlugin(), execution.getGoal(),
-                            project.getRemotePluginRepositories(),
-                            session.getRepositorySession() );
+        if (mojoDescriptor == null) {
+            mojoDescriptor = pluginManager.getMojoDescriptor(
+                    execution.getPlugin(),
+                    execution.getGoal(),
+                    project.getRemotePluginRepositories(),
+                    session.getRepositorySession());
 
-            execution.setMojoDescriptor( mojoDescriptor );
+            execution.setMojoDescriptor(mojoDescriptor);
         }
 
         return mojoDescriptor;
     }
 
     @Override
-    public void setupMojoExecution( MavenSession session, MavenProject project, MojoExecution mojoExecution,
-                                    Set<MojoDescriptor> alreadyPlannedExecutions )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        fillMojoDescriptor( session, project, mojoExecution );
+    public void setupMojoExecution(
+            MavenSession session,
+            MavenProject project,
+            MojoExecution mojoExecution,
+            Set<MojoDescriptor> alreadyPlannedExecutions)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
+        fillMojoDescriptor(session, project, mojoExecution);
 
-        mojoExecutionConfigurator( mojoExecution ).configure( project,
-                                                              mojoExecution,
-                                                        MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) );
+        mojoExecutionConfigurator(mojoExecution)
+                .configure(project, mojoExecution, MojoExecution.Source.CLI.equals(mojoExecution.getSource()));
 
-        finalizeMojoConfiguration( mojoExecution );
+        finalizeMojoConfiguration(mojoExecution);
 
-        calculateForkedExecutions( mojoExecution, session, project, alreadyPlannedExecutions );
+        calculateForkedExecutions(mojoExecution, session, project, alreadyPlannedExecutions);
     }
 
-    public List<MojoExecution> calculateMojoExecutions( MavenSession session, MavenProject project, List<Object> tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException, LifecyclePhaseNotFoundException
-    {
+    public List<MojoExecution> calculateMojoExecutions(MavenSession session, MavenProject project, List<Object> tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginVersionResolutionException, LifecyclePhaseNotFoundException {
         final List<MojoExecution> mojoExecutions = new ArrayList<>();
 
-        for ( Object task : tasks )
-        {
-            if ( task instanceof GoalTask )
-            {
-                String pluginGoal = ( (GoalTask) task ).pluginGoal;
+        for (Object task : tasks) {
+            if (task instanceof GoalTask) {
+                String pluginGoal = ((GoalTask) task).pluginGoal;
 
                 String executionId = "default-cli";
-                int executionIdx = pluginGoal.indexOf( '@' );
-                if ( executionIdx > 0 )
-                {
-                    executionId = pluginGoal.substring( executionIdx + 1 );
+                int executionIdx = pluginGoal.indexOf('@');
+                if (executionIdx > 0) {
+                    executionId = pluginGoal.substring(executionIdx + 1);
                 }
 
-                MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( pluginGoal, session, project );
+                MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor(pluginGoal, session, project);
 
-                MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, executionId,
-                                                                 MojoExecution.Source.CLI );
+                MojoExecution mojoExecution = new MojoExecution(mojoDescriptor, executionId, MojoExecution.Source.CLI);
 
-                mojoExecutions.add( mojoExecution );
-            }
-            else if ( task instanceof LifecycleTask )
-            {
-                String lifecyclePhase = ( (LifecycleTask) task ).getLifecyclePhase();
+                mojoExecutions.add(mojoExecution);
+            } else if (task instanceof LifecycleTask) {
+                String lifecyclePhase = ((LifecycleTask) task).getLifecyclePhase();
 
                 Map<String, List<MojoExecution>> phaseToMojoMapping =
-                    calculateLifecycleMappings( session, project, lifecyclePhase );
+                        calculateLifecycleMappings(session, project, lifecyclePhase);
 
-                for ( List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values() )
-                {
-                    mojoExecutions.addAll( mojoExecutionsFromLifecycle );
+                for (List<MojoExecution> mojoExecutionsFromLifecycle : phaseToMojoMapping.values()) {
+                    mojoExecutions.addAll(mojoExecutionsFromLifecycle);
                 }
-            }
-            else
-            {
-                throw new IllegalStateException( "unexpected task " + task );
+            } else {
+                throw new IllegalStateException("unexpected task " + task);
             }
         }
         return mojoExecutions;
     }
 
-    private Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
-                                                                         String lifecyclePhase )
-        throws LifecyclePhaseNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException
-    {
+    private Map<String, List<MojoExecution>> calculateLifecycleMappings(
+            MavenSession session, MavenProject project, String lifecyclePhase)
+            throws LifecyclePhaseNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException {
         /*
          * Determine the lifecycle that corresponds to the given phase.
          */
 
-        Lifecycle lifecycle = defaultLifecycles.get( lifecyclePhase );
+        Lifecycle lifecycle = defaultLifecycles.get(lifecyclePhase);
 
-        if ( lifecycle == null )
-        {
-            throw new LifecyclePhaseNotFoundException( "Unknown lifecycle phase \"" + lifecyclePhase
-                + "\". You must specify a valid lifecycle phase" + " or a goal in the format <plugin-prefix>:<goal> or"
-                + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: "
-                + defaultLifecycles.getLifecyclePhaseList() + ".", lifecyclePhase );
+        if (lifecycle == null) {
+            throw new LifecyclePhaseNotFoundException(
+                    "Unknown lifecycle phase \"" + lifecyclePhase
+                            + "\". You must specify a valid lifecycle phase"
+                            + " or a goal in the format <plugin-prefix>:<goal> or"
+                            + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: "
+                            + defaultLifecycles.getLifecyclePhaseList() + ".",
+                    lifecyclePhase);
         }
 
         LifecycleMappingDelegate delegate;
-        if ( Arrays.binarySearch( DefaultLifecycles.STANDARD_LIFECYCLES, lifecycle.getId() ) >= 0 )
-        {
+        if (Arrays.binarySearch(DefaultLifecycles.STANDARD_LIFECYCLES, lifecycle.getId()) >= 0) {
             delegate = standardDelegate;
-        }
-        else
-        {
-            delegate = delegates.get( lifecycle.getId() );
-            if ( delegate == null )
-            {
+        } else {
+            delegate = delegates.get(lifecycle.getId());
+            if (delegate == null) {
                 delegate = standardDelegate;
             }
         }
 
-        return delegate.calculateLifecycleMappings( session, project, lifecycle, lifecyclePhase );
+        return delegate.calculateLifecycleMappings(session, project, lifecycle, lifecyclePhase);
     }
 
     /**
@@ -310,161 +276,160 @@
      *
      * @param mojoExecution The mojo execution whose configuration should be finalized, must not be {@code null}.
      */
-    private void finalizeMojoConfiguration( MojoExecution mojoExecution )
-    {
+    private void finalizeMojoConfiguration(MojoExecution mojoExecution) {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
-        Xpp3Dom executionConfiguration = mojoExecution.getConfiguration();
-        if ( executionConfiguration == null )
-        {
-            executionConfiguration = new Xpp3Dom( "configuration" );
+        XmlNode executionConfiguration = mojoExecution.getConfiguration() != null
+                ? mojoExecution.getConfiguration().getDom()
+                : null;
+        if (executionConfiguration == null) {
+            executionConfiguration = new XmlNodeImpl("configuration");
         }
 
-        Xpp3Dom defaultConfiguration = getMojoConfiguration( mojoDescriptor );
+        XmlNode defaultConfiguration = getMojoConfiguration(mojoDescriptor);
 
-        Xpp3Dom finalConfiguration = new Xpp3Dom( "configuration" );
+        List<XmlNode> children = new ArrayList<>();
+        if (mojoDescriptor.getParameters() != null) {
+            for (Parameter parameter : mojoDescriptor.getParameters()) {
+                XmlNode parameterConfiguration = executionConfiguration.getChild(parameter.getName());
 
-        if ( mojoDescriptor.getParameters() != null )
-        {
-            for ( Parameter parameter : mojoDescriptor.getParameters() )
-            {
-                Xpp3Dom parameterConfiguration = executionConfiguration.getChild( parameter.getName() );
-
-                if ( parameterConfiguration == null )
-                {
-                    parameterConfiguration = executionConfiguration.getChild( parameter.getAlias() );
+                if (parameterConfiguration == null) {
+                    parameterConfiguration = executionConfiguration.getChild(parameter.getAlias());
                 }
 
-                Xpp3Dom parameterDefaults = defaultConfiguration.getChild( parameter.getName() );
+                XmlNode parameterDefaults = defaultConfiguration.getChild(parameter.getName());
 
-                parameterConfiguration = Xpp3Dom.mergeXpp3Dom( parameterConfiguration, parameterDefaults,
-                                                               Boolean.TRUE );
+                if (parameterConfiguration != null) {
+                    parameterConfiguration = parameterConfiguration.merge(parameterDefaults, Boolean.TRUE);
+                } else {
+                    parameterConfiguration = parameterDefaults;
+                }
 
-                if ( parameterConfiguration != null )
-                {
-                    parameterConfiguration = new Xpp3Dom( parameterConfiguration, parameter.getName() );
+                if (parameterConfiguration != null) {
+                    Map<String, String> attributes = new HashMap<>(parameterConfiguration.getAttributes());
 
-                    if ( StringUtils.isEmpty( parameterConfiguration.getAttribute( "implementation" ) )
-                        && StringUtils.isNotEmpty( parameter.getImplementation() ) )
-                    {
-                        parameterConfiguration.setAttribute( "implementation", parameter.getImplementation() );
+                    String attributeForImplementation = parameterConfiguration.getAttribute("implementation");
+                    String parameterForImplementation = parameter.getImplementation();
+                    if ((attributeForImplementation == null || attributeForImplementation.isEmpty())
+                            && ((parameterForImplementation != null) && !parameterForImplementation.isEmpty())) {
+                        attributes.put("implementation", parameter.getImplementation());
                     }
 
-                    finalConfiguration.addChild( parameterConfiguration );
+                    parameterConfiguration = new XmlNodeImpl(
+                            parameter.getName(),
+                            parameterConfiguration.getValue(),
+                            attributes,
+                            parameterConfiguration.getChildren(),
+                            parameterConfiguration.getInputLocation());
+
+                    children.add(parameterConfiguration);
                 }
             }
         }
+        XmlNode finalConfiguration = new XmlNodeImpl("configuration", null, null, children, null);
 
-        mojoExecution.setConfiguration( finalConfiguration );
+        mojoExecution.setConfiguration(finalConfiguration);
     }
 
-    private Xpp3Dom getMojoConfiguration( MojoDescriptor mojoDescriptor )
-    {
-        return MojoDescriptorCreator.convert( mojoDescriptor );
+    private XmlNode getMojoConfiguration(MojoDescriptor mojoDescriptor) {
+        if (mojoDescriptor.isV4Api()) {
+            return MojoDescriptorCreator.convert(mojoDescriptor.getMojoDescriptorV4());
+        } else {
+            return MojoDescriptorCreator.convert(mojoDescriptor).getDom();
+        }
     }
 
     @Override
-    public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        calculateForkedExecutions( mojoExecution, session, session.getCurrentProject(), new HashSet<>() );
+    public void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
+        calculateForkedExecutions(mojoExecution, session, session.getCurrentProject(), new HashSet<>());
     }
 
-    private void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session, MavenProject project,
-                                            Collection<MojoDescriptor> alreadyPlannedExecutions )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
+    private void calculateForkedExecutions(
+            MojoExecution mojoExecution,
+            MavenSession session,
+            MavenProject project,
+            Collection<MojoDescriptor> alreadyPlannedExecutions)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
-        if ( !mojoDescriptor.isForking() )
-        {
+        if (!mojoDescriptor.isForking()) {
             return;
         }
 
-        alreadyPlannedExecutions.add( mojoDescriptor );
+        alreadyPlannedExecutions.add(mojoDescriptor);
 
         List<MavenProject> forkedProjects =
-            LifecycleDependencyResolver.getProjects( project, session, mojoDescriptor.isAggregator() );
+                LifecycleDependencyResolver.getProjects(project, session, mojoDescriptor.isAggregator());
 
-        for ( MavenProject forkedProject : forkedProjects )
-        {
-            if ( forkedProject != project )
-            {
-                lifecyclePluginResolver.resolveMissingPluginVersions( forkedProject, session );
+        for (MavenProject forkedProject : forkedProjects) {
+            if (forkedProject != project) {
+                lifecyclePluginResolver.resolveMissingPluginVersions(forkedProject, session);
             }
 
             List<MojoExecution> forkedExecutions;
 
-            if ( StringUtils.isNotEmpty( mojoDescriptor.getExecutePhase() ) )
-            {
+            if (mojoDescriptor.getExecutePhase() != null
+                    && !mojoDescriptor.getExecutePhase().isEmpty()) {
                 forkedExecutions =
-                    calculateForkedLifecycle( mojoExecution, session, forkedProject, alreadyPlannedExecutions );
-            }
-            else
-            {
-                forkedExecutions = calculateForkedGoal( mojoExecution, session, forkedProject,
-                                                        alreadyPlannedExecutions );
+                        calculateForkedLifecycle(mojoExecution, session, forkedProject, alreadyPlannedExecutions);
+            } else {
+                forkedExecutions = calculateForkedGoal(mojoExecution, session, forkedProject, alreadyPlannedExecutions);
             }
 
             // This List can be empty when the executions are already present in the plan
-            if ( !forkedExecutions.isEmpty() )
-            {
-                mojoExecution.setForkedExecutions( BuilderCommon.getKey( forkedProject ), forkedExecutions );
+            if (!forkedExecutions.isEmpty()) {
+                mojoExecution.setForkedExecutions(BuilderCommon.getKey(forkedProject), forkedExecutions);
             }
         }
     }
 
-    private List<MojoExecution> calculateForkedLifecycle( MojoExecution mojoExecution, MavenSession session,
-                                                          MavenProject project,
-                                                          Collection<MojoDescriptor> alreadyPlannedExecutions )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
+    private List<MojoExecution> calculateForkedLifecycle(
+            MojoExecution mojoExecution,
+            MavenSession session,
+            MavenProject project,
+            Collection<MojoDescriptor> alreadyPlannedExecutions)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
         String forkedPhase = mojoDescriptor.getExecutePhase();
 
-        Map<String, List<MojoExecution>> lifecycleMappings = calculateLifecycleMappings( session, project,
-                                                                                         forkedPhase );
+        Map<String, List<MojoExecution>> lifecycleMappings = calculateLifecycleMappings(session, project, forkedPhase);
 
-        for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
-        {
-            for ( MojoExecution forkedExecution : forkedExecutions )
-            {
-                if ( forkedExecution.getMojoDescriptor() == null )
-                {
-                    MojoDescriptor forkedMojoDescriptor =
-                        pluginManager.getMojoDescriptor( forkedExecution.getPlugin(), forkedExecution.getGoal(),
-                                                         project.getRemotePluginRepositories(),
-                                                         session.getRepositorySession() );
+        for (List<MojoExecution> forkedExecutions : lifecycleMappings.values()) {
+            for (MojoExecution forkedExecution : forkedExecutions) {
+                if (forkedExecution.getMojoDescriptor() == null) {
+                    MojoDescriptor forkedMojoDescriptor = pluginManager.getMojoDescriptor(
+                            forkedExecution.getPlugin(),
+                            forkedExecution.getGoal(),
+                            project.getRemotePluginRepositories(),
+                            session.getRepositorySession());
 
-                    forkedExecution.setMojoDescriptor( forkedMojoDescriptor );
+                    forkedExecution.setMojoDescriptor(forkedMojoDescriptor);
                 }
 
-                mojoExecutionConfigurator( forkedExecution ).configure( project, forkedExecution, false );
+                mojoExecutionConfigurator(forkedExecution).configure(project, forkedExecution, false);
             }
         }
 
-        injectLifecycleOverlay( lifecycleMappings, mojoExecution, session, project );
+        injectLifecycleOverlay(lifecycleMappings, mojoExecution, session, project);
 
         List<MojoExecution> mojoExecutions = new ArrayList<>();
 
-        for ( List<MojoExecution> forkedExecutions : lifecycleMappings.values() )
-        {
-            for ( MojoExecution forkedExecution : forkedExecutions )
-            {
-                if ( !alreadyPlannedExecutions.contains( forkedExecution.getMojoDescriptor() ) )
-                {
-                    finalizeMojoConfiguration( forkedExecution );
+        for (List<MojoExecution> forkedExecutions : lifecycleMappings.values()) {
+            for (MojoExecution forkedExecution : forkedExecutions) {
+                if (!alreadyPlannedExecutions.contains(forkedExecution.getMojoDescriptor())) {
+                    finalizeMojoConfiguration(forkedExecution);
 
-                    calculateForkedExecutions( forkedExecution, session, project, alreadyPlannedExecutions );
+                    calculateForkedExecutions(forkedExecution, session, project, alreadyPlannedExecutions);
 
-                    mojoExecutions.add( forkedExecution );
+                    mojoExecutions.add(forkedExecution);
                 }
             }
         }
@@ -472,88 +437,79 @@
         return mojoExecutions;
     }
 
-    private void injectLifecycleOverlay( Map<String, List<MojoExecution>> lifecycleMappings,
-                                         MojoExecution mojoExecution, MavenSession session, MavenProject project )
-        throws PluginDescriptorParsingException, LifecycleNotFoundException, MojoNotFoundException,
-        PluginNotFoundException, PluginResolutionException, NoPluginFoundForPrefixException,
-        InvalidPluginDescriptorException, PluginVersionResolutionException
-    {
+    private void injectLifecycleOverlay(
+            Map<String, List<MojoExecution>> lifecycleMappings,
+            MojoExecution mojoExecution,
+            MavenSession session,
+            MavenProject project)
+            throws PluginDescriptorParsingException, LifecycleNotFoundException, MojoNotFoundException,
+                    PluginNotFoundException, PluginResolutionException, NoPluginFoundForPrefixException,
+                    InvalidPluginDescriptorException, PluginVersionResolutionException {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
 
         String forkedLifecycle = mojoDescriptor.getExecuteLifecycle();
 
-        if ( StringUtils.isEmpty( forkedLifecycle ) )
-        {
+        if (forkedLifecycle == null || forkedLifecycle.isEmpty()) {
             return;
         }
 
-        org.apache.maven.plugin.lifecycle.Lifecycle lifecycleOverlay;
+        org.apache.maven.api.plugin.descriptor.lifecycle.Lifecycle lifecycleOverlay;
 
-        try
-        {
-            lifecycleOverlay = pluginDescriptor.getLifecycleMapping( forkedLifecycle );
-        }
-        catch ( IOException | XmlPullParserException e )
-        {
-            throw new PluginDescriptorParsingException( pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e );
+        try {
+            lifecycleOverlay = pluginDescriptor.getLifecycleMapping(forkedLifecycle);
+        } catch (IOException | XMLStreamException e) {
+            throw new PluginDescriptorParsingException(pluginDescriptor.getPlugin(), pluginDescriptor.getSource(), e);
         }
 
-        if ( lifecycleOverlay == null )
-        {
-            throw new LifecycleNotFoundException( forkedLifecycle );
+        if (lifecycleOverlay == null) {
+            throw new LifecycleNotFoundException(forkedLifecycle);
         }
 
-        for ( Phase phase : lifecycleOverlay.getPhases() )
-        {
-            List<MojoExecution> forkedExecutions = lifecycleMappings.get( phase.getId() );
+        for (Phase phase : lifecycleOverlay.getPhases()) {
+            List<MojoExecution> forkedExecutions = lifecycleMappings.get(phase.getId());
 
-            if ( forkedExecutions != null )
-            {
-                for ( Execution execution : phase.getExecutions() )
-                {
-                    for ( String goal : execution.getGoals() )
-                    {
+            if (forkedExecutions != null) {
+                for (Execution execution : phase.getExecutions()) {
+                    for (String goal : execution.getGoals()) {
                         MojoDescriptor forkedMojoDescriptor;
 
-                        if ( goal.indexOf( ':' ) < 0 )
-                        {
-                            forkedMojoDescriptor = pluginDescriptor.getMojo( goal );
-                            if ( forkedMojoDescriptor == null )
-                            {
-                                throw new MojoNotFoundException( goal, pluginDescriptor );
+                        if (goal.indexOf(':') < 0) {
+                            forkedMojoDescriptor = pluginDescriptor.getMojo(goal);
+                            if (forkedMojoDescriptor == null) {
+                                throw new MojoNotFoundException(goal, pluginDescriptor);
                             }
-                        }
-                        else
-                        {
-                            forkedMojoDescriptor = mojoDescriptorCreator.getMojoDescriptor( goal, session, project );
+                        } else {
+                            forkedMojoDescriptor = mojoDescriptorCreator.getMojoDescriptor(goal, session, project);
                         }
 
                         MojoExecution forkedExecution =
-                            new MojoExecution( forkedMojoDescriptor, mojoExecution.getExecutionId() );
+                                new MojoExecution(forkedMojoDescriptor, mojoExecution.getExecutionId());
 
-                        Xpp3Dom forkedConfiguration = (Xpp3Dom) execution.getConfiguration();
+                        XmlNode forkedConfiguration = execution.getConfiguration();
 
-                        forkedExecution.setConfiguration( forkedConfiguration );
+                        forkedExecution.setConfiguration(forkedConfiguration);
 
-                        mojoExecutionConfigurator( forkedExecution ).configure( project, forkedExecution, true );
+                        mojoExecutionConfigurator(forkedExecution).configure(project, forkedExecution, true);
 
-                        forkedExecutions.add( forkedExecution );
+                        forkedExecutions.add(forkedExecution);
                     }
                 }
 
-                Xpp3Dom phaseConfiguration = (Xpp3Dom) phase.getConfiguration();
+                XmlNode phaseConfiguration = phase.getConfiguration();
 
-                if ( phaseConfiguration != null )
-                {
-                    for ( MojoExecution forkedExecution : forkedExecutions )
-                    {
-                        Xpp3Dom forkedConfiguration = forkedExecution.getConfiguration();
+                if (phaseConfiguration != null) {
+                    for (MojoExecution forkedExecution : forkedExecutions) {
+                        org.codehaus.plexus.util.xml.Xpp3Dom config = forkedExecution.getConfiguration();
 
-                        forkedConfiguration = Xpp3Dom.mergeXpp3Dom( phaseConfiguration, forkedConfiguration );
+                        if (config != null) {
+                            XmlNode forkedConfiguration = config.getDom();
 
-                        forkedExecution.setConfiguration( forkedConfiguration );
+                            forkedConfiguration = phaseConfiguration.merge(forkedConfiguration);
+
+                            forkedExecution.setConfiguration(forkedConfiguration);
+                        }
                     }
                 }
             }
@@ -565,58 +521,54 @@
     // TODO collect at the root of the repository, read the one at the root, and fetch remote if something is missing
     // or the user forces the issue
 
-    private List<MojoExecution> calculateForkedGoal( MojoExecution mojoExecution, MavenSession session,
-                                                     MavenProject project,
-                                                     Collection<MojoDescriptor> alreadyPlannedExecutions )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
+    private List<MojoExecution> calculateForkedGoal(
+            MojoExecution mojoExecution,
+            MavenSession session,
+            MavenProject project,
+            Collection<MojoDescriptor> alreadyPlannedExecutions)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
 
         String forkedGoal = mojoDescriptor.getExecuteGoal();
 
-        MojoDescriptor forkedMojoDescriptor = pluginDescriptor.getMojo( forkedGoal );
-        if ( forkedMojoDescriptor == null )
-        {
-            throw new MojoNotFoundException( forkedGoal, pluginDescriptor );
+        MojoDescriptor forkedMojoDescriptor = pluginDescriptor.getMojo(forkedGoal);
+        if (forkedMojoDescriptor == null) {
+            throw new MojoNotFoundException(forkedGoal, pluginDescriptor);
         }
 
-        if ( alreadyPlannedExecutions.contains( forkedMojoDescriptor ) )
-        {
+        if (alreadyPlannedExecutions.contains(forkedMojoDescriptor)) {
             return Collections.emptyList();
         }
 
-        MojoExecution forkedExecution = new MojoExecution( forkedMojoDescriptor, forkedGoal );
+        MojoExecution forkedExecution = new MojoExecution(forkedMojoDescriptor, forkedGoal);
 
-        mojoExecutionConfigurator( forkedExecution ).configure( project, forkedExecution, true );
+        mojoExecutionConfigurator(forkedExecution).configure(project, forkedExecution, true);
 
-        finalizeMojoConfiguration( forkedExecution );
+        finalizeMojoConfiguration(forkedExecution);
 
-        calculateForkedExecutions( forkedExecution, session, project, alreadyPlannedExecutions );
+        calculateForkedExecutions(forkedExecution, session, project, alreadyPlannedExecutions);
 
-        return Collections.singletonList( forkedExecution );
+        return Collections.singletonList(forkedExecution);
     }
 
-    private MojoExecutionConfigurator mojoExecutionConfigurator( MojoExecution mojoExecution )
-    {
+    private MojoExecutionConfigurator mojoExecutionConfigurator(MojoExecution mojoExecution) {
         String configuratorId = mojoExecution.getMojoDescriptor().getComponentConfigurator();
-        if ( configuratorId == null )
-        {
+        if (configuratorId == null) {
             configuratorId = "default";
         }
 
-        MojoExecutionConfigurator mojoExecutionConfigurator = mojoExecutionConfigurators.get( configuratorId );
+        MojoExecutionConfigurator mojoExecutionConfigurator = mojoExecutionConfigurators.get(configuratorId);
 
-        if ( mojoExecutionConfigurator == null )
-        {
+        if (mojoExecutionConfigurator == null) {
             //
             // The plugin has a custom component configurator but does not have a custom mojo execution configurator
             // so fall back to the default mojo execution configurator.
             //
-            mojoExecutionConfigurator = mojoExecutionConfigurators.get( "default" );
+            mojoExecutionConfigurator = mojoExecutionConfigurators.get("default");
         }
         return mojoExecutionConfigurator;
     }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java
index cd7c812..96ba78e 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleMappingDelegate.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -25,10 +28,6 @@
 import java.util.Map;
 import java.util.TreeMap;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.Lifecycle;
 import org.apache.maven.lifecycle.LifecycleMappingDelegate;
@@ -49,42 +48,35 @@
  * lifecycle phase. Standard lifecycles use plugin execution {@code <phase>} or mojo default lifecycle phase to
  * calculate the execution plan, but custom lifecycles can use alternative mapping strategies.
  */
-@Named( DefaultLifecycleMappingDelegate.HINT )
+@Named(DefaultLifecycleMappingDelegate.HINT)
 @Singleton
-public class DefaultLifecycleMappingDelegate
-    implements LifecycleMappingDelegate
-{
+public class DefaultLifecycleMappingDelegate implements LifecycleMappingDelegate {
     public static final String HINT = "default";
 
     private final BuildPluginManager pluginManager;
 
     @Inject
-    public DefaultLifecycleMappingDelegate( BuildPluginManager pluginManager )
-    {
+    public DefaultLifecycleMappingDelegate(BuildPluginManager pluginManager) {
         this.pluginManager = pluginManager;
     }
 
-    public Map<String, List<MojoExecution>> calculateLifecycleMappings( MavenSession session, MavenProject project,
-                                                                        Lifecycle lifecycle, String lifecyclePhase )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException
-    {
+    public Map<String, List<MojoExecution>> calculateLifecycleMappings(
+            MavenSession session, MavenProject project, Lifecycle lifecycle, String lifecyclePhase)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException {
         /*
          * Initialize mapping from lifecycle phase to bound mojos. The key set of this map denotes the phases the caller
          * is interested in, i.e. all phases up to and including the specified phase.
          */
 
-        Map<String, Map<Integer, List<MojoExecution>>> mappings =
-            new LinkedHashMap<>();
+        Map<String, Map<Integer, List<MojoExecution>>> mappings = new LinkedHashMap<>();
 
-        for ( String phase : lifecycle.getPhases() )
-        {
+        for (String phase : lifecycle.getPhases()) {
             Map<Integer, List<MojoExecution>> phaseBindings = new TreeMap<>();
 
-            mappings.put( phase, phaseBindings );
+            mappings.put(phase, phaseBindings);
 
-            if ( phase.equals( lifecyclePhase ) )
-            {
+            if (phase.equals(lifecyclePhase)) {
                 break;
             }
         }
@@ -96,40 +88,31 @@
          * not interested in any of the executions bound to it.
          */
 
-        for ( Plugin plugin : project.getBuild().getPlugins() )
-        {
-            for ( PluginExecution execution : plugin.getExecutions() )
-            {
+        for (Plugin plugin : project.getBuild().getPlugins()) {
+            for (PluginExecution execution : plugin.getExecutions()) {
                 // if the phase is specified then I don't have to go fetch the plugin yet and pull it down
                 // to examine the phase it is associated to.
-                if ( execution.getPhase() != null )
-                {
-                    Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( execution.getPhase() );
-                    if ( phaseBindings != null )
-                    {
-                        for ( String goal : execution.getGoals() )
-                        {
-                            MojoExecution mojoExecution = new MojoExecution( plugin, goal, execution.getId() );
-                            mojoExecution.setLifecyclePhase( execution.getPhase() );
-                            addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
+                if (execution.getPhase() != null) {
+                    Map<Integer, List<MojoExecution>> phaseBindings = mappings.get(execution.getPhase());
+                    if (phaseBindings != null) {
+                        for (String goal : execution.getGoals()) {
+                            MojoExecution mojoExecution = new MojoExecution(plugin, goal, execution.getId());
+                            mojoExecution.setLifecyclePhase(execution.getPhase());
+                            addMojoExecution(phaseBindings, mojoExecution, execution.getPriority());
                         }
                     }
                 }
                 // if not then I need to grab the mojo descriptor and look at the phase that is specified
-                else
-                {
-                    for ( String goal : execution.getGoals() )
-                    {
-                        MojoDescriptor mojoDescriptor =
-                            pluginManager.getMojoDescriptor( plugin, goal, project.getRemotePluginRepositories(),
-                                                             session.getRepositorySession() );
+                else {
+                    for (String goal : execution.getGoals()) {
+                        MojoDescriptor mojoDescriptor = pluginManager.getMojoDescriptor(
+                                plugin, goal, project.getRemotePluginRepositories(), session.getRepositorySession());
 
-                        Map<Integer, List<MojoExecution>> phaseBindings = mappings.get( mojoDescriptor.getPhase() );
-                        if ( phaseBindings != null )
-                        {
-                            MojoExecution mojoExecution = new MojoExecution( mojoDescriptor, execution.getId() );
-                            mojoExecution.setLifecyclePhase( mojoDescriptor.getPhase() );
-                            addMojoExecution( phaseBindings, mojoExecution, execution.getPriority() );
+                        Map<Integer, List<MojoExecution>> phaseBindings = mappings.get(mojoDescriptor.getPhase());
+                        if (phaseBindings != null) {
+                            MojoExecution mojoExecution = new MojoExecution(mojoDescriptor, execution.getId());
+                            mojoExecution.setLifecyclePhase(mojoDescriptor.getPhase());
+                            addMojoExecution(phaseBindings, mojoExecution, execution.getPriority());
                         }
                     }
                 }
@@ -138,28 +121,23 @@
 
         Map<String, List<MojoExecution>> lifecycleMappings = new LinkedHashMap<>();
 
-        for ( Map.Entry<String, Map<Integer, List<MojoExecution>>> entry : mappings.entrySet() )
-        {
+        for (Map.Entry<String, Map<Integer, List<MojoExecution>>> entry : mappings.entrySet()) {
             List<MojoExecution> mojoExecutions = new ArrayList<>();
 
-            for ( List<MojoExecution> executions : entry.getValue().values() )
-            {
-                mojoExecutions.addAll( executions );
+            for (List<MojoExecution> executions : entry.getValue().values()) {
+                mojoExecutions.addAll(executions);
             }
 
-            lifecycleMappings.put( entry.getKey(), mojoExecutions );
+            lifecycleMappings.put(entry.getKey(), mojoExecutions);
         }
 
         return lifecycleMappings;
-
     }
 
-    private void addMojoExecution( Map<Integer, List<MojoExecution>> phaseBindings, MojoExecution mojoExecution,
-                                   int priority )
-    {
-        List<MojoExecution> mojoExecutions = phaseBindings.computeIfAbsent( priority, k -> new ArrayList<>() );
+    private void addMojoExecution(
+            Map<Integer, List<MojoExecution>> phaseBindings, MojoExecution mojoExecution, int priority) {
+        List<MojoExecution> mojoExecutions = phaseBindings.computeIfAbsent(priority, k -> new ArrayList<>());
 
-        mojoExecutions.add( mojoExecution );
+        mojoExecutions.add(mojoExecution);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java
index b0e3fa1..652de2c 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecyclePluginAnalyzer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.HashSet;
 import java.util.LinkedHashMap;
@@ -26,6 +29,7 @@
 import java.util.NoSuchElementException;
 import java.util.Set;
 
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.lifecycle.DefaultLifecycles;
 import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
 import org.apache.maven.lifecycle.Lifecycle;
@@ -38,46 +42,35 @@
 import org.apache.maven.model.PluginExecution;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
-import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import static java.util.Objects.requireNonNull;
 
 /**
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Jason van Zyl
- * @author jdcasey
- * @author Kristian Rosenvold (extracted class only)
  */
 @Singleton
 @Named
-public class DefaultLifecyclePluginAnalyzer
-    implements LifeCyclePluginAnalyzer
-{
+public class DefaultLifecyclePluginAnalyzer implements LifeCyclePluginAnalyzer {
     public static final String DEFAULTLIFECYCLEBINDINGS_MODELID = "org.apache.maven:maven-core:"
-        + DefaultLifecyclePluginAnalyzer.class.getPackage().getImplementationVersion() + ":default-lifecycle-bindings";
+            + DefaultLifecyclePluginAnalyzer.class.getPackage().getImplementationVersion()
+            + ":default-lifecycle-bindings";
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final PlexusContainer plexusContainer;
 
     private final DefaultLifecycles defaultLifeCycles;
 
     @Inject
-    public DefaultLifecyclePluginAnalyzer( final PlexusContainer plexusContainer,
-                                           final DefaultLifecycles defaultLifeCycles )
-    {
-        this.plexusContainer = requireNonNull( plexusContainer );
-        this.defaultLifeCycles = requireNonNull( defaultLifeCycles );
+    public DefaultLifecyclePluginAnalyzer(
+            final PlexusContainer plexusContainer, final DefaultLifecycles defaultLifeCycles) {
+        this.plexusContainer = requireNonNull(plexusContainer);
+        this.defaultLifeCycles = requireNonNull(defaultLifeCycles);
     }
 
     // These methods deal with construction intact Plugin object that look like they come from a standard
@@ -91,48 +84,38 @@
     //
 
     @Override
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
-        if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "Looking up lifecycle mappings for packaging " + packaging + " from "
-                + Thread.currentThread().getContextClassLoader() );
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("Looking up lifecycle mappings for packaging " + packaging + " from "
+                    + Thread.currentThread().getContextClassLoader());
         }
 
-        LifecycleMapping lifecycleMappingForPackaging = lookupLifecycleMapping( packaging );
+        LifecycleMapping lifecycleMappingForPackaging = lookupLifecycleMapping(packaging);
 
-        if ( lifecycleMappingForPackaging == null )
-        {
+        if (lifecycleMappingForPackaging == null) {
             return null;
         }
 
         Map<Plugin, Plugin> plugins = new LinkedHashMap<>();
 
-        for ( Lifecycle lifecycle : defaultLifeCycles.getLifeCycles() )
-        {
+        for (Lifecycle lifecycle : defaultLifeCycles.getLifeCycles()) {
             org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration =
-                lifecycleMappingForPackaging.getLifecycles().get( lifecycle.getId() );
+                    lifecycleMappingForPackaging.getLifecycles().get(lifecycle.getId());
 
             Map<String, LifecyclePhase> phaseToGoalMapping = null;
 
-            if ( lifecycleConfiguration != null )
-            {
+            if (lifecycleConfiguration != null) {
                 phaseToGoalMapping = lifecycleConfiguration.getLifecyclePhases();
-            }
-            else if ( lifecycle.getDefaultLifecyclePhases() != null )
-            {
+            } else if (lifecycle.getDefaultLifecyclePhases() != null) {
                 phaseToGoalMapping = lifecycle.getDefaultLifecyclePhases();
             }
 
-            if ( phaseToGoalMapping != null )
-            {
-                for ( Map.Entry<String, LifecyclePhase> goalsForLifecyclePhase : phaseToGoalMapping.entrySet() )
-                {
+            if (phaseToGoalMapping != null) {
+                for (Map.Entry<String, LifecyclePhase> goalsForLifecyclePhase : phaseToGoalMapping.entrySet()) {
                     String phase = goalsForLifecyclePhase.getKey();
                     LifecyclePhase goals = goalsForLifecyclePhase.getValue();
-                    if ( goals != null )
-                    {
-                        parseLifecyclePhaseDefinitions( plugins, phase, goals );
+                    if (goals != null) {
+                        parseLifecyclePhaseDefinitions(plugins, phase, goals);
                     }
                 }
             }
@@ -145,117 +128,101 @@
      * Performs a lookup using Plexus API to make sure we can look up only "visible" (see Maven classloading) components
      * from current module and for example not extensions coming from other modules.
      */
-    private LifecycleMapping lookupLifecycleMapping( final String packaging )
-    {
-        try
-        {
-            return plexusContainer.lookup( LifecycleMapping.class, packaging );
-        }
-        catch ( ComponentLookupException e )
-        {
-            if ( e.getCause() instanceof NoSuchElementException )
-            {
+    private LifecycleMapping lookupLifecycleMapping(final String packaging) {
+        try {
+            return plexusContainer.lookup(LifecycleMapping.class, packaging);
+        } catch (ComponentLookupException e) {
+            if (e.getCause() instanceof NoSuchElementException) {
                 return null;
             }
-            throw new RuntimeException( e );
+            throw new RuntimeException(e);
         }
     }
 
-    private void parseLifecyclePhaseDefinitions( Map<Plugin, Plugin> plugins, String phase, LifecyclePhase goals )
-    {
+    private void parseLifecyclePhaseDefinitions(Map<Plugin, Plugin> plugins, String phase, LifecyclePhase goals) {
         InputSource inputSource = new InputSource();
-        inputSource.setModelId( DEFAULTLIFECYCLEBINDINGS_MODELID );
-        InputLocation location = new InputLocation( -1, -1, inputSource );
-        location.setLocation( 0, location );
+        inputSource.setModelId(DEFAULTLIFECYCLEBINDINGS_MODELID);
+        InputLocation location = new InputLocation(-1, -1, inputSource);
+        location.setLocation(0, location);
 
         List<LifecycleMojo> mojos = goals.getMojos();
-        if ( mojos != null )
-        {
+        if (mojos != null) {
 
-            for ( int i = 0; i < mojos.size(); i++ )
-            {
-                LifecycleMojo mojo = mojos.get( i );
+            for (int i = 0; i < mojos.size(); i++) {
+                LifecycleMojo mojo = mojos.get(i);
 
-                GoalSpec gs = parseGoalSpec( mojo.getGoal() );
+                GoalSpec gs = parseGoalSpec(mojo.getGoal());
 
-                if ( gs == null )
-                {
-                    logger.warn( "Ignored invalid goal specification '" + mojo.getGoal()
-                            + "' from lifecycle mapping for phase " + phase );
+                if (gs == null) {
+                    logger.warn(
+                            "Ignored invalid goal specification '{}' from lifecycle mapping for phase {}",
+                            mojo.getGoal(),
+                            phase);
                     continue;
                 }
 
                 Plugin plugin = new Plugin();
-                plugin.setGroupId( gs.groupId );
-                plugin.setArtifactId( gs.artifactId );
-                plugin.setVersion( gs.version );
+                plugin.setGroupId(gs.groupId);
+                plugin.setArtifactId(gs.artifactId);
+                plugin.setVersion(gs.version);
 
-                plugin.setLocation( "", location );
-                plugin.setLocation( "groupId", location );
-                plugin.setLocation( "artifactId", location );
-                plugin.setLocation( "version", location );
+                plugin.setLocation("", location);
+                plugin.setLocation("groupId", location);
+                plugin.setLocation("artifactId", location);
+                plugin.setLocation("version", location);
 
-                Plugin existing = plugins.get( plugin );
-                if ( existing != null )
-                {
-                    if ( existing.getVersion() == null )
-                    {
-                        existing.setVersion( plugin.getVersion() );
-                        existing.setLocation( "version", location );
+                Plugin existing = plugins.get(plugin);
+                if (existing != null) {
+                    if (existing.getVersion() == null) {
+                        existing.setVersion(plugin.getVersion());
+                        existing.setLocation("version", location);
                     }
                     plugin = existing;
-                }
-                else
-                {
-                    plugins.put( plugin, plugin );
+                } else {
+                    plugins.put(plugin, plugin);
                 }
 
                 PluginExecution execution = new PluginExecution();
-                execution.setId( getExecutionId( plugin, gs.goal ) );
-                execution.setPhase( phase );
-                execution.setPriority( i - mojos.size() );
-                execution.getGoals().add( gs.goal );
+                execution.setId(getExecutionId(plugin, gs.goal));
+                execution.setPhase(phase);
+                execution.setPriority(i - mojos.size());
+                execution.getGoals().add(gs.goal);
 
-                execution.setLocation( "", location );
-                execution.setLocation( "id", location );
-                execution.setLocation( "phase", location );
-                execution.setLocation( "goals", location );
+                execution.setLocation("", location);
+                execution.setLocation("id", location);
+                execution.setLocation("phase", location);
+                execution.setLocation("goals", location);
 
-                Xpp3Dom lifecycleConfiguration = mojo.getConfiguration();
-                if ( lifecycleConfiguration != null )
-                {
-                    execution.setConfiguration( new Xpp3Dom( lifecycleConfiguration ) );
+                XmlNode lifecycleConfiguration = mojo.getConfiguration();
+                if (lifecycleConfiguration != null) {
+                    execution.setConfiguration(new Xpp3Dom(lifecycleConfiguration));
                 }
 
-                plugin.setDependencies( mojo.getDependencies() );
-                plugin.getExecutions().add( execution );
+                if (mojo.getDependencies() != null) {
+                    plugin.setDependencies(mojo.getDependencies());
+                }
+                plugin.getExecutions().add(execution);
             }
         }
     }
 
-    private GoalSpec parseGoalSpec( String goalSpec )
-    {
+    private GoalSpec parseGoalSpec(String goalSpec) {
         GoalSpec gs = new GoalSpec();
 
-        String[] p = StringUtils.split( goalSpec.trim(), ":" );
+        String[] p = goalSpec.trim().split(":");
 
-        if ( p.length == 3 )
-        {
+        if (p.length == 3) {
             // <groupId>:<artifactId>:<goal>
             gs.groupId = p[0];
             gs.artifactId = p[1];
             gs.goal = p[2];
-        }
-        else if ( p.length == 4 )
-        {
+        } else if (p.length == 4) {
             // <groupId>:<artifactId>:<version>:<goal>
             gs.groupId = p[0];
             gs.artifactId = p[1];
             gs.version = p[2];
             gs.goal = p[3];
-        }
-        else
-        {
+        } else {
             // invalid
             gs = null;
         }
@@ -263,27 +230,23 @@
         return gs;
     }
 
-    private String getExecutionId( Plugin plugin, String goal )
-    {
+    private String getExecutionId(Plugin plugin, String goal) {
         Set<String> existingIds = new HashSet<>();
-        for ( PluginExecution execution : plugin.getExecutions() )
-        {
-            existingIds.add( execution.getId() );
+        for (PluginExecution execution : plugin.getExecutions()) {
+            existingIds.add(execution.getId());
         }
 
         String base = "default-" + goal;
         String id = base;
 
-        for ( int index = 1; existingIds.contains( id ); index++ )
-        {
+        for (int index = 1; existingIds.contains(id); index++) {
             id = base + '-' + index;
         }
 
         return id;
     }
 
-    static class GoalSpec
-    {
+    static class GoalSpec {
 
         String groupId;
 
@@ -292,7 +255,5 @@
         String version;
 
         String goal;
-
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator.java
index 01686f0..78dc0b7 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultLifecycleTaskSegmentCalculator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.LifecycleNotFoundException;
 import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
@@ -39,7 +39,6 @@
 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * <p>
@@ -48,103 +47,86 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Jason van Zyl
- * @author jdcasey
- * @author Kristian Rosenvold (extracted class)
  */
 @Named
 @Singleton
-public class DefaultLifecycleTaskSegmentCalculator
-    implements LifecycleTaskSegmentCalculator
-{
+public class DefaultLifecycleTaskSegmentCalculator implements LifecycleTaskSegmentCalculator {
     private final MojoDescriptorCreator mojoDescriptorCreator;
 
     private final LifecyclePluginResolver lifecyclePluginResolver;
 
     @Inject
     public DefaultLifecycleTaskSegmentCalculator(
-            MojoDescriptorCreator mojoDescriptorCreator,
-            LifecyclePluginResolver lifecyclePluginResolver )
-    {
+            MojoDescriptorCreator mojoDescriptorCreator, LifecyclePluginResolver lifecyclePluginResolver) {
         this.mojoDescriptorCreator = mojoDescriptorCreator;
         this.lifecyclePluginResolver = lifecyclePluginResolver;
     }
 
-    public List<TaskSegment> calculateTaskSegments( MavenSession session )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+    public List<TaskSegment> calculateTaskSegments(MavenSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
 
         MavenProject rootProject = session.getTopLevelProject();
 
         List<String> tasks = session.getGoals();
 
-        if ( ( tasks == null || tasks.isEmpty() ) && !StringUtils.isEmpty( rootProject.getDefaultGoal() ) )
-        {
-            tasks = Arrays.asList( StringUtils.split( rootProject.getDefaultGoal() ) );
+        if ((tasks == null || tasks.isEmpty())
+                && (rootProject.getDefaultGoal() != null
+                        && !rootProject.getDefaultGoal().isEmpty())) {
+            tasks = Stream.of(rootProject.getDefaultGoal().split("\\s+"))
+                    .filter(g -> !g.isEmpty())
+                    .collect(Collectors.toList());
         }
 
-        return calculateTaskSegments( session, tasks );
+        return calculateTaskSegments(session, tasks);
     }
 
-    public List<TaskSegment> calculateTaskSegments( MavenSession session, List<String> tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException
-    {
-        List<TaskSegment> taskSegments = new ArrayList<>( tasks.size() );
+    public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginVersionResolutionException {
+        List<TaskSegment> taskSegments = new ArrayList<>(tasks.size());
 
         TaskSegment currentSegment = null;
 
-        for ( String task : tasks )
-        {
-            if ( isGoalSpecification( task ) )
-            {
+        for (String task : tasks) {
+            if (isGoalSpecification(task)) {
                 // "pluginPrefix[:version]:goal" or "groupId:artifactId[:version]:goal"
 
-                lifecyclePluginResolver.resolveMissingPluginVersions( session.getTopLevelProject(), session );
+                lifecyclePluginResolver.resolveMissingPluginVersions(session.getTopLevelProject(), session);
 
                 MojoDescriptor mojoDescriptor =
-                    mojoDescriptorCreator.getMojoDescriptor( task, session, session.getTopLevelProject() );
+                        mojoDescriptorCreator.getMojoDescriptor(task, session, session.getTopLevelProject());
 
                 boolean aggregating = mojoDescriptor.isAggregator() || !mojoDescriptor.isProjectRequired();
 
-                if ( currentSegment == null || currentSegment.isAggregating() != aggregating )
-                {
-                    currentSegment = new TaskSegment( aggregating );
-                    taskSegments.add( currentSegment );
+                if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
+                    currentSegment = new TaskSegment(aggregating);
+                    taskSegments.add(currentSegment);
                 }
 
-                currentSegment.getTasks().add( new GoalTask( task ) );
-            }
-            else
-            {
+                currentSegment.getTasks().add(new GoalTask(task));
+            } else {
                 // lifecycle phase
 
-                if ( currentSegment == null || currentSegment.isAggregating() )
-                {
-                    currentSegment = new TaskSegment( false );
-                    taskSegments.add( currentSegment );
+                if (currentSegment == null || currentSegment.isAggregating()) {
+                    currentSegment = new TaskSegment(false);
+                    taskSegments.add(currentSegment);
                 }
 
-                currentSegment.getTasks().add( new LifecycleTask( task ) );
+                currentSegment.getTasks().add(new LifecycleTask(task));
             }
         }
 
         return taskSegments;
     }
 
-    public boolean requiresProject( MavenSession session )
-    {
+    public boolean requiresProject(MavenSession session) {
         List<String> goals = session.getGoals();
-        if ( goals != null )
-        {
-            for ( String goal : goals )
-            {
-                if ( !isGoalSpecification( goal ) )
-                {
+        if (goals != null) {
+            for (String goal : goals) {
+                if (!isGoalSpecification(goal)) {
                     return true;
                 }
             }
@@ -152,10 +134,7 @@
         return false;
     }
 
-
-    private boolean isGoalSpecification( String task )
-    {
-        return task.indexOf( ':' ) >= 0;
+    private boolean isGoalSpecification(String task) {
+        return task.indexOf(':') >= 0;
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java
index 298562d..a00d3b5 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Collection;
 import java.util.Set;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
+import org.apache.maven.api.services.MessageBuilder;
+import org.apache.maven.api.services.MessageBuilderFactory;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeImpl;
 import org.apache.maven.lifecycle.MojoExecutionConfigurator;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginExecution;
@@ -34,9 +38,6 @@
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.apache.maven.shared.utils.logging.MessageUtils;
-import org.codehaus.plexus.util.StringUtils;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,57 +49,51 @@
  */
 @Named
 @Singleton
-public class DefaultMojoExecutionConfigurator
-    implements MojoExecutionConfigurator
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class DefaultMojoExecutionConfigurator implements MojoExecutionConfigurator {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Inject
+    MessageBuilderFactory messageBuilderFactory;
 
     @Override
-    public void configure( MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig )
-    {
+    public void configure(MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig) {
         String g = mojoExecution.getPlugin().getGroupId();
 
         String a = mojoExecution.getPlugin().getArtifactId();
 
-        Plugin plugin = findPlugin( g, a, project.getBuildPlugins() );
+        Plugin plugin = findPlugin(g, a, project.getBuildPlugins());
 
-        if ( plugin == null && project.getPluginManagement() != null )
-        {
-            plugin = findPlugin( g, a, project.getPluginManagement().getPlugins() );
+        if (plugin == null && project.getPluginManagement() != null) {
+            plugin = findPlugin(g, a, project.getPluginManagement().getPlugins());
         }
 
-        if ( plugin != null )
-        {
+        if (plugin != null) {
             PluginExecution pluginExecution =
-                findPluginExecution( mojoExecution.getExecutionId(), plugin.getExecutions() );
+                    findPluginExecution(mojoExecution.getExecutionId(), plugin.getExecutions());
 
-            Xpp3Dom pomConfiguration = null;
+            XmlNode pomConfiguration = null;
 
-            if ( pluginExecution != null )
-            {
-                pomConfiguration = (Xpp3Dom) pluginExecution.getConfiguration();
-            }
-            else if ( allowPluginLevelConfig )
-            {
-                pomConfiguration = (Xpp3Dom) plugin.getConfiguration();
+            if (pluginExecution != null) {
+                pomConfiguration = pluginExecution.getDelegate().getConfiguration();
+            } else if (allowPluginLevelConfig) {
+                pomConfiguration = plugin.getDelegate().getConfiguration();
             }
 
-            Xpp3Dom mojoConfiguration = ( pomConfiguration != null ) ? new Xpp3Dom( pomConfiguration ) : null;
+            XmlNode mojoConfiguration = mojoExecution.getConfiguration() != null
+                    ? mojoExecution.getConfiguration().getDom()
+                    : null;
 
-            mojoConfiguration = Xpp3Dom.mergeXpp3Dom( mojoExecution.getConfiguration(), mojoConfiguration );
+            XmlNode mergedConfiguration = XmlNodeImpl.merge(mojoConfiguration, pomConfiguration);
 
-            mojoExecution.setConfiguration( mojoConfiguration );
+            mojoExecution.setConfiguration(mergedConfiguration);
 
-            checkUnknownMojoConfigurationParameters( mojoExecution );
+            checkUnknownMojoConfigurationParameters(mojoExecution);
         }
     }
 
-    private Plugin findPlugin( String groupId, String artifactId, Collection<Plugin> plugins )
-    {
-        for ( Plugin plugin : plugins )
-        {
-            if ( artifactId.equals( plugin.getArtifactId() ) && groupId.equals( plugin.getGroupId() ) )
-            {
+    private Plugin findPlugin(String groupId, String artifactId, Collection<Plugin> plugins) {
+        for (Plugin plugin : plugins) {
+            if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) {
                 return plugin;
             }
         }
@@ -106,14 +101,10 @@
         return null;
     }
 
-    private PluginExecution findPluginExecution( String executionId, Collection<PluginExecution> executions )
-    {
-        if ( StringUtils.isNotEmpty( executionId ) )
-        {
-            for ( PluginExecution execution : executions )
-            {
-                if ( executionId.equals( execution.getId() ) )
-                {
+    private PluginExecution findPluginExecution(String executionId, Collection<PluginExecution> executions) {
+        if (executionId != null && !executionId.isEmpty()) {
+            for (PluginExecution execution : executions) {
+                if (executionId.equals(execution.getId())) {
                     return execution;
                 }
             }
@@ -122,10 +113,9 @@
         return null;
     }
 
-    private void checkUnknownMojoConfigurationParameters( MojoExecution mojoExecution )
-    {
-        if ( mojoExecution.getConfiguration() == null || mojoExecution.getConfiguration().getChildCount() == 0 )
-        {
+    private void checkUnknownMojoConfigurationParameters(MojoExecution mojoExecution) {
+        if (mojoExecution.getConfiguration() == null
+                || mojoExecution.getConfiguration().getChildCount() == 0) {
             return;
         }
 
@@ -133,66 +123,59 @@
 
         // in first step get parameter names of current goal
         Set<String> parametersNamesGoal = mojoDescriptor.getParameters().stream()
-            .flatMap( this::getParameterNames )
-            .collect( Collectors.toSet() );
+                .flatMap(this::getParameterNames)
+                .collect(Collectors.toSet());
 
-        Set<String> unknownParameters = getUnknownParameters( mojoExecution, parametersNamesGoal );
+        Set<String> unknownParameters = getUnknownParameters(mojoExecution, parametersNamesGoal);
 
-        if ( unknownParameters.isEmpty() )
-        {
+        if (unknownParameters.isEmpty()) {
             return;
         }
 
         // second step get parameter names of all plugin goals
         Set<String> parametersNamesAll = mojoDescriptor.getPluginDescriptor().getMojos().stream()
-            .flatMap( m -> m.getParameters().stream() )
-            .flatMap( this::getParameterNames )
-            .collect( Collectors.toSet() );
+                .flatMap(m -> m.getParameters().stream())
+                .flatMap(this::getParameterNames)
+                .collect(Collectors.toSet());
 
-        unknownParameters = getUnknownParameters( mojoExecution, parametersNamesAll );
+        unknownParameters = getUnknownParameters(mojoExecution, parametersNamesAll);
 
-        unknownParameters.forEach(
-            name ->
-            {
-                MessageBuilder messageBuilder = MessageUtils.buffer()
-                    .warning( "Parameter '" )
-                    .warning( name )
-                    .warning( "' is unknown for plugin '" )
-                    .warning( mojoExecution.getArtifactId() ).warning( ":" )
-                    .warning( mojoExecution.getVersion() ).warning( ":" )
-                    .warning( mojoExecution.getGoal() );
+        unknownParameters.forEach(name -> {
+            MessageBuilder messageBuilder = messageBuilderFactory
+                    .builder()
+                    .warning("Parameter '")
+                    .warning(name)
+                    .warning("' is unknown for plugin '")
+                    .warning(mojoExecution.getArtifactId())
+                    .warning(":")
+                    .warning(mojoExecution.getVersion())
+                    .warning(":")
+                    .warning(mojoExecution.getGoal());
 
-                if ( mojoExecution.getExecutionId() != null )
-                {
-                    messageBuilder.warning( " (" );
-                    messageBuilder.warning( mojoExecution.getExecutionId() );
-                    messageBuilder.warning( ")" );
-                }
+            if (mojoExecution.getExecutionId() != null) {
+                messageBuilder.warning(" (");
+                messageBuilder.warning(mojoExecution.getExecutionId());
+                messageBuilder.warning(")");
+            }
 
-                messageBuilder.warning( "'" );
+            messageBuilder.warning("'");
 
-                logger.warn( messageBuilder.toString() );
-            } );
+            logger.warn(messageBuilder.toString());
+        });
     }
 
-    private Stream<String> getParameterNames( Parameter parameter )
-    {
-        if ( parameter.getAlias() != null )
-        {
-            return Stream.of( parameter.getName(), parameter.getAlias() );
-        }
-        else
-        {
-            return Stream.of( parameter.getName() );
+    private Stream<String> getParameterNames(Parameter parameter) {
+        if (parameter.getAlias() != null) {
+            return Stream.of(parameter.getName(), parameter.getAlias());
+        } else {
+            return Stream.of(parameter.getName());
         }
     }
 
-    private Set<String> getUnknownParameters( MojoExecution mojoExecution, Set<String> parameters )
-    {
-        return stream( mojoExecution.getConfiguration().getChildren() )
-            .map( Xpp3Dom::getName )
-            .filter( name -> !parameters.contains( name ) )
-            .collect( Collectors.toSet() );
+    private Set<String> getUnknownParameters(MojoExecution mojoExecution, Set<String> parameters) {
+        return stream(mojoExecution.getConfiguration().getChildren())
+                .map(Xpp3Dom::getName)
+                .filter(name -> !parameters.contains(name))
+                .collect(Collectors.toSet());
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory.java
index a64da04..6ae029e 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultProjectArtifactFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,39 +16,143 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.Set;
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import java.io.File;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.factory.ArtifactFactory;
+import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.artifact.resolver.filter.ExclusionArtifactFilter;
+import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
+import org.apache.maven.artifact.versioning.VersionRange;
+import org.apache.maven.model.Dependency;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
-import org.apache.maven.project.artifact.MavenMetadataSource;
 
 /**
  * Default component responsible for creation of MavenProject#dependencyArtifacts instances.
  */
-@SuppressWarnings( "deprecation" )
+@SuppressWarnings("deprecation")
 @Named
-public class DefaultProjectArtifactFactory
-    implements ProjectArtifactFactory
-{
+public class DefaultProjectArtifactFactory implements ProjectArtifactFactory {
     private final ArtifactFactory artifactFactory;
 
     @Inject
-    public DefaultProjectArtifactFactory( ArtifactFactory artifactFactory )
-    {
+    public DefaultProjectArtifactFactory(ArtifactFactory artifactFactory) {
         this.artifactFactory = artifactFactory;
     }
 
     @Override
-    public Set<Artifact> createArtifacts( MavenProject project )
-        throws InvalidDependencyVersionException
-    {
-        return MavenMetadataSource.createArtifacts( artifactFactory, project.getDependencies(), null, null, project );
+    public Set<Artifact> createArtifacts(MavenProject project) throws InvalidDependencyVersionException {
+        return createArtifacts(artifactFactory, project.getDependencies(), null, null, project);
     }
 
+    public static Set<Artifact> createArtifacts(
+            ArtifactFactory artifactFactory,
+            List<Dependency> dependencies,
+            String inheritedScope,
+            ArtifactFilter dependencyFilter,
+            MavenProject project)
+            throws InvalidDependencyVersionException {
+        Set<Artifact> artifacts = new LinkedHashSet<>();
+
+        for (Dependency d : dependencies) {
+            Artifact dependencyArtifact;
+            try {
+                dependencyArtifact = createDependencyArtifact(artifactFactory, d, inheritedScope, dependencyFilter);
+            } catch (InvalidVersionSpecificationException e) {
+                throw new InvalidDependencyVersionException(project.getId(), d, project.getFile(), e);
+            }
+
+            if (dependencyArtifact != null) {
+                artifacts.add(dependencyArtifact);
+            }
+        }
+
+        return artifacts;
+    }
+
+    private static Artifact createDependencyArtifact(
+            ArtifactFactory factory, Dependency dependency, String inheritedScope, ArtifactFilter inheritedFilter)
+            throws InvalidVersionSpecificationException {
+        String effectiveScope = getEffectiveScope(dependency.getScope(), inheritedScope);
+
+        if (effectiveScope == null) {
+            return null;
+        }
+
+        VersionRange versionRange = VersionRange.createFromVersionSpec(dependency.getVersion());
+
+        Artifact dependencyArtifact = factory.createDependencyArtifact(
+                dependency.getGroupId(),
+                dependency.getArtifactId(),
+                versionRange,
+                dependency.getType(),
+                dependency.getClassifier(),
+                effectiveScope,
+                dependency.isOptional());
+
+        if (inheritedFilter != null && !inheritedFilter.include(dependencyArtifact)) {
+            return null;
+        }
+
+        if (Artifact.SCOPE_SYSTEM.equals(effectiveScope)) {
+            dependencyArtifact.setFile(new File(dependency.getSystemPath()));
+        }
+
+        dependencyArtifact.setDependencyFilter(createDependencyFilter(dependency, inheritedFilter));
+
+        return dependencyArtifact;
+    }
+
+    private static String getEffectiveScope(String originalScope, String inheritedScope) {
+        String effectiveScope = Artifact.SCOPE_RUNTIME;
+
+        if (originalScope == null) {
+            originalScope = Artifact.SCOPE_COMPILE;
+        }
+
+        if (inheritedScope == null) {
+            // direct dependency retains its scope
+            effectiveScope = originalScope;
+        } else if (Artifact.SCOPE_TEST.equals(originalScope) || Artifact.SCOPE_PROVIDED.equals(originalScope)) {
+            // test and provided are not transitive, so exclude them
+            effectiveScope = null;
+        } else if (Artifact.SCOPE_SYSTEM.equals(originalScope)) {
+            // system scope come through unchanged...
+            effectiveScope = Artifact.SCOPE_SYSTEM;
+        } else if (Artifact.SCOPE_COMPILE.equals(originalScope) && Artifact.SCOPE_COMPILE.equals(inheritedScope)) {
+            // added to retain compile scope. Remove if you want compile inherited as runtime
+            effectiveScope = Artifact.SCOPE_COMPILE;
+        } else if (Artifact.SCOPE_TEST.equals(inheritedScope)) {
+            effectiveScope = Artifact.SCOPE_TEST;
+        } else if (Artifact.SCOPE_PROVIDED.equals(inheritedScope)) {
+            effectiveScope = Artifact.SCOPE_PROVIDED;
+        }
+
+        return effectiveScope;
+    }
+
+    private static ArtifactFilter createDependencyFilter(Dependency dependency, ArtifactFilter inheritedFilter) {
+        ArtifactFilter effectiveFilter = inheritedFilter;
+
+        if (!dependency.getExclusions().isEmpty()) {
+            effectiveFilter = new ExclusionArtifactFilter(dependency.getExclusions());
+
+            if (inheritedFilter != null) {
+                effectiveFilter = new AndArtifactFilter(Arrays.asList(inheritedFilter, effectiveFilter));
+            }
+        }
+
+        return effectiveFilter;
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
index 5572f52..3a71995 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DependencyContext.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.project.MavenProject;
+package org.apache.maven.lifecycle.internal;
 
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.TreeSet;
 
+import org.apache.maven.project.MavenProject;
+
 /**
  * <p>
  * Context of dependency artifacts for a particular project.
@@ -33,12 +32,9 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold (class extract only)
  */
 // TODO From a concurrency perspective, this class is not good. The combination of mutable/immutable state is not nice
-public class DependencyContext
-{
+public class DependencyContext {
 
     private static final Collection<?> UNRESOLVED = Arrays.asList();
 
@@ -56,58 +52,48 @@
 
     private volatile int lastDependencyArtifactCount = -1;
 
-    public DependencyContext( MavenProject project, Collection<String> scopesToCollect,
-                              Collection<String> scopesToResolve )
-    {
+    public DependencyContext(
+            MavenProject project, Collection<String> scopesToCollect, Collection<String> scopesToResolve) {
         this.project = project;
         scopesToCollectForCurrentProject = scopesToCollect;
         scopesToResolveForCurrentProject = scopesToResolve;
-        scopesToCollectForAggregatedProjects = Collections.synchronizedSet( new TreeSet<>() );
-        scopesToResolveForAggregatedProjects = Collections.synchronizedSet( new TreeSet<>() );
+        scopesToCollectForAggregatedProjects = Collections.synchronizedSet(new TreeSet<>());
+        scopesToResolveForAggregatedProjects = Collections.synchronizedSet(new TreeSet<>());
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public Collection<String> getScopesToCollectForCurrentProject()
-    {
+    public Collection<String> getScopesToCollectForCurrentProject() {
         return scopesToCollectForCurrentProject;
     }
 
-    public Collection<String> getScopesToResolveForCurrentProject()
-    {
+    public Collection<String> getScopesToResolveForCurrentProject() {
         return scopesToResolveForCurrentProject;
     }
 
-    public Collection<String> getScopesToCollectForAggregatedProjects()
-    {
+    public Collection<String> getScopesToCollectForAggregatedProjects() {
         return scopesToCollectForAggregatedProjects;
     }
 
-    public Collection<String> getScopesToResolveForAggregatedProjects()
-    {
+    public Collection<String> getScopesToResolveForAggregatedProjects() {
         return scopesToResolveForAggregatedProjects;
     }
 
-    public boolean isResolutionRequiredForCurrentProject()
-    {
-        return lastDependencyArtifacts != project.getDependencyArtifacts() || ( lastDependencyArtifacts != null
-            && lastDependencyArtifactCount != lastDependencyArtifacts.size() );
+    public boolean isResolutionRequiredForCurrentProject() {
+        return lastDependencyArtifacts != project.getDependencyArtifacts()
+                || (lastDependencyArtifacts != null && lastDependencyArtifactCount != lastDependencyArtifacts.size());
     }
 
-    public boolean isResolutionRequiredForAggregatedProjects( Collection<String> scopesToCollect,
-                                                              Collection<String> scopesToResolve )
-    {
-        return scopesToCollectForAggregatedProjects.addAll( scopesToCollect )
-            || scopesToResolveForAggregatedProjects.addAll( scopesToResolve );
+    public boolean isResolutionRequiredForAggregatedProjects(
+            Collection<String> scopesToCollect, Collection<String> scopesToResolve) {
+        return scopesToCollectForAggregatedProjects.addAll(scopesToCollect)
+                || scopesToResolveForAggregatedProjects.addAll(scopesToResolve);
     }
 
-    public void synchronizeWithProjectState()
-    {
+    public void synchronizeWithProjectState() {
         lastDependencyArtifacts = project.getDependencyArtifacts();
-        lastDependencyArtifactCount = ( lastDependencyArtifacts != null ) ? lastDependencyArtifacts.size() : 0;
+        lastDependencyArtifactCount = (lastDependencyArtifacts != null) ? lastDependencyArtifacts.size() : 0;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionEventCatapult.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionEventCatapult.java
index acff566..bdf310a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionEventCatapult.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionEventCatapult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenSession;
@@ -28,13 +27,10 @@
  * public for technical reasons, it is not part of the public API. In particular, this interface can be changed or
  * deleted without prior notice.
  *
- * @author Benjamin Bentmann
  */
-public interface ExecutionEventCatapult
-{
+public interface ExecutionEventCatapult {
 
-    void fire( ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution );
+    void fire(ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution);
 
-    void fire( ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution, Exception exception );
-
+    void fire(ExecutionEvent.Type eventType, MavenSession session, MojoExecution mojoExecution, Exception exception);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionPlanItem.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionPlanItem.java
index a52eeb0..9f25fc1 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionPlanItem.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ExecutionPlanItem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
 import org.apache.maven.model.Plugin;
@@ -25,9 +27,6 @@
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.project.MavenProject;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * <p>
  * Wraps individual MojoExecutions, containing information about completion status and scheduling.
@@ -35,51 +34,40 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Kristian Rosenvold
  */
-public class ExecutionPlanItem
-{
+public class ExecutionPlanItem {
     private final MojoExecution mojoExecution;
 
-    public ExecutionPlanItem( MojoExecution mojoExecution )
-    {
+    public ExecutionPlanItem(MojoExecution mojoExecution) {
         this.mojoExecution = mojoExecution;
     }
 
-    public static List<ExecutionPlanItem> createExecutionPlanItems( MavenProject mavenProject,
-                                                                    List<MojoExecution> executions )
-    {
-        BuilderCommon.attachToThread( mavenProject );
+    public static List<ExecutionPlanItem> createExecutionPlanItems(
+            MavenProject mavenProject, List<MojoExecution> executions) {
+        BuilderCommon.attachToThread(mavenProject);
 
         List<ExecutionPlanItem> result = new ArrayList<>();
-        for ( MojoExecution mojoExecution : executions )
-        {
-            result.add( new ExecutionPlanItem( mojoExecution ) );
+        for (MojoExecution mojoExecution : executions) {
+            result.add(new ExecutionPlanItem(mojoExecution));
         }
         return result;
     }
 
-    public MojoExecution getMojoExecution()
-    {
+    public MojoExecution getMojoExecution() {
         return mojoExecution;
     }
 
-    public String getLifecyclePhase()
-    {
+    public String getLifecyclePhase() {
         return mojoExecution.getLifecyclePhase();
     }
 
-    public Plugin getPlugin()
-    {
+    public Plugin getPlugin() {
         final MojoDescriptor mojoDescriptor = getMojoExecution().getMojoDescriptor();
         return mojoDescriptor.getPluginDescriptor().getPlugin();
     }
 
     @Override
-    public String toString()
-    {
-        return "ExecutionPlanItem{" + ", mojoExecution=" + mojoExecution + '}'
-            + super.toString();
+    public String toString() {
+        return "ExecutionPlanItem{" + ", mojoExecution=" + mojoExecution + '}' + super.toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/GoalTask.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/GoalTask.java
index abcdda5..155bebd 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/GoalTask.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/GoalTask.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 /**
  * <p>
@@ -26,21 +25,17 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public final class GoalTask
-{
+public final class GoalTask {
 
     final String pluginGoal;
 
-    public GoalTask( String pluginGoal )
-    {
+    public GoalTask(String pluginGoal) {
         this.pluginGoal = pluginGoal;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return pluginGoal;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java
index a26b197..6695b69 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDebugLogger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Iterator;
 import java.util.List;
@@ -25,15 +27,11 @@
 import java.util.Set;
 import java.util.TreeSet;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.lifecycle.MavenExecutionPlan;
 import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -44,131 +42,108 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Jason van Zyl
- * @author Kristian Rosenvold (extracted class only)
  */
 @Named
 @Singleton
-public class LifecycleDebugLogger
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class LifecycleDebugLogger {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
-    public void debug( String s )
-    {
-        logger.debug( s );
+    public void debug(String s) {
+        logger.debug(s);
     }
 
-    public void info( String s )
-    {
-        logger.info( s );
+    public void info(String s) {
+        logger.info(s);
     }
 
-    public void debugReactorPlan( ProjectBuildList projectBuilds )
-    {
-        if ( !logger.isDebugEnabled() )
-        {
+    public void debugReactorPlan(ProjectBuildList projectBuilds) {
+        if (!logger.isDebugEnabled()) {
             return;
         }
 
-        logger.debug( "=== REACTOR BUILD PLAN ================================================" );
+        logger.debug("=== REACTOR BUILD PLAN ================================================");
 
-        for ( Iterator<ProjectSegment> it = projectBuilds.iterator(); it.hasNext(); )
-        {
+        for (Iterator<ProjectSegment> it = projectBuilds.iterator(); it.hasNext(); ) {
             ProjectSegment projectBuild = it.next();
 
-            logger.debug( "Project: " + projectBuild.getProject().getId() );
-            logger.debug( "Tasks:   " + projectBuild.getTaskSegment().getTasks() );
-            logger.debug( "Style:   " + ( projectBuild.getTaskSegment().isAggregating() ? "Aggregating" : "Regular" ) );
+            logger.debug("Project: " + projectBuild.getProject().getId());
+            logger.debug("Tasks:   " + projectBuild.getTaskSegment().getTasks());
+            logger.debug("Style:   " + (projectBuild.getTaskSegment().isAggregating() ? "Aggregating" : "Regular"));
 
-            if ( it.hasNext() )
-            {
-                logger.debug( "-----------------------------------------------------------------------" );
+            if (it.hasNext()) {
+                logger.debug("-----------------------------------------------------------------------");
             }
         }
 
-        logger.debug( "=======================================================================" );
+        logger.debug("=======================================================================");
     }
 
-
-    public void debugProjectPlan( MavenProject currentProject, MavenExecutionPlan executionPlan )
-    {
-        if ( !logger.isDebugEnabled() )
-        {
+    public void debugProjectPlan(MavenProject currentProject, MavenExecutionPlan executionPlan) {
+        if (!logger.isDebugEnabled()) {
             return;
         }
 
-        logger.debug( "=== PROJECT BUILD PLAN ================================================" );
-        logger.debug( "Project:       " + BuilderCommon.getKey( currentProject ) );
+        logger.debug("=== PROJECT BUILD PLAN ================================================");
+        logger.debug("Project:       " + BuilderCommon.getKey(currentProject));
 
-        debugDependencyRequirements( executionPlan.getMojoExecutions() );
+        debugDependencyRequirements(executionPlan.getMojoExecutions());
 
-        logger.debug( "Repositories (dependencies): " + currentProject.getRemoteProjectRepositories() );
-        logger.debug( "Repositories (plugins)     : " + currentProject.getRemotePluginRepositories() );
+        logger.debug("Repositories (dependencies): " + currentProject.getRemoteProjectRepositories());
+        logger.debug("Repositories (plugins)     : " + currentProject.getRemotePluginRepositories());
 
-        for ( ExecutionPlanItem mojoExecution : executionPlan )
-        {
-            debugMojoExecution( mojoExecution.getMojoExecution() );
+        for (ExecutionPlanItem mojoExecution : executionPlan) {
+            debugMojoExecution(mojoExecution.getMojoExecution());
         }
 
-        logger.debug( "=======================================================================" );
+        logger.debug("=======================================================================");
     }
 
-    private void debugMojoExecution( MojoExecution mojoExecution )
-    {
+    private void debugMojoExecution(MojoExecution mojoExecution) {
         String mojoExecId =
-            mojoExecution.getGroupId() + ':' + mojoExecution.getArtifactId() + ':' + mojoExecution.getVersion() + ':'
-                + mojoExecution.getGoal() + " (" + mojoExecution.getExecutionId() + ')';
+                mojoExecution.getGroupId() + ':' + mojoExecution.getArtifactId() + ':' + mojoExecution.getVersion()
+                        + ':' + mojoExecution.getGoal() + " (" + mojoExecution.getExecutionId() + ')';
 
         Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
-        if ( !forkedExecutions.isEmpty() )
-        {
-            for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() )
-            {
-                logger.debug( "--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---" );
+        if (!forkedExecutions.isEmpty()) {
+            for (Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet()) {
+                logger.debug("--- init fork of " + fork.getKey() + " for " + mojoExecId + " ---");
 
-                debugDependencyRequirements( fork.getValue() );
+                debugDependencyRequirements(fork.getValue());
 
-                for ( MojoExecution forkedExecution : fork.getValue() )
-                {
-                    debugMojoExecution( forkedExecution );
+                for (MojoExecution forkedExecution : fork.getValue()) {
+                    debugMojoExecution(forkedExecution);
                 }
 
-                logger.debug( "--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---" );
+                logger.debug("--- exit fork of " + fork.getKey() + " for " + mojoExecId + " ---");
             }
         }
 
-        logger.debug( "-----------------------------------------------------------------------" );
-        logger.debug( "Goal:          " + mojoExecId );
+        logger.debug("-----------------------------------------------------------------------");
+        logger.debug("Goal:          " + mojoExecId);
         logger.debug(
-            "Style:         " + ( mojoExecution.getMojoDescriptor().isAggregator() ? "Aggregating" : "Regular" ) );
-        logger.debug( "Configuration: " + mojoExecution.getConfiguration() );
+                "Style:         " + (mojoExecution.getMojoDescriptor().isAggregator() ? "Aggregating" : "Regular"));
+        logger.debug("Configuration: " + mojoExecution.getConfiguration());
     }
 
-    private void debugDependencyRequirements( List<MojoExecution> mojoExecutions )
-    {
+    private void debugDependencyRequirements(List<MojoExecution> mojoExecutions) {
         Set<String> scopesToCollect = new TreeSet<>();
         Set<String> scopesToResolve = new TreeSet<>();
 
-        for ( MojoExecution mojoExecution : mojoExecutions )
-        {
+        for (MojoExecution mojoExecution : mojoExecutions) {
             MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
             String scopeToCollect = mojoDescriptor.getDependencyCollectionRequired();
-            if ( StringUtils.isNotEmpty( scopeToCollect ) )
-            {
-                scopesToCollect.add( scopeToCollect );
+            if (scopeToCollect != null && !scopeToCollect.isEmpty()) {
+                scopesToCollect.add(scopeToCollect);
             }
 
             String scopeToResolve = mojoDescriptor.getDependencyResolutionRequired();
-            if ( StringUtils.isNotEmpty( scopeToResolve ) )
-            {
-                scopesToResolve.add( scopeToResolve );
+            if (scopeToResolve != null && !scopeToResolve.isEmpty()) {
+                scopesToResolve.add(scopeToResolve);
             }
         }
 
-        logger.debug( "Dependencies (collect): " + scopesToCollect );
-        logger.debug( "Dependencies (resolve): " + scopesToResolve );
+        logger.debug("Dependencies (collect): " + scopesToCollect);
+        logger.debug("Dependencies (resolve): " + scopesToResolve);
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
index 1eb7beb..bd5fc46 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,9 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
 
 import java.io.File;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -29,11 +30,10 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-
-import javax.inject.Inject;
-import javax.inject.Named;
+import java.util.stream.Collectors;
 
 import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.services.MessageBuilderFactory;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
@@ -60,14 +60,10 @@
  * </p>
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Jason van Zyl
- * @author Kristian Rosenvold (extracted class)
  */
 @Named
-public class LifecycleDependencyResolver
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class LifecycleDependencyResolver {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final ProjectDependenciesResolver dependenciesResolver;
 
@@ -77,171 +73,171 @@
 
     private final ProjectArtifactsCache projectArtifactsCache;
 
+    private final MessageBuilderFactory messageBuilderFactory;
+
     @Inject
     public LifecycleDependencyResolver(
             ProjectDependenciesResolver dependenciesResolver,
             ProjectArtifactFactory artifactFactory,
             EventSpyDispatcher eventSpyDispatcher,
-            ProjectArtifactsCache projectArtifactsCache )
-    {
+            ProjectArtifactsCache projectArtifactsCache,
+            MessageBuilderFactory messageBuilderFactory) {
         this.dependenciesResolver = dependenciesResolver;
         this.artifactFactory = artifactFactory;
         this.eventSpyDispatcher = eventSpyDispatcher;
         this.projectArtifactsCache = projectArtifactsCache;
+        this.messageBuilderFactory = messageBuilderFactory;
     }
 
-    public static List<MavenProject> getProjects( MavenProject project, MavenSession session, boolean aggregator )
-    {
-        if ( aggregator )
-        {
-            return session.getProjects();
-        }
-        else
-        {
-            return Collections.singletonList( project );
+    public static List<MavenProject> getProjects(MavenProject project, MavenSession session, boolean aggregator) {
+        if (aggregator && project.getCollectedProjects() != null) {
+            // get the unsorted list of wanted projects
+            Set<MavenProject> projectAndSubmodules = new HashSet<>(project.getCollectedProjects());
+            projectAndSubmodules.add(project);
+            return session.getProjects().stream() // sorted all
+                    .filter(projectAndSubmodules::contains)
+                    .collect(Collectors.toList()); // sorted and filtered to what we need
+        } else {
+            return Collections.singletonList(project);
         }
     }
 
-    public void resolveProjectDependencies( MavenProject project, Collection<String> scopesToCollect,
-                                            Collection<String> scopesToResolve, MavenSession session,
-                                            boolean aggregating, Set<Artifact> projectArtifacts )
-        throws LifecycleExecutionException
-    {
+    public void resolveProjectDependencies(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session,
+            boolean aggregating,
+            Set<Artifact> projectArtifacts)
+            throws LifecycleExecutionException {
         ClassLoader tccl = Thread.currentThread().getContextClassLoader();
-        try
-        {
+        try {
             ClassLoader projectRealm = project.getClassRealm();
-            if ( projectRealm != null && projectRealm != tccl )
-            {
-                Thread.currentThread().setContextClassLoader( projectRealm );
+            if (projectRealm != null && projectRealm != tccl) {
+                Thread.currentThread().setContextClassLoader(projectRealm);
             }
 
-            if ( project.getDependencyArtifacts() == null )
-            {
-                try
-                {
-                    project.setDependencyArtifacts( artifactFactory.createArtifacts( project ) );
-                }
-                catch ( InvalidDependencyVersionException e )
-                {
-                    throw new LifecycleExecutionException( e );
+            if (project.getDependencyArtifacts() == null) {
+                try {
+                    project.setDependencyArtifacts(artifactFactory.createArtifacts(project));
+                } catch (InvalidDependencyVersionException e) {
+                    throw new LifecycleExecutionException(e);
                 }
             }
 
-            Set<Artifact> resolvedArtifacts;
-            ProjectArtifactsCache.Key cacheKey = projectArtifactsCache.createKey( project,  scopesToCollect,
-                scopesToResolve, aggregating, session.getRepositorySession() );
-            ProjectArtifactsCache.CacheRecord recordArtifacts;
-            recordArtifacts = projectArtifactsCache.get( cacheKey );
+            Set<Artifact> resolvedArtifacts = resolveProjectArtifacts(
+                    project, scopesToCollect, scopesToResolve, session, aggregating, projectArtifacts);
 
-            if ( recordArtifacts != null )
-            {
-                resolvedArtifacts = recordArtifacts.getArtifacts();
-            }
-            else
-            {
-                try
-                {
-                    resolvedArtifacts = getDependencies( project, scopesToCollect, scopesToResolve, session,
-                                                         aggregating, projectArtifacts );
-                    recordArtifacts = projectArtifactsCache.put( cacheKey, resolvedArtifacts );
-                }
-                catch ( LifecycleExecutionException e )
-                {
-                  projectArtifactsCache.put( cacheKey, e );
-                  projectArtifactsCache.register( project, cacheKey, recordArtifacts );
-                    throw e;
-                }
-            }
-            projectArtifactsCache.register( project, cacheKey, recordArtifacts );
-
-            Map<Artifact, File> reactorProjects = new HashMap<>( session.getProjects().size() );
-            for ( MavenProject reactorProject : session.getProjects() )
-            {
-                reactorProjects.put( reactorProject.getArtifact(), reactorProject.getArtifact().getFile() );
+            Map<Artifact, File> reactorProjects =
+                    new HashMap<>(session.getProjects().size());
+            for (MavenProject reactorProject : session.getProjects()) {
+                reactorProjects.put(
+                        reactorProject.getArtifact(),
+                        reactorProject.getArtifact().getFile());
             }
 
             Map<String, Artifact> map = new HashMap<>();
-            for ( Artifact artifact : resolvedArtifacts )
-            {
+            for (Artifact artifact : resolvedArtifacts) {
                 /**
                  * MNG-6300: resolvedArtifacts can be cache result; this ensures reactor files are always up-to-date
                  * During lifecycle the Artifact.getFile() can change from target/classes to the actual jar.
                  * This clearly shows that target/classes should not be abused as artifactFile just for the classpath
                  */
-                File reactorProjectFile = reactorProjects.get( artifact );
-                if ( reactorProjectFile != null )
-                {
-                    artifact.setFile( reactorProjectFile );
+                File reactorProjectFile = reactorProjects.get(artifact);
+                if (reactorProjectFile != null) {
+                    artifact.setFile(reactorProjectFile);
                 }
 
-                map.put( artifact.getDependencyConflictId(), artifact );
+                map.put(artifact.getDependencyConflictId(), artifact);
             }
 
-            project.setResolvedArtifacts( resolvedArtifacts );
+            project.setResolvedArtifacts(resolvedArtifacts);
 
-            for ( Artifact artifact : project.getDependencyArtifacts() )
-            {
-                if ( artifact.getFile() == null )
-                {
-                    Artifact resolved = map.get( artifact.getDependencyConflictId() );
-                    if ( resolved != null )
-                    {
-                        artifact.setFile( resolved.getFile() );
-                        artifact.setDependencyTrail( resolved.getDependencyTrail() );
-                        artifact.setResolvedVersion( resolved.getVersion() );
-                        artifact.setResolved( true );
+            for (Artifact artifact : project.getDependencyArtifacts()) {
+                if (artifact.getFile() == null) {
+                    Artifact resolved = map.get(artifact.getDependencyConflictId());
+                    if (resolved != null) {
+                        artifact.setFile(resolved.getFile());
+                        artifact.setDependencyTrail(resolved.getDependencyTrail());
+                        artifact.setResolvedVersion(resolved.getVersion());
+                        artifact.setResolved(true);
                     }
                 }
             }
-        }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( tccl );
+        } finally {
+            Thread.currentThread().setContextClassLoader(tccl);
         }
     }
 
-    private Set<Artifact> getDependencies( MavenProject project, Collection<String> scopesToCollect,
-                                           Collection<String> scopesToResolve, MavenSession session,
-                                           boolean aggregating, Set<Artifact> projectArtifacts )
-        throws LifecycleExecutionException
-    {
-        if ( scopesToCollect == null )
-        {
+    public Set<Artifact> resolveProjectArtifacts(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session,
+            boolean aggregating,
+            Set<Artifact> projectArtifacts)
+            throws LifecycleExecutionException {
+        Set<Artifact> resolvedArtifacts;
+        ProjectArtifactsCache.Key cacheKey = projectArtifactsCache.createKey(
+                project, scopesToCollect, scopesToResolve, aggregating, session.getRepositorySession());
+        ProjectArtifactsCache.CacheRecord recordArtifacts;
+        recordArtifacts = projectArtifactsCache.get(cacheKey);
+
+        if (recordArtifacts != null) {
+            resolvedArtifacts = recordArtifacts.getArtifacts();
+        } else {
+            try {
+                resolvedArtifacts = getDependencies(
+                        project, scopesToCollect, scopesToResolve, session, aggregating, projectArtifacts);
+                recordArtifacts = projectArtifactsCache.put(cacheKey, resolvedArtifacts);
+            } catch (LifecycleExecutionException e) {
+                projectArtifactsCache.put(cacheKey, e);
+                projectArtifactsCache.register(project, cacheKey, recordArtifacts);
+                throw e;
+            }
+        }
+        projectArtifactsCache.register(project, cacheKey, recordArtifacts);
+        return resolvedArtifacts;
+    }
+
+    private Set<Artifact> getDependencies(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            MavenSession session,
+            boolean aggregating,
+            Set<Artifact> projectArtifacts)
+            throws LifecycleExecutionException {
+        if (scopesToCollect == null) {
             scopesToCollect = Collections.emptySet();
         }
-        if ( scopesToResolve == null )
-        {
+        if (scopesToResolve == null) {
             scopesToResolve = Collections.emptySet();
         }
 
-        if ( scopesToCollect.isEmpty() && scopesToResolve.isEmpty() )
-        {
+        if (scopesToCollect.isEmpty() && scopesToResolve.isEmpty()) {
             return new LinkedHashSet<>();
         }
 
-        scopesToCollect = new HashSet<>( scopesToCollect );
-        scopesToCollect.addAll( scopesToResolve );
+        scopesToCollect = new HashSet<>(scopesToCollect);
+        scopesToCollect.addAll(scopesToResolve);
 
-        DependencyFilter collectionFilter = new ScopeDependencyFilter( null, negate( scopesToCollect ) );
-        DependencyFilter resolutionFilter = new ScopeDependencyFilter( null, negate( scopesToResolve ) );
-        resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, resolutionFilter );
+        DependencyFilter collectionFilter = new ScopeDependencyFilter(null, negate(scopesToCollect));
+        DependencyFilter resolutionFilter = new ScopeDependencyFilter(null, negate(scopesToResolve));
+        resolutionFilter = AndDependencyFilter.newInstance(collectionFilter, resolutionFilter);
         resolutionFilter =
-            AndDependencyFilter.newInstance( resolutionFilter, new ReactorDependencyFilter( projectArtifacts ) );
+                AndDependencyFilter.newInstance(resolutionFilter, new ReactorDependencyFilter(projectArtifacts));
 
         DependencyResolutionResult result;
-        try
-        {
+        try {
             DefaultDependencyResolutionRequest request =
-                new DefaultDependencyResolutionRequest( project, session.getRepositorySession() );
-            request.setResolutionFilter( resolutionFilter );
+                    new DefaultDependencyResolutionRequest(project, session.getRepositorySession());
+            request.setResolutionFilter(resolutionFilter);
 
-            eventSpyDispatcher.onEvent( request );
+            eventSpyDispatcher.onEvent(request);
 
-            result = dependenciesResolver.resolve( request );
-        }
-        catch ( DependencyResolutionException e )
-        {
+            result = dependenciesResolver.resolve(request);
+        } catch (DependencyResolutionException e) {
             result = e.getResult();
 
             /*
@@ -249,47 +245,42 @@
              * plugins that require dependency resolution although they usually run in phases of the build where project
              * artifacts haven't been assembled yet. The prime example of this is "mvn release:prepare".
              */
-            if ( aggregating && areAllDependenciesInReactor( session.getProjects(),
-                                                             result.getUnresolvedDependencies() ) )
-            {
-                logger.warn( "The following dependencies could not be resolved at this point of the build"
-                    + " but seem to be part of the reactor:" );
+            if (aggregating && areAllDependenciesInReactor(session.getProjects(), result.getUnresolvedDependencies())) {
+                logger.warn("The following dependencies could not be resolved at this point of the build"
+                        + " but seem to be part of the reactor:");
 
-                for ( Dependency dependency : result.getUnresolvedDependencies() )
-                {
-                    logger.warn( "o " + dependency );
+                for (Dependency dependency : result.getUnresolvedDependencies()) {
+                    logger.warn("o {}", dependency);
                 }
 
-                logger.warn( "Try running the build up to the lifecycle phase \"package\"" );
-            }
-            else
-            {
-                throw new LifecycleExecutionException( null, project, e );
+                logger.warn("Try running the build up to the lifecycle phase \"package\"");
+            } else {
+                throw new LifecycleExecutionException(messageBuilderFactory, null, project, e);
             }
         }
 
-        eventSpyDispatcher.onEvent( result );
+        eventSpyDispatcher.onEvent(result);
 
         Set<Artifact> artifacts = new LinkedHashSet<>();
-        if ( result.getDependencyGraph() != null && !result.getDependencyGraph().getChildren().isEmpty() )
-        {
-            RepositoryUtils.toArtifacts( artifacts, result.getDependencyGraph().getChildren(),
-                                         Collections.singletonList( project.getArtifact().getId() ), collectionFilter );
+        if (result.getDependencyGraph() != null
+                && !result.getDependencyGraph().getChildren().isEmpty()) {
+            RepositoryUtils.toArtifacts(
+                    artifacts,
+                    result.getDependencyGraph().getChildren(),
+                    Collections.singletonList(project.getArtifact().getId()),
+                    collectionFilter);
         }
         return artifacts;
     }
 
-    private boolean areAllDependenciesInReactor( Collection<MavenProject> projects,
-                                                 Collection<Dependency> dependencies )
-    {
-        Set<String> projectKeys = getReactorProjectKeys( projects );
+    private boolean areAllDependenciesInReactor(
+            Collection<MavenProject> projects, Collection<Dependency> dependencies) {
+        Set<String> projectKeys = getReactorProjectKeys(projects);
 
-        for ( Dependency dependency : dependencies )
-        {
+        for (Dependency dependency : dependencies) {
             org.eclipse.aether.artifact.Artifact a = dependency.getArtifact();
-            String key = ArtifactUtils.key( a.getGroupId(), a.getArtifactId(), a.getVersion() );
-            if ( !projectKeys.contains( key ) )
-            {
+            String key = ArtifactUtils.key(a.getGroupId(), a.getArtifactId(), a.getVersion());
+            if (!projectKeys.contains(key)) {
                 return false;
             }
         }
@@ -297,50 +288,37 @@
         return true;
     }
 
-    private Set<String> getReactorProjectKeys( Collection<MavenProject> projects )
-    {
-        Set<String> projectKeys = new HashSet<>( projects.size() * 2 );
-        for ( MavenProject project : projects )
-        {
-            String key = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
-            projectKeys.add( key );
+    private Set<String> getReactorProjectKeys(Collection<MavenProject> projects) {
+        Set<String> projectKeys = new HashSet<>(projects.size() * 2);
+        for (MavenProject project : projects) {
+            String key = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion());
+            projectKeys.add(key);
         }
         return projectKeys;
     }
 
-    private Collection<String> negate( Collection<String> scopes )
-    {
+    private Collection<String> negate(Collection<String> scopes) {
         Collection<String> result = new HashSet<>();
-        Collections.addAll( result, "system", "compile", "provided", "runtime", "test" );
+        Collections.addAll(result, "system", "compile", "provided", "runtime", "test");
 
-        for ( String scope : scopes )
-        {
-            if ( "compile".equals( scope ) )
-            {
-                result.remove( "compile" );
-                result.remove( "system" );
-                result.remove( "provided" );
-            }
-            else if ( "runtime".equals( scope ) )
-            {
-                result.remove( "compile" );
-                result.remove( "runtime" );
-            }
-            else if ( "compile+runtime".equals( scope ) )
-            {
-                result.remove( "compile" );
-                result.remove( "system" );
-                result.remove( "provided" );
-                result.remove( "runtime" );
-            }
-            else if ( "runtime+system".equals( scope ) )
-            {
-                result.remove( "compile" );
-                result.remove( "system" );
-                result.remove( "runtime" );
-            }
-            else if ( "test".equals( scope ) )
-            {
+        for (String scope : scopes) {
+            if ("compile".equals(scope)) {
+                result.remove("compile");
+                result.remove("system");
+                result.remove("provided");
+            } else if ("runtime".equals(scope)) {
+                result.remove("compile");
+                result.remove("runtime");
+            } else if ("compile+runtime".equals(scope)) {
+                result.remove("compile");
+                result.remove("system");
+                result.remove("provided");
+                result.remove("runtime");
+            } else if ("runtime+system".equals(scope)) {
+                result.remove("compile");
+                result.remove("system");
+                result.remove("runtime");
+            } else if ("test".equals(scope)) {
                 result.clear();
             }
         }
@@ -348,33 +326,25 @@
         return result;
     }
 
-    private static class ReactorDependencyFilter
-        implements DependencyFilter
-    {
+    private static class ReactorDependencyFilter implements DependencyFilter {
 
         private Set<String> keys = new HashSet<>();
 
-        ReactorDependencyFilter( Collection<Artifact> artifacts )
-        {
-            for ( Artifact artifact : artifacts )
-            {
-                String key = ArtifactUtils.key( artifact );
-                keys.add( key );
+        ReactorDependencyFilter(Collection<Artifact> artifacts) {
+            for (Artifact artifact : artifacts) {
+                String key = ArtifactUtils.key(artifact);
+                keys.add(key);
             }
         }
 
-        public boolean accept( DependencyNode node, List<DependencyNode> parents )
-        {
+        public boolean accept(DependencyNode node, List<DependencyNode> parents) {
             Dependency dependency = node.getDependency();
-            if ( dependency != null )
-            {
+            if (dependency != null) {
                 org.eclipse.aether.artifact.Artifact a = dependency.getArtifact();
-                String key = ArtifactUtils.key( a.getGroupId(), a.getArtifactId(), a.getVersion() );
-                return !keys.contains( key );
+                String key = ArtifactUtils.key(a.getGroupId(), a.getArtifactId(), a.getVersion());
+                return !keys.contains(key);
             }
             return false;
         }
-
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator.java
index c5ed0f1..43273fd 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import java.util.List;
+import java.util.Set;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.LifecycleNotFoundException;
@@ -34,36 +36,32 @@
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.apache.maven.project.MavenProject;
 
-import java.util.List;
-import java.util.Set;
-
 /**
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold  (extract interface only)
  */
-public interface LifecycleExecutionPlanCalculator
-{
-    MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException;
+public interface LifecycleExecutionPlanCalculator {
+    MavenExecutionPlan calculateExecutionPlan(MavenSession session, MavenProject project, List<Object> tasks)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException;
 
-    MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks,
-                                               boolean setup )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException;
+    MavenExecutionPlan calculateExecutionPlan(
+            MavenSession session, MavenProject project, List<Object> tasks, boolean setup)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException;
 
-    void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException;
+    void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException;
 
-    void setupMojoExecution( MavenSession session, MavenProject project, MojoExecution mojoExecution,
-                             Set<MojoDescriptor> alreadyPlannedExecutions )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException;
-
+    void setupMojoExecution(
+            MavenSession session,
+            MavenProject project,
+            MojoExecution mojoExecution,
+            Set<MojoDescriptor> alreadyPlannedExecutions)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java
index 17340fb..caec1dc 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.HashSet;
-import java.util.List;
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.HashSet;
+import java.util.List;
+
 import org.apache.maven.execution.BuildSuccess;
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectExecutionEvent;
 import org.apache.maven.execution.ProjectExecutionListener;
+import org.apache.maven.internal.transformation.ConsumerPomArtifactTransformer;
 import org.apache.maven.lifecycle.MavenExecutionPlan;
 import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
 import org.apache.maven.plugin.MojoExecution;
@@ -44,19 +44,16 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Jason van Zyl
- * @author Kristian Rosenvold (extracted class)
  */
 @Named
 @Singleton
-public class LifecycleModuleBuilder
-{
+public class LifecycleModuleBuilder {
 
     private final MojoExecutor mojoExecutor;
     private final BuilderCommon builderCommon;
     private final ExecutionEventCatapult eventCatapult;
     private final ProjectExecutionListener projectExecutionListener;
+    private final ConsumerPomArtifactTransformer consumerPomArtifactTransformer;
     private final SessionScope sessionScope;
 
     @Inject
@@ -65,84 +62,79 @@
             BuilderCommon builderCommon,
             ExecutionEventCatapult eventCatapult,
             List<ProjectExecutionListener> listeners,
-            SessionScope sessionScope )
-    {
+            ConsumerPomArtifactTransformer consumerPomArtifactTransformer,
+            SessionScope sessionScope) {
         this.mojoExecutor = mojoExecutor;
         this.builderCommon = builderCommon;
         this.eventCatapult = eventCatapult;
-        this.projectExecutionListener = new CompoundProjectExecutionListener( listeners );
+        this.projectExecutionListener = new CompoundProjectExecutionListener(listeners);
+        this.consumerPomArtifactTransformer = consumerPomArtifactTransformer;
         this.sessionScope = sessionScope;
     }
 
-    public void buildProject( MavenSession session, ReactorContext reactorContext, MavenProject currentProject,
-                              TaskSegment taskSegment )
-    {
-        buildProject( session, session, reactorContext, currentProject, taskSegment );
+    public void buildProject(
+            MavenSession session, ReactorContext reactorContext, MavenProject currentProject, TaskSegment taskSegment) {
+        buildProject(session, session, reactorContext, currentProject, taskSegment);
     }
 
-    public void buildProject( MavenSession session, MavenSession rootSession, ReactorContext reactorContext,
-                              MavenProject currentProject, TaskSegment taskSegment )
-    {
-        session.setCurrentProject( currentProject );
+    public void buildProject(
+            MavenSession session,
+            MavenSession rootSession,
+            ReactorContext reactorContext,
+            MavenProject currentProject,
+            TaskSegment taskSegment) {
+        session.setCurrentProject(currentProject);
 
         long buildStartTime = System.currentTimeMillis();
 
-        try
-        {
+        try {
 
-            if ( reactorContext.getReactorBuildStatus().isHaltedOrBlacklisted( currentProject ) )
-            {
-                eventCatapult.fire( ExecutionEvent.Type.ProjectSkipped, session, null );
+            if (reactorContext.getReactorBuildStatus().isHaltedOrBlacklisted(currentProject)) {
+                eventCatapult.fire(ExecutionEvent.Type.ProjectSkipped, session, null);
                 return;
             }
 
-            BuilderCommon.attachToThread( currentProject );
+            consumerPomArtifactTransformer.injectTransformedArtifacts(session.getRepositorySession(), currentProject);
 
-            projectExecutionListener.beforeProjectExecution( new ProjectExecutionEvent( session, currentProject ) );
+            BuilderCommon.attachToThread(currentProject);
 
-            eventCatapult.fire( ExecutionEvent.Type.ProjectStarted, session, null );
+            projectExecutionListener.beforeProjectExecution(new ProjectExecutionEvent(session, currentProject));
+
+            eventCatapult.fire(ExecutionEvent.Type.ProjectStarted, session, null);
 
             MavenExecutionPlan executionPlan =
-                builderCommon.resolveBuildPlan( session, currentProject, taskSegment, new HashSet<>() );
+                    builderCommon.resolveBuildPlan(session, currentProject, taskSegment, new HashSet<>());
             List<MojoExecution> mojoExecutions = executionPlan.getMojoExecutions();
 
-            projectExecutionListener.beforeProjectLifecycleExecution( new ProjectExecutionEvent( session,
-                                                                                                 currentProject,
-                                                                                                 mojoExecutions ) );
-            mojoExecutor.execute( session, mojoExecutions, reactorContext.getProjectIndex() );
+            projectExecutionListener.beforeProjectLifecycleExecution(
+                    new ProjectExecutionEvent(session, currentProject, mojoExecutions));
+            mojoExecutor.execute(session, mojoExecutions, reactorContext.getProjectIndex());
 
             long buildEndTime = System.currentTimeMillis();
 
-            projectExecutionListener.afterProjectExecutionSuccess( new ProjectExecutionEvent( session, currentProject,
-                                                                                              mojoExecutions ) );
+            projectExecutionListener.afterProjectExecutionSuccess(
+                    new ProjectExecutionEvent(session, currentProject, mojoExecutions));
 
-            reactorContext.getResult().addBuildSummary( new BuildSuccess( currentProject,
-                                                                          buildEndTime - buildStartTime ) );
+            reactorContext.getResult().addBuildSummary(new BuildSuccess(currentProject, buildEndTime - buildStartTime));
 
-            eventCatapult.fire( ExecutionEvent.Type.ProjectSucceeded, session, null );
-        }
-        catch ( Throwable t )
-        {
-            builderCommon.handleBuildError( reactorContext, rootSession, session, currentProject, t, buildStartTime );
+            eventCatapult.fire(ExecutionEvent.Type.ProjectSucceeded, session, null);
+        } catch (Throwable t) {
+            builderCommon.handleBuildError(reactorContext, rootSession, session, currentProject, t, buildStartTime);
 
-            projectExecutionListener.afterProjectExecutionFailure( new ProjectExecutionEvent( session, currentProject,
-                                                                                              t ) );
+            projectExecutionListener.afterProjectExecutionFailure(
+                    new ProjectExecutionEvent(session, currentProject, t));
 
             // rethrow original errors and runtime exceptions
-            if ( t instanceof RuntimeException )
-            {
+            if (t instanceof RuntimeException) {
                 throw (RuntimeException) t;
             }
-            if ( t instanceof Error )
-            {
+            if (t instanceof Error) {
                 throw (Error) t;
             }
-        }
-        finally
-        {
-            session.setCurrentProject( null );
+        } finally {
+            session.setCurrentProject(null);
 
-            Thread.currentThread().setContextClassLoader( reactorContext.getOriginalContextClassLoader() );
+            Thread.currentThread().setContextClassLoader(reactorContext.getOriginalContextClassLoader());
         }
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecyclePluginResolver.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecyclePluginResolver.java
index 1f6fab0..81232b0 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecyclePluginResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecyclePluginResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.HashMap;
-import java.util.Map;
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginManagement;
@@ -38,54 +37,42 @@
 /**
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold (Extract class)
  */
 @Named
 @Singleton
-public class LifecyclePluginResolver
-{
+public class LifecyclePluginResolver {
     private final PluginVersionResolver pluginVersionResolver;
 
     @Inject
-    public LifecyclePluginResolver( PluginVersionResolver pluginVersionResolver )
-    {
+    public LifecyclePluginResolver(PluginVersionResolver pluginVersionResolver) {
         this.pluginVersionResolver = pluginVersionResolver;
     }
 
-    public void resolveMissingPluginVersions( MavenProject project, MavenSession session )
-        throws PluginVersionResolutionException
-    {
-        Map<String, String> versions = new HashMap<>( 64 );
+    public void resolveMissingPluginVersions(MavenProject project, MavenSession session)
+            throws PluginVersionResolutionException {
+        Map<String, String> versions = new HashMap<>(64);
 
-        for ( Plugin plugin : project.getBuildPlugins() )
-        {
-            if ( plugin.getVersion() == null )
-            {
-                PluginVersionRequest request = new DefaultPluginVersionRequest( plugin, session.getRepositorySession(),
-                                                                                project.getRemotePluginRepositories() );
-                plugin.setVersion( pluginVersionResolver.resolve( request ).getVersion() );
+        for (Plugin plugin : project.getBuildPlugins()) {
+            if (plugin.getVersion() == null) {
+                PluginVersionRequest request = new DefaultPluginVersionRequest(
+                        plugin, session.getRepositorySession(), project.getRemotePluginRepositories());
+                plugin.setVersion(pluginVersionResolver.resolve(request).getVersion());
             }
-            versions.put( plugin.getKey(), plugin.getVersion() );
+            versions.put(plugin.getKey(), plugin.getVersion());
         }
 
         PluginManagement pluginManagement = project.getPluginManagement();
-        if ( pluginManagement != null )
-        {
-            for ( Plugin plugin : pluginManagement.getPlugins() )
-            {
-                if ( plugin.getVersion() == null )
-                {
-                    plugin.setVersion( versions.get( plugin.getKey() ) );
-                    if ( plugin.getVersion() == null )
-                    {
-                        PluginVersionRequest request =
-                            new DefaultPluginVersionRequest( plugin, session.getRepositorySession(),
-                                                             project.getRemotePluginRepositories() );
-                        plugin.setVersion( pluginVersionResolver.resolve( request ).getVersion() );
+        if (pluginManagement != null) {
+            for (Plugin plugin : pluginManagement.getPlugins()) {
+                if (plugin.getVersion() == null) {
+                    plugin.setVersion(versions.get(plugin.getKey()));
+                    if (plugin.getVersion() == null) {
+                        PluginVersionRequest request = new DefaultPluginVersionRequest(
+                                plugin, session.getRepositorySession(), project.getRemotePluginRepositories());
+                        plugin.setVersion(pluginVersionResolver.resolve(request).getVersion());
                     }
                 }
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java
index 9f2eb5e..9bdc59a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleStarter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.List;
-import java.util.Map;
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.List;
+import java.util.Map;
+
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenExecutionResult;
 import org.apache.maven.execution.MavenSession;
@@ -41,15 +40,11 @@
 /**
  * Starts the build life cycle
  *
- * @author Jason van Zyl
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold
  */
 @Named
 @Singleton
-public class LifecycleStarter
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class LifecycleStarter {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final ExecutionEventCatapult eventCatapult;
 
@@ -73,8 +68,7 @@
             LifecycleDebugLogger lifecycleDebugLogger,
             LifecycleTaskSegmentCalculator lifecycleTaskSegmentCalculator,
             Map<String, Builder> builders,
-            SessionScope sessionScope )
-    {
+            SessionScope sessionScope) {
         this.eventCatapult = eventCatapult;
         this.defaultLifeCycles = defaultLifeCycles;
         this.buildListCalculator = buildListCalculator;
@@ -84,80 +78,68 @@
         this.sessionScope = sessionScope;
     }
 
-    public void execute( MavenSession session )
-    {
-        eventCatapult.fire( ExecutionEvent.Type.SessionStarted, session, null );
+    public void execute(MavenSession session) {
+        eventCatapult.fire(ExecutionEvent.Type.SessionStarted, session, null);
 
         ReactorContext reactorContext = null;
         ProjectBuildList projectBuilds = null;
         MavenExecutionResult result = session.getResult();
 
-        try
-        {
-            if ( buildExecutionRequiresProject( session ) && projectIsNotPresent( session ) )
-            {
-                throw new MissingProjectException( "The goal you specified requires a project to execute"
-                    + " but there is no POM in this directory (" + session.getExecutionRootDirectory() + ")."
-                    + " Please verify you invoked Maven from the correct directory." );
+        try {
+            if (buildExecutionRequiresProject(session) && projectIsNotPresent(session)) {
+                throw new MissingProjectException("The goal you specified requires a project to execute"
+                        + " but there is no POM in this directory (" + session.getExecutionRootDirectory() + ")."
+                        + " Please verify you invoked Maven from the correct directory.");
             }
 
-            List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments( session );
-            projectBuilds = buildListCalculator.calculateProjectBuilds( session, taskSegments );
+            List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments(session);
+            projectBuilds = buildListCalculator.calculateProjectBuilds(session, taskSegments);
 
-            if ( projectBuilds.isEmpty() )
-            {
-                throw new NoGoalSpecifiedException( "No goals have been specified for this build."
-                    + " You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or"
-                    + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>."
-                    + " Available lifecycle phases are: " + defaultLifeCycles.getLifecyclePhaseList() + "." );
+            if (projectBuilds.isEmpty()) {
+                throw new NoGoalSpecifiedException("No goals have been specified for this build."
+                        + " You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or"
+                        + " <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>."
+                        + " Available lifecycle phases are: " + defaultLifeCycles.getLifecyclePhaseList() + ".");
             }
 
-            ProjectIndex projectIndex = new ProjectIndex( session.getProjects() );
+            ProjectIndex projectIndex = new ProjectIndex(session.getProjects());
 
-            if ( logger.isDebugEnabled() )
-            {
-                lifecycleDebugLogger.debugReactorPlan( projectBuilds );
+            if (logger.isDebugEnabled()) {
+                lifecycleDebugLogger.debugReactorPlan(projectBuilds);
             }
 
             ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
-            ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus( session.getProjectDependencyGraph() );
-            reactorContext = new ReactorContext( result, projectIndex, oldContextClassLoader, reactorBuildStatus );
+            ReactorBuildStatus reactorBuildStatus = new ReactorBuildStatus(session.getProjectDependencyGraph());
+            reactorContext = new ReactorContext(result, projectIndex, oldContextClassLoader, reactorBuildStatus);
 
             String builderId = session.getRequest().getBuilderId();
-            Builder builder = builders.get( builderId );
-            if ( builder == null )
-            {
-                throw new BuilderNotFoundException( String.format( "The builder requested using id = %s cannot be"
-                    + " found", builderId ) );
+            Builder builder = builders.get(builderId);
+            if (builder == null) {
+                throw new BuilderNotFoundException(
+                        String.format("The builder requested using id = %s cannot be" + " found", builderId));
             }
 
             int degreeOfConcurrency = session.getRequest().getDegreeOfConcurrency();
-            if ( degreeOfConcurrency > 1 )
-            {
-                logger.info( "" );
-                logger.info( String.format( "Using the %s implementation with a thread count of %d",
-                                            builder.getClass().getSimpleName(), degreeOfConcurrency ) );
+            if (degreeOfConcurrency > 1) {
+                logger.info("");
+                logger.info(String.format(
+                        "Using the %s implementation with a thread count of %d",
+                        builder.getClass().getSimpleName(), degreeOfConcurrency));
             }
-            builder.build( session, reactorContext, projectBuilds, taskSegments, reactorBuildStatus );
+            builder.build(session, reactorContext, projectBuilds, taskSegments, reactorBuildStatus);
 
-        }
-        catch ( Exception e )
-        {
-            result.addException( e );
-        }
-        finally
-        {
-            eventCatapult.fire( ExecutionEvent.Type.SessionEnded, session, null );
+        } catch (Exception e) {
+            result.addException(e);
+        } finally {
+            eventCatapult.fire(ExecutionEvent.Type.SessionEnded, session, null);
         }
     }
 
-    private boolean buildExecutionRequiresProject( MavenSession session )
-    {
-        return lifecycleTaskSegmentCalculator.requiresProject( session );
+    private boolean buildExecutionRequiresProject(MavenSession session) {
+        return lifecycleTaskSegmentCalculator.requiresProject(session);
     }
 
-    private boolean projectIsNotPresent( MavenSession session )
-    {
+    private boolean projectIsNotPresent(MavenSession session) {
         return !session.getRequest().isProjectPresent();
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTask.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTask.java
index 56aafd5..e2080c1 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTask.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTask.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 /**
  * <p>
@@ -26,26 +25,21 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public final class LifecycleTask
-{
+public final class LifecycleTask {
 
     private final String lifecyclePhase;
 
-    public LifecycleTask( String lifecyclePhase )
-    {
+    public LifecycleTask(String lifecyclePhase) {
         this.lifecyclePhase = lifecyclePhase;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getLifecyclePhase();
     }
 
-    public String getLifecyclePhase()
-    {
+    public String getLifecyclePhase() {
         return lifecyclePhase;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator.java
index 7dd84d8..db188c4 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import java.util.List;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.LifecycleNotFoundException;
@@ -30,8 +31,6 @@
 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 
-import java.util.List;
-
 /**
  * <p>
  * Calculates the task segments in the build
@@ -39,23 +38,17 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Jason van Zyl
- * @author jdcasey
- * @author Kristian Rosenvold (extracted interface)
  */
-public interface LifecycleTaskSegmentCalculator
-{
-    List<TaskSegment> calculateTaskSegments( MavenSession session )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException;
+public interface LifecycleTaskSegmentCalculator {
+    List<TaskSegment> calculateTaskSegments(MavenSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginVersionResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException;
 
-    List<TaskSegment> calculateTaskSegments( MavenSession session, List<String> tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException;
+    List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginVersionResolutionException;
 
-    boolean requiresProject( MavenSession session );
-
+    boolean requiresProject(MavenSession session);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java
index 778aa33..1557879 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoDescriptorCreator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.StringTokenizer;
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.xml.XmlNodeImpl;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.BuildPluginManager;
 import org.apache.maven.plugin.InvalidPluginDescriptorException;
@@ -47,7 +50,6 @@
 import org.apache.maven.plugin.version.PluginVersionResolver;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,16 +60,11 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Jason van Zyl
- * @author jdcasey
- * @author Kristian Rosenvold (extracted class only)
  */
 @Named
 @Singleton
-public class MojoDescriptorCreator
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class MojoDescriptorCreator {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
     private final PluginVersionResolver pluginVersionResolver;
     private final BuildPluginManager pluginManager;
     private final PluginPrefixResolver pluginPrefixResolver;
@@ -78,20 +75,16 @@
             PluginVersionResolver pluginVersionResolver,
             BuildPluginManager pluginManager,
             PluginPrefixResolver pluginPrefixResolver,
-            LifecyclePluginResolver lifecyclePluginResolver )
-    {
+            LifecyclePluginResolver lifecyclePluginResolver) {
         this.pluginVersionResolver = pluginVersionResolver;
         this.pluginManager = pluginManager;
         this.pluginPrefixResolver = pluginPrefixResolver;
         this.lifecyclePluginResolver = lifecyclePluginResolver;
     }
 
-    private Plugin findPlugin( String groupId, String artifactId, Collection<Plugin> plugins )
-    {
-        for ( Plugin plugin : plugins )
-        {
-            if ( artifactId.equals( plugin.getArtifactId() ) && groupId.equals( plugin.getGroupId() ) )
-            {
+    private Plugin findPlugin(String groupId, String artifactId, Collection<Plugin> plugins) {
+        for (Plugin plugin : plugins) {
+            if (artifactId.equals(plugin.getArtifactId()) && groupId.equals(plugin.getGroupId())) {
                 return plugin;
             }
         }
@@ -99,53 +92,61 @@
         return null;
     }
 
-    public static Xpp3Dom convert( MojoDescriptor mojoDescriptor )
-    {
-        Xpp3Dom dom = new Xpp3Dom( "configuration" );
+    public static XmlNode convert(org.apache.maven.api.plugin.descriptor.MojoDescriptor mojoDescriptor) {
+        List<XmlNode> children = mojoDescriptor.getParameters().stream()
+                .filter(p -> p.getDefaultValue() != null || p.getExpression() != null)
+                .map(p -> new XmlNodeImpl(
+                        p.getName(),
+                        p.getExpression(),
+                        p.getDefaultValue() != null
+                                ? Collections.singletonMap("default-value", p.getDefaultValue())
+                                : null,
+                        null,
+                        null))
+                .collect(Collectors.toList());
+        return new XmlNodeImpl("configuration", null, null, children, null);
+    }
 
+    public static org.codehaus.plexus.util.xml.Xpp3Dom convert(MojoDescriptor mojoDescriptor) {
         PlexusConfiguration c = mojoDescriptor.getMojoConfiguration();
 
+        List<XmlNode> children = new ArrayList<>();
         PlexusConfiguration[] ces = c.getChildren();
-
-        if ( ces != null )
-        {
-            for ( PlexusConfiguration ce : ces )
-            {
-                String value = ce.getValue( null );
-                String defaultValue = ce.getAttribute( "default-value", null );
-                if ( value != null || defaultValue != null )
-                {
-                    Xpp3Dom e = new Xpp3Dom( ce.getName() );
-                    e.setValue( value );
-                    if ( defaultValue != null )
-                    {
-                        e.setAttribute( "default-value", defaultValue );
-                    }
-                    dom.addChild( e );
+        if (ces != null) {
+            for (PlexusConfiguration ce : ces) {
+                String value = ce.getValue(null);
+                String defaultValue = ce.getAttribute("default-value", null);
+                if (value != null || defaultValue != null) {
+                    XmlNodeImpl e = new XmlNodeImpl(
+                            ce.getName(),
+                            value,
+                            defaultValue != null ? Collections.singletonMap("default-value", defaultValue) : null,
+                            null,
+                            null);
+                    children.add(e);
                 }
             }
         }
 
-        return dom;
+        XmlNodeImpl dom = new XmlNodeImpl("configuration", null, null, children, null);
+        return new org.codehaus.plexus.util.xml.Xpp3Dom(dom);
     }
 
     // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process@executionId
 
-    public MojoDescriptor getMojoDescriptor( String task, MavenSession session, MavenProject project )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException
-    {
+    public MojoDescriptor getMojoDescriptor(String task, MavenSession session, MavenProject project)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginVersionResolutionException {
         String goal = null;
 
         Plugin plugin = null;
 
-        StringTokenizer tok = new StringTokenizer( task, ":" );
+        String[] tok = task.split(":");
 
-        int numTokens = tok.countTokens();
+        int numTokens = tok.length;
 
-        if ( numTokens >= 4 )
-        {
+        if (numTokens >= 4) {
             // We have everything that we need
             //
             // org.apache.maven.plugins:maven-remote-resources-plugin:1.0:process
@@ -156,25 +157,21 @@
             // goal
             //
             plugin = new Plugin();
-            plugin.setGroupId( tok.nextToken() );
-            plugin.setArtifactId( tok.nextToken() );
-            plugin.setVersion( tok.nextToken() );
-            goal = tok.nextToken();
+            plugin.setGroupId(tok[0]);
+            plugin.setArtifactId(tok[1]);
+            plugin.setVersion(tok[2]);
+            goal = tok[3];
 
             // This won't be valid, but it constructs something easy to read in the error message
-            while ( tok.hasMoreTokens() )
-            {
-                goal += ":" + tok.nextToken();
+            for (int idx = 4; idx < tok.length; idx++) {
+                goal += ":" + tok[idx];
             }
-        }
-        else if ( numTokens == 3 )
-        {
+        } else if (numTokens == 3) {
             // groupId:artifactId:goal or pluginPrefix:version:goal (since Maven 3.9.0)
 
-            String firstToken = tok.nextToken();
+            String firstToken = tok[0];
             // groupId or pluginPrefix? heuristics: groupId contains dot (.) but not pluginPrefix
-            if ( firstToken.contains( "." ) )
-            {
+            if (firstToken.contains(".")) {
                 // We have everything that we need except the version
                 //
                 // org.apache.maven.plugins:maven-remote-resources-plugin:???:process
@@ -185,31 +182,24 @@
                 // goal
                 //
                 plugin = new Plugin();
-                plugin.setGroupId( firstToken );
-                plugin.setArtifactId( tok.nextToken() );
-            }
-            else
-            {
+                plugin.setGroupId(firstToken);
+                plugin.setArtifactId(tok[1]);
+            } else {
                 // pluginPrefix:version:goal, like remote-resources:3.5.0:process
-                plugin = findPluginForPrefix( firstToken, session );
-                plugin.setVersion( tok.nextToken() );
+                plugin = findPluginForPrefix(firstToken, session);
+                plugin.setVersion(tok[1]);
             }
-            goal = tok.nextToken();
-        }
-        else
-        {
+            goal = tok[2];
+        } else {
             // We have a prefix and goal
             //
             // idea:idea
             //
-            String prefix = tok.nextToken();
+            String prefix = tok[0];
 
-            if ( numTokens == 2 )
-            {
-                goal = tok.nextToken();
-            }
-            else
-            {
+            if (numTokens == 2) {
+                goal = tok[1];
+            } else {
                 // goal was missing - pass through to MojoNotFoundException
                 goal = "";
             }
@@ -223,93 +213,77 @@
             // Maven plugin deployment we will find the right PluginDescriptor from the remote
             // repository.
 
-            plugin = findPluginForPrefix( prefix, session );
+            plugin = findPluginForPrefix(prefix, session);
         }
 
-        int executionIdx = goal.indexOf( '@' );
-        if ( executionIdx > 0 )
-        {
-            goal = goal.substring( 0, executionIdx );
+        int executionIdx = goal.indexOf('@');
+        if (executionIdx > 0) {
+            goal = goal.substring(0, executionIdx);
         }
 
-        injectPluginDeclarationFromProject( plugin, project );
+        injectPluginDeclarationFromProject(plugin, project);
 
         // If there is no version to be found then we need to look in the repository metadata for
         // this plugin and see what's specified as the latest release.
         //
-        if ( plugin.getVersion() == null )
-        {
-            resolvePluginVersion( plugin, session, project );
+        if (plugin.getVersion() == null) {
+            resolvePluginVersion(plugin, session, project);
         }
 
-        return pluginManager.getMojoDescriptor( plugin, goal.toString(), project.getRemotePluginRepositories(),
-                                                session.getRepositorySession() );
+        return pluginManager.getMojoDescriptor(
+                plugin, goal.toString(), project.getRemotePluginRepositories(), session.getRepositorySession());
     }
 
     // TODO take repo mans into account as one may be aggregating prefixes of many
     // TODO collect at the root of the repository, read the one at the root, and fetch remote if something is missing
     // or the user forces the issue
 
-    public Plugin findPluginForPrefix( String prefix, MavenSession session )
-        throws NoPluginFoundForPrefixException
-    {
+    public Plugin findPluginForPrefix(String prefix, MavenSession session) throws NoPluginFoundForPrefixException {
         // [prefix]:[goal]
 
-        if ( session.getCurrentProject() != null )
-        {
-            try
-            {
-                lifecyclePluginResolver.resolveMissingPluginVersions( session.getCurrentProject(), session );
-            }
-            catch ( PluginVersionResolutionException e )
-            {
+        if (session.getCurrentProject() != null) {
+            try {
+                lifecyclePluginResolver.resolveMissingPluginVersions(session.getCurrentProject(), session);
+            } catch (PluginVersionResolutionException e) {
                 // not critical here
-                logger.debug( e.getMessage(), e );
+                logger.debug(e.getMessage(), e);
             }
         }
 
-        PluginPrefixRequest prefixRequest = new DefaultPluginPrefixRequest( prefix, session );
-        PluginPrefixResult prefixResult = pluginPrefixResolver.resolve( prefixRequest );
+        PluginPrefixRequest prefixRequest = new DefaultPluginPrefixRequest(prefix, session);
+        PluginPrefixResult prefixResult = pluginPrefixResolver.resolve(prefixRequest);
 
         Plugin plugin = new Plugin();
-        plugin.setGroupId( prefixResult.getGroupId() );
-        plugin.setArtifactId( prefixResult.getArtifactId() );
+        plugin.setGroupId(prefixResult.getGroupId());
+        plugin.setArtifactId(prefixResult.getArtifactId());
 
         return plugin;
     }
 
-    private void resolvePluginVersion( Plugin plugin, MavenSession session, MavenProject project )
-        throws PluginVersionResolutionException
-    {
-        PluginVersionRequest versionRequest =
-            new DefaultPluginVersionRequest( plugin, session.getRepositorySession(),
-                                             project.getRemotePluginRepositories() );
-        plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
+    private void resolvePluginVersion(Plugin plugin, MavenSession session, MavenProject project)
+            throws PluginVersionResolutionException {
+        PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(
+                plugin, session.getRepositorySession(), project.getRemotePluginRepositories());
+        plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
     }
 
-    private void injectPluginDeclarationFromProject( Plugin plugin, MavenProject project )
-    {
-        Plugin pluginInPom = findPlugin( plugin, project.getBuildPlugins() );
+    private void injectPluginDeclarationFromProject(Plugin plugin, MavenProject project) {
+        Plugin pluginInPom = findPlugin(plugin, project.getBuildPlugins());
 
-        if ( pluginInPom == null && project.getPluginManagement() != null )
-        {
-            pluginInPom = findPlugin( plugin, project.getPluginManagement().getPlugins() );
+        if (pluginInPom == null && project.getPluginManagement() != null) {
+            pluginInPom = findPlugin(plugin, project.getPluginManagement().getPlugins());
         }
 
-        if ( pluginInPom != null )
-        {
-            if ( plugin.getVersion() == null )
-            {
-                plugin.setVersion( pluginInPom.getVersion() );
+        if (pluginInPom != null) {
+            if (plugin.getVersion() == null) {
+                plugin.setVersion(pluginInPom.getVersion());
             }
 
-            plugin.setDependencies( new ArrayList<>( pluginInPom.getDependencies() ) );
+            plugin.setDependencies(new ArrayList<>(pluginInPom.getDependencies()));
         }
     }
 
-    private Plugin findPlugin( Plugin plugin, Collection<Plugin> plugins )
-    {
-        return findPlugin( plugin.getGroupId(), plugin.getArtifactId(), plugins );
+    private Plugin findPlugin(Plugin plugin, Collection<Plugin> plugins) {
+        return findPlugin(plugin.getGroupId(), plugin.getArtifactId(), plugins);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
index d251d51..52a7ce0 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Provider;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -32,11 +36,7 @@
 import java.util.concurrent.locks.ReentrantLock;
 import java.util.concurrent.locks.ReentrantReadWriteLock;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Provider;
-import javax.inject.Singleton;
-
+import org.apache.maven.api.services.MessageBuilderFactory;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
 import org.apache.maven.artifact.resolver.filter.CumulativeScopeArtifactFilter;
@@ -50,14 +50,13 @@
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoExecutionRunner;
-import org.apache.maven.plugin.MojosExecutionStrategy;
 import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.MojosExecutionStrategy;
 import org.apache.maven.plugin.PluginConfigurationException;
 import org.apache.maven.plugin.PluginIncompatibleException;
 import org.apache.maven.plugin.PluginManagerException;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.SessionData;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -68,17 +67,13 @@
  * </p>
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
- * @author Jason van Zyl
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold
  * @since 3.0
  */
 @Named
 @Singleton
-public class MojoExecutor
-{
+public class MojoExecutor {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger( MojoExecutor.class );
+    private static final Logger LOGGER = LoggerFactory.getLogger(MojoExecutor.class);
 
     private final BuildPluginManager pluginManager;
     private final MavenPluginManager mavenPluginManager;
@@ -89,6 +84,8 @@
 
     private final Provider<MojosExecutionStrategy> mojosExecutionStrategy;
 
+    private final MessageBuilderFactory messageBuilderFactory;
+
     private final Map<Thread, MojoDescriptor> mojos = new ConcurrentHashMap<>();
 
     @Inject
@@ -97,139 +94,124 @@
             MavenPluginManager mavenPluginManager,
             LifecycleDependencyResolver lifeCycleDependencyResolver,
             ExecutionEventCatapult eventCatapult,
-            Provider<MojosExecutionStrategy> mojosExecutionStrategy )
-    {
+            Provider<MojosExecutionStrategy> mojosExecutionStrategy,
+            MessageBuilderFactory messageBuilderFactory) {
         this.pluginManager = pluginManager;
         this.mavenPluginManager = mavenPluginManager;
         this.lifeCycleDependencyResolver = lifeCycleDependencyResolver;
         this.eventCatapult = eventCatapult;
         this.mojosExecutionStrategy = mojosExecutionStrategy;
+        this.messageBuilderFactory = messageBuilderFactory;
     }
 
-    public DependencyContext newDependencyContext( MavenSession session, List<MojoExecution> mojoExecutions )
-    {
+    public DependencyContext newDependencyContext(MavenSession session, List<MojoExecution> mojoExecutions) {
         Set<String> scopesToCollect = new TreeSet<>();
         Set<String> scopesToResolve = new TreeSet<>();
 
-        collectDependencyRequirements( scopesToResolve, scopesToCollect, mojoExecutions );
+        collectDependencyRequirements(scopesToResolve, scopesToCollect, mojoExecutions);
 
-        return new DependencyContext( session.getCurrentProject(), scopesToCollect, scopesToResolve );
+        return new DependencyContext(session.getCurrentProject(), scopesToCollect, scopesToResolve);
     }
 
-    private void collectDependencyRequirements( Set<String> scopesToResolve, Set<String> scopesToCollect,
-                                                Collection<MojoExecution> mojoExecutions )
-    {
-        for ( MojoExecution mojoExecution : mojoExecutions )
-        {
+    private void collectDependencyRequirements(
+            Set<String> scopesToResolve, Set<String> scopesToCollect, Collection<MojoExecution> mojoExecutions) {
+        for (MojoExecution mojoExecution : mojoExecutions) {
             MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
-            scopesToResolve.addAll( toScopes( mojoDescriptor.getDependencyResolutionRequired() ) );
+            scopesToResolve.addAll(toScopes(mojoDescriptor.getDependencyResolutionRequired()));
 
-            scopesToCollect.addAll( toScopes( mojoDescriptor.getDependencyCollectionRequired() ) );
+            scopesToCollect.addAll(toScopes(mojoDescriptor.getDependencyCollectionRequired()));
         }
     }
 
-    private Collection<String> toScopes( String classpath )
-    {
+    private Collection<String> toScopes(String classpath) {
         Collection<String> scopes = Collections.emptyList();
 
-        if ( StringUtils.isNotEmpty( classpath ) )
-        {
-            if ( Artifact.SCOPE_COMPILE.equals( classpath ) )
-            {
-                scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED );
-            }
-            else if ( Artifact.SCOPE_RUNTIME.equals( classpath ) )
-            {
-                scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME );
-            }
-            else if ( Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals( classpath ) )
-            {
-                scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED,
-                                        Artifact.SCOPE_RUNTIME );
-            }
-            else if ( Artifact.SCOPE_RUNTIME_PLUS_SYSTEM.equals( classpath ) )
-            {
-                scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME );
-            }
-            else if ( Artifact.SCOPE_TEST.equals( classpath ) )
-            {
-                scopes = Arrays.asList( Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED,
-                                        Artifact.SCOPE_RUNTIME, Artifact.SCOPE_TEST );
+        if (classpath != null && !classpath.isEmpty()) {
+            if (Artifact.SCOPE_COMPILE.equals(classpath)) {
+                scopes = Arrays.asList(Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED);
+            } else if (Artifact.SCOPE_RUNTIME.equals(classpath)) {
+                scopes = Arrays.asList(Artifact.SCOPE_COMPILE, Artifact.SCOPE_RUNTIME);
+            } else if (Artifact.SCOPE_COMPILE_PLUS_RUNTIME.equals(classpath)) {
+                scopes = Arrays.asList(
+                        Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_PROVIDED, Artifact.SCOPE_RUNTIME);
+            } else if (Artifact.SCOPE_RUNTIME_PLUS_SYSTEM.equals(classpath)) {
+                scopes = Arrays.asList(Artifact.SCOPE_COMPILE, Artifact.SCOPE_SYSTEM, Artifact.SCOPE_RUNTIME);
+            } else if (Artifact.SCOPE_TEST.equals(classpath)) {
+                scopes = Arrays.asList(
+                        Artifact.SCOPE_COMPILE,
+                        Artifact.SCOPE_SYSTEM,
+                        Artifact.SCOPE_PROVIDED,
+                        Artifact.SCOPE_RUNTIME,
+                        Artifact.SCOPE_TEST);
             }
         }
-        return Collections.unmodifiableCollection( scopes );
+        return Collections.unmodifiableCollection(scopes);
     }
 
-    public void execute( final MavenSession session,
-                         final List<MojoExecution> mojoExecutions,
-                         final ProjectIndex projectIndex )
-        throws LifecycleExecutionException
+    public void execute(
+            final MavenSession session, final List<MojoExecution> mojoExecutions, final ProjectIndex projectIndex)
+            throws LifecycleExecutionException {
 
-    {
-        final DependencyContext dependencyContext = newDependencyContext( session, mojoExecutions );
+        final DependencyContext dependencyContext = newDependencyContext(session, mojoExecutions);
 
-        final PhaseRecorder phaseRecorder = new PhaseRecorder( session.getCurrentProject() );
+        final PhaseRecorder phaseRecorder = new PhaseRecorder(session.getCurrentProject());
 
-        mojosExecutionStrategy.get().execute( mojoExecutions, session, new MojoExecutionRunner()
-        {
+        mojosExecutionStrategy.get().execute(mojoExecutions, session, new MojoExecutionRunner() {
             @Override
-            public void run( MojoExecution mojoExecution ) throws LifecycleExecutionException
-            {
-                MojoExecutor.this.execute( session, mojoExecution, projectIndex, dependencyContext, phaseRecorder );
+            public void run(MojoExecution mojoExecution) throws LifecycleExecutionException {
+                MojoExecutor.this.execute(session, mojoExecution, projectIndex, dependencyContext, phaseRecorder);
             }
-        } );
+        });
     }
 
-    private void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
-                         DependencyContext dependencyContext, PhaseRecorder phaseRecorder )
-        throws LifecycleExecutionException
-    {
-        execute( session, mojoExecution, projectIndex, dependencyContext );
-        phaseRecorder.observeExecution( mojoExecution );
+    private void execute(
+            MavenSession session,
+            MojoExecution mojoExecution,
+            ProjectIndex projectIndex,
+            DependencyContext dependencyContext,
+            PhaseRecorder phaseRecorder)
+            throws LifecycleExecutionException {
+        execute(session, mojoExecution, projectIndex, dependencyContext);
+        phaseRecorder.observeExecution(mojoExecution);
     }
 
-    private void execute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
-                          DependencyContext dependencyContext )
-        throws LifecycleExecutionException
-    {
+    private void execute(
+            MavenSession session,
+            MojoExecution mojoExecution,
+            ProjectIndex projectIndex,
+            DependencyContext dependencyContext)
+            throws LifecycleExecutionException {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
-        try
-        {
-            mavenPluginManager.checkRequiredMavenVersion( mojoDescriptor.getPluginDescriptor() );
-        }
-        catch ( PluginIncompatibleException e )
-        {
-            throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
+        try {
+            mavenPluginManager.checkPrerequisites(mojoDescriptor.getPluginDescriptor());
+        } catch (PluginIncompatibleException e) {
+            throw new LifecycleExecutionException(messageBuilderFactory, mojoExecution, session.getCurrentProject(), e);
         }
 
-        if ( mojoDescriptor.isProjectRequired() && !session.getRequest().isProjectPresent() )
-        {
+        if (mojoDescriptor.isProjectRequired() && !session.getRequest().isProjectPresent()) {
             Throwable cause = new MissingProjectException(
-                "Goal requires a project to execute" + " but there is no POM in this directory ("
-                    + session.getExecutionRootDirectory() + ")."
-                    + " Please verify you invoked Maven from the correct directory." );
-            throw new LifecycleExecutionException( mojoExecution, null, cause );
+                    "Goal requires a project to execute" + " but there is no POM in this directory ("
+                            + session.getExecutionRootDirectory() + ")."
+                            + " Please verify you invoked Maven from the correct directory.");
+            throw new LifecycleExecutionException(messageBuilderFactory, mojoExecution, null, cause);
         }
 
-        if ( mojoDescriptor.isOnlineRequired() && session.isOffline() )
-        {
-            if ( MojoExecution.Source.CLI.equals( mojoExecution.getSource() ) )
-            {
+        if (mojoDescriptor.isOnlineRequired() && session.isOffline()) {
+            if (MojoExecution.Source.CLI.equals(mojoExecution.getSource())) {
                 Throwable cause = new IllegalStateException(
-                    "Goal requires online mode for execution" + " but Maven is currently offline." );
-                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), cause );
-            }
-            else
-            {
-                eventCatapult.fire( ExecutionEvent.Type.MojoSkipped, session, mojoExecution );
+                        "Goal requires online mode for execution" + " but Maven is currently offline.");
+                throw new LifecycleExecutionException(
+                        messageBuilderFactory, mojoExecution, session.getCurrentProject(), cause);
+            } else {
+                eventCatapult.fire(ExecutionEvent.Type.MojoSkipped, session, mojoExecution);
 
                 return;
             }
         }
 
-        doExecute( session, mojoExecution, projectIndex, dependencyContext );
+        doExecute(session, mojoExecution, projectIndex, dependencyContext);
     }
 
     /**
@@ -240,304 +222,249 @@
      * TODO: ideally, the builder should take care of the ordering in a smarter way
      * TODO: and concurrency issues fixed with MNG-7157
      */
-    private class ProjectLock implements AutoCloseable
-    {
+    private class ProjectLock implements AutoCloseable {
         final Lock acquiredAggregatorLock;
         final OwnerReentrantLock acquiredProjectLock;
 
-        ProjectLock( MavenSession session, MojoDescriptor mojoDescriptor )
-        {
-            mojos.put( Thread.currentThread(), mojoDescriptor );
-            if ( session.getRequest().getDegreeOfConcurrency() > 1 )
-            {
+        ProjectLock(MavenSession session, MojoDescriptor mojoDescriptor) {
+            mojos.put(Thread.currentThread(), mojoDescriptor);
+            if (session.getRequest().getDegreeOfConcurrency() > 1) {
                 boolean aggregator = mojoDescriptor.isAggregator();
                 acquiredAggregatorLock = aggregator ? aggregatorLock.writeLock() : aggregatorLock.readLock();
-                acquiredProjectLock = getProjectLock( session );
-                if ( !acquiredAggregatorLock.tryLock() )
-                {
+                acquiredProjectLock = getProjectLock(session);
+                if (!acquiredAggregatorLock.tryLock()) {
                     Thread owner = aggregatorLock.getOwner();
-                    MojoDescriptor ownerMojo = owner != null ? mojos.get( owner ) : null;
+                    MojoDescriptor ownerMojo = owner != null ? mojos.get(owner) : null;
                     String str = ownerMojo != null ? " The " + ownerMojo.getId() : "An";
                     String msg = str + " aggregator mojo is already being executed "
                             + "in this parallel build, those kind of mojos require exclusive access to "
                             + "reactor to prevent race conditions. This mojo execution will be blocked "
                             + "until the aggregator mojo is done.";
-                    warn( msg );
+                    warn(msg);
                     acquiredAggregatorLock.lock();
                 }
-                if ( !acquiredProjectLock.tryLock() )
-                {
+                if (!acquiredProjectLock.tryLock()) {
                     Thread owner = acquiredProjectLock.getOwner();
-                    MojoDescriptor ownerMojo = owner != null ? mojos.get( owner ) : null;
+                    MojoDescriptor ownerMojo = owner != null ? mojos.get(owner) : null;
                     String str = ownerMojo != null ? " The " + ownerMojo.getId() : "A";
                     String msg = str + " mojo is already being executed "
                             + "on the project " + session.getCurrentProject().getGroupId()
                             + ":" + session.getCurrentProject().getArtifactId() + ". "
                             + "This mojo execution will be blocked "
                             + "until the mojo is done.";
-                    warn( msg );
+                    warn(msg);
                     acquiredProjectLock.lock();
                 }
-            }
-            else
-            {
+            } else {
                 acquiredAggregatorLock = null;
                 acquiredProjectLock = null;
             }
         }
 
         @Override
-        public void close()
-        {
+        public void close() {
             // release the lock in the reverse order of the acquisition
-            if ( acquiredProjectLock != null )
-            {
+            if (acquiredProjectLock != null) {
                 acquiredProjectLock.unlock();
             }
-            if ( acquiredAggregatorLock != null )
-            {
+            if (acquiredAggregatorLock != null) {
                 acquiredAggregatorLock.unlock();
             }
-            mojos.remove( Thread.currentThread() );
+            mojos.remove(Thread.currentThread());
         }
 
-        @SuppressWarnings( { "unchecked", "rawtypes" } )
-        private OwnerReentrantLock getProjectLock( MavenSession session )
-        {
+        @SuppressWarnings({"unchecked", "rawtypes"})
+        private OwnerReentrantLock getProjectLock(MavenSession session) {
             SessionData data = session.getRepositorySession().getData();
-            // TODO: when resolver 1.7.3 is released, the code below should be changed to
-            // TODO: Map<MavenProject, Lock> locks = ( Map ) ((Map) data).computeIfAbsent(
-            // TODO:         ProjectLock.class, l -> new ConcurrentHashMap<>() );
-            Map<MavenProject, OwnerReentrantLock> locks = ( Map ) data.get( ProjectLock.class );
-            // initialize the value if not already done (in case of a concurrent access) to the method
-            if ( locks == null )
-            {
-                // the call to data.set(k, null, v) is effectively a call to data.putIfAbsent(k, v)
-                data.set( ProjectLock.class, null, new ConcurrentHashMap<>() );
-                locks = ( Map ) data.get( ProjectLock.class );
-            }
-            return locks.computeIfAbsent( session.getCurrentProject(), p -> new OwnerReentrantLock() );
+            Map<MavenProject, OwnerReentrantLock> locks =
+                    (Map) data.computeIfAbsent(ProjectLock.class, ConcurrentHashMap::new);
+            return locks.computeIfAbsent(session.getCurrentProject(), p -> new OwnerReentrantLock());
         }
     }
 
-    static class OwnerReentrantLock extends ReentrantLock
-    {
+    static class OwnerReentrantLock extends ReentrantLock {
         @Override
-        public Thread getOwner()
-        {
+        public Thread getOwner() {
             return super.getOwner();
         }
     }
 
-    static class OwnerReentrantReadWriteLock extends ReentrantReadWriteLock
-    {
+    static class OwnerReentrantReadWriteLock extends ReentrantReadWriteLock {
         @Override
-        public Thread getOwner()
-        {
+        public Thread getOwner() {
             return super.getOwner();
         }
     }
 
-    private static void warn( String msg )
-    {
-        for ( String s : MultilineMessageHelper.format( msg ) )
-        {
-            LOGGER.warn( s );
+    private static void warn(String msg) {
+        for (String s : MultilineMessageHelper.format(msg)) {
+            LOGGER.warn(s);
         }
     }
 
-    private void doExecute( MavenSession session, MojoExecution mojoExecution, ProjectIndex projectIndex,
-                            DependencyContext dependencyContext )
-            throws LifecycleExecutionException
-    {
+    private void doExecute(
+            MavenSession session,
+            MojoExecution mojoExecution,
+            ProjectIndex projectIndex,
+            DependencyContext dependencyContext)
+            throws LifecycleExecutionException {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
-        List<MavenProject> forkedProjects = executeForkedExecutions( mojoExecution, session, projectIndex );
+        List<MavenProject> forkedProjects = executeForkedExecutions(mojoExecution, session, projectIndex);
 
-        ensureDependenciesAreResolved( mojoDescriptor, session, dependencyContext );
+        ensureDependenciesAreResolved(mojoDescriptor, session, dependencyContext);
 
-        try ( ProjectLock lock = new ProjectLock( session, mojoDescriptor ) )
-        {
-            doExecute2( session, mojoExecution );
-        }
-        finally
-        {
-            for ( MavenProject forkedProject : forkedProjects )
-            {
-                forkedProject.setExecutionProject( null );
+        try (ProjectLock lock = new ProjectLock(session, mojoDescriptor)) {
+            doExecute2(session, mojoExecution);
+        } finally {
+            for (MavenProject forkedProject : forkedProjects) {
+                forkedProject.setExecutionProject(null);
             }
         }
     }
 
-    private void doExecute2( MavenSession session, MojoExecution mojoExecution )
-            throws LifecycleExecutionException
-    {
-        eventCatapult.fire( ExecutionEvent.Type.MojoStarted, session, mojoExecution );
-        try
-        {
-            try
-            {
-                pluginManager.executeMojo( session, mojoExecution );
-            }
-            catch ( MojoFailureException | PluginManagerException | PluginConfigurationException
-                | MojoExecutionException e )
-            {
-                throw new LifecycleExecutionException( mojoExecution, session.getCurrentProject(), e );
+    private void doExecute2(MavenSession session, MojoExecution mojoExecution) throws LifecycleExecutionException {
+        eventCatapult.fire(ExecutionEvent.Type.MojoStarted, session, mojoExecution);
+        try {
+            try {
+                pluginManager.executeMojo(session, mojoExecution);
+            } catch (MojoFailureException
+                    | PluginManagerException
+                    | PluginConfigurationException
+                    | MojoExecutionException e) {
+                throw new LifecycleExecutionException(
+                        messageBuilderFactory, mojoExecution, session.getCurrentProject(), e);
             }
 
-            eventCatapult.fire( ExecutionEvent.Type.MojoSucceeded, session, mojoExecution );
-        }
-        catch ( LifecycleExecutionException e )
-        {
-            eventCatapult.fire( ExecutionEvent.Type.MojoFailed, session, mojoExecution, e );
+            eventCatapult.fire(ExecutionEvent.Type.MojoSucceeded, session, mojoExecution);
+        } catch (LifecycleExecutionException e) {
+            eventCatapult.fire(ExecutionEvent.Type.MojoFailed, session, mojoExecution, e);
 
             throw e;
         }
     }
 
-    public void ensureDependenciesAreResolved( MojoDescriptor mojoDescriptor, MavenSession session,
-                                               DependencyContext dependencyContext )
-        throws LifecycleExecutionException
+    public void ensureDependenciesAreResolved(
+            MojoDescriptor mojoDescriptor, MavenSession session, DependencyContext dependencyContext)
+            throws LifecycleExecutionException {
 
-    {
         MavenProject project = dependencyContext.getProject();
         boolean aggregating = mojoDescriptor.isAggregator();
 
-        if ( dependencyContext.isResolutionRequiredForCurrentProject() )
-        {
+        if (dependencyContext.isResolutionRequiredForCurrentProject()) {
             Collection<String> scopesToCollect = dependencyContext.getScopesToCollectForCurrentProject();
             Collection<String> scopesToResolve = dependencyContext.getScopesToResolveForCurrentProject();
 
-            lifeCycleDependencyResolver.resolveProjectDependencies( project, scopesToCollect, scopesToResolve, session,
-                                                                    aggregating, Collections.emptySet() );
+            lifeCycleDependencyResolver.resolveProjectDependencies(
+                    project, scopesToCollect, scopesToResolve, session, aggregating, Collections.emptySet());
 
             dependencyContext.synchronizeWithProjectState();
         }
 
-        if ( aggregating )
-        {
-            Collection<String> scopesToCollect = toScopes( mojoDescriptor.getDependencyCollectionRequired() );
-            Collection<String> scopesToResolve = toScopes( mojoDescriptor.getDependencyResolutionRequired() );
+        if (aggregating) {
+            Collection<String> scopesToCollect = toScopes(mojoDescriptor.getDependencyCollectionRequired());
+            Collection<String> scopesToResolve = toScopes(mojoDescriptor.getDependencyResolutionRequired());
 
-            if ( dependencyContext.isResolutionRequiredForAggregatedProjects( scopesToCollect, scopesToResolve ) )
-            {
-                for ( MavenProject aggregatedProject : session.getProjects() )
-                {
-                    if ( aggregatedProject != project )
-                    {
-                        lifeCycleDependencyResolver.resolveProjectDependencies( aggregatedProject, scopesToCollect,
-                                                                                scopesToResolve, session, aggregating,
-                                                                                Collections.emptySet() );
+            if (dependencyContext.isResolutionRequiredForAggregatedProjects(scopesToCollect, scopesToResolve)) {
+                for (MavenProject aggregatedProject : session.getProjects()) {
+                    if (aggregatedProject != project) {
+                        lifeCycleDependencyResolver.resolveProjectDependencies(
+                                aggregatedProject,
+                                scopesToCollect,
+                                scopesToResolve,
+                                session,
+                                aggregating,
+                                Collections.emptySet());
                     }
                 }
             }
         }
 
-        ArtifactFilter artifactFilter = getArtifactFilter( mojoDescriptor );
-        List<MavenProject> projectsToResolve =
-            LifecycleDependencyResolver.getProjects( session.getCurrentProject(), session,
-                                                     mojoDescriptor.isAggregator() );
-        for ( MavenProject projectToResolve : projectsToResolve )
-        {
-            projectToResolve.setArtifactFilter( artifactFilter );
+        ArtifactFilter artifactFilter = getArtifactFilter(mojoDescriptor);
+        List<MavenProject> projectsToResolve = LifecycleDependencyResolver.getProjects(
+                session.getCurrentProject(), session, mojoDescriptor.isAggregator());
+        for (MavenProject projectToResolve : projectsToResolve) {
+            projectToResolve.setArtifactFilter(artifactFilter);
         }
     }
 
-    private ArtifactFilter getArtifactFilter( MojoDescriptor mojoDescriptor )
-    {
+    private ArtifactFilter getArtifactFilter(MojoDescriptor mojoDescriptor) {
         String scopeToResolve = mojoDescriptor.getDependencyResolutionRequired();
         String scopeToCollect = mojoDescriptor.getDependencyCollectionRequired();
 
-        List<String> scopes = new ArrayList<>( 2 );
-        if ( StringUtils.isNotEmpty( scopeToCollect ) )
-        {
-            scopes.add( scopeToCollect );
+        List<String> scopes = new ArrayList<>(2);
+        if (scopeToCollect != null && !scopeToCollect.isEmpty()) {
+            scopes.add(scopeToCollect);
         }
-        if ( StringUtils.isNotEmpty( scopeToResolve ) )
-        {
-            scopes.add( scopeToResolve );
+        if (scopeToResolve != null && !scopeToResolve.isEmpty()) {
+            scopes.add(scopeToResolve);
         }
 
-        if ( scopes.isEmpty() )
-        {
+        if (scopes.isEmpty()) {
             return null;
-        }
-        else
-        {
-            return new CumulativeScopeArtifactFilter( scopes );
+        } else {
+            return new CumulativeScopeArtifactFilter(scopes);
         }
     }
 
-    public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session,
-                                                       ProjectIndex projectIndex )
-        throws LifecycleExecutionException
-    {
+    public List<MavenProject> executeForkedExecutions(
+            MojoExecution mojoExecution, MavenSession session, ProjectIndex projectIndex)
+            throws LifecycleExecutionException {
         List<MavenProject> forkedProjects = Collections.emptyList();
 
         Map<String, List<MojoExecution>> forkedExecutions = mojoExecution.getForkedExecutions();
 
-        if ( !forkedExecutions.isEmpty() )
-        {
-            eventCatapult.fire( ExecutionEvent.Type.ForkStarted, session, mojoExecution );
+        if (!forkedExecutions.isEmpty()) {
+            eventCatapult.fire(ExecutionEvent.Type.ForkStarted, session, mojoExecution);
 
             MavenProject project = session.getCurrentProject();
 
-            forkedProjects = new ArrayList<>( forkedExecutions.size() );
+            forkedProjects = new ArrayList<>(forkedExecutions.size());
 
-            try
-            {
-                for ( Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet() )
-                {
+            try {
+                for (Map.Entry<String, List<MojoExecution>> fork : forkedExecutions.entrySet()) {
                     String projectId = fork.getKey();
 
-                    int index = projectIndex.getIndices().get( projectId );
+                    int index = projectIndex.getIndices().get(projectId);
 
-                    MavenProject forkedProject = projectIndex.getProjects().get( projectId );
+                    MavenProject forkedProject = projectIndex.getProjects().get(projectId);
 
-                    forkedProjects.add( forkedProject );
+                    forkedProjects.add(forkedProject);
 
                     MavenProject executedProject = forkedProject.clone();
 
-                    forkedProject.setExecutionProject( executedProject );
+                    forkedProject.setExecutionProject(executedProject);
 
                     List<MojoExecution> mojoExecutions = fork.getValue();
 
-                    if ( mojoExecutions.isEmpty() )
-                    {
+                    if (mojoExecutions.isEmpty()) {
                         continue;
                     }
 
-                    try
-                    {
-                        session.setCurrentProject( executedProject );
-                        session.getProjects().set( index, executedProject );
-                        projectIndex.getProjects().put( projectId, executedProject );
+                    try {
+                        session.setCurrentProject(executedProject);
+                        session.getProjects().set(index, executedProject);
+                        projectIndex.getProjects().put(projectId, executedProject);
 
-                        eventCatapult.fire( ExecutionEvent.Type.ForkedProjectStarted, session, mojoExecution );
+                        eventCatapult.fire(ExecutionEvent.Type.ForkedProjectStarted, session, mojoExecution);
 
-                        execute( session, mojoExecutions, projectIndex );
+                        execute(session, mojoExecutions, projectIndex);
 
-                        eventCatapult.fire( ExecutionEvent.Type.ForkedProjectSucceeded, session, mojoExecution );
-                    }
-                    catch ( LifecycleExecutionException e )
-                    {
-                        eventCatapult.fire( ExecutionEvent.Type.ForkedProjectFailed, session, mojoExecution, e );
+                        eventCatapult.fire(ExecutionEvent.Type.ForkedProjectSucceeded, session, mojoExecution);
+                    } catch (LifecycleExecutionException e) {
+                        eventCatapult.fire(ExecutionEvent.Type.ForkedProjectFailed, session, mojoExecution, e);
 
                         throw e;
-                    }
-                    finally
-                    {
-                        projectIndex.getProjects().put( projectId, forkedProject );
-                        session.getProjects().set( index, forkedProject );
-                        session.setCurrentProject( project );
+                    } finally {
+                        projectIndex.getProjects().put(projectId, forkedProject);
+                        session.getProjects().set(index, forkedProject);
+                        session.setCurrentProject(project);
                     }
                 }
 
-                eventCatapult.fire( ExecutionEvent.Type.ForkSucceeded, session, mojoExecution );
-            }
-            catch ( LifecycleExecutionException e )
-            {
-                eventCatapult.fire( ExecutionEvent.Type.ForkFailed, session, mojoExecution, e );
+                eventCatapult.fire(ExecutionEvent.Type.ForkSucceeded, session, mojoExecution);
+            } catch (LifecycleExecutionException e) {
+                eventCatapult.fire(ExecutionEvent.Type.ForkFailed, session, mojoExecution, e);
 
                 throw e;
             }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseRecorder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseRecorder.java
index 3316c50..c037af5 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseRecorder.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/PhaseRecorder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.project.MavenProject;
@@ -25,53 +24,38 @@
 /**
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold
  */
-public class PhaseRecorder
-{
+public class PhaseRecorder {
     private String lastLifecyclePhase;
 
     private final MavenProject project;
 
-    public PhaseRecorder( MavenProject project )
-    {
+    public PhaseRecorder(MavenProject project) {
         this.project = project;
     }
 
-    public void observeExecution( MojoExecution mojoExecution )
-    {
+    public void observeExecution(MojoExecution mojoExecution) {
         String lifecyclePhase = mojoExecution.getLifecyclePhase();
 
-        if ( lifecyclePhase != null )
-        {
-            if ( lastLifecyclePhase == null )
-            {
+        if (lifecyclePhase != null) {
+            if (lastLifecyclePhase == null) {
                 lastLifecyclePhase = lifecyclePhase;
-            }
-            else if ( !lifecyclePhase.equals( lastLifecyclePhase ) )
-            {
-                project.addLifecyclePhase( lastLifecyclePhase );
+            } else if (!lifecyclePhase.equals(lastLifecyclePhase)) {
+                project.addLifecyclePhase(lastLifecyclePhase);
                 lastLifecyclePhase = lifecyclePhase;
             }
         }
 
-        if ( lastLifecyclePhase != null )
-        {
-            project.addLifecyclePhase( lastLifecyclePhase );
+        if (lastLifecyclePhase != null) {
+            project.addLifecyclePhase(lastLifecyclePhase);
         }
     }
 
-    public boolean isDifferentPhase( MojoExecution nextMojoExecution )
-    {
+    public boolean isDifferentPhase(MojoExecution nextMojoExecution) {
         String lifecyclePhase = nextMojoExecution.getLifecyclePhase();
-        if ( lifecyclePhase == null )
-        {
+        if (lifecyclePhase == null) {
             return lastLifecyclePhase != null;
         }
-        return !lifecyclePhase.equals( lastLifecyclePhase );
-
+        return !lifecyclePhase.equals(lastLifecyclePhase);
     }
-
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectArtifactFactory.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectArtifactFactory.java
index e698811..8d9217d 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectArtifactFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectArtifactFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.Set;
 
@@ -33,8 +32,6 @@
  *
  * @since 3.2.4
  */
-public interface ProjectArtifactFactory
-{
-    Set<Artifact> createArtifacts( MavenProject project )
-        throws InvalidDependencyVersionException;
+public interface ProjectArtifactFactory {
+    Set<Artifact> createArtifacts(MavenProject project) throws InvalidDependencyVersionException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java
index 6e54398..8b2a9ae 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectBuildList.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.execution.MavenSession;
@@ -40,16 +39,12 @@
  * <strong>Note:</strong> This interface is part of work in progress and can be changed or removed without notice.
  *
  * @since 3.0
- * @author Kristian Rosenvold
  */
-public class ProjectBuildList
-    implements Iterable<ProjectSegment>
-{
+public class ProjectBuildList implements Iterable<ProjectSegment> {
     private final List<ProjectSegment> items;
 
-    public ProjectBuildList( List<ProjectSegment> items )
-    {
-        this.items = Collections.unmodifiableList( items );
+    public ProjectBuildList(List<ProjectSegment> items) {
+        this.items = Collections.unmodifiableList(items);
     }
 
     // TODO Optimize; or maybe just rewrite the whole way aggregating mojos are being run.
@@ -58,30 +53,15 @@
      * @param taskSegment the requested task segment
      * @return a project build list for the supplied task segment
      */
-    public ProjectBuildList getByTaskSegment( TaskSegment taskSegment )
-    {
-        List<ProjectSegment> currentSegment = new ArrayList<>();
-        for ( ProjectSegment projectBuild : items )
-        {
-            if ( taskSegment == projectBuild.getTaskSegment() )
-            { // NOTE: There's no notion of taskSegment equality.
-                currentSegment.add( projectBuild );
-            }
-        }
-        return new ProjectBuildList( currentSegment );
+    public ProjectBuildList getByTaskSegment(TaskSegment taskSegment) {
+        return new ProjectBuildList(
+                items.stream().filter(pb -> taskSegment == pb.getTaskSegment()).collect(Collectors.toList()));
     }
 
-    public Map<MavenProject, ProjectSegment> selectSegment( TaskSegment taskSegment )
-    {
-        Map<MavenProject, ProjectSegment> result = new HashMap<>();
-        for ( ProjectSegment projectBuild : items )
-        {
-            if ( taskSegment == projectBuild.getTaskSegment() )
-            { // NOTE: There's no notion of taskSegment equality.
-                result.put( projectBuild.getProject(), projectBuild );
-            }
-        }
-        return result;
+    public Map<MavenProject, ProjectSegment> selectSegment(TaskSegment taskSegment) {
+        return items.stream()
+                .filter(pb -> taskSegment == pb.getTaskSegment())
+                .collect(Collectors.toMap(ProjectSegment::getProject, Function.identity()));
     }
 
     /**
@@ -89,71 +69,50 @@
      * @param mavenProject the requested project
      * @return The projectSegment or null.
      */
-    public ProjectSegment findByMavenProject( MavenProject mavenProject )
-    {
-        for ( ProjectSegment projectBuild : items )
-        {
-            if ( mavenProject.equals( projectBuild.getProject() ) )
-            {
-                return projectBuild;
-            }
-        }
-        return null;
+    public ProjectSegment findByMavenProject(MavenProject mavenProject) {
+        return items.stream()
+                .filter(pb -> mavenProject.equals(pb.getProject()))
+                .findFirst()
+                .orElse(null);
     }
 
-    public Iterator<ProjectSegment> iterator()
-    {
+    public Iterator<ProjectSegment> iterator() {
         return items.iterator();
     }
 
-    public void closeAll()
-    {
-        for ( ProjectSegment item : items )
-        {
+    public void closeAll() {
+        for (ProjectSegment item : items) {
             MavenSession sessionForThisModule = item.getSession();
-            sessionForThisModule.setCurrentProject( null );
+            sessionForThisModule.setCurrentProject(null);
         }
     }
 
-    public int size()
-    {
+    public int size() {
         return items.size();
     }
 
-    public ProjectSegment get( int index )
-    {
-        return items.get( index );
+    public ProjectSegment get(int index) {
+        return items.get(index);
     }
 
-    public Set<String> getReactorProjectKeys()
-    {
-        Set<String> projectKeys = new HashSet<>( items.size() * 2 );
-        for ( ProjectSegment projectBuild : items )
-        {
+    public Set<String> getReactorProjectKeys() {
+        Set<String> projectKeys = new HashSet<>(items.size() * 2);
+        for (ProjectSegment projectBuild : items) {
             MavenProject project = projectBuild.getProject();
-            String key = ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
-            projectKeys.add( key );
+            String key = ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion());
+            projectKeys.add(key);
         }
         return projectKeys;
     }
 
-
-    public boolean isEmpty()
-    {
+    public boolean isEmpty() {
         return items.isEmpty();
     }
 
     /**
      * @return a set of all the projects managed by the build
      */
-    public Set<MavenProject> getProjects()
-    {
-        Set<MavenProject> projects = new HashSet<>();
-
-        for ( ProjectSegment s : items )
-        {
-            projects.add( s.getProject() );
-        }
-        return projects;
+    public Set<MavenProject> getProjects() {
+        return items.stream().map(ProjectSegment::getProject).collect(Collectors.toSet());
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectIndex.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectIndex.java
index 1c1cae4..8799cb2 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectIndex.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectIndex.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
-import org.apache.maven.project.MavenProject;
+package org.apache.maven.lifecycle.internal;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
+import org.apache.maven.project.MavenProject;
+
 /**
  * <p>
  * Provides the positional index of the project
@@ -33,39 +32,32 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold (extracted class only)
  */
 // TODO Kristian wonders if this class really is necessary and if it overlaps other concepts.
-public final class ProjectIndex
-{
+public final class ProjectIndex {
 
     private final Map<String, MavenProject> projects;
 
     private final Map<String, Integer> indices;
 
-    public ProjectIndex( List<MavenProject> projects )
-    {
-        this.projects = new HashMap<>( projects.size() * 2 );
-        this.indices = new HashMap<>( projects.size() * 2 );
+    public ProjectIndex(List<MavenProject> projects) {
+        this.projects = new HashMap<>(projects.size() * 2);
+        this.indices = new HashMap<>(projects.size() * 2);
 
-        for ( int i = 0; i < projects.size(); i++ )
-        {
-            MavenProject project = projects.get( i );
-            String key = BuilderCommon.getKey( project );
+        for (int i = 0; i < projects.size(); i++) {
+            MavenProject project = projects.get(i);
+            String key = BuilderCommon.getKey(project);
 
-            this.getProjects().put( key, project );
-            this.getIndices().put( key, i );
+            this.getProjects().put(key, project);
+            this.getIndices().put(key, i);
         }
     }
 
-    public Map<String, MavenProject> getProjects()
-    {
+    public Map<String, MavenProject> getProjects() {
         return projects;
     }
 
-    public Map<String, Integer> getIndices()
-    {
+    public Map<String, Integer> getIndices() {
         return indices;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectSegment.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectSegment.java
index 6b736a1..aa155d6 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectSegment.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ProjectSegment.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import java.util.List;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.project.MavenProject;
 
-import java.util.List;
-
 /**
  * A build context that matches a Maven project to a given task segment, and the session to be used.
  * <p>
@@ -51,12 +50,8 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Jason van Zyl
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold
  */
-public final class ProjectSegment
-{
+public final class ProjectSegment {
     private final MavenProject project;
 
     private final TaskSegment taskSegment;
@@ -67,44 +62,37 @@
 
     private final List<MavenProject> transitiveUpstreamProjects;
 
-    public ProjectSegment( MavenProject project, TaskSegment taskSegment, MavenSession copiedSession )
-    {
+    public ProjectSegment(MavenProject project, TaskSegment taskSegment, MavenSession copiedSession) {
         this.project = project;
         this.taskSegment = taskSegment;
         this.session = copiedSession;
         final ProjectDependencyGraph dependencyGraph = getSession().getProjectDependencyGraph();
-        nonTransitiveUpstreamProjects = dependencyGraph.getUpstreamProjects( getProject(), false );
-        transitiveUpstreamProjects = dependencyGraph.getUpstreamProjects( getProject(), true );
+        nonTransitiveUpstreamProjects = dependencyGraph.getUpstreamProjects(getProject(), false);
+        transitiveUpstreamProjects = dependencyGraph.getUpstreamProjects(getProject(), true);
     }
 
-    public MavenSession getSession()
-    {
+    public MavenSession getSession() {
         return session;
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public TaskSegment getTaskSegment()
-    {
+    public TaskSegment getTaskSegment() {
         return taskSegment;
     }
 
-    public List<MavenProject> getImmediateUpstreamProjects()
-    {
+    public List<MavenProject> getImmediateUpstreamProjects() {
         return nonTransitiveUpstreamProjects;
     }
 
-    public List<MavenProject> getTransitiveUpstreamProjects()
-    {
+    public List<MavenProject> getTransitiveUpstreamProjects() {
         return transitiveUpstreamProjects;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getProject().getId() + " -> " + getTaskSegment();
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorBuildStatus.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorBuildStatus.java
index 9bd8b86..afb3228 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorBuildStatus.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorBuildStatus.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,63 +16,53 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.execution.ProjectDependencyGraph;
-import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
-import org.apache.maven.project.MavenProject;
+package org.apache.maven.lifecycle.internal;
 
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 
+import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.lifecycle.internal.builder.BuilderCommon;
+import org.apache.maven.project.MavenProject;
+
 /**
  * Contains status information that is global to an entire reactor build.
  *
  * @since 3.0
- * @author <a href="mailto:kristian.rosenvold@gmail.com">Kristian Rosenvold</a>
  */
-public class ReactorBuildStatus
-{
+public class ReactorBuildStatus {
     private final ProjectDependencyGraph projectDependencyGraph;
 
-    private final Collection<String> blackListedProjects = Collections.synchronizedSet( new HashSet<>() );
+    private final Collection<String> blackListedProjects = Collections.synchronizedSet(new HashSet<>());
 
     private volatile boolean halted = false;
 
-    public ReactorBuildStatus( ProjectDependencyGraph projectDependencyGraph )
-    {
+    public ReactorBuildStatus(ProjectDependencyGraph projectDependencyGraph) {
         this.projectDependencyGraph = projectDependencyGraph;
     }
 
-    public boolean isBlackListed( MavenProject project )
-    {
-        return blackListedProjects.contains( BuilderCommon.getKey( project ) );
+    public boolean isBlackListed(MavenProject project) {
+        return blackListedProjects.contains(BuilderCommon.getKey(project));
     }
 
-    public void blackList( MavenProject project )
-    {
-        if ( blackListedProjects.add( BuilderCommon.getKey( project ) ) && projectDependencyGraph != null )
-        {
-            for ( MavenProject downstreamProject : projectDependencyGraph.getDownstreamProjects( project, true ) )
-            {
-                blackListedProjects.add( BuilderCommon.getKey( downstreamProject ) );
+    public void blackList(MavenProject project) {
+        if (blackListedProjects.add(BuilderCommon.getKey(project)) && projectDependencyGraph != null) {
+            for (MavenProject downstreamProject : projectDependencyGraph.getDownstreamProjects(project, true)) {
+                blackListedProjects.add(BuilderCommon.getKey(downstreamProject));
             }
         }
     }
 
-    public void halt()
-    {
+    public void halt() {
         halted = true;
     }
 
-    public boolean isHalted()
-    {
+    public boolean isHalted() {
         return halted;
     }
 
-    public boolean isHaltedOrBlacklisted( MavenProject mavenProject )
-    {
-        return isBlackListed( mavenProject ) || isHalted();
+    public boolean isHaltedOrBlacklisted(MavenProject mavenProject) {
+        return isBlackListed(mavenProject) || isHalted();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java
index 076c622..b0ab335 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/ReactorContext.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import org.apache.maven.execution.MavenExecutionResult;
 
@@ -25,12 +24,9 @@
  * Context that is fixed for the entire reactor build.
  *
  * @since 3.0
- * @author Jason van Zyl
- * @author Kristian Rosenvold
  *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
  */
-public class ReactorContext
-{
+public class ReactorContext {
     private final MavenExecutionResult result;
 
     private final ProjectIndex projectIndex;
@@ -39,33 +35,30 @@
 
     private final ReactorBuildStatus reactorBuildStatus;
 
-    public ReactorContext( MavenExecutionResult result, ProjectIndex projectIndex,
-                           ClassLoader originalContextClassLoader, ReactorBuildStatus reactorBuildStatus )
-    {
+    public ReactorContext(
+            MavenExecutionResult result,
+            ProjectIndex projectIndex,
+            ClassLoader originalContextClassLoader,
+            ReactorBuildStatus reactorBuildStatus) {
         this.result = result;
         this.projectIndex = projectIndex;
         this.originalContextClassLoader = originalContextClassLoader;
         this.reactorBuildStatus = reactorBuildStatus;
     }
 
-    public ReactorBuildStatus getReactorBuildStatus()
-    {
+    public ReactorBuildStatus getReactorBuildStatus() {
         return reactorBuildStatus;
     }
 
-    public MavenExecutionResult getResult()
-    {
+    public MavenExecutionResult getResult() {
         return result;
     }
 
-    public ProjectIndex getProjectIndex()
-    {
+    public ProjectIndex getProjectIndex() {
         return projectIndex;
     }
 
-    public ClassLoader getOriginalContextClassLoader()
-    {
+    public ClassLoader getOriginalContextClassLoader() {
         return originalContextClassLoader;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/TaskSegment.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/TaskSegment.java
index 5b0165f..40769f0 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/TaskSegment.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/TaskSegment.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -29,11 +28,8 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
- * @author Kristian Rosenvold (extracted class only)
  */
-public final class TaskSegment
-{
+public final class TaskSegment {
 
     // Can be both "LifeCycleTask" (clean/install) and "GoalTask" (org.mortbay.jetty:maven-jetty-plugin:6.1.19:run)
 
@@ -41,31 +37,26 @@
 
     private final boolean aggregating;
 
-    public TaskSegment( boolean aggregating )
-    {
+    public TaskSegment(boolean aggregating) {
         this.aggregating = aggregating;
         tasks = new ArrayList<>();
     }
 
-    public TaskSegment( boolean aggregating, Object... tasks )
-    {
+    public TaskSegment(boolean aggregating, Object... tasks) {
         this.aggregating = aggregating;
-        this.tasks = new ArrayList<>( Arrays.asList( tasks ) );
+        this.tasks = new ArrayList<>(Arrays.asList(tasks));
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         return getTasks().toString();
     }
 
-    public List<Object> getTasks()
-    {
+    public List<Object> getTasks() {
         return tasks;
     }
 
-    public boolean isAggregating()
-    {
+    public boolean isAggregating() {
         return aggregating;
     }
 
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/Builder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/Builder.java
index 95e387d..c201e65 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/Builder.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/Builder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.builder;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal.builder;
 
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -34,15 +33,17 @@
  * the the projects serially, but a {@link Builder} can employ any type of concurrency model to build the projects.
  * </p>
  * <strong>Note:</strong> This interface is part of work in progress and can be changed or removed without notice.
- * @author jvanzyl
  */
-public interface Builder
-{
+public interface Builder {
     //
     // Be nice to whittle this down to Session, maybe add task segments to the session. The session really is
     // the place to store reactor related information.
     //
-    void build( MavenSession session, ReactorContext reactorContext, ProjectBuildList projectBuilds,
-                List<TaskSegment> taskSegments, ReactorBuildStatus reactorBuildStatus )
-        throws ExecutionException, InterruptedException;
+    void build(
+            MavenSession session,
+            ReactorContext reactorContext,
+            ProjectBuildList projectBuilds,
+            List<TaskSegment> taskSegments,
+            ReactorBuildStatus reactorBuildStatus)
+            throws ExecutionException, InterruptedException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java
index 5415413..81bb559 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderCommon.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.builder;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Properties;
-import java.util.Set;
-import java.util.stream.Collectors;
+package org.apache.maven.lifecycle.internal.builder;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.execution.BuildFailure;
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.feature.Features;
 import org.apache.maven.internal.MultilineMessageHelper;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.lifecycle.LifecycleNotFoundException;
@@ -65,14 +61,12 @@
  * Common code that is shared by the LifecycleModuleBuilder and the LifeCycleWeaveBuilder
  *
  * @since 3.0
- * @author Kristian Rosenvold
  *         Builds one or more lifecycles for a full module
  *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
  */
 @Named
 @Singleton
-public class BuilderCommon
-{
+public class BuilderCommon {
     private final Logger logger;
     private final LifecycleDebugLogger lifecycleDebugLogger;
     private final LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator;
@@ -82,9 +76,8 @@
     public BuilderCommon(
             LifecycleDebugLogger lifecycleDebugLogger,
             LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator,
-            ExecutionEventCatapult eventCatapult )
-    {
-        this.logger = LoggerFactory.getLogger( getClass() );
+            ExecutionEventCatapult eventCatapult) {
+        this.logger = LoggerFactory.getLogger(getClass());
         this.lifecycleDebugLogger = lifecycleDebugLogger;
         this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator;
         this.eventCatapult = eventCatapult;
@@ -97,161 +90,121 @@
             LifecycleDebugLogger lifecycleDebugLogger,
             LifecycleExecutionPlanCalculator lifeCycleExecutionPlanCalculator,
             ExecutionEventCatapult eventCatapult,
-            Logger logger )
-    {
+            Logger logger) {
         this.lifecycleDebugLogger = lifecycleDebugLogger;
         this.lifeCycleExecutionPlanCalculator = lifeCycleExecutionPlanCalculator;
         this.eventCatapult = eventCatapult;
         this.logger = logger;
     }
 
-    public MavenExecutionPlan resolveBuildPlan( MavenSession session, MavenProject project, TaskSegment taskSegment,
-                                                Set<Artifact> projectArtifacts )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException,
-        LifecycleExecutionException
-    {
+    public MavenExecutionPlan resolveBuildPlan(
+            MavenSession session, MavenProject project, TaskSegment taskSegment, Set<Artifact> projectArtifacts)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException,
+                    LifecycleExecutionException {
         MavenExecutionPlan executionPlan =
-            lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, project, taskSegment.getTasks() );
+                lifeCycleExecutionPlanCalculator.calculateExecutionPlan(session, project, taskSegment.getTasks());
 
-        lifecycleDebugLogger.debugProjectPlan( project, executionPlan );
+        lifecycleDebugLogger.debugProjectPlan(project, executionPlan);
 
-        // With Maven 4's build/consumer the POM will always rewrite during distribution.
-        // The maven-gpg-plugin uses the original POM, causing an invalid signature.
-        // Fail as long as there's no solution available yet
-        Properties userProperties = session.getUserProperties();
-        if ( Features.buildConsumer( userProperties ).isActive() )
-        {
-            Optional<MojoExecution> gpgMojo = executionPlan.getMojoExecutions().stream()
-                            .filter( m -> "maven-gpg-plugin".equals( m.getArtifactId() )
-                                       && "org.apache.maven.plugins".equals( m.getGroupId() ) )
-                            .findAny();
-
-            if ( gpgMojo.isPresent() )
-            {
-                throw new LifecycleExecutionException( "The maven-gpg-plugin is not supported by Maven 4."
-                    + " Verify if there is a compatible signing solution,"
-                    + " add -D" + Features.buildConsumer( userProperties ).propertyName() + "=false"
-                    + " or use Maven 3." );
-            }
-        }
-
-        if ( session.getRequest().getDegreeOfConcurrency() > 1 && session.getProjects().size() > 1 )
-        {
+        if (session.getRequest().getDegreeOfConcurrency() > 1
+                && session.getProjects().size() > 1) {
             final Set<Plugin> unsafePlugins = executionPlan.getNonThreadSafePlugins();
-            if ( !unsafePlugins.isEmpty() )
-            {
-                for ( String s : MultilineMessageHelper.format(
+            if (!unsafePlugins.isEmpty()) {
+                for (String s : MultilineMessageHelper.format(
                         "Your build is requesting parallel execution, but this project contains the following "
                                 + "plugin(s) that have goals not marked as thread-safe to support parallel execution.",
                         "While this /may/ work fine, please look for plugin updates and/or "
                                 + "request plugins be made thread-safe.",
-                        "If reporting an issue, report it against the plugin in question, not against Apache Maven." ) )
-                {
-                    logger.warn( s );
+                        "If reporting an issue, report it against the plugin in question, not against Apache Maven.")) {
+                    logger.warn(s);
                 }
-                if ( logger.isDebugEnabled() )
-                {
+                if (logger.isDebugEnabled()) {
                     final Set<MojoDescriptor> unsafeGoals = executionPlan.getNonThreadSafeMojos();
-                    logger.warn( "The following goals are not marked as thread-safe in " + project.getName() + ":" );
-                    for ( MojoDescriptor unsafeGoal : unsafeGoals )
-                    {
-                        logger.warn( "  " + unsafeGoal.getId() );
+                    logger.warn("The following goals are not marked as thread-safe in " + project.getName() + ":");
+                    for (MojoDescriptor unsafeGoal : unsafeGoals) {
+                        logger.warn("  " + unsafeGoal.getId());
                     }
-                }
-                else
-                {
-                    logger.warn( "The following plugins are not marked as thread-safe in " + project.getName() + ":" );
-                    for ( Plugin unsafePlugin : unsafePlugins )
-                    {
-                        logger.warn( "  " + unsafePlugin.getId() );
+                } else {
+                    logger.warn("The following plugins are not marked as thread-safe in " + project.getName() + ":");
+                    for (Plugin unsafePlugin : unsafePlugins) {
+                        logger.warn("  " + unsafePlugin.getId());
                     }
-                    logger.warn( "" );
-                    logger.warn( "Enable verbose output (-X) to see precisely which goals are not marked as"
-                            + " thread-safe." );
+                    logger.warn("");
+                    logger.warn("Enable verbose output (-X) to see precisely which goals are not marked as"
+                            + " thread-safe.");
                 }
-                logger.warn( MultilineMessageHelper.separatorLine() );
+                logger.warn(MultilineMessageHelper.separatorLine());
             }
         }
 
         final String defaulModelId = DefaultLifecyclePluginAnalyzer.DEFAULTLIFECYCLEBINDINGS_MODELID;
 
         List<String> unversionedPlugins = executionPlan.getMojoExecutions().stream()
-                         .map( MojoExecution::getPlugin )
-                         .filter( p -> p.getLocation( "version" ) != null ) // versionless cli goal (?)
-                         .filter( p -> p.getLocation( "version" ).getSource() != null ) // versionless in pom (?)
-                         .filter( p -> defaulModelId.equals( p.getLocation( "version" ).getSource().getModelId() ) )
-                         .distinct()
-                         .map( Plugin::getArtifactId ) // managed by us, groupId is always o.a.m.plugins
-                         .collect( Collectors.toList() );
+                .map(MojoExecution::getPlugin)
+                .filter(p -> p.getLocation("version") != null
+                        && p.getLocation("version").getSource() != null
+                        && defaulModelId.equals(
+                                p.getLocation("version").getSource().getModelId()))
+                .distinct()
+                .map(Plugin::getArtifactId) // managed by us, groupId is always o.a.m.plugins
+                .collect(Collectors.toList());
 
-        if ( !unversionedPlugins.isEmpty() )
-        {
-            logger.warn( "Version not locked for default bindings plugins " + unversionedPlugins
-                + ", you should define versions in pluginManagement section of your " + "pom.xml or parent" );
+        if (!unversionedPlugins.isEmpty()) {
+            logger.warn("Version not locked for default bindings plugins " + unversionedPlugins
+                    + ", you should define versions in pluginManagement section of your " + "pom.xml or parent");
         }
 
         return executionPlan;
     }
 
-    public void handleBuildError( final ReactorContext buildContext, final MavenSession rootSession,
-                                  final MavenSession currentSession, final MavenProject mavenProject, Throwable t,
-                                  final long buildStartTime )
-    {
+    public void handleBuildError(
+            final ReactorContext buildContext,
+            final MavenSession rootSession,
+            final MavenSession currentSession,
+            final MavenProject mavenProject,
+            Throwable t,
+            final long buildStartTime) {
         // record the error and mark the project as failed
         long buildEndTime = System.currentTimeMillis();
-        buildContext.getResult().addException( t );
-        buildContext.getResult().addBuildSummary( new BuildFailure( mavenProject, buildEndTime - buildStartTime, t ) );
+        buildContext.getResult().addException(t);
+        buildContext.getResult().addBuildSummary(new BuildFailure(mavenProject, buildEndTime - buildStartTime, t));
 
         // notify listeners about "soft" project build failures only
-        if ( t instanceof Exception && !( t instanceof RuntimeException ) )
-        {
-            eventCatapult.fire( ExecutionEvent.Type.ProjectFailed, currentSession, null, (Exception) t );
+        if (t instanceof Exception && !(t instanceof RuntimeException)) {
+            eventCatapult.fire(ExecutionEvent.Type.ProjectFailed, currentSession, null, (Exception) t);
         }
 
         // reactor failure modes
-        if ( t instanceof RuntimeException || !( t instanceof Exception ) )
-        {
+        if (t instanceof RuntimeException || !(t instanceof Exception)) {
             // fail fast on RuntimeExceptions, Errors and "other" Throwables
             // assume these are system errors and further build is meaningless
             buildContext.getReactorBuildStatus().halt();
-        }
-        else if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( rootSession.getReactorFailureBehavior() ) )
-        {
+        } else if (MavenExecutionRequest.REACTOR_FAIL_NEVER.equals(rootSession.getReactorFailureBehavior())) {
             // continue the build
-        }
-        else if ( MavenExecutionRequest.REACTOR_FAIL_AT_END.equals( rootSession.getReactorFailureBehavior() ) )
-        {
+        } else if (MavenExecutionRequest.REACTOR_FAIL_AT_END.equals(rootSession.getReactorFailureBehavior())) {
             // continue the build but ban all projects that depend on the failed one
-            buildContext.getReactorBuildStatus().blackList( mavenProject );
-        }
-        else if ( MavenExecutionRequest.REACTOR_FAIL_FAST.equals( rootSession.getReactorFailureBehavior() ) )
-        {
+            buildContext.getReactorBuildStatus().blackList(mavenProject);
+        } else if (MavenExecutionRequest.REACTOR_FAIL_FAST.equals(rootSession.getReactorFailureBehavior())) {
             buildContext.getReactorBuildStatus().halt();
-        }
-        else
-        {
-            logger.error( "invalid reactor failure behavior " + rootSession.getReactorFailureBehavior() );
+        } else {
+            logger.error("invalid reactor failure behavior " + rootSession.getReactorFailureBehavior());
             buildContext.getReactorBuildStatus().halt();
         }
     }
 
-    public static void attachToThread( MavenProject currentProject )
-    {
+    public static void attachToThread(MavenProject currentProject) {
         ClassRealm projectRealm = currentProject.getClassRealm();
-        if ( projectRealm != null )
-        {
-            Thread.currentThread().setContextClassLoader( projectRealm );
+        if (projectRealm != null) {
+            Thread.currentThread().setContextClassLoader(projectRealm);
         }
     }
 
     // TODO I'm really wondering where this method belongs; smells like it should be on MavenProject, but for some
     // reason it isn't ? This localization is kind-of a code smell.
 
-    public static String getKey( MavenProject project )
-    {
+    public static String getKey(MavenProject project) {
         return project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderNotFoundException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderNotFoundException.java
index 250d65d..bcb7c90 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderNotFoundException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/BuilderNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.builder;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal.builder;
 
 /**
  * BuilderNotFoundException
  */
-public class BuilderNotFoundException
-    extends Exception
-{
-    public BuilderNotFoundException( String message )
-    {
-        super( message );
+public class BuilderNotFoundException extends Exception {
+    public BuilderNotFoundException(String message) {
+        super(message);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraph.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraph.java
index efa8c28..ed0c36a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraph.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraph.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.builder.multithreaded;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,11 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.execution.ProjectDependencyGraph;
-import org.apache.maven.lifecycle.internal.ProjectBuildList;
-import org.apache.maven.lifecycle.internal.ProjectSegment;
-import org.apache.maven.project.MavenProject;
+package org.apache.maven.lifecycle.internal.builder.multithreaded;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -30,6 +24,11 @@
 import java.util.List;
 import java.util.Set;
 
+import org.apache.maven.execution.ProjectDependencyGraph;
+import org.apache.maven.lifecycle.internal.ProjectBuildList;
+import org.apache.maven.lifecycle.internal.ProjectSegment;
+import org.apache.maven.project.MavenProject;
+
 /**
  * <p>
  * Presents a view of the Dependency Graph that is suited for concurrent building.
@@ -37,10 +36,8 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Kristian Rosenvold
  */
-public class ConcurrencyDependencyGraph
-{
+public class ConcurrencyDependencyGraph {
 
     private final ProjectBuildList projectBuilds;
 
@@ -48,14 +45,12 @@
 
     private final Set<MavenProject> finishedProjects = new HashSet<>();
 
-    public ConcurrencyDependencyGraph( ProjectBuildList projectBuilds, ProjectDependencyGraph projectDependencyGraph )
-    {
+    public ConcurrencyDependencyGraph(ProjectBuildList projectBuilds, ProjectDependencyGraph projectDependencyGraph) {
         this.projectDependencyGraph = projectDependencyGraph;
         this.projectBuilds = projectBuilds;
     }
 
-    public int getNumberOfBuilds()
-    {
+    public int getNumberOfBuilds() {
         return projectBuilds.size();
     }
 
@@ -64,18 +59,20 @@
      *
      * @return A set of all the initial builds
      */
-
-    public List<MavenProject> getRootSchedulableBuilds()
-    {
+    public List<MavenProject> getRootSchedulableBuilds() {
         Set<MavenProject> result = new LinkedHashSet<>();
-        for ( ProjectSegment projectBuild : projectBuilds )
-        {
-            if ( projectDependencyGraph.getUpstreamProjects( projectBuild.getProject(), false ).isEmpty() )
-            {
-                result.add( projectBuild.getProject() );
+        for (ProjectSegment projectBuild : projectBuilds) {
+            if (projectDependencyGraph
+                    .getUpstreamProjects(projectBuild.getProject(), false)
+                    .isEmpty()) {
+                result.add(projectBuild.getProject());
             }
         }
-        return new ArrayList<>( result );
+        if (result.isEmpty() && projectBuilds.size() > 0) {
+            // Must return at least one project
+            result.add(projectBuilds.get(0).getProject());
+        }
+        return new ArrayList<>(result);
     }
 
     /**
@@ -84,23 +81,19 @@
      * @param mavenProject The project
      * @return The list of builds that are eligible for starting now that the provided project is done
      */
-    public List<MavenProject> markAsFinished( MavenProject mavenProject )
-    {
-        finishedProjects.add( mavenProject );
-        return getSchedulableNewProcesses( mavenProject );
+    public List<MavenProject> markAsFinished(MavenProject mavenProject) {
+        finishedProjects.add(mavenProject);
+        return getSchedulableNewProcesses(mavenProject);
     }
 
-    private List<MavenProject> getSchedulableNewProcesses( MavenProject finishedProject )
-    {
+    private List<MavenProject> getSchedulableNewProcesses(MavenProject finishedProject) {
         List<MavenProject> result = new ArrayList<>();
         // schedule dependent projects, if all of their requirements are met
-        for ( MavenProject dependentProject : projectDependencyGraph.getDownstreamProjects( finishedProject, false ) )
-        {
+        for (MavenProject dependentProject : projectDependencyGraph.getDownstreamProjects(finishedProject, false)) {
             final List<MavenProject> upstreamProjects =
-                projectDependencyGraph.getUpstreamProjects( dependentProject, false );
-            if ( finishedProjects.containsAll( upstreamProjects ) )
-            {
-                result.add( dependentProject );
+                    projectDependencyGraph.getUpstreamProjects(dependentProject, false);
+            if (finishedProjects.containsAll(upstreamProjects)) {
+                result.add(dependentProject);
             }
         }
         return result;
@@ -109,23 +102,20 @@
     /**
      * @return set of projects that have yet to be processed successfully by the build.
      */
-    public Set<MavenProject> getUnfinishedProjects()
-    {
-        Set<MavenProject> unfinished = new HashSet<>( projectBuilds.getProjects() );
-        unfinished.removeAll( finishedProjects );
+    public Set<MavenProject> getUnfinishedProjects() {
+        Set<MavenProject> unfinished = new HashSet<>(projectBuilds.getProjects());
+        unfinished.removeAll(finishedProjects);
         return unfinished;
     }
 
     /**
      * @return set of projects that have been successfully processed by the build.
      */
-    protected Set<MavenProject> getFinishedProjects()
-    {
+    protected Set<MavenProject> getFinishedProjects() {
         return finishedProjects;
     }
 
-    protected ProjectBuildList getProjectBuilds()
-    {
+    protected ProjectBuildList getProjectBuilds() {
         return projectBuilds;
     }
 
@@ -135,9 +125,8 @@
      * @param p
      * @return List of prerequisite projects
      */
-    protected List<MavenProject> getDependencies( MavenProject p )
-    {
-        return projectDependencyGraph.getUpstreamProjects( p, false );
+    protected List<MavenProject> getDependencies(MavenProject p) {
+        return projectDependencyGraph.getUpstreamProjects(p, false);
     }
 
     /**
@@ -146,10 +135,9 @@
      * @param p
      * @return List of uncompleted prerequisite projects
      */
-    public List<MavenProject> getActiveDependencies( MavenProject p )
-    {
-        List<MavenProject> activeDependencies = projectDependencyGraph.getUpstreamProjects( p, false );
-        activeDependencies.removeAll( finishedProjects );
+    public List<MavenProject> getActiveDependencies(MavenProject p) {
+        List<MavenProject> activeDependencies = projectDependencyGraph.getUpstreamProjects(p, false);
+        activeDependencies.removeAll(finishedProjects);
         return activeDependencies;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java
index 7c5ca00..2a76afb 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/MultiThreadedBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.builder.multithreaded;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal.builder.multithreaded;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.List;
 import java.util.Map;
@@ -32,10 +35,6 @@
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.internal.BuildThreadFactory;
 import org.apache.maven.lifecycle.internal.LifecycleModuleBuilder;
@@ -59,170 +58,154 @@
  * <strong>NOTE:</strong> This class is not part of any public api and can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Kristian Rosenvold
  *         Builds one or more lifecycles for a full module
  *         NOTE: This class is not part of any public api and can be changed or deleted without prior notice.
  */
-@Named( "multithreaded" )
+@Named("multithreaded")
 @Singleton
-public class MultiThreadedBuilder
-    implements Builder
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class MultiThreadedBuilder implements Builder {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final LifecycleModuleBuilder lifecycleModuleBuilder;
 
     @Inject
-    public MultiThreadedBuilder( LifecycleModuleBuilder lifecycleModuleBuilder )
-    {
+    public MultiThreadedBuilder(LifecycleModuleBuilder lifecycleModuleBuilder) {
         this.lifecycleModuleBuilder = lifecycleModuleBuilder;
     }
 
     @Override
-    public void build( MavenSession session, ReactorContext reactorContext, ProjectBuildList projectBuilds,
-                       List<TaskSegment> taskSegments, ReactorBuildStatus reactorBuildStatus )
-        throws ExecutionException, InterruptedException
-    {
-        int nThreads = Math.min( session.getRequest().getDegreeOfConcurrency(), session.getProjects().size() );
+    public void build(
+            MavenSession session,
+            ReactorContext reactorContext,
+            ProjectBuildList projectBuilds,
+            List<TaskSegment> taskSegments,
+            ReactorBuildStatus reactorBuildStatus)
+            throws ExecutionException, InterruptedException {
+        int nThreads = Math.min(
+                session.getRequest().getDegreeOfConcurrency(),
+                session.getProjects().size());
         boolean parallel = nThreads > 1;
         // Propagate the parallel flag to the root session and all of the cloned sessions in each project segment
-        session.setParallel( parallel );
-        for ( ProjectSegment segment : projectBuilds )
-        {
-            segment.getSession().setParallel( parallel );
+        session.setParallel(parallel);
+        for (ProjectSegment segment : projectBuilds) {
+            segment.getSession().setParallel(parallel);
         }
-        ExecutorService executor = Executors.newFixedThreadPool( nThreads, new BuildThreadFactory() );
-        CompletionService<ProjectSegment> service = new ExecutorCompletionService<>( executor );
+        ExecutorService executor = Executors.newFixedThreadPool(nThreads, new BuildThreadFactory());
+        CompletionService<ProjectSegment> service = new ExecutorCompletionService<>(executor);
 
         // Currently disabled
         ThreadOutputMuxer muxer = null; // new ThreadOutputMuxer( analyzer.getProjectBuilds(), System.out );
 
-        for ( TaskSegment taskSegment : taskSegments )
-        {
-            ProjectBuildList segmentProjectBuilds = projectBuilds.getByTaskSegment( taskSegment );
-            Map<MavenProject, ProjectSegment> projectBuildMap = projectBuilds.selectSegment( taskSegment );
-            try
-            {
+        for (TaskSegment taskSegment : taskSegments) {
+            ProjectBuildList segmentProjectBuilds = projectBuilds.getByTaskSegment(taskSegment);
+            Map<MavenProject, ProjectSegment> projectBuildMap = projectBuilds.selectSegment(taskSegment);
+            try {
                 ConcurrencyDependencyGraph analyzer =
-                    new ConcurrencyDependencyGraph( segmentProjectBuilds,
-                                                    session.getProjectDependencyGraph() );
-                multiThreadedProjectTaskSegmentBuild( analyzer, reactorContext, session, service, taskSegment,
-                                                      projectBuildMap, muxer );
-                if ( reactorContext.getReactorBuildStatus().isHalted() )
-                {
+                        new ConcurrencyDependencyGraph(segmentProjectBuilds, session.getProjectDependencyGraph());
+                multiThreadedProjectTaskSegmentBuild(
+                        analyzer, reactorContext, session, service, taskSegment, projectBuildMap, muxer);
+                if (reactorContext.getReactorBuildStatus().isHalted()) {
                     break;
                 }
-            }
-            catch ( Exception e )
-            {
-                session.getResult().addException( e );
+            } catch (Exception e) {
+                session.getResult().addException(e);
                 break;
             }
-
         }
 
         executor.shutdown();
-        executor.awaitTermination( Long.MAX_VALUE, TimeUnit.MILLISECONDS );
+        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
     }
 
-    private void multiThreadedProjectTaskSegmentBuild( ConcurrencyDependencyGraph analyzer,
-                                                       ReactorContext reactorContext, MavenSession rootSession,
-                                                       CompletionService<ProjectSegment> service,
-                                                       TaskSegment taskSegment,
-                                                       Map<MavenProject, ProjectSegment> projectBuildList,
-                                                       ThreadOutputMuxer muxer )
-    {
+    private void multiThreadedProjectTaskSegmentBuild(
+            ConcurrencyDependencyGraph analyzer,
+            ReactorContext reactorContext,
+            MavenSession rootSession,
+            CompletionService<ProjectSegment> service,
+            TaskSegment taskSegment,
+            Map<MavenProject, ProjectSegment> projectBuildList,
+            ThreadOutputMuxer muxer) {
         // gather artifactIds which are not unique so that the respective thread names can be extended with the groupId
         Set<String> duplicateArtifactIds = projectBuildList.keySet().stream()
-                .map( MavenProject::getArtifactId )
-                .collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) )
-                .entrySet().stream()
-                .filter( p -> p.getValue() > 1 )
-                .map( Map.Entry::getKey )
-                .collect( Collectors.toSet() );
+                .map(MavenProject::getArtifactId)
+                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
+                .entrySet()
+                .stream()
+                .filter(p -> p.getValue() > 1)
+                .map(Map.Entry::getKey)
+                .collect(Collectors.toSet());
 
         // schedule independent projects
-        for ( MavenProject mavenProject : analyzer.getRootSchedulableBuilds() )
-        {
-            ProjectSegment projectSegment = projectBuildList.get( mavenProject );
-            logger.debug( "Scheduling: " + projectSegment.getProject() );
-            Callable<ProjectSegment> cb =
-                createBuildCallable( rootSession, projectSegment, reactorContext, taskSegment, muxer,
-                                     duplicateArtifactIds );
-            service.submit( cb );
+        for (MavenProject mavenProject : analyzer.getRootSchedulableBuilds()) {
+            ProjectSegment projectSegment = projectBuildList.get(mavenProject);
+            logger.debug("Scheduling: {}", projectSegment.getProject());
+            Callable<ProjectSegment> cb = createBuildCallable(
+                    rootSession, projectSegment, reactorContext, taskSegment, muxer, duplicateArtifactIds);
+            service.submit(cb);
         }
 
         // for each finished project
-        for ( int i = 0; i < analyzer.getNumberOfBuilds(); i++ )
-        {
-            try
-            {
+        for (int i = 0; i < analyzer.getNumberOfBuilds(); i++) {
+            try {
                 ProjectSegment projectBuild = service.take().get();
-                if ( reactorContext.getReactorBuildStatus().isHalted() )
-                {
+                if (reactorContext.getReactorBuildStatus().isHalted()) {
                     break;
                 }
 
                 // MNG-6170: Only schedule other modules from reactor if we have more modules to build than one.
-                if ( analyzer.getNumberOfBuilds() > 1 )
-                {
+                if (analyzer.getNumberOfBuilds() > 1) {
                     final List<MavenProject> newItemsThatCanBeBuilt =
-                        analyzer.markAsFinished( projectBuild.getProject() );
-                    for ( MavenProject mavenProject : newItemsThatCanBeBuilt )
-                    {
-                        ProjectSegment scheduledDependent = projectBuildList.get( mavenProject );
-                        logger.debug( "Scheduling: " + scheduledDependent );
-                        Callable<ProjectSegment> cb =
-                            createBuildCallable( rootSession, scheduledDependent, reactorContext, taskSegment, muxer,
-                                                 duplicateArtifactIds );
-                        service.submit( cb );
+                            analyzer.markAsFinished(projectBuild.getProject());
+                    for (MavenProject mavenProject : newItemsThatCanBeBuilt) {
+                        ProjectSegment scheduledDependent = projectBuildList.get(mavenProject);
+                        logger.debug("Scheduling: {}", scheduledDependent);
+                        Callable<ProjectSegment> cb = createBuildCallable(
+                                rootSession,
+                                scheduledDependent,
+                                reactorContext,
+                                taskSegment,
+                                muxer,
+                                duplicateArtifactIds);
+                        service.submit(cb);
                     }
                 }
-            }
-            catch ( InterruptedException e )
-            {
-                rootSession.getResult().addException( e );
+            } catch (InterruptedException e) {
+                rootSession.getResult().addException(e);
                 break;
-            }
-            catch ( ExecutionException e )
-            {
+            } catch (ExecutionException e) {
                 // TODO MNG-5766 changes likely made this redundant
-                rootSession.getResult().addException( e );
+                rootSession.getResult().addException(e);
                 break;
             }
         }
     }
 
-    private Callable<ProjectSegment> createBuildCallable( final MavenSession rootSession,
-                                                          final ProjectSegment projectBuild,
-                                                          final ReactorContext reactorContext,
-                                                          final TaskSegment taskSegment,
-                                                          final ThreadOutputMuxer muxer,
-                                                          final Set<String> duplicateArtifactIds )
-    {
-        return () ->
-        {
+    private Callable<ProjectSegment> createBuildCallable(
+            final MavenSession rootSession,
+            final ProjectSegment projectBuild,
+            final ReactorContext reactorContext,
+            final TaskSegment taskSegment,
+            final ThreadOutputMuxer muxer,
+            final Set<String> duplicateArtifactIds) {
+        return () -> {
             final Thread currentThread = Thread.currentThread();
             final String originalThreadName = currentThread.getName();
             final MavenProject project = projectBuild.getProject();
 
-            final String threadNameSuffix = duplicateArtifactIds.contains( project.getArtifactId() )
+            final String threadNameSuffix = duplicateArtifactIds.contains(project.getArtifactId())
                     ? project.getGroupId() + ":" + project.getArtifactId()
                     : project.getArtifactId();
-            currentThread.setName( "mvn-builder-" + threadNameSuffix );
+            currentThread.setName("mvn-builder-" + threadNameSuffix);
 
-            try
-            {
+            try {
                 // muxer.associateThreadWithProjectSegment( projectBuild );
-                lifecycleModuleBuilder.buildProject( projectBuild.getSession(), rootSession, reactorContext, project,
-                                                     taskSegment );
+                lifecycleModuleBuilder.buildProject(
+                        projectBuild.getSession(), rootSession, reactorContext, project, taskSegment);
                 // muxer.setThisModuleComplete( projectBuild );
 
                 return projectBuild;
-            }
-            finally
-            {
-                 currentThread.setName( originalThreadName );
+            } finally {
+                currentThread.setName(originalThreadName);
             }
         };
     }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxer.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxer.java
index 273570b..45ab841 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxer.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.builder.multithreaded;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal.builder.multithreaded;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -38,25 +37,22 @@
  * logger implementation at any time.
  *
  * @since 3.0
- * @author Kristian Rosenvold
  */
-@SuppressWarnings( { "SynchronizationOnLocalVariableOrMethodParameter" } )
-public class ThreadOutputMuxer
-{
+@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"})
+public class ThreadOutputMuxer {
     private final Iterator<ProjectSegment> projects;
 
     private final ThreadLocal<ProjectSegment> projectBuildThreadLocal = new ThreadLocal<>();
 
-    private final Map<ProjectSegment, ByteArrayOutputStream> streams =
-        new HashMap<>();
+    private final Map<ProjectSegment, ByteArrayOutputStream> streams = new HashMap<>();
 
     private final Map<ProjectSegment, PrintStream> printStreams = new HashMap<>();
 
     private final ByteArrayOutputStream defaultOutputStreamForUnknownData = new ByteArrayOutputStream();
 
-    private final PrintStream defaultPrintStream = new PrintStream( defaultOutputStreamForUnknownData );
+    private final PrintStream defaultPrintStream = new PrintStream(defaultOutputStreamForUnknownData);
 
-    private final Set<ProjectSegment> completedBuilds = Collections.synchronizedSet( new HashSet<>() );
+    private final Set<ProjectSegment> completedBuilds = Collections.synchronizedSet(new HashSet<>());
 
     private volatile ProjectSegment currentBuild;
 
@@ -67,52 +63,37 @@
     /**
      * A simple but safe solution for printing to the console.
      */
-
-    class ConsolePrinter
-        implements Runnable
-    {
+    class ConsolePrinter implements Runnable {
         private volatile boolean running;
 
         private final ProjectBuildList projectBuildList;
 
-        ConsolePrinter( ProjectBuildList projectBuildList )
-        {
+        ConsolePrinter(ProjectBuildList projectBuildList) {
             this.projectBuildList = projectBuildList;
         }
 
-        public void run()
-        {
+        public void run() {
             running = true;
-            for ( ProjectSegment projectBuild : projectBuildList )
-            {
-                final PrintStream projectStream = printStreams.get( projectBuild );
-                ByteArrayOutputStream projectOs = streams.get( projectBuild );
+            for (ProjectSegment projectBuild : projectBuildList) {
+                final PrintStream projectStream = printStreams.get(projectBuild);
+                ByteArrayOutputStream projectOs = streams.get(projectBuild);
 
-                do
-                {
-                    synchronized ( projectStream )
-                    {
-                        try
-                        {
-                            projectStream.wait( 100 );
+                do {
+                    synchronized (projectStream) {
+                        try {
+                            projectStream.wait(100);
+                        } catch (InterruptedException e) {
+                            throw new RuntimeException(e);
                         }
-                        catch ( InterruptedException e )
-                        {
-                            throw new RuntimeException( e );
-                        }
-                        try
-                        {
-                            projectOs.writeTo( originalSystemOUtStream );
-                        }
-                        catch ( IOException e )
-                        {
-                            throw new RuntimeException( e );
+                        try {
+                            projectOs.writeTo(originalSystemOUtStream);
+                        } catch (IOException e) {
+                            throw new RuntimeException(e);
                         }
 
                         projectOs.reset();
                     }
-                }
-                while ( !completedBuilds.contains( projectBuild ) );
+                } while (!completedBuilds.contains(projectBuild));
             }
             running = false;
         }
@@ -121,355 +102,287 @@
         Wait until we are sure the print-stream thread is running.
          */
 
-        public void waitUntilRunning( boolean expect )
-        {
-            while ( !running == expect )
-            {
-                try
-                {
-                    Thread.sleep( 10 );
-                }
-                catch ( InterruptedException e )
-                {
-                    throw new RuntimeException( e );
+        public void waitUntilRunning(boolean expect) {
+            while (!running == expect) {
+                try {
+                    Thread.sleep(10);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
                 }
             }
         }
     }
 
-    public ThreadOutputMuxer( ProjectBuildList segmentChunks, PrintStream originalSystemOut )
-    {
+    public ThreadOutputMuxer(ProjectBuildList segmentChunks, PrintStream originalSystemOut) {
         projects = segmentChunks.iterator();
-        for ( ProjectSegment segmentChunk : segmentChunks )
-        {
+        for (ProjectSegment segmentChunk : segmentChunks) {
             final ByteArrayOutputStream value = new ByteArrayOutputStream();
-            streams.put( segmentChunk, value );
-            printStreams.put( segmentChunk, new PrintStream( value ) );
+            streams.put(segmentChunk, value);
+            printStreams.put(segmentChunk, new PrintStream(value));
         }
         setNext();
         this.originalSystemOUtStream = originalSystemOut;
-        System.setOut( new ThreadBoundPrintStream( this.originalSystemOUtStream ) );
-        printer = new ConsolePrinter( segmentChunks );
-        new Thread( printer ).start();
-        printer.waitUntilRunning( true );
+        System.setOut(new ThreadBoundPrintStream(this.originalSystemOUtStream));
+        printer = new ConsolePrinter(segmentChunks);
+        new Thread(printer).start();
+        printer.waitUntilRunning(true);
     }
 
-    public void close()
-    {
-        printer.waitUntilRunning( false );
-        System.setOut( this.originalSystemOUtStream );
+    public void close() {
+        printer.waitUntilRunning(false);
+        System.setOut(this.originalSystemOUtStream);
     }
 
-    private void setNext()
-    {
+    private void setNext() {
         currentBuild = projects.hasNext() ? projects.next() : null;
     }
 
-    private boolean ownsRealOutputStream( ProjectSegment projectBuild )
-    {
-        return projectBuild.equals( currentBuild );
+    private boolean ownsRealOutputStream(ProjectSegment projectBuild) {
+        return projectBuild.equals(currentBuild);
     }
 
-    private PrintStream getThreadBoundPrintStream()
-    {
+    private PrintStream getThreadBoundPrintStream() {
         ProjectSegment threadProject = projectBuildThreadLocal.get();
-        if ( threadProject == null )
-        {
+        if (threadProject == null) {
             return defaultPrintStream;
         }
-        if ( ownsRealOutputStream( threadProject ) )
-        {
+        if (ownsRealOutputStream(threadProject)) {
             return originalSystemOUtStream;
         }
-        return printStreams.get( threadProject );
+        return printStreams.get(threadProject);
     }
 
-    public void associateThreadWithProjectSegment( ProjectSegment projectBuild )
-    {
-        projectBuildThreadLocal.set( projectBuild );
+    public void associateThreadWithProjectSegment(ProjectSegment projectBuild) {
+        projectBuildThreadLocal.set(projectBuild);
     }
 
-    public void setThisModuleComplete( ProjectSegment projectBuild )
-    {
-        completedBuilds.add( projectBuild );
-        PrintStream stream = printStreams.get( projectBuild );
-        synchronized ( stream )
-        {
+    public void setThisModuleComplete(ProjectSegment projectBuild) {
+        completedBuilds.add(projectBuild);
+        PrintStream stream = printStreams.get(projectBuild);
+        synchronized (stream) {
             stream.notifyAll();
         }
         disconnectThreadFromProject();
     }
 
-    private void disconnectThreadFromProject()
-    {
+    private void disconnectThreadFromProject() {
         projectBuildThreadLocal.remove();
     }
 
-    private class ThreadBoundPrintStream
-        extends PrintStream
-    {
+    private class ThreadBoundPrintStream extends PrintStream {
 
-        ThreadBoundPrintStream( PrintStream systemOutStream )
-        {
-            super( systemOutStream );
+        ThreadBoundPrintStream(PrintStream systemOutStream) {
+            super(systemOutStream);
         }
 
-        private PrintStream getOutputStreamForCurrentThread()
-        {
+        private PrintStream getOutputStreamForCurrentThread() {
             return getThreadBoundPrintStream();
         }
 
         @Override
-        public void println()
-        {
+        public void println() {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
+            synchronized (currentStream) {
                 currentStream.println();
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( char c )
-        {
+        public void print(char c) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( c );
+            synchronized (currentStream) {
+                currentStream.print(c);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( char x )
-        {
+        public void println(char x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.println( x );
+            synchronized (currentStream) {
+                currentStream.println(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( double d )
-        {
+        public void print(double d) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( d );
+            synchronized (currentStream) {
+                currentStream.print(d);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( double x )
-        {
+        public void println(double x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.println( x );
+            synchronized (currentStream) {
+                currentStream.println(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( float f )
-        {
+        public void print(float f) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( f );
+            synchronized (currentStream) {
+                currentStream.print(f);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( float x )
-        {
+        public void println(float x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.println( x );
+            synchronized (currentStream) {
+                currentStream.println(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( int i )
-        {
+        public void print(int i) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( i );
+            synchronized (currentStream) {
+                currentStream.print(i);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( int x )
-        {
+        public void println(int x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.println( x );
+            synchronized (currentStream) {
+                currentStream.println(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( long l )
-        {
+        public void print(long l) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( l );
+            synchronized (currentStream) {
+                currentStream.print(l);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( long x )
-        {
+        public void println(long x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( x );
+            synchronized (currentStream) {
+                currentStream.print(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( boolean b )
-        {
+        public void print(boolean b) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( b );
+            synchronized (currentStream) {
+                currentStream.print(b);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( boolean x )
-        {
+        public void println(boolean x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( x );
+            synchronized (currentStream) {
+                currentStream.print(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( char s[] )
-        {
+        public void print(char s[]) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( s );
+            synchronized (currentStream) {
+                currentStream.print(s);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( char x[] )
-        {
+        public void println(char x[]) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( x );
+            synchronized (currentStream) {
+                currentStream.print(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( Object obj )
-        {
+        public void print(Object obj) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( obj );
+            synchronized (currentStream) {
+                currentStream.print(obj);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( Object x )
-        {
+        public void println(Object x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.println( x );
+            synchronized (currentStream) {
+                currentStream.println(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void print( String s )
-        {
+        public void print(String s) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.print( s );
+            synchronized (currentStream) {
+                currentStream.print(s);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void println( String x )
-        {
+        public void println(String x) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.println( x );
+            synchronized (currentStream) {
+                currentStream.println(x);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void write( byte b[], int off, int len )
-        {
+        public void write(byte b[], int off, int len) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.write( b, off, len );
+            synchronized (currentStream) {
+                currentStream.write(b, off, len);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void close()
-        {
+        public void close() {
             getOutputStreamForCurrentThread().close();
         }
 
         @Override
-        public void flush()
-        {
+        public void flush() {
             getOutputStreamForCurrentThread().flush();
         }
 
         @Override
-        public void write( int b )
-        {
+        public void write(int b) {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.write( b );
+            synchronized (currentStream) {
+                currentStream.write(b);
                 currentStream.notifyAll();
             }
         }
 
         @Override
-        public void write( byte b[] )
-            throws IOException
-        {
+        public void write(byte b[]) throws IOException {
             final PrintStream currentStream = getOutputStreamForCurrentThread();
-            synchronized ( currentStream )
-            {
-                currentStream.write( b );
+            synchronized (currentStream) {
+                currentStream.write(b);
                 currentStream.notifyAll();
             }
         }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder.java
index fee39d5..fc814e7 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/builder/singlethreaded/SingleThreadedBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.builder.singlethreaded;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.List;
+package org.apache.maven.lifecycle.internal.builder.singlethreaded;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.List;
+
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.internal.LifecycleModuleBuilder;
 import org.apache.maven.lifecycle.internal.ProjectBuildList;
@@ -39,37 +38,31 @@
  * A {@link Builder} encapsulates a strategy for building a set of Maven projects. The default strategy in Maven builds
  * the the projects serially, but a {@link Builder} can employ any type of concurrency model to build the projects.
  */
-@Named( "singlethreaded" )
+@Named("singlethreaded")
 @Singleton
-public class SingleThreadedBuilder
-    implements Builder
-{
+public class SingleThreadedBuilder implements Builder {
     private final LifecycleModuleBuilder lifecycleModuleBuilder;
 
     @Inject
-    public SingleThreadedBuilder( LifecycleModuleBuilder lifecycleModuleBuilder )
-    {
+    public SingleThreadedBuilder(LifecycleModuleBuilder lifecycleModuleBuilder) {
         this.lifecycleModuleBuilder = lifecycleModuleBuilder;
     }
 
-    public void build( MavenSession session, ReactorContext reactorContext, ProjectBuildList projectBuilds,
-                       List<TaskSegment> taskSegments, ReactorBuildStatus reactorBuildStatus )
-    {
-        for ( TaskSegment taskSegment : taskSegments )
-        {
-            for ( ProjectSegment projectBuild : projectBuilds.getByTaskSegment( taskSegment ) )
-            {
-                try
-                {
-                    lifecycleModuleBuilder.buildProject( session, reactorContext, projectBuild.getProject(),
-                                                         taskSegment );
-                    if ( reactorBuildStatus.isHalted() )
-                    {
+    public void build(
+            MavenSession session,
+            ReactorContext reactorContext,
+            ProjectBuildList projectBuilds,
+            List<TaskSegment> taskSegments,
+            ReactorBuildStatus reactorBuildStatus) {
+        for (TaskSegment taskSegment : taskSegments) {
+            for (ProjectSegment projectBuild : projectBuilds.getByTaskSegment(taskSegment)) {
+                try {
+                    lifecycleModuleBuilder.buildProject(
+                            session, reactorContext, projectBuild.getProject(), taskSegment);
+                    if (reactorBuildStatus.isHalted()) {
                         break;
                     }
-                }
-                catch ( Exception e )
-                {
+                } catch (Exception e) {
                     break; // Why are we just ignoring this exception? Are exceptions are being used for flow control
                 }
             }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java
index 4001a97..da7f6b2 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/DefaultLifecycleMapping.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.mapping;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.mapping;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -30,15 +29,14 @@
 /**
  * DefaultLifecycleMapping
  */
-public class DefaultLifecycleMapping
-    implements LifecycleMapping
-{
+public class DefaultLifecycleMapping implements LifecycleMapping {
 
     private List<Lifecycle> lifecycles;
 
     private Map<String, Lifecycle> lifecycleMap;
 
     /** @deprecated use lifecycles instead */
+    @Deprecated
     private Map<String, LifecyclePhase> phases;
 
     /**
@@ -48,56 +46,44 @@
      * @deprecated Should not be used in Java code.
      */
     @Deprecated
-    public DefaultLifecycleMapping()
-    {
-    }
+    public DefaultLifecycleMapping() {}
 
     /**
      * Ctor to be used in Java code/providers.
      */
-    public DefaultLifecycleMapping( final List<Lifecycle> lifecycles )
-    {
-        this.lifecycleMap = Collections.unmodifiableMap(
-                lifecycles.stream().collect( toMap( Lifecycle::getId, identity() ) )
-        );
+    public DefaultLifecycleMapping(final List<Lifecycle> lifecycles) {
+        this.lifecycleMap =
+                Collections.unmodifiableMap(lifecycles.stream().collect(toMap(Lifecycle::getId, identity())));
     }
 
     /**
      * Plexus: Populates the lifecycle map from the injected list of lifecycle mappings (if not already done).
      */
-    private void initLifecycleMap()
-    {
-        if ( lifecycleMap == null )
-        {
+    private void initLifecycleMap() {
+        if (lifecycleMap == null) {
             lifecycleMap = new HashMap<>();
 
-            if ( lifecycles != null )
-            {
-                for ( Lifecycle lifecycle : lifecycles )
-                {
-                    lifecycleMap.put( lifecycle.getId(), lifecycle );
+            if (lifecycles != null) {
+                for (Lifecycle lifecycle : lifecycles) {
+                    lifecycleMap.put(lifecycle.getId(), lifecycle);
                 }
-            }
-            else
-            {
+            } else {
                 /*
                  * NOTE: This is to provide a migration path for implementors of the legacy API which did not know about
                  * getLifecycles().
                  */
 
-                String[] lifecycleIds = { "default", "clean", "site" };
+                String[] lifecycleIds = {"default", "clean", "site"};
 
-                for ( String lifecycleId : lifecycleIds )
-                {
-                    Map<String, LifecyclePhase> phases = getLifecyclePhases( lifecycleId );
-                    if ( phases != null )
-                    {
+                for (String lifecycleId : lifecycleIds) {
+                    Map<String, LifecyclePhase> phases = getLifecyclePhases(lifecycleId);
+                    if (phases != null) {
                         Lifecycle lifecycle = new Lifecycle();
 
-                        lifecycle.setId( lifecycleId );
-                        lifecycle.setLifecyclePhases( phases );
+                        lifecycle.setId(lifecycleId);
+                        lifecycle.setLifecyclePhases(phases);
 
-                        lifecycleMap.put( lifecycleId, lifecycle );
+                        lifecycleMap.put(lifecycleId, lifecycle);
                     }
                 }
             }
@@ -105,8 +91,7 @@
     }
 
     @Override
-    public Map<String, Lifecycle> getLifecycles()
-    {
+    public Map<String, Lifecycle> getLifecycles() {
         initLifecycleMap();
 
         return lifecycleMap;
@@ -114,35 +99,27 @@
 
     @Deprecated
     @Override
-    public List<String> getOptionalMojos( String lifecycle )
-    {
+    public List<String> getOptionalMojos(String lifecycle) {
         return null;
     }
 
-    private Map<String, LifecyclePhase> getLifecyclePhases( String lifecycle )
-    {
+    private Map<String, LifecyclePhase> getLifecyclePhases(String lifecycle) {
         initLifecycleMap();
 
-        Lifecycle lifecycleMapping = lifecycleMap.get( lifecycle );
+        Lifecycle lifecycleMapping = lifecycleMap.get(lifecycle);
 
-        if ( lifecycleMapping != null )
-        {
+        if (lifecycleMapping != null) {
             return lifecycleMapping.getLifecyclePhases();
-        }
-        else if ( "default".equals( lifecycle ) )
-        {
+        } else if ("default".equals(lifecycle)) {
             return phases;
-        }
-        else
-        {
+        } else {
             return null;
         }
     }
 
     @Deprecated
     @Override
-    public Map<String, String> getPhases( String lifecycle )
-    {
-        return LifecyclePhase.toLegacyMap( getLifecyclePhases( lifecycle ) );
+    public Map<String, String> getPhases(String lifecycle) {
+        return LifecyclePhase.toLegacyMap(getLifecyclePhases(lifecycle));
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/Lifecycle.java b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/Lifecycle.java
index 8afffd9..8b6387f 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/Lifecycle.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/Lifecycle.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.mapping;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.mapping;
 
 import java.util.Collections;
 import java.util.LinkedHashMap;
@@ -26,8 +25,7 @@
 /**
  * Lifecycle definition for a packaging (multiple packagings share the same lifecycle id = usually "default").
  */
-public class Lifecycle
-{
+public class Lifecycle {
     /**
      * Field id
      */
@@ -41,16 +39,14 @@
     /**
      * Method getId
      */
-    public String getId()
-    {
+    public String getId() {
         return this.id;
     }
 
     /**
      * Method getLifecyclePhases
      */
-    public Map<String, LifecyclePhase> getLifecyclePhases()
-    {
+    public Map<String, LifecyclePhase> getLifecyclePhases() {
         return this.lifecyclePhases;
     }
 
@@ -59,8 +55,7 @@
      *
      * @param id
      */
-    public void setId( String id )
-    {
+    public void setId(String id) {
         this.id = id;
     }
 
@@ -69,41 +64,34 @@
      *
      * @param lifecyclePhases
      */
-    public void setLifecyclePhases( Map<String, LifecyclePhase> lifecyclePhases )
-    {
+    public void setLifecyclePhases(Map<String, LifecyclePhase> lifecyclePhases) {
         this.lifecyclePhases = lifecyclePhases;
     }
 
     @Deprecated
-    public Map<String, String> getPhases()
-    {
+    public Map<String, String> getPhases() {
         Map<String, LifecyclePhase> lphases = getLifecyclePhases();
-        if ( lphases == null )
-        {
+        if (lphases == null) {
             return null;
         }
 
-        if ( lphases.isEmpty() )
-        {
+        if (lphases.isEmpty()) {
             return Collections.emptyMap();
         }
 
         Map<String, String> phases = new LinkedHashMap<>();
-        for ( Map.Entry<String, LifecyclePhase> e: lphases.entrySet() )
-        {
-            phases.put( e.getKey(), e.getValue().toString() );
+        for (Map.Entry<String, LifecyclePhase> e : lphases.entrySet()) {
+            phases.put(e.getKey(), e.getValue().toString());
         }
         return phases;
     }
 
     @Deprecated
-    public void setPhases( Map<String, String> phases )
-    {
+    public void setPhases(Map<String, String> phases) {
         Map<String, LifecyclePhase> lphases = new LinkedHashMap<>();
-        for ( Map.Entry<String, String> e: phases.entrySet() )
-        {
-            lphases.put( e.getKey(), new LifecyclePhase( e.getValue() ) );
+        for (Map.Entry<String, String> e : phases.entrySet()) {
+            lphases.put(e.getKey(), new LifecyclePhase(e.getValue()));
         }
-        setLifecyclePhases( lphases );
+        setLifecyclePhases(lphases);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMapping.java b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMapping.java
index 55d5544..a33ec32 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMapping.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMapping.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.mapping;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.mapping;
 
 import java.util.List;
 import java.util.Map;
@@ -25,8 +24,7 @@
 /**
  * LifecycleMapping
  */
-public interface LifecycleMapping
-{
+public interface LifecycleMapping {
 
     @Deprecated
     String ROLE = LifecycleMapping.class.getName();
@@ -34,9 +32,8 @@
     Map<String, Lifecycle> getLifecycles();
 
     @Deprecated
-    List<String> getOptionalMojos( String lifecycle );
+    List<String> getOptionalMojos(String lifecycle);
 
     @Deprecated
-    Map<String, String> getPhases( String lifecycle );
-
+    Map<String, String> getPhases(String lifecycle);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMojo.java b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMojo.java
index 1e274c4..ea12ae0 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMojo.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecycleMojo.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.mapping;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,51 +16,45 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.mapping;
 
 import java.util.List;
 
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.model.Dependency;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * Mojo (plugin goal) binding to a lifecycle phase.
  *
  * @see LifecyclePhase
  */
-public class LifecycleMojo
-{
+public class LifecycleMojo {
 
     private String goal;
-    private Xpp3Dom configuration;
+    private XmlNode configuration;
     private List<Dependency> dependencies;
 
-    public String getGoal()
-    {
+    public String getGoal() {
         return goal;
     }
 
-    public Xpp3Dom getConfiguration()
-    {
+    public XmlNode getConfiguration() {
         return configuration;
     }
 
-    public List<Dependency> getDependencies()
-    {
+    public List<Dependency> getDependencies() {
         return dependencies;
     }
 
-    public void setGoal( String goal )
-    {
+    public void setGoal(String goal) {
         this.goal = goal;
     }
 
-    public void setConfiguration( Xpp3Dom configuration )
-    {
+    public void setConfiguration(XmlNode configuration) {
         this.configuration = configuration;
     }
 
-    public void setDependencies( List<Dependency> dependencies )
-    {
+    public void setDependencies(List<Dependency> dependencies) {
         this.dependencies = dependencies;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecyclePhase.java b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecyclePhase.java
index 4f8b603..7cc6593 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecyclePhase.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/mapping/LifecyclePhase.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.mapping;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,104 +16,77 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.mapping;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-
-import org.codehaus.plexus.util.StringUtils;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 /**
  * Mojo (goals) bindings to a lifecycle phase.
  *
  * @see LifecycleMojo
  */
-public class LifecyclePhase
-{
+public class LifecyclePhase {
 
     private List<LifecycleMojo> mojos;
 
-    public LifecyclePhase()
-    {
+    public LifecyclePhase() {}
+
+    public LifecyclePhase(String goals) {
+        set(goals);
     }
 
-    public LifecyclePhase( String goals )
-    {
-        set( goals );
-    }
-
-    public List<LifecycleMojo> getMojos()
-    {
+    public List<LifecycleMojo> getMojos() {
         return mojos;
     }
 
-    public void setMojos( List<LifecycleMojo> mojos )
-    {
+    public void setMojos(List<LifecycleMojo> mojos) {
         this.mojos = mojos;
     }
 
-    public void set( String goals )
-    {
+    public void set(String goals) {
         mojos = new ArrayList<>();
 
-        if ( StringUtils.isNotEmpty( goals ) )
-        {
-            String[] mojoGoals = StringUtils.split( goals, "," );
-
-            for ( String mojoGoal: mojoGoals )
-            {
-                LifecycleMojo lifecycleMojo = new LifecycleMojo();
-                lifecycleMojo.setGoal( mojoGoal.trim() );
-                mojos.add( lifecycleMojo );
-            }
+        if (goals != null && !goals.isEmpty()) {
+            String[] mojoGoals = goals.split(",");
+            mojos = Arrays.stream(mojoGoals).map(fromGoalIntoLifecycleMojo).collect(Collectors.toList());
         }
     }
 
+    private final Function<String, LifecycleMojo> fromGoalIntoLifecycleMojo = s -> {
+        LifecycleMojo lifecycleMojo = new LifecycleMojo();
+        lifecycleMojo.setGoal(s.trim());
+        return lifecycleMojo;
+    };
+
     @Override
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder();
-        boolean first = true;
-        List<LifecycleMojo> mojos = getMojos();
-        if ( mojos != null )
-        {
-            for ( LifecycleMojo mojo: mojos )
-            {
-                if ( first )
-                {
-                    first = false;
-                }
-                else
-                {
-                    sb.append( ',' );
-                }
-                sb.append( mojo.getGoal() );
-            }
-        }
-        return sb.toString();
+    public String toString() {
+        return Optional.ofNullable(getMojos()).orElse(Collections.emptyList()).stream()
+                .map(LifecycleMojo::getGoal)
+                .collect(Collectors.joining(","));
     }
 
     @Deprecated
-    public static Map<String, String> toLegacyMap( Map<String, LifecyclePhase> lifecyclePhases )
-    {
-        if ( lifecyclePhases == null )
-        {
+    public static Map<String, String> toLegacyMap(Map<String, LifecyclePhase> lifecyclePhases) {
+        if (lifecyclePhases == null) {
             return null;
         }
 
-        if ( lifecyclePhases.isEmpty() )
-        {
+        if (lifecyclePhases.isEmpty()) {
             return Collections.emptyMap();
         }
 
         Map<String, String> phases = new LinkedHashMap<>();
-        for ( Map.Entry<String, LifecyclePhase> e: lifecyclePhases.entrySet() )
-        {
-            phases.put( e.getKey(), e.getValue().toString() );
+        for (Map.Entry<String, LifecyclePhase> e : lifecyclePhases.entrySet()) {
+            phases.put(e.getKey(), e.getValue().toString());
         }
         return phases;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/AbstractLifecycleProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/AbstractLifecycleProvider.java
index e167cac..0a48691 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/AbstractLifecycleProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/AbstractLifecycleProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,12 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers;
+
+import javax.inject.Provider;
 
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
-
-import javax.inject.Provider;
+import java.util.LinkedHashMap;
 
 import org.apache.maven.lifecycle.Lifecycle;
 import org.apache.maven.lifecycle.mapping.LifecyclePhase;
@@ -31,41 +31,33 @@
 /**
  * Base lifecycle provider.
  */
-public abstract class AbstractLifecycleProvider
-    implements Provider<Lifecycle>
-{
+public abstract class AbstractLifecycleProvider implements Provider<Lifecycle> {
     private final Lifecycle lifecycle;
 
-    protected AbstractLifecycleProvider( String id, String[] phases, String[] pluginBindings )
-    {
+    protected AbstractLifecycleProvider(String id, String[] phases, String[] pluginBindings) {
         HashMap<String, LifecyclePhase> defaultBindings = null;
-        if ( pluginBindings != null )
-        {
+        if (pluginBindings != null) {
             final int len = pluginBindings.length;
 
-            if ( len < 2 || len % 2 != 0 )
-            {
-                throw new IllegalArgumentException( "Plugin bindings must have more than 0, even count of elements" );
+            if (len < 2 || len % 2 != 0) {
+                throw new IllegalArgumentException("Plugin bindings must have more than 0, even count of elements");
             }
 
-            defaultBindings = new HashMap<>( len / 2 );
+            defaultBindings = new LinkedHashMap<>(len / 2);
 
-            for ( int i = 0; i < len; i += 2 )
-            {
-                defaultBindings.put( pluginBindings[i], new LifecyclePhase( pluginBindings[i + 1] ) );
+            for (int i = 0; i < len; i += 2) {
+                defaultBindings.put(pluginBindings[i], new LifecyclePhase(pluginBindings[i + 1]));
             }
         }
 
         this.lifecycle = new Lifecycle(
-            id,
-            Collections.unmodifiableList( Arrays.asList( phases ) ),
-            defaultBindings == null ? null : Collections.unmodifiableMap( defaultBindings )
-        );
+                id,
+                Collections.unmodifiableList(Arrays.asList(phases)),
+                defaultBindings == null ? null : Collections.unmodifiableMap(defaultBindings));
     }
 
     @Override
-    public Lifecycle get()
-    {
+    public Lifecycle get() {
         return lifecycle;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/CleanLifecycleProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/CleanLifecycleProvider.java
index db42df1..cd8873d 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/CleanLifecycleProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/CleanLifecycleProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,28 +25,23 @@
 /**
  * {@code clean} lifecycle provider.
  */
-@Named( CleanLifecycleProvider.LIFECYCLE_ID )
+@Named(CleanLifecycleProvider.LIFECYCLE_ID)
 @Singleton
-public final class CleanLifecycleProvider
-    extends AbstractLifecycleProvider
-{
-    protected static final String LIFECYCLE_ID = "clean";
+public final class CleanLifecycleProvider extends AbstractLifecycleProvider {
+    static final String LIFECYCLE_ID = "clean";
 
     // START SNIPPET: clean
-    private static final String[] PHASES = {
-        "pre-clean",
-        "clean",
-        "post-clean"
-    };
+    private static final String[] PHASES = {"pre-clean", "clean", "post-clean"};
+
+    private static final String MAVEN_CLEAN_PLUGIN_VERSION = "3.2.0";
 
     private static final String[] BINDINGS = {
-        "clean", "org.apache.maven.plugins:maven-clean-plugin:3.1.0:clean"
+        "clean", "org.apache.maven.plugins:maven-clean-plugin:" + MAVEN_CLEAN_PLUGIN_VERSION + ":clean"
     };
     // END SNIPPET: clean
 
     @Inject
-    public CleanLifecycleProvider()
-    {
-        super( LIFECYCLE_ID, PHASES, BINDINGS );
+    public CleanLifecycleProvider() {
+        super(LIFECYCLE_ID, PHASES, BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/DefaultLifecycleProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/DefaultLifecycleProvider.java
index 7eb2247..9f7602a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/DefaultLifecycleProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/DefaultLifecycleProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,12 +25,10 @@
 /**
  * {@code default} lifecycle provider.
  */
-@Named( DefaultLifecycleProvider.LIFECYCLE_ID )
+@Named(DefaultLifecycleProvider.LIFECYCLE_ID)
 @Singleton
-public final class DefaultLifecycleProvider
-    extends AbstractLifecycleProvider
-{
-    protected static final String LIFECYCLE_ID = "default";
+public final class DefaultLifecycleProvider extends AbstractLifecycleProvider {
+    static final String LIFECYCLE_ID = "default";
 
     // START SNIPPET: default
     private static final String[] PHASES = {
@@ -62,10 +59,12 @@
     // END SNIPPET: default
 
     @Inject
-    public DefaultLifecycleProvider()
-    {
-      super( LIFECYCLE_ID, PHASES,
-          null // no global plugin bindings for default lifecycle: they are defined per-packaging in separate providers
-      );
+    public DefaultLifecycleProvider() {
+        super(
+                LIFECYCLE_ID,
+                PHASES,
+                null // no global plugin bindings for default lifecycle: they are defined per-packaging in separate
+                // providers
+                );
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/SiteLifecycleProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/SiteLifecycleProvider.java
index 4c6a59d..8dd6439 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/SiteLifecycleProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/SiteLifecycleProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,30 +25,24 @@
 /**
  * {@code site} lifecycle provider.
  */
-@Named( SiteLifecycleProvider.LIFECYCLE_ID )
+@Named(SiteLifecycleProvider.LIFECYCLE_ID)
 @Singleton
-public final class SiteLifecycleProvider
-    extends AbstractLifecycleProvider
-{
-    protected static final String LIFECYCLE_ID = "site";
+public final class SiteLifecycleProvider extends AbstractLifecycleProvider {
+    static final String LIFECYCLE_ID = "site";
 
     // START SNIPPET: site
-    private static final String[] PHASES = {
-        "pre-site",
-        "site",
-        "post-site",
-        "site-deploy"
-    };
+    private static final String[] PHASES = {"pre-site", "site", "post-site", "site-deploy"};
+
+    private static final String MAVEN_SITE_PLUGIN_VERSION = "3.12.1";
 
     private static final String[] BINDINGS = {
-        "site",        "org.apache.maven.plugins:maven-site-plugin:3.9.1:site",
-        "site-deploy", "org.apache.maven.plugins:maven-site-plugin:3.9.1:deploy"
+        "site", "org.apache.maven.plugins:maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":site",
+        "site-deploy", "org.apache.maven.plugins:maven-site-plugin:" + MAVEN_SITE_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: site
 
     @Inject
-    public SiteLifecycleProvider()
-    {
-        super( LIFECYCLE_ID, PHASES, BINDINGS );
+    public SiteLifecycleProvider() {
+        super(LIFECYCLE_ID, PHASES, BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/WrapperLifecycleProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/WrapperLifecycleProvider.java
index b4a1966..29ddaea 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/WrapperLifecycleProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/WrapperLifecycleProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,27 +25,23 @@
 /**
  * {@code wrapper} lifecycle provider.
  */
-@Named( WrapperLifecycleProvider.LIFECYCLE_ID )
+@Named(WrapperLifecycleProvider.LIFECYCLE_ID)
 @Singleton
-public final class WrapperLifecycleProvider
-    extends AbstractLifecycleProvider
-{
-    protected static final String LIFECYCLE_ID = "wrapper";
+public final class WrapperLifecycleProvider extends AbstractLifecycleProvider {
+    static final String LIFECYCLE_ID = "wrapper";
 
     // START SNIPPET: wrapper
-    private static final String[] PHASES =
-    {
-        "wrapper"
-    };
+    private static final String[] PHASES = {"wrapper"};
+
+    private static final String MAVEN_WRAPPER_PLUGIN_VERSION = "3.2.0";
 
     private static final String[] BINDINGS = {
-        "wrapper", "org.apache.maven.plugins:maven-wrapper-plugin:3.1.0:wrapper"
+        "wrapper", "org.apache.maven.plugins:maven-wrapper-plugin:" + MAVEN_WRAPPER_PLUGIN_VERSION + ":wrapper"
     };
     // END SNIPPET: wrapper
 
     @Inject
-    public WrapperLifecycleProvider()
-    {
-        super( LIFECYCLE_ID, PHASES, BINDINGS );
+    public WrapperLifecycleProvider() {
+        super(LIFECYCLE_ID, PHASES, BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
index 9faae05..152bf66 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,12 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
+
+import javax.inject.Provider;
 
 import java.util.Collections;
 import java.util.HashMap;
 
-import javax.inject.Provider;
-
 import org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping;
 import org.apache.maven.lifecycle.mapping.Lifecycle;
 import org.apache.maven.lifecycle.mapping.LifecycleMapping;
@@ -34,60 +33,56 @@
 /**
  * Base lifecycle mapping provider, ie per-packaging plugin bindings for {@code default} lifecycle.
  */
-public abstract class AbstractLifecycleMappingProvider
-    implements Provider<LifecycleMapping>
-{
-    protected static final String RESOURCES_PLUGIN_VERSION = "3.2.0";
+public abstract class AbstractLifecycleMappingProvider implements Provider<LifecycleMapping> {
+    // START SNIPPET: versions
+    protected static final String RESOURCES_PLUGIN_VERSION = "3.3.1";
 
-    protected static final String COMPILER_PLUGIN_VERSION = "3.8.1";
+    protected static final String COMPILER_PLUGIN_VERSION = "3.11.0";
 
-    protected static final String SUREFIRE_PLUGIN_VERSION = "3.0.0-M5";
+    protected static final String SUREFIRE_PLUGIN_VERSION = "3.1.2";
 
-    protected static final String INSTALL_PLUGIN_VERSION = "3.0.0-M1";
+    protected static final String INSTALL_PLUGIN_VERSION = "3.1.1";
 
-    protected static final String DEPLOY_PLUGIN_VERSION = "3.0.0-M2";
+    protected static final String DEPLOY_PLUGIN_VERSION = "3.1.1";
 
     // packaging
 
-    protected static final String JAR_PLUGIN_VERSION = "3.2.0";
+    protected static final String JAR_PLUGIN_VERSION = "3.3.0";
 
-    protected static final String EAR_PLUGIN_VERSION = "3.1.2";
+    protected static final String EAR_PLUGIN_VERSION = "3.3.0";
 
-    protected static final String EJB_PLUGIN_VERSION = "3.1.0";
+    protected static final String EJB_PLUGIN_VERSION = "3.2.1";
 
-    protected static final String PLUGIN_PLUGIN_VERSION = "3.6.0";
+    protected static final String PLUGIN_PLUGIN_VERSION = "3.9.0";
 
-    protected static final String RAR_PLUGIN_VERSION = "2.4"; // TODO: Update!!!
+    protected static final String RAR_PLUGIN_VERSION = "3.0.0";
 
-    protected static final String WAR_PLUGIN_VERSION = "3.3.1";
+    protected static final String WAR_PLUGIN_VERSION = "3.4.0";
+    // END SNIPPET: versions
 
     private final LifecycleMapping lifecycleMapping;
 
-    protected AbstractLifecycleMappingProvider( String[] pluginBindings )
-    {
-        requireNonNull( pluginBindings );
+    protected AbstractLifecycleMappingProvider(String[] pluginBindings) {
+        requireNonNull(pluginBindings);
         final int len = pluginBindings.length;
-        if ( len < 2 || len % 2 != 0 )
-        {
-            throw new IllegalArgumentException( "Plugin bindings must have more than 0, even count of elements" );
+        if (len < 2 || len % 2 != 0) {
+            throw new IllegalArgumentException("Plugin bindings must have more than 0, even count of elements");
         }
 
-        HashMap<String, LifecyclePhase> lifecyclePhaseBindings = new HashMap<>( len / 2 );
-        for ( int i = 0; i < len; i = i + 2 )
-        {
-            lifecyclePhaseBindings.put( pluginBindings[i], new LifecyclePhase( pluginBindings[i + 1] ) );
+        HashMap<String, LifecyclePhase> lifecyclePhaseBindings = new HashMap<>(len / 2);
+        for (int i = 0; i < len; i = i + 2) {
+            lifecyclePhaseBindings.put(pluginBindings[i], new LifecyclePhase(pluginBindings[i + 1]));
         }
 
         Lifecycle lifecycle = new Lifecycle();
-        lifecycle.setId( "default" );
-        lifecycle.setLifecyclePhases( Collections.unmodifiableMap( lifecyclePhaseBindings ) );
+        lifecycle.setId("default");
+        lifecycle.setLifecyclePhases(Collections.unmodifiableMap(lifecyclePhaseBindings));
 
-        this.lifecycleMapping = new DefaultLifecycleMapping( Collections.singletonList( lifecycle ) );
+        this.lifecycleMapping = new DefaultLifecycleMapping(Collections.singletonList(lifecycle));
     }
 
     @Override
-    public LifecycleMapping get()
-    {
+    public LifecycleMapping get() {
         return lifecycleMapping;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/BomLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/BomLifecycleMappingProvider.java
new file mode 100644
index 0000000..3c0e23c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/BomLifecycleMappingProvider.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.lifecycle.providers.packaging;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+/**
+ * {@code bom} packaging plugins bindings provider for {@code default} lifecycle.
+ */
+@Named("bom")
+@Singleton
+public final class BomLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
+    // START SNIPPET: bom
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
+        "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+    };
+    // END SNIPPET: bom
+
+    @Inject
+    public BomLifecycleMappingProvider() {
+        super(BINDINGS);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EarLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EarLifecycleMappingProvider.java
index 4c6eec7..feef89a 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EarLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EarLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,26 +25,24 @@
 /**
  * {@code ear} packaging plugins bindings provider for {@code default} lifecycle.
  */
-@Named( "ear" )
+@Named("ear")
 @Singleton
-public final class EarLifecycleMappingProvider
-    extends AbstractLifecycleMappingProvider
-{
+public final class EarLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
     // START SNIPPET: ear
-    @SuppressWarnings( "checkstyle:linelength" )
-    private static final String[] BINDINGS =
-    {
-        "generate-resources", "org.apache.maven.plugins:maven-ear-plugin:" + EAR_PLUGIN_VERSION + ":generate-application-xml",
-        "process-resources",  "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
-        "package",            "org.apache.maven.plugins:maven-ear-plugin:" + EAR_PLUGIN_VERSION + ":ear",
-        "install",            "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
-        "deploy",             "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
+        "generate-resources",
+                "org.apache.maven.plugins:maven-ear-plugin:" + EAR_PLUGIN_VERSION + ":generate-application-xml",
+        "process-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
+        "package", "org.apache.maven.plugins:maven-ear-plugin:" + EAR_PLUGIN_VERSION + ":ear",
+        "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: ear
 
     @Inject
-    public EarLifecycleMappingProvider()
-    {
-        super( BINDINGS );
+    public EarLifecycleMappingProvider() {
+        super(BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EjbLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EjbLifecycleMappingProvider.java
index ce90d69..272d2ad 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EjbLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/EjbLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,29 +25,27 @@
 /**
  * {@code ejb} packaging plugins bindings provider for {@code default} lifecycle.
  */
-@Named( "ejb" )
+@Named("ejb")
 @Singleton
-public final class EjbLifecycleMappingProvider
-    extends AbstractLifecycleMappingProvider
-{
+public final class EjbLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
     // START SNIPPET: ejb
-    @SuppressWarnings( "checkstyle:linelength" )
-    private static final String[] BINDINGS =
-    {
-        "process-resources",      "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
-        "compile",                "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
-        "process-test-resources", "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
-        "test-compile",           "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
-        "test",                   "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
-        "package",                "org.apache.maven.plugins:maven-ejb-plugin:" + EJB_PLUGIN_VERSION + ":ejb",
-        "install",                "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
-        "deploy",                 "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
+        "process-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
+        "compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
+        "process-test-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
+        "test-compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
+        "test", "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
+        "package", "org.apache.maven.plugins:maven-ejb-plugin:" + EJB_PLUGIN_VERSION + ":ejb",
+        "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: ejb
-    
+
     @Inject
-    public EjbLifecycleMappingProvider()
-    {
-        super( BINDINGS );
+    public EjbLifecycleMappingProvider() {
+        super(BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/JarLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/JarLifecycleMappingProvider.java
index 05bfe98..455d9b7 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/JarLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/JarLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,29 +25,27 @@
 /**
  * {@code jar} packaging plugins bindings provider for {@code default} lifecycle.
  */
-@Named( "jar" )
+@Named("jar")
 @Singleton
-public final class JarLifecycleMappingProvider
-    extends AbstractLifecycleMappingProvider
-{
+public final class JarLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
     // START SNIPPET: jar
-    @SuppressWarnings( "checkstyle:linelength" )
-    private static final String[] BINDINGS =
-    {
-        "process-resources",      "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
-        "compile",                "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
-        "process-test-resources", "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
-        "test-compile",           "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
-        "test",                   "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
-        "package",                "org.apache.maven.plugins:maven-jar-plugin:" + JAR_PLUGIN_VERSION + ":jar",
-        "install",                "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
-        "deploy",                 "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
+        "process-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
+        "compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
+        "process-test-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
+        "test-compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
+        "test", "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
+        "package", "org.apache.maven.plugins:maven-jar-plugin:" + JAR_PLUGIN_VERSION + ":jar",
+        "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: jar
-    
+
     @Inject
-    public JarLifecycleMappingProvider()
-    {
-        super( BINDINGS );
+    public JarLifecycleMappingProvider() {
+        super(BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/MavenPluginLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/MavenPluginLifecycleMappingProvider.java
index 82e1a40..cacbefd 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/MavenPluginLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/MavenPluginLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,31 +25,31 @@
 /**
  * {@code maven-plugin} packaging plugins bindings provider for {@code default} lifecycle.
  */
-@Named( "maven-plugin" )
+@Named("maven-plugin")
 @Singleton
-public final class MavenPluginLifecycleMappingProvider
-    extends AbstractLifecycleMappingProvider
-{
+public final class MavenPluginLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
     // START SNIPPET: maven-plugin
-    @SuppressWarnings( "checkstyle:linelength" )
-    private static final String[] BINDINGS =
-    {
-        "process-resources",      "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
-        "compile",                "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
-        "process-classes",        "org.apache.maven.plugins:maven-plugin-plugin:" + PLUGIN_PLUGIN_VERSION + ":descriptor",
-        "process-test-resources", "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
-        "test-compile",           "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
-        "test",                   "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
-        "package",                "org.apache.maven.plugins:maven-jar-plugin:" + JAR_PLUGIN_VERSION + ":jar,"
-                                + "org.apache.maven.plugins:maven-plugin-plugin:" + PLUGIN_PLUGIN_VERSION + ":addPluginArtifactMetadata",
-        "install",                "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
-        "deploy",                 "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
+        "process-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
+        "compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
+        "process-classes", "org.apache.maven.plugins:maven-plugin-plugin:" + PLUGIN_PLUGIN_VERSION + ":descriptor",
+        "process-test-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
+        "test-compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
+        "test", "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
+        "package",
+                "org.apache.maven.plugins:maven-jar-plugin:" + JAR_PLUGIN_VERSION + ":jar,"
+                        + "org.apache.maven.plugins:maven-plugin-plugin:" + PLUGIN_PLUGIN_VERSION
+                        + ":addPluginArtifactMetadata",
+        "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: maven-plugin
-    
+
     @Inject
-    public MavenPluginLifecycleMappingProvider()
-    {
-        super( BINDINGS );
+    public MavenPluginLifecycleMappingProvider() {
+        super(BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/PomLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/PomLifecycleMappingProvider.java
index 3237e3c..1f05e9d 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/PomLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/PomLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,23 +25,19 @@
 /**
  * {@code pom} packaging plugins bindings provider for {@code default} lifecycle.
  */
-@Named( "pom" )
+@Named("pom")
 @Singleton
-public final class PomLifecycleMappingProvider
-    extends AbstractLifecycleMappingProvider
-{
+public final class PomLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
     // START SNIPPET: pom
-    @SuppressWarnings( "checkstyle:linelength" )
-    private static final String[] BINDINGS =
-    {
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
         "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
-        "deploy",  "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: pom
-    
+
     @Inject
-    public PomLifecycleMappingProvider()
-    {
-        super( BINDINGS );
+    public PomLifecycleMappingProvider() {
+        super(BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/RarLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/RarLifecycleMappingProvider.java
index 0d85e96..1bcffde 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/RarLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/RarLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,29 +25,27 @@
 /**
  * {@code rar} packaging plugins bindings provider for {@code default} lifecycle.
  */
-@Named( "rar" )
+@Named("rar")
 @Singleton
-public final class RarLifecycleMappingProvider
-    extends AbstractLifecycleMappingProvider
-{
+public final class RarLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
     // START SNIPPET: rar
-    @SuppressWarnings( "checkstyle:linelength" )
-    private static final String[] BINDINGS =
-    {
-        "process-resources",      "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
-        "compile",                "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
-        "process-test-resources", "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
-        "test-compile",           "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
-        "test",                   "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
-        "package",                "org.apache.maven.plugins:maven-rar-plugin:" + RAR_PLUGIN_VERSION + ":rar",
-        "install",                "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
-        "deploy",                 "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
+        "process-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
+        "compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
+        "process-test-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
+        "test-compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
+        "test", "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
+        "package", "org.apache.maven.plugins:maven-rar-plugin:" + RAR_PLUGIN_VERSION + ":rar",
+        "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: rar
-    
+
     @Inject
-    public RarLifecycleMappingProvider()
-    {
-        super( BINDINGS );
+    public RarLifecycleMappingProvider() {
+        super(BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/WarLifecycleMappingProvider.java b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/WarLifecycleMappingProvider.java
index 33f2290..9765701 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/WarLifecycleMappingProvider.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/providers/packaging/WarLifecycleMappingProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.providers.packaging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.providers.packaging;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -26,29 +25,27 @@
 /**
  * {@code war} packaging plugins bindings provider for {@code default} lifecycle.
  */
-@Named( "war" )
+@Named("war")
 @Singleton
-public final class WarLifecycleMappingProvider
-    extends AbstractLifecycleMappingProvider
-{
+public final class WarLifecycleMappingProvider extends AbstractLifecycleMappingProvider {
     // START SNIPPET: war
-    @SuppressWarnings( "checkstyle:linelength" )
-    private static final String[] BINDINGS =
-    {
-        "process-resources",      "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
-        "compile",                "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
-        "process-test-resources", "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
-        "test-compile",           "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
-        "test",                   "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
-        "package",                "org.apache.maven.plugins:maven-war-plugin:" + WAR_PLUGIN_VERSION + ":war",
-        "install",                "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
-        "deploy",                 "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
+    @SuppressWarnings("checkstyle:linelength")
+    private static final String[] BINDINGS = {
+        "process-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":resources",
+        "compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":compile",
+        "process-test-resources",
+                "org.apache.maven.plugins:maven-resources-plugin:" + RESOURCES_PLUGIN_VERSION + ":testResources",
+        "test-compile", "org.apache.maven.plugins:maven-compiler-plugin:" + COMPILER_PLUGIN_VERSION + ":testCompile",
+        "test", "org.apache.maven.plugins:maven-surefire-plugin:" + SUREFIRE_PLUGIN_VERSION + ":test",
+        "package", "org.apache.maven.plugins:maven-war-plugin:" + WAR_PLUGIN_VERSION + ":war",
+        "install", "org.apache.maven.plugins:maven-install-plugin:" + INSTALL_PLUGIN_VERSION + ":install",
+        "deploy", "org.apache.maven.plugins:maven-deploy-plugin:" + DEPLOY_PLUGIN_VERSION + ":deploy"
     };
     // END SNIPPET: war
-    
+
     @Inject
-    public WarLifecycleMappingProvider()
-    {
-        super( BINDINGS );
+    public WarLifecycleMappingProvider() {
+        super(BINDINGS);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java b/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java
index ec0800f..ce53874 100644
--- a/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java
+++ b/maven-core/src/main/java/org/apache/maven/model/plugin/DefaultLifecycleBindingsInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.plugin;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -25,159 +28,149 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginContainer;
+import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.model.PluginManagement;
 import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
-import org.apache.maven.model.Build;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.PluginManagement;
 import org.apache.maven.model.building.ModelBuildingRequest;
-import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblem.Severity;
 import org.apache.maven.model.building.ModelProblem.Version;
+import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblemCollectorRequest;
 import org.apache.maven.model.merge.MavenModelMerger;
 
 /**
  * Handles injection of plugin executions induced by the lifecycle bindings for a packaging.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultLifecycleBindingsInjector
-    implements LifecycleBindingsInjector
-{
+public class DefaultLifecycleBindingsInjector implements LifecycleBindingsInjector {
 
     private final LifecycleBindingsMerger merger = new LifecycleBindingsMerger();
 
     private final LifeCyclePluginAnalyzer lifecycle;
 
     @Inject
-    public DefaultLifecycleBindingsInjector( LifeCyclePluginAnalyzer lifecycle )
-    {
+    public DefaultLifecycleBindingsInjector(LifeCyclePluginAnalyzer lifecycle) {
         this.lifecycle = lifecycle;
     }
 
-    public void injectLifecycleBindings( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    public void injectLifecycleBindings(
+            org.apache.maven.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
         String packaging = model.getPackaging();
 
-        Collection<Plugin> defaultPlugins = lifecycle.getPluginsBoundByDefaultToAllLifecycles( packaging );
+        Collection<org.apache.maven.model.Plugin> defaultPlugins =
+                lifecycle.getPluginsBoundByDefaultToAllLifecycles(packaging);
 
-        if ( defaultPlugins == null )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "Unknown packaging: " + packaging )
-                    .setLocation( model.getLocation( "packaging" ) ) );
-        }
-        else if ( !defaultPlugins.isEmpty() )
-        {
-            Model lifecycleModel = new Model();
-            lifecycleModel.setBuild( new Build() );
-            lifecycleModel.getBuild().getPlugins().addAll( defaultPlugins );
-
-            merger.merge( model, lifecycleModel );
+        if (defaultPlugins == null) {
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                    .setMessage("Unknown packaging: " + packaging)
+                    .setLocation(model.getLocation("packaging")));
+        } else if (!defaultPlugins.isEmpty()) {
+            List<Plugin> plugins = defaultPlugins.stream()
+                    .map(org.apache.maven.model.Plugin::getDelegate)
+                    .collect(Collectors.toList());
+            Model lifecycleModel = Model.newBuilder()
+                    .build(Build.newBuilder().plugins(plugins).build())
+                    .build();
+            model.update(merger.merge(model.getDelegate(), lifecycleModel));
         }
     }
 
     /**
      *  The domain-specific model merger for lifecycle bindings
      */
-    protected static class LifecycleBindingsMerger
-        extends MavenModelMerger
-    {
+    protected static class LifecycleBindingsMerger extends MavenModelMerger {
 
         private static final String PLUGIN_MANAGEMENT = "plugin-management";
 
-        public void merge( Model target, Model source )
-        {
-            if ( target.getBuild() == null )
-            {
-                target.setBuild( new Build() );
+        public Model merge(Model target, Model source) {
+            Build targetBuild = target.getBuild();
+            if (targetBuild == null) {
+                targetBuild = Build.newInstance();
             }
 
-            Map<Object, Object> context =
-                Collections.singletonMap( PLUGIN_MANAGEMENT, target.getBuild().getPluginManagement() );
+            Map<Object, Object> context = Collections.singletonMap(
+                    PLUGIN_MANAGEMENT, target.getBuild().getPluginManagement());
 
-            mergePluginContainer_Plugins( target.getBuild(), source.getBuild(), false, context );
+            Build.Builder builder = Build.newBuilder(target.getBuild());
+            mergePluginContainer_Plugins(builder, targetBuild, source.getBuild(), false, context);
+
+            return target.withBuild(builder.build());
         }
 
-        @SuppressWarnings( { "checkstyle:methodname" } )
+        @SuppressWarnings({"checkstyle:methodname"})
         @Override
-        protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
-                                                     boolean sourceDominant, Map<Object, Object> context )
-        {
+        protected void mergePluginContainer_Plugins(
+                PluginContainer.Builder builder,
+                PluginContainer target,
+                PluginContainer source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<Plugin> src = source.getPlugins();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<Plugin> tgt = target.getPlugins();
 
-                Map<Object, Plugin> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+                Map<Object, Plugin> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-                for ( Plugin element : tgt )
-                {
-                    Object key = getPluginKey().apply( element );
-                    merged.put( key, element );
+                for (Plugin element : tgt) {
+                    Object key = getPluginKey().apply(element);
+                    merged.put(key, element);
                 }
 
                 Map<Object, Plugin> added = new LinkedHashMap<>();
 
-                for ( Plugin element : src )
-                {
-                    Object key = getPluginKey().apply( element );
-                    Plugin existing = merged.get( key );
-                    if ( existing != null )
-                    {
-                        mergePlugin( existing, element, sourceDominant, context );
+                for (Plugin element : src) {
+                    Object key = getPluginKey().apply(element);
+                    Plugin existing = merged.get(key);
+                    if (existing != null) {
+                        element = mergePlugin(existing, element, sourceDominant, context);
+                    } else {
+                        added.put(key, element);
                     }
-                    else
-                    {
-                        merged.put( key, element );
-                        added.put( key, element );
-                    }
+                    merged.put(key, element);
                 }
 
-                if ( !added.isEmpty() )
-                {
-                    PluginManagement pluginMgmt = (PluginManagement) context.get( PLUGIN_MANAGEMENT );
-                    if ( pluginMgmt != null )
-                    {
-                        for ( Plugin managedPlugin : pluginMgmt.getPlugins() )
-                        {
-                            Object key = getPluginKey().apply( managedPlugin );
-                            Plugin addedPlugin = added.get( key );
-                            if ( addedPlugin != null )
-                            {
-                                Plugin plugin = managedPlugin.clone();
-                                mergePlugin( plugin, addedPlugin, sourceDominant, Collections.emptyMap() );
-                                merged.put( key, plugin );
+                if (!added.isEmpty()) {
+                    PluginManagement pluginMgmt = (PluginManagement) context.get(PLUGIN_MANAGEMENT);
+                    if (pluginMgmt != null) {
+                        for (Plugin managedPlugin : pluginMgmt.getPlugins()) {
+                            Object key = getPluginKey().apply(managedPlugin);
+                            Plugin addedPlugin = added.get(key);
+                            if (addedPlugin != null) {
+                                Plugin plugin =
+                                        mergePlugin(managedPlugin, addedPlugin, sourceDominant, Collections.emptyMap());
+                                merged.put(key, plugin);
                             }
                         }
                     }
                 }
 
-                List<Plugin> result = new ArrayList<>( merged.values() );
+                List<Plugin> result = new ArrayList<>(merged.values());
 
-                target.setPlugins( result );
+                builder.plugins(result);
             }
         }
 
         @Override
-        protected void mergePluginExecution( PluginExecution target, PluginExecution source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-        {
-            super.mergePluginExecution( target, source, sourceDominant, context );
-
-            target.setPriority( Math.min( target.getPriority(), source.getPriority() ) );
+        protected void mergePluginExecution_Priority(
+                PluginExecution.Builder builder,
+                PluginExecution target,
+                PluginExecution source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
+            if (target.getPriority() > source.getPriority()) {
+                builder.priority(source.getPriority());
+                builder.location("priority", source.getLocation("priority"));
+            }
         }
+        // mergePluginExecution_Priority( builder, target, source, sourceDominant, context );
 
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/monitor/event/EventDispatcher.java b/maven-core/src/main/java/org/apache/maven/monitor/event/EventDispatcher.java
index 492a298..62c25e8 100644
--- a/maven-core/src/main/java/org/apache/maven/monitor/event/EventDispatcher.java
+++ b/maven-core/src/main/java/org/apache/maven/monitor/event/EventDispatcher.java
@@ -1,5 +1,3 @@
-package org.apache.maven.monitor.event;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,20 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.monitor.event;
 
 /**
- * @author jdcasey
  */
 @Deprecated
-public interface EventDispatcher
-{
+public interface EventDispatcher {
 
-    void addEventMonitor( EventMonitor monitor );
+    void addEventMonitor(EventMonitor monitor);
 
-    void dispatchStart( String event, String target );
+    void dispatchStart(String event, String target);
 
-    void dispatchEnd( String event, String target );
+    void dispatchEnd(String event, String target);
 
-    void dispatchError( String event, String target, Throwable cause );
-
-}
\ No newline at end of file
+    void dispatchError(String event, String target, Throwable cause);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/monitor/event/EventMonitor.java b/maven-core/src/main/java/org/apache/maven/monitor/event/EventMonitor.java
index 3e72674..236f995 100644
--- a/maven-core/src/main/java/org/apache/maven/monitor/event/EventMonitor.java
+++ b/maven-core/src/main/java/org/apache/maven/monitor/event/EventMonitor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.monitor.event;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,18 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.monitor.event;
 
 /**
- * @author jdcasey
  */
 @Deprecated
-public interface EventMonitor
-{
+public interface EventMonitor {
 
-    void startEvent( String eventName, String target, long timestamp );
+    void startEvent(String eventName, String target, long timestamp);
 
-    void endEvent( String eventName, String target, long timestamp );
+    void endEvent(String eventName, String target, long timestamp);
 
-    void errorEvent( String eventName, String target, long timestamp, Throwable cause );
-
-}
\ No newline at end of file
+    void errorEvent(String eventName, String target, long timestamp, Throwable cause);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/BuildPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/BuildPluginManager.java
index 6c1b9cb..b374104 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/BuildPluginManager.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/BuildPluginManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 
@@ -30,25 +29,22 @@
 import org.eclipse.aether.repository.RemoteRepository;
 
 /**
- * @author Jason van Zyl
  */
-public interface BuildPluginManager
-{
+public interface BuildPluginManager {
     // igorf: Way too many declared exceptions!
-    PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        InvalidPluginDescriptorException;
+    PluginDescriptor loadPlugin(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    InvalidPluginDescriptorException;
 
     // igorf: Way too many declared exceptions!
-    MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
-                                      RepositorySystemSession session )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException;
+    MojoDescriptor getMojoDescriptor(
+            Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException;
 
-    ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor )
-        throws PluginResolutionException, PluginManagerException;
+    ClassRealm getPluginRealm(MavenSession session, PluginDescriptor pluginDescriptor)
+            throws PluginResolutionException, PluginManagerException;
 
-    void executeMojo( MavenSession session, MojoExecution execution )
-        throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException;
-
+    void executeMojo(MavenSession session, MojoExecution execution)
+            throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/CacheUtils.java b/maven-core/src/main/java/org/apache/maven/plugin/CacheUtils.java
index 118db83..5f98414 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/CacheUtils.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/CacheUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.Iterator;
 import java.util.List;
@@ -28,93 +27,81 @@
 import org.apache.maven.model.Plugin;
 
 /**
- * @author Benjamin Bentmann
  */
-class CacheUtils
-{
+class CacheUtils {
 
     /**
      * @deprecated Use {@link Objects#equals(Object)}
      */
     @Deprecated
-    public static <T> boolean eq( T s1, T s2 )
-    {
-        return Objects.equals( s1, s2 );
+    public static <T> boolean eq(T s1, T s2) {
+        return Objects.equals(s1, s2);
     }
 
     /**
      * @deprecated Use {@link Objects#hashCode(Object)}
      */
     @Deprecated
-    public static int hash( Object obj )
-    {
+    public static int hash(Object obj) {
         return obj != null ? obj.hashCode() : 0;
     }
 
-    public static int pluginHashCode( Plugin plugin )
-    {
+    public static int pluginHashCode(Plugin plugin) {
         int hash = 17;
 
-        hash = hash * 31 + Objects.hashCode( plugin.getGroupId() );
-        hash = hash * 31 + Objects.hashCode( plugin.getArtifactId() );
-        hash = hash * 31 + Objects.hashCode( plugin.getVersion() );
+        hash = hash * 31 + Objects.hashCode(plugin.getGroupId());
+        hash = hash * 31 + Objects.hashCode(plugin.getArtifactId());
+        hash = hash * 31 + Objects.hashCode(plugin.getVersion());
 
-        hash = hash * 31 + ( plugin.isExtensions() ? 1 : 0 );
+        hash = hash * 31 + (plugin.isExtensions() ? 1 : 0);
 
-        for ( Dependency dependency : plugin.getDependencies() )
-        {
-            hash = hash * 31 + Objects.hashCode( dependency.getGroupId() );
-            hash = hash * 31 + Objects.hashCode( dependency.getArtifactId() );
-            hash = hash * 31 + Objects.hashCode( dependency.getVersion() );
-            hash = hash * 31 + Objects.hashCode( dependency.getType() );
-            hash = hash * 31 + Objects.hashCode( dependency.getClassifier() );
-            hash = hash * 31 + Objects.hashCode( dependency.getScope() );
+        for (Dependency dependency : plugin.getDependencies()) {
+            hash = hash * 31 + Objects.hashCode(dependency.getGroupId());
+            hash = hash * 31 + Objects.hashCode(dependency.getArtifactId());
+            hash = hash * 31 + Objects.hashCode(dependency.getVersion());
+            hash = hash * 31 + Objects.hashCode(dependency.getType());
+            hash = hash * 31 + Objects.hashCode(dependency.getClassifier());
+            hash = hash * 31 + Objects.hashCode(dependency.getScope());
 
-            for ( Exclusion exclusion : dependency.getExclusions() )
-            {
-                hash = hash * 31 + Objects.hashCode( exclusion.getGroupId() );
-                hash = hash * 31 + Objects.hashCode( exclusion.getArtifactId() );
+            for (Exclusion exclusion : dependency.getExclusions()) {
+                hash = hash * 31 + Objects.hashCode(exclusion.getGroupId());
+                hash = hash * 31 + Objects.hashCode(exclusion.getArtifactId());
             }
         }
 
         return hash;
     }
 
-    public static boolean pluginEquals( Plugin a, Plugin b )
-    {
-        return Objects.equals( a.getArtifactId(), b.getArtifactId() ) //
-            && Objects.equals( a.getGroupId(), b.getGroupId() ) //
-            && Objects.equals( a.getVersion(), b.getVersion() ) //
-            && a.isExtensions() == b.isExtensions() //
-            && dependenciesEquals( a.getDependencies(), b.getDependencies() );
+    public static boolean pluginEquals(Plugin a, Plugin b) {
+        return Objects.equals(a.getArtifactId(), b.getArtifactId()) //
+                && Objects.equals(a.getGroupId(), b.getGroupId()) //
+                && Objects.equals(a.getVersion(), b.getVersion()) //
+                && a.isExtensions() == b.isExtensions() //
+                && dependenciesEquals(a.getDependencies(), b.getDependencies());
     }
 
-    private static boolean dependenciesEquals( List<Dependency> a, List<Dependency> b )
-    {
-        if ( a.size() != b.size() )
-        {
+    private static boolean dependenciesEquals(List<Dependency> a, List<Dependency> b) {
+        if (a.size() != b.size()) {
             return false;
         }
 
         Iterator<Dependency> aI = a.iterator();
         Iterator<Dependency> bI = b.iterator();
 
-        while ( aI.hasNext() )
-        {
+        while (aI.hasNext()) {
             Dependency aD = aI.next();
             Dependency bD = bI.next();
 
-            boolean r = Objects.equals( aD.getGroupId(), bD.getGroupId() ) //
-                && Objects.equals( aD.getArtifactId(), bD.getArtifactId() ) //
-                && Objects.equals( aD.getVersion(), bD.getVersion() ) //
-                && Objects.equals( aD.getType(), bD.getType() ) //
-                && Objects.equals( aD.getClassifier(), bD.getClassifier() ) //
-                && Objects.equals( aD.getScope(), bD.getScope() );
+            boolean r = Objects.equals(aD.getGroupId(), bD.getGroupId()) //
+                    && Objects.equals(aD.getArtifactId(), bD.getArtifactId()) //
+                    && Objects.equals(aD.getVersion(), bD.getVersion()) //
+                    && Objects.equals(aD.getType(), bD.getType()) //
+                    && Objects.equals(aD.getClassifier(), bD.getClassifier()) //
+                    && Objects.equals(aD.getScope(), bD.getScope());
 
-            r &= exclusionsEquals( aD.getExclusions(), bD.getExclusions() );
+            r &= exclusionsEquals(aD.getExclusions(), bD.getExclusions());
 
-            if ( !r )
-            {
+            if (!r) {
                 return false;
             }
         }
@@ -122,31 +109,26 @@
         return true;
     }
 
-    private static boolean exclusionsEquals( List<Exclusion> a, List<Exclusion> b )
-    {
-        if ( a.size() != b.size() )
-        {
+    private static boolean exclusionsEquals(List<Exclusion> a, List<Exclusion> b) {
+        if (a.size() != b.size()) {
             return false;
         }
 
         Iterator<Exclusion> aI = a.iterator();
         Iterator<Exclusion> bI = b.iterator();
 
-        while ( aI.hasNext() )
-        {
+        while (aI.hasNext()) {
             Exclusion aD = aI.next();
             Exclusion bD = bI.next();
 
-            boolean r = Objects.equals( aD.getGroupId(), bD.getGroupId() ) //
-                && Objects.equals( aD.getArtifactId(), bD.getArtifactId() );
+            boolean r = Objects.equals(aD.getGroupId(), bD.getGroupId()) //
+                    && Objects.equals(aD.getArtifactId(), bD.getArtifactId());
 
-            if ( !r )
-            {
+            if (!r) {
                 return false;
             }
         }
 
         return true;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java b/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java
index e61ffbd..f8f53fc 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/CompoundMojoExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,47 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.Collection;
 
 import org.apache.maven.execution.MojoExecutionEvent;
 import org.apache.maven.execution.MojoExecutionListener;
 
-class CompoundMojoExecutionListener
-    implements MojoExecutionListener
-{
+class CompoundMojoExecutionListener implements MojoExecutionListener {
 
     private final Collection<MojoExecutionListener> listeners;
 
-    CompoundMojoExecutionListener( Collection<MojoExecutionListener> listeners )
-    {
+    CompoundMojoExecutionListener(Collection<MojoExecutionListener> listeners) {
         this.listeners = listeners; // NB this is live injected collection
     }
 
-    public void beforeMojoExecution( MojoExecutionEvent event )
-        throws MojoExecutionException
-    {
-        for ( MojoExecutionListener listener : listeners )
-        {
-            listener.beforeMojoExecution( event );
+    public void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException {
+        for (MojoExecutionListener listener : listeners) {
+            listener.beforeMojoExecution(event);
         }
     }
 
-    public void afterMojoExecutionSuccess( MojoExecutionEvent event )
-        throws MojoExecutionException
-    {
-        for ( MojoExecutionListener listener : listeners )
-        {
-            listener.afterMojoExecutionSuccess( event );
+    public void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException {
+        for (MojoExecutionListener listener : listeners) {
+            listener.afterMojoExecutionSuccess(event);
         }
     }
 
-    public void afterExecutionFailure( MojoExecutionEvent event )
-    {
-        for ( MojoExecutionListener listener : listeners )
-        {
-            listener.afterExecutionFailure( event );
+    public void afterExecutionFailure(MojoExecutionEvent event) {
+        for (MojoExecutionListener listener : listeners) {
+            listener.afterExecutionFailure(event);
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/CycleDetectedInPluginGraphException.java b/maven-core/src/main/java/org/apache/maven/plugin/CycleDetectedInPluginGraphException.java
index f77461f..dfcf3b1 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/CycleDetectedInPluginGraphException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/CycleDetectedInPluginGraphException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.model.Plugin;
 import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
@@ -25,22 +24,17 @@
 /**
  * Exception occurring trying to resolve a plugin.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class CycleDetectedInPluginGraphException
-    extends Exception
-{
+public class CycleDetectedInPluginGraphException extends Exception {
     private final Plugin plugin;
 
-    public CycleDetectedInPluginGraphException( Plugin plugin, CycleDetectedInComponentGraphException e )
-    {
-        super( "A cycle was detected in the component graph of the plugin: " + plugin.getArtifactId() );
+    public CycleDetectedInPluginGraphException(Plugin plugin, CycleDetectedInComponentGraphException e) {
+        super("A cycle was detected in the component graph of the plugin: " + plugin.getArtifactId());
 
         this.plugin = plugin;
     }
 
-    public Plugin getPlugin()
-    {
+    public Plugin getPlugin() {
         return plugin;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DebugConfigurationListener.java b/maven-core/src/main/java/org/apache/maven/plugin/DebugConfigurationListener.java
index 2ad629f..de20ea2 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DebugConfigurationListener.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DebugConfigurationListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,41 +16,43 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.lang.reflect.Array;
 
 import org.codehaus.plexus.component.configurator.ConfigurationListener;
 import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  * Log at debug level the mojo configuration.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
 @Deprecated
-public class DebugConfigurationListener
-    implements ConfigurationListener
-{
+public class DebugConfigurationListener implements ConfigurationListener {
     private final Logger logger;
 
-    public DebugConfigurationListener( Logger logger )
-    {
+    /**
+     * @deprecated Use {@link #DebugConfigurationListener(Logger)} instead.
+     */
+    @Deprecated
+    public DebugConfigurationListener(org.codehaus.plexus.logging.Logger logger) {
+        this(LoggerFactory.getLogger(logger.getName()));
+    }
+
+    public DebugConfigurationListener(Logger logger) {
         this.logger = logger;
     }
 
-    public void notifyFieldChangeUsingSetter( String fieldName, Object value, Object target )
-    {
-        if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "  (s) " + fieldName + " = " + toString( value ) );
+    public void notifyFieldChangeUsingSetter(String fieldName, Object value, Object target) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("  (s) " + fieldName + " = " + toString(value));
         }
     }
 
-    public void notifyFieldChangeUsingReflection( String fieldName, Object value, Object target )
-    {
-        if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "  (f) " + fieldName + " = " + toString( value ) );
+    public void notifyFieldChangeUsingReflection(String fieldName, Object value, Object target) {
+        if (logger.isDebugEnabled()) {
+            logger.debug("  (f) " + fieldName + " = " + toString(value));
         }
     }
 
@@ -62,30 +62,23 @@
      * @param obj The object to create a string representation for, may be <code>null</code>.
      * @return The string representation, never <code>null</code>.
      */
-    private String toString( Object obj )
-    {
+    private String toString(Object obj) {
         String str;
-        if ( obj != null && obj.getClass().isArray() )
-        {
-            int n = Array.getLength( obj );
-            StringBuilder buf = new StringBuilder( 256 );
-            buf.append( '[' );
-            for ( int i = 0; i < n; i++ )
-            {
-                if ( i > 0 )
-                {
-                    buf.append( ", " );
+        if (obj != null && obj.getClass().isArray()) {
+            int n = Array.getLength(obj);
+            StringBuilder buf = new StringBuilder(256);
+            buf.append('[');
+            for (int i = 0; i < n; i++) {
+                if (i > 0) {
+                    buf.append(", ");
                 }
-                buf.append( String.valueOf( Array.get( obj, i ) ) );
+                buf.append(String.valueOf(Array.get(obj, i)));
             }
-            buf.append( ']' );
+            buf.append(']');
             str = buf.toString();
-        }
-        else
-        {
-            str = String.valueOf( obj );
+        } else {
+            str = String.valueOf(obj);
         }
         return str;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java
index 272371a..3c81234 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultBuildPluginManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,26 +16,34 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.ByteArrayOutputStream;
-import java.io.PrintStream;
-import java.util.List;
+package org.apache.maven.plugin;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.List;
+
+import org.apache.maven.api.Project;
+import org.apache.maven.api.plugin.MojoException;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.MojoExecutionEvent;
 import org.apache.maven.execution.MojoExecutionListener;
 import org.apache.maven.execution.scope.internal.MojoExecutionScope;
+import org.apache.maven.internal.impl.DefaultLog;
+import org.apache.maven.internal.impl.DefaultMojoExecution;
+import org.apache.maven.internal.impl.InternalSession;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.repository.RemoteRepository;
+import org.slf4j.LoggerFactory;
 
 // TODO the antrun plugin has its own configurator, the only plugin that does. might need to think about how that works
 // TODO remove the coreArtifactFilterManager
@@ -47,9 +53,7 @@
  */
 @Named
 @Singleton
-public class DefaultBuildPluginManager
-    implements BuildPluginManager
-{
+public class DefaultBuildPluginManager implements BuildPluginManager {
 
     private final MavenPluginManager mavenPluginManager;
     private final LegacySupport legacySupport;
@@ -61,12 +65,11 @@
             MavenPluginManager mavenPluginManager,
             LegacySupport legacySupport,
             MojoExecutionScope scope,
-            List<MojoExecutionListener> mojoExecutionListeners )
-    {
+            List<MojoExecutionListener> mojoExecutionListeners) {
         this.mavenPluginManager = mavenPluginManager;
         this.legacySupport = legacySupport;
         this.scope = scope;
-        this.mojoExecutionListener = new CompoundMojoExecutionListener( mojoExecutionListeners );
+        this.mojoExecutionListener = new CompoundMojoExecutionListener(mojoExecutionListeners);
     }
 
     /**
@@ -78,21 +81,19 @@
      * @throws PluginResolutionException The plugin could be found but could not be resolved.
      * @throws InvalidPluginDescriptorException
      */
-    public PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories,
-                                        RepositorySystemSession session )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        InvalidPluginDescriptorException
-    {
-        return mavenPluginManager.getPluginDescriptor( plugin, repositories, session );
+    public PluginDescriptor loadPlugin(
+            Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    InvalidPluginDescriptorException {
+        return mavenPluginManager.getPluginDescriptor(plugin, repositories, session);
     }
 
     // ----------------------------------------------------------------------
     // Mojo execution
     // ----------------------------------------------------------------------
 
-    public void executeMojo( MavenSession session, MojoExecution mojoExecution )
-        throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException
-    {
+    public void executeMojo(MavenSession session, MojoExecution mojoExecution)
+            throws MojoFailureException, MojoExecutionException, PluginConfigurationException, PluginManagerException {
         MavenProject project = session.getCurrentProject();
 
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
@@ -100,120 +101,96 @@
         Mojo mojo = null;
 
         ClassRealm pluginRealm;
-        try
-        {
-            pluginRealm = getPluginRealm( session, mojoDescriptor.getPluginDescriptor() );
-        }
-        catch ( PluginResolutionException e )
-        {
-            throw new PluginExecutionException( mojoExecution, project, e );
+        try {
+            pluginRealm = getPluginRealm(session, mojoDescriptor.getPluginDescriptor());
+        } catch (PluginResolutionException e) {
+            throw new PluginExecutionException(mojoExecution, project, e);
         }
 
         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
-        Thread.currentThread().setContextClassLoader( pluginRealm );
+        Thread.currentThread().setContextClassLoader(pluginRealm);
 
         MavenSession oldSession = legacySupport.getSession();
 
         scope.enter();
 
-        try
-        {
-            scope.seed( MavenProject.class, project );
-            scope.seed( MojoExecution.class, mojoExecution );
+        try {
+            scope.seed(MavenProject.class, project);
+            scope.seed(MojoExecution.class, mojoExecution);
+            scope.seed(
+                    org.apache.maven.api.plugin.Log.class,
+                    new DefaultLog(LoggerFactory.getLogger(
+                            mojoExecution.getMojoDescriptor().getFullGoalName())));
+            InternalSession sessionV4 = InternalSession.from(session.getSession());
+            scope.seed(Project.class, sessionV4.getProject(project));
+            scope.seed(org.apache.maven.api.MojoExecution.class, new DefaultMojoExecution(sessionV4, mojoExecution));
 
-            mojo = mavenPluginManager.getConfiguredMojo( Mojo.class, session, mojoExecution );
+            if (mojoDescriptor.isV4Api()) {
+                org.apache.maven.api.plugin.Mojo mojoV4 = mavenPluginManager.getConfiguredMojo(
+                        org.apache.maven.api.plugin.Mojo.class, session, mojoExecution);
+                mojo = new MojoWrapper(mojoV4);
+            } else {
+                mojo = mavenPluginManager.getConfiguredMojo(Mojo.class, session, mojoExecution);
+            }
 
-            legacySupport.setSession( session );
+            legacySupport.setSession(session);
 
             // NOTE: DuplicateArtifactAttachmentException is currently unchecked, so be careful removing this try/catch!
             // This is necessary to avoid creating compatibility problems for existing plugins that use
             // MavenProjectHelper.attachArtifact(..).
-            try
-            {
-                MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent( session, project, mojoExecution, mojo );
-
-                mojoExecutionListener.beforeMojoExecution( mojoExecutionEvent );
-
+            try {
+                MojoExecutionEvent mojoExecutionEvent = new MojoExecutionEvent(session, project, mojoExecution, mojo);
+                mojoExecutionListener.beforeMojoExecution(mojoExecutionEvent);
                 mojo.execute();
-
-                mojoExecutionListener.afterMojoExecutionSuccess( mojoExecutionEvent );
-            }
-            catch ( ClassCastException e )
-            {
+                mojoExecutionListener.afterMojoExecutionSuccess(mojoExecutionEvent);
+            } catch (ClassCastException e) {
                 // to be processed in the outer catch block
                 throw e;
+            } catch (RuntimeException e) {
+                throw new PluginExecutionException(mojoExecution, project, e);
             }
-            catch ( RuntimeException e )
-            {
-                throw new PluginExecutionException( mojoExecution, project, e );
-            }
-        }
-        catch ( PluginContainerException e )
-        {
-            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
-                                                                                 e ) );
-
-            throw new PluginExecutionException( mojoExecution, project, e );
-        }
-        catch ( NoClassDefFoundError e )
-        {
-            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
-                                                                                 e ) );
-
-            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
-            PrintStream ps = new PrintStream( os );
-            ps.println( "A required class was missing while executing " + mojoDescriptor.getId() + ": "
-                + e.getMessage() );
-            pluginRealm.display( ps );
-
-            Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
-
-            throw new PluginExecutionException( mojoExecution, project, wrapper );
-        }
-        catch ( LinkageError e )
-        {
-            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
-                                                                                 e ) );
-
-            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
-            PrintStream ps = new PrintStream( os );
-            ps.println( "An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
-                + e.getClass().getName() + ": " + e.getMessage() );
-            pluginRealm.display( ps );
-
-            Exception wrapper = new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), e );
-
-            throw new PluginExecutionException( mojoExecution, project, wrapper );
-        }
-        catch ( ClassCastException e )
-        {
-            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
-                                                                                 e ) );
-
-            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
-            PrintStream ps = new PrintStream( os );
-            ps.println( "A type incompatibility occurred while executing " + mojoDescriptor.getId() + ": "
-                + e.getMessage() );
-            pluginRealm.display( ps );
-
-            throw new PluginExecutionException( mojoExecution, project, os.toString(), e );
-        }
-        catch ( RuntimeException e )
-        {
-            mojoExecutionListener.afterExecutionFailure( new MojoExecutionEvent( session, project, mojoExecution, mojo,
-                                                                                 e ) );
-
+        } catch (PluginContainerException e) {
+            mojoExecutionListener.afterExecutionFailure(
+                    new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
+            throw new PluginExecutionException(mojoExecution, project, e);
+        } catch (NoClassDefFoundError e) {
+            mojoExecutionListener.afterExecutionFailure(
+                    new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
+            ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
+            PrintStream ps = new PrintStream(os);
+            ps.println(
+                    "A required class was missing while executing " + mojoDescriptor.getId() + ": " + e.getMessage());
+            pluginRealm.display(ps);
+            Exception wrapper = new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), e);
+            throw new PluginExecutionException(mojoExecution, project, wrapper);
+        } catch (LinkageError e) {
+            mojoExecutionListener.afterExecutionFailure(
+                    new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
+            ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
+            PrintStream ps = new PrintStream(os);
+            ps.println("An API incompatibility was encountered while executing " + mojoDescriptor.getId() + ": "
+                    + e.getClass().getName() + ": " + e.getMessage());
+            pluginRealm.display(ps);
+            Exception wrapper = new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), e);
+            throw new PluginExecutionException(mojoExecution, project, wrapper);
+        } catch (ClassCastException e) {
+            mojoExecutionListener.afterExecutionFailure(
+                    new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
+            ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
+            PrintStream ps = new PrintStream(os);
+            ps.println("A type incompatibility occurred while executing " + mojoDescriptor.getId() + ": "
+                    + e.getMessage());
+            pluginRealm.display(ps);
+            throw new PluginExecutionException(mojoExecution, project, os.toString(), e);
+        } catch (RuntimeException e) {
+            mojoExecutionListener.afterExecutionFailure(
+                    new MojoExecutionEvent(session, project, mojoExecution, mojo, e));
             throw e;
-        }
-        finally
-        {
-            mavenPluginManager.releaseMojo( mojo, mojoExecution );
-
+        } finally {
+            mavenPluginManager.releaseMojo(mojo, mojoExecution);
             scope.exit();
-
-            Thread.currentThread().setContextClassLoader( oldClassLoader );
-
-            legacySupport.setSession( oldSession );
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+            legacySupport.setSession(oldSession);
         }
     }
 
@@ -222,26 +199,47 @@
      *      call, which is not nice.
      * @throws PluginResolutionException
      */
-    public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor )
-        throws PluginResolutionException, PluginManagerException
-    {
+    public ClassRealm getPluginRealm(MavenSession session, PluginDescriptor pluginDescriptor)
+            throws PluginResolutionException, PluginManagerException {
         ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
-        if ( pluginRealm != null )
-        {
+        if (pluginRealm != null) {
             return pluginRealm;
         }
 
-        mavenPluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
+        mavenPluginManager.setupPluginRealm(pluginDescriptor, session, null, null, null);
 
         return pluginDescriptor.getClassRealm();
     }
 
-    public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
-                                             RepositorySystemSession session )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException
-    {
-        return mavenPluginManager.getMojoDescriptor( plugin, goal, repositories, session );
+    public MojoDescriptor getMojoDescriptor(
+            Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException {
+        return mavenPluginManager.getMojoDescriptor(plugin, goal, repositories, session);
     }
 
+    private static class MojoWrapper implements Mojo {
+        private final org.apache.maven.api.plugin.Mojo mojoV4;
+
+        MojoWrapper(org.apache.maven.api.plugin.Mojo mojoV4) {
+            this.mojoV4 = mojoV4;
+        }
+
+        @Override
+        public void execute() throws MojoExecutionException, MojoFailureException {
+            try {
+                mojoV4.execute();
+            } catch (MojoException e) {
+                throw new MojoExecutionException(e.getMessage(), e);
+            }
+        }
+
+        @Override
+        public void setLog(Log log) {}
+
+        @Override
+        public Log getLog() {
+            return null;
+        }
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultExtensionRealmCache.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultExtensionRealmCache.java
index dd48a4f..da83a99 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultExtensionRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultExtensionRealmCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -26,9 +28,6 @@
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.project.ExtensionDescriptor;
 import org.apache.maven.project.MavenProject;
@@ -41,15 +40,11 @@
  */
 @Named
 @Singleton
-public class DefaultExtensionRealmCache
-    implements ExtensionRealmCache, Disposable
-{
+public class DefaultExtensionRealmCache implements ExtensionRealmCache, Disposable {
     /**
      * CacheKey
      */
-    protected static class CacheKey
-        implements Key
-    {
+    protected static class CacheKey implements Key {
 
         private final List<File> files;
 
@@ -61,54 +56,49 @@
 
         private final int hashCode;
 
-        public CacheKey( List<Artifact> extensionArtifacts )
-        {
-            this.files = new ArrayList<>( extensionArtifacts.size() );
-            this.timestamps = new ArrayList<>( extensionArtifacts.size() );
-            this.sizes = new ArrayList<>( extensionArtifacts.size() );
-            this.ids = new ArrayList<>( extensionArtifacts.size() );
+        public CacheKey(List<Artifact> extensionArtifacts) {
+            this.files = new ArrayList<>(extensionArtifacts.size());
+            this.timestamps = new ArrayList<>(extensionArtifacts.size());
+            this.sizes = new ArrayList<>(extensionArtifacts.size());
+            this.ids = new ArrayList<>(extensionArtifacts.size());
 
-            for ( Artifact artifact : extensionArtifacts )
-            {
+            for (Artifact artifact : extensionArtifacts) {
                 File file = artifact.getFile();
-                files.add( file );
-                timestamps.add( ( file != null ) ? Long.valueOf( file.lastModified() ) : Long.valueOf( 0 ) );
-                sizes.add( ( file != null ) ? Long.valueOf( file.length() ) : Long.valueOf( 0 ) );
-                ids.add( artifact.getVersion() );
+                files.add(file);
+                timestamps.add((file != null) ? Long.valueOf(file.lastModified()) : Long.valueOf(0));
+                sizes.add((file != null) ? Long.valueOf(file.length()) : Long.valueOf(0));
+                ids.add(artifact.getVersion());
             }
 
             this.hashCode =
-                31 * files.hashCode() + 31 * ids.hashCode() + 31 * timestamps.hashCode() + 31 * sizes.hashCode();
+                    31 * files.hashCode() + 31 * ids.hashCode() + 31 * timestamps.hashCode() + 31 * sizes.hashCode();
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( o == this )
-            {
+        public boolean equals(Object o) {
+            if (o == this) {
                 return true;
             }
 
-            if ( !( o instanceof CacheKey ) )
-            {
+            if (!(o instanceof CacheKey)) {
                 return false;
             }
 
             CacheKey other = (CacheKey) o;
 
-            return ids.equals( other.ids ) && files.equals( other.files ) && timestamps.equals( other.timestamps )
-                && sizes.equals( other.sizes );
+            return ids.equals(other.ids)
+                    && files.equals(other.files)
+                    && timestamps.equals(other.timestamps)
+                    && sizes.equals(other.sizes);
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return files.toString();
         }
     }
@@ -116,58 +106,46 @@
     protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
 
     @Override
-    public Key createKey( List<Artifact> extensionArtifacts )
-    {
-        return new CacheKey( extensionArtifacts );
+    public Key createKey(List<Artifact> extensionArtifacts) {
+        return new CacheKey(extensionArtifacts);
     }
 
-    public CacheRecord get( Key key )
-    {
-        return cache.get( key );
+    public CacheRecord get(Key key) {
+        return cache.get(key);
     }
 
-    public CacheRecord put( Key key, ClassRealm extensionRealm, ExtensionDescriptor extensionDescriptor,
-                            List<Artifact> artifacts )
-    {
-        Objects.requireNonNull( extensionRealm, "extensionRealm cannot be null" );
+    public CacheRecord put(
+            Key key, ClassRealm extensionRealm, ExtensionDescriptor extensionDescriptor, List<Artifact> artifacts) {
+        Objects.requireNonNull(extensionRealm, "extensionRealm cannot be null");
 
-        if ( cache.containsKey( key ) )
-        {
-            throw new IllegalStateException( "Duplicate extension realm for extension " + key );
+        if (cache.containsKey(key)) {
+            throw new IllegalStateException("Duplicate extension realm for extension " + key);
         }
 
-        CacheRecord record = new CacheRecord( extensionRealm, extensionDescriptor, artifacts );
+        CacheRecord record = new CacheRecord(extensionRealm, extensionDescriptor, artifacts);
 
-        cache.put( key, record );
+        cache.put(key, record);
 
         return record;
     }
 
-    public void flush()
-    {
-        for ( CacheRecord record : cache.values() )
-        {
+    public void flush() {
+        for (CacheRecord record : cache.values()) {
             ClassRealm realm = record.getRealm();
-            try
-            {
-                realm.getWorld().disposeRealm( realm.getId() );
-            }
-            catch ( NoSuchRealmException e )
-            {
+            try {
+                realm.getWorld().disposeRealm(realm.getId());
+            } catch (NoSuchRealmException e) {
                 // ignore
             }
         }
         cache.clear();
     }
 
-    public void register( MavenProject project, Key key, CacheRecord record )
-    {
+    public void register(MavenProject project, Key key, CacheRecord record) {
         // default cache does not track extension usage
     }
 
-    public void dispose()
-    {
+    public void dispose() {
         flush();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultMojosExecutionStrategy.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultMojosExecutionStrategy.java
index 9507c7a..828fe5a 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultMojosExecutionStrategy.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultMojosExecutionStrategy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,29 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.lifecycle.LifecycleExecutionException;
+package org.apache.maven.plugin;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
+
 import java.util.List;
 
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.LifecycleExecutionException;
+
 /**
  * Default mojo execution strategy. It just iterates over mojo executions and runs one by one
  */
 @Named
 @Singleton
-public class DefaultMojosExecutionStrategy implements MojosExecutionStrategy
-{
+public class DefaultMojosExecutionStrategy implements MojosExecutionStrategy {
     @Override
-    public void execute( List<MojoExecution> mojos, MavenSession session, MojoExecutionRunner mojoRunner )
-            throws LifecycleExecutionException
-    {
-        for ( MojoExecution mojoExecution : mojos )
-        {
-            mojoRunner.run( mojoExecution );
+    public void execute(List<MojoExecution> mojos, MavenSession session, MojoExecutionRunner mojoRunner)
+            throws LifecycleExecutionException {
+        for (MojoExecution mojoExecution : mojos) {
+            mojoRunner.run(mojoExecution);
         }
-
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginArtifactsCache.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginArtifactsCache.java
index 7f8ff14..154fee3 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginArtifactsCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginArtifactsCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -26,9 +28,6 @@
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.model.Plugin;
@@ -40,20 +39,14 @@
 import org.eclipse.aether.repository.WorkspaceRepository;
 
 /**
- * @author Igor Fedorenko
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultPluginArtifactsCache
-    implements PluginArtifactsCache
-{
+public class DefaultPluginArtifactsCache implements PluginArtifactsCache {
     /**
      * CacheKey
      */
-    protected static class CacheKey
-        implements Key
-    {
+    protected static class CacheKey implements Key {
         private final Plugin plugin;
 
         private final WorkspaceRepository workspace;
@@ -66,144 +59,126 @@
 
         private final int hashCode;
 
-        public CacheKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepository> repositories,
-                         RepositorySystemSession session )
-        {
+        public CacheKey(
+                Plugin plugin,
+                DependencyFilter extensionFilter,
+                List<RemoteRepository> repositories,
+                RepositorySystemSession session) {
             this.plugin = plugin.clone();
-            workspace = RepositoryUtils.getWorkspace( session );
+            workspace = RepositoryUtils.getWorkspace(session);
             this.localRepo = session.getLocalRepository();
-            this.repositories = new ArrayList<>( repositories.size() );
-            for ( RemoteRepository repository : repositories )
-            {
-                if ( repository.isRepositoryManager() )
-                {
-                    this.repositories.addAll( repository.getMirroredRepositories() );
-                }
-                else
-                {
-                    this.repositories.add( repository );
+            this.repositories = new ArrayList<>(repositories.size());
+            for (RemoteRepository repository : repositories) {
+                if (repository.isRepositoryManager()) {
+                    this.repositories.addAll(repository.getMirroredRepositories());
+                } else {
+                    this.repositories.add(repository);
                 }
             }
             this.filter = extensionFilter;
 
             int hash = 17;
-            hash = hash * 31 + CacheUtils.pluginHashCode( plugin );
-            hash = hash * 31 + Objects.hashCode( workspace );
-            hash = hash * 31 + Objects.hashCode( localRepo );
-            hash = hash * 31 + RepositoryUtils.repositoriesHashCode( repositories );
-            hash = hash * 31 + Objects.hashCode( extensionFilter );
+            hash = hash * 31 + CacheUtils.pluginHashCode(plugin);
+            hash = hash * 31 + Objects.hashCode(workspace);
+            hash = hash * 31 + Objects.hashCode(localRepo);
+            hash = hash * 31 + RepositoryUtils.repositoriesHashCode(repositories);
+            hash = hash * 31 + Objects.hashCode(extensionFilter);
             this.hashCode = hash;
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return plugin.getId();
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( o == this )
-            {
+        public boolean equals(Object o) {
+            if (o == this) {
                 return true;
             }
 
-            if ( !( o instanceof CacheKey ) )
-            {
+            if (!(o instanceof CacheKey)) {
                 return false;
             }
 
             CacheKey that = (CacheKey) o;
 
-            return CacheUtils.pluginEquals( plugin, that.plugin )
-                && Objects.equals( workspace, that.workspace )
-                && Objects.equals( localRepo, that.localRepo )
-                && RepositoryUtils.repositoriesEquals( repositories, that.repositories )
-                && Objects.equals( filter, that.filter );
+            return CacheUtils.pluginEquals(plugin, that.plugin)
+                    && Objects.equals(workspace, that.workspace)
+                    && Objects.equals(localRepo, that.localRepo)
+                    && RepositoryUtils.repositoriesEquals(repositories, that.repositories)
+                    && Objects.equals(filter, that.filter);
         }
     }
 
     protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
 
-    public Key createKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepository> repositories,
-                          RepositorySystemSession session )
-    {
-        return new CacheKey( plugin, extensionFilter, repositories, session );
+    public Key createKey(
+            Plugin plugin,
+            DependencyFilter extensionFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session) {
+        return new CacheKey(plugin, extensionFilter, repositories, session);
     }
 
-    public CacheRecord get( Key key )
-        throws PluginResolutionException
-    {
-        CacheRecord cacheRecord = cache.get( key );
+    public CacheRecord get(Key key) throws PluginResolutionException {
+        CacheRecord cacheRecord = cache.get(key);
 
-        if ( cacheRecord != null && cacheRecord.getException() != null )
-        {
+        if (cacheRecord != null && cacheRecord.getException() != null) {
             throw cacheRecord.getException();
         }
 
         return cacheRecord;
     }
 
-    public CacheRecord put( Key key, List<Artifact> pluginArtifacts )
-    {
-        Objects.requireNonNull( pluginArtifacts, "pluginArtifacts cannot be null" );
+    public CacheRecord put(Key key, List<Artifact> pluginArtifacts) {
+        Objects.requireNonNull(pluginArtifacts, "pluginArtifacts cannot be null");
 
-        assertUniqueKey( key );
+        assertUniqueKey(key);
 
-        CacheRecord record =
-            new CacheRecord( Collections.unmodifiableList( new ArrayList<>( pluginArtifacts ) ) );
+        CacheRecord record = new CacheRecord(Collections.unmodifiableList(new ArrayList<>(pluginArtifacts)));
 
-        cache.put( key, record );
+        cache.put(key, record);
 
         return record;
     }
 
-    protected void assertUniqueKey( Key key )
-    {
-        if ( cache.containsKey( key ) )
-        {
-            throw new IllegalStateException( "Duplicate artifact resolution result for plugin " + key );
+    protected void assertUniqueKey(Key key) {
+        if (cache.containsKey(key)) {
+            throw new IllegalStateException("Duplicate artifact resolution result for plugin " + key);
         }
     }
 
-    public CacheRecord put( Key key, PluginResolutionException exception )
-    {
-        Objects.requireNonNull( exception, "exception cannot be null" );
+    public CacheRecord put(Key key, PluginResolutionException exception) {
+        Objects.requireNonNull(exception, "exception cannot be null");
 
-        assertUniqueKey( key );
+        assertUniqueKey(key);
 
-        CacheRecord record = new CacheRecord( exception );
+        CacheRecord record = new CacheRecord(exception);
 
-        cache.put( key, record );
+        cache.put(key, record);
 
         return record;
     }
 
-    public void flush()
-    {
+    public void flush() {
         cache.clear();
     }
 
-    protected static int pluginHashCode( Plugin plugin )
-    {
-        return CacheUtils.pluginHashCode( plugin );
+    protected static int pluginHashCode(Plugin plugin) {
+        return CacheUtils.pluginHashCode(plugin);
     }
 
-    protected static boolean pluginEquals( Plugin a, Plugin b )
-    {
-        return CacheUtils.pluginEquals( a, b );
+    protected static boolean pluginEquals(Plugin a, Plugin b) {
+        return CacheUtils.pluginEquals(a, b);
     }
 
-    public void register( MavenProject project, Key cacheKey, CacheRecord record )
-    {
+    public void register(MavenProject project, Key cacheKey, CacheRecord record) {
         // default cache does not track record usage
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java
index 69297ea..3e5f8e8 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginDescriptorCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,22 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+package org.apache.maven.plugin;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
 import org.apache.maven.RepositoryUtils;
-import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.model.Plugin;
-import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.codehaus.plexus.component.repository.ComponentDescriptor;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.repository.LocalRepository;
 import org.eclipse.aether.repository.RemoteRepository;
@@ -47,89 +43,61 @@
  * prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultPluginDescriptorCache
-    implements PluginDescriptorCache
-{
+public class DefaultPluginDescriptorCache implements PluginDescriptorCache {
 
-    private Map<Key, PluginDescriptor> descriptors = new HashMap<>( 128 );
+    private Map<Key, PluginDescriptor> descriptors = new ConcurrentHashMap<>(128);
 
-    public void flush()
-    {
+    public void flush() {
         descriptors.clear();
     }
 
-    public Key createKey( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
-    {
-        return new CacheKey( plugin, repositories, session );
+    public Key createKey(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session) {
+        return new CacheKey(plugin, repositories, session);
     }
 
-    public PluginDescriptor get( Key cacheKey )
-    {
-        return clone( descriptors.get( cacheKey ) );
+    public PluginDescriptor get(Key cacheKey) {
+        return clone(descriptors.get(cacheKey));
     }
 
-    public void put( Key cacheKey, PluginDescriptor pluginDescriptor )
-    {
-        descriptors.put( cacheKey, clone( pluginDescriptor ) );
-    }
-
-    protected static PluginDescriptor clone( PluginDescriptor original )
-    {
-        PluginDescriptor clone = null;
-
-        if ( original != null )
-        {
-            clone = new PluginDescriptor();
-
-            clone.setGroupId( original.getGroupId() );
-            clone.setArtifactId( original.getArtifactId() );
-            clone.setVersion( original.getVersion() );
-            clone.setGoalPrefix( original.getGoalPrefix() );
-            clone.setInheritedByDefault( original.isInheritedByDefault() );
-
-            clone.setName( original.getName() );
-            clone.setDescription( original.getDescription() );
-            clone.setRequiredMavenVersion( original.getRequiredMavenVersion() );
-
-            clone.setPluginArtifact( ArtifactUtils.copyArtifactSafe( original.getPluginArtifact() ) );
-
-            clone.setComponents( clone( original.getMojos(), clone ) );
-            clone.setId( original.getId() );
-            clone.setIsolatedRealm( original.isIsolatedRealm() );
-            clone.setSource( original.getSource() );
-
-            clone.setDependencies( original.getDependencies() );
-        }
-
-        return clone;
-    }
-
-    private static List<ComponentDescriptor<?>> clone( List<MojoDescriptor> mojos, PluginDescriptor pluginDescriptor )
-    {
-        List<ComponentDescriptor<?>> clones = null;
-
-        if ( mojos != null )
-        {
-            clones = new ArrayList<>( mojos.size() );
-
-            for ( MojoDescriptor mojo : mojos )
-            {
-                MojoDescriptor clone = mojo.clone();
-                clone.setPluginDescriptor( pluginDescriptor );
-                clones.add( clone );
+    @Override
+    public PluginDescriptor get(Key key, PluginDescriptorSupplier supplier)
+            throws PluginDescriptorParsingException, PluginResolutionException, InvalidPluginDescriptorException {
+        try {
+            return clone(descriptors.computeIfAbsent(key, k -> {
+                try {
+                    return clone(supplier.load());
+                } catch (PluginDescriptorParsingException
+                        | PluginResolutionException
+                        | InvalidPluginDescriptorException e) {
+                    throw new RuntimeException(e);
+                }
+            }));
+        } catch (RuntimeException e) {
+            if (e.getCause() instanceof PluginDescriptorParsingException) {
+                throw (PluginDescriptorParsingException) e.getCause();
             }
+            if (e.getCause() instanceof PluginResolutionException) {
+                throw (PluginResolutionException) e.getCause();
+            }
+            if (e.getCause() instanceof InvalidPluginDescriptorException) {
+                throw (InvalidPluginDescriptorException) e.getCause();
+            }
+            throw e;
         }
-
-        return clones;
     }
 
-    private static final class CacheKey
-        implements Key
-    {
+    public void put(Key cacheKey, PluginDescriptor pluginDescriptor) {
+        descriptors.put(cacheKey, clone(pluginDescriptor));
+    }
+
+    protected static PluginDescriptor clone(PluginDescriptor original) {
+        return new PluginDescriptor(original);
+    }
+
+    private static final class CacheKey implements Key {
 
         private final String groupId;
 
@@ -145,24 +113,19 @@
 
         private final int hashCode;
 
-        CacheKey( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
-        {
+        CacheKey(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session) {
             groupId = plugin.getGroupId();
             artifactId = plugin.getArtifactId();
             version = plugin.getVersion();
 
-            workspace = RepositoryUtils.getWorkspace( session );
+            workspace = RepositoryUtils.getWorkspace(session);
             localRepo = session.getLocalRepository();
-            this.repositories = new ArrayList<>( repositories.size() );
-            for ( RemoteRepository repository : repositories )
-            {
-                if ( repository.isRepositoryManager() )
-                {
-                    this.repositories.addAll( repository.getMirroredRepositories() );
-                }
-                else
-                {
-                    this.repositories.add( repository );
+            this.repositories = new ArrayList<>(repositories.size());
+            for (RemoteRepository repository : repositories) {
+                if (repository.isRepositoryManager()) {
+                    this.repositories.addAll(repository.getMirroredRepositories());
+                } else {
+                    this.repositories.add(repository);
                 }
             }
 
@@ -170,52 +133,44 @@
             hash = hash * 31 + groupId.hashCode();
             hash = hash * 31 + artifactId.hashCode();
             hash = hash * 31 + version.hashCode();
-            hash = hash * 31 + hash( workspace );
+            hash = hash * 31 + hash(workspace);
             hash = hash * 31 + localRepo.hashCode();
-            hash = hash * 31 + RepositoryUtils.repositoriesHashCode( repositories );
+            hash = hash * 31 + RepositoryUtils.repositoriesHashCode(repositories);
             this.hashCode = hash;
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public boolean equals( Object obj )
-        {
-            if ( this == obj )
-            {
+        public boolean equals(Object obj) {
+            if (this == obj) {
                 return true;
             }
 
-            if ( !( obj instanceof CacheKey ) )
-            {
+            if (!(obj instanceof CacheKey)) {
                 return false;
             }
 
             CacheKey that = (CacheKey) obj;
 
-            return Objects.equals( this.artifactId, that.artifactId )
-                && Objects.equals( this.groupId, that.groupId )
-                && Objects.equals( this.version, that.version )
-                && Objects.equals( this.localRepo, that.localRepo )
-                && Objects.equals( this.workspace, that.workspace )
-                && RepositoryUtils.repositoriesEquals( this.repositories, that.repositories );
+            return Objects.equals(this.artifactId, that.artifactId)
+                    && Objects.equals(this.groupId, that.groupId)
+                    && Objects.equals(this.version, that.version)
+                    && Objects.equals(this.localRepo, that.localRepo)
+                    && Objects.equals(this.workspace, that.workspace)
+                    && RepositoryUtils.repositoriesEquals(this.repositories, that.repositories);
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return groupId + ':' + artifactId + ':' + version;
         }
 
-        private static int hash( Object obj )
-        {
+        private static int hash(Object obj) {
             return obj != null ? obj.hashCode() : 0;
         }
-
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java
index fef5fe1..dfbee39 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/DefaultPluginRealmCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -26,9 +28,6 @@
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.model.Plugin;
@@ -47,15 +46,11 @@
  */
 @Named
 @Singleton
-public class DefaultPluginRealmCache
-    implements PluginRealmCache, Disposable
-{
+public class DefaultPluginRealmCache implements PluginRealmCache, Disposable {
     /**
      * CacheKey
      */
-    protected static class CacheKey
-        implements Key
-    {
+    protected static class CacheKey implements Key {
 
         private final Plugin plugin;
 
@@ -73,144 +68,149 @@
 
         private final int hashCode;
 
-        public CacheKey( Plugin plugin, ClassLoader parentRealm, Map<String, ClassLoader> foreignImports,
-                         DependencyFilter dependencyFilter, List<RemoteRepository> repositories,
-                         RepositorySystemSession session )
-        {
+        public CacheKey(
+                Plugin plugin,
+                ClassLoader parentRealm,
+                Map<String, ClassLoader> foreignImports,
+                DependencyFilter dependencyFilter,
+                List<RemoteRepository> repositories,
+                RepositorySystemSession session) {
             this.plugin = plugin.clone();
-            this.workspace = RepositoryUtils.getWorkspace( session );
+            this.workspace = RepositoryUtils.getWorkspace(session);
             this.localRepo = session.getLocalRepository();
-            this.repositories = new ArrayList<>( repositories.size() );
-            for ( RemoteRepository repository : repositories )
-            {
-                if ( repository.isRepositoryManager() )
-                {
-                    this.repositories.addAll( repository.getMirroredRepositories() );
-                }
-                else
-                {
-                    this.repositories.add( repository );
+            this.repositories = new ArrayList<>(repositories.size());
+            for (RemoteRepository repository : repositories) {
+                if (repository.isRepositoryManager()) {
+                    this.repositories.addAll(repository.getMirroredRepositories());
+                } else {
+                    this.repositories.add(repository);
                 }
             }
             this.parentRealm = parentRealm;
-            this.foreignImports =
-                ( foreignImports != null ) ? foreignImports : Collections.emptyMap();
+            this.foreignImports = (foreignImports != null) ? foreignImports : Collections.emptyMap();
             this.filter = dependencyFilter;
 
             int hash = 17;
-            hash = hash * 31 + CacheUtils.pluginHashCode( plugin );
-            hash = hash * 31 + Objects.hashCode( workspace );
-            hash = hash * 31 + Objects.hashCode( localRepo );
-            hash = hash * 31 + RepositoryUtils.repositoriesHashCode( repositories );
-            hash = hash * 31 + Objects.hashCode( parentRealm );
+            hash = hash * 31 + CacheUtils.pluginHashCode(plugin);
+            hash = hash * 31 + Objects.hashCode(workspace);
+            hash = hash * 31 + Objects.hashCode(localRepo);
+            hash = hash * 31 + RepositoryUtils.repositoriesHashCode(repositories);
+            hash = hash * 31 + Objects.hashCode(parentRealm);
             hash = hash * 31 + this.foreignImports.hashCode();
-            hash = hash * 31 + Objects.hashCode( dependencyFilter );
+            hash = hash * 31 + Objects.hashCode(dependencyFilter);
             this.hashCode = hash;
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return plugin.getId();
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( o == this )
-            {
+        public boolean equals(Object o) {
+            if (o == this) {
                 return true;
             }
 
-            if ( !( o instanceof CacheKey ) )
-            {
+            if (!(o instanceof CacheKey)) {
                 return false;
             }
 
             CacheKey that = (CacheKey) o;
 
             return parentRealm == that.parentRealm
-                && CacheUtils.pluginEquals( plugin, that.plugin )
-                && Objects.equals( workspace, that.workspace )
-                && Objects.equals( localRepo, that.localRepo )
-                && RepositoryUtils.repositoriesEquals( this.repositories, that.repositories )
-                && Objects.equals( filter, that.filter )
-                && Objects.equals( foreignImports, that.foreignImports );
+                    && CacheUtils.pluginEquals(plugin, that.plugin)
+                    && Objects.equals(workspace, that.workspace)
+                    && Objects.equals(localRepo, that.localRepo)
+                    && RepositoryUtils.repositoriesEquals(this.repositories, that.repositories)
+                    && Objects.equals(filter, that.filter)
+                    && Objects.equals(foreignImports, that.foreignImports);
         }
     }
 
     protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
 
-    public Key createKey( Plugin plugin, ClassLoader parentRealm, Map<String, ClassLoader> foreignImports,
-                          DependencyFilter dependencyFilter, List<RemoteRepository> repositories,
-                          RepositorySystemSession session )
-    {
-        return new CacheKey( plugin, parentRealm, foreignImports, dependencyFilter, repositories, session );
+    public Key createKey(
+            Plugin plugin,
+            ClassLoader parentRealm,
+            Map<String, ClassLoader> foreignImports,
+            DependencyFilter dependencyFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session) {
+        return new CacheKey(plugin, parentRealm, foreignImports, dependencyFilter, repositories, session);
     }
 
-    public CacheRecord get( Key key )
-    {
-        return cache.get( key );
+    public CacheRecord get(Key key) {
+        return cache.get(key);
     }
 
-    public CacheRecord put( Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts )
-    {
-        Objects.requireNonNull( pluginRealm, "pluginRealm cannot be null" );
-        Objects.requireNonNull( pluginArtifacts, "pluginArtifacts cannot be null" );
+    @Override
+    public CacheRecord get(Key key, PluginRealmSupplier supplier)
+            throws PluginResolutionException, PluginContainerException {
+        try {
+            return cache.computeIfAbsent(key, k -> {
+                try {
+                    return supplier.load();
+                } catch (PluginResolutionException | PluginContainerException e) {
+                    throw new RuntimeException(e);
+                }
+            });
+        } catch (RuntimeException e) {
+            if (e.getCause() instanceof PluginResolutionException) {
+                throw (PluginResolutionException) e.getCause();
+            }
+            if (e.getCause() instanceof PluginContainerException) {
+                throw (PluginContainerException) e.getCause();
+            }
+            throw e;
+        }
+    }
 
-        if ( cache.containsKey( key ) )
-        {
-            throw new IllegalStateException( "Duplicate plugin realm for plugin " + key );
+    public CacheRecord put(Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts) {
+        Objects.requireNonNull(pluginRealm, "pluginRealm cannot be null");
+        Objects.requireNonNull(pluginArtifacts, "pluginArtifacts cannot be null");
+
+        if (cache.containsKey(key)) {
+            throw new IllegalStateException("Duplicate plugin realm for plugin " + key);
         }
 
-        CacheRecord record = new CacheRecord( pluginRealm, pluginArtifacts );
+        CacheRecord record = new CacheRecord(pluginRealm, pluginArtifacts);
 
-        cache.put( key, record );
+        cache.put(key, record);
 
         return record;
     }
 
-    public void flush()
-    {
-        for ( CacheRecord record : cache.values() )
-        {
+    public void flush() {
+        for (CacheRecord record : cache.values()) {
             ClassRealm realm = record.getRealm();
-            try
-            {
-                realm.getWorld().disposeRealm( realm.getId() );
-            }
-            catch ( NoSuchRealmException e )
-            {
+            try {
+                realm.getWorld().disposeRealm(realm.getId());
+            } catch (NoSuchRealmException e) {
                 // ignore
             }
         }
         cache.clear();
     }
 
-    protected static int pluginHashCode( Plugin plugin )
-    {
-        return CacheUtils.pluginHashCode( plugin );
+    protected static int pluginHashCode(Plugin plugin) {
+        return CacheUtils.pluginHashCode(plugin);
     }
 
-    protected static boolean pluginEquals( Plugin a, Plugin b )
-    {
-        return CacheUtils.pluginEquals( a, b );
+    protected static boolean pluginEquals(Plugin a, Plugin b) {
+        return CacheUtils.pluginEquals(a, b);
     }
 
-    public void register( MavenProject project, Key key, CacheRecord record )
-    {
+    public void register(MavenProject project, Key key, CacheRecord record) {
         // default cache does not track plugin usage
     }
 
-    public void dispose()
-    {
+    public void dispose() {
         flush();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/ExtensionRealmCache.java b/maven-core/src/main/java/org/apache/maven/plugin/ExtensionRealmCache.java
index 4d01aca..22bb57e 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/ExtensionRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/ExtensionRealmCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 
@@ -31,24 +30,19 @@
  * for technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted
  * without prior notice.
  *
- * @author Igor Fedorenko
- * @author Benjamin Bentmann
  */
-public interface ExtensionRealmCache
-{
+public interface ExtensionRealmCache {
     /**
      * A cache key.
      */
-    interface Key
-    {
+    interface Key {
         // marker interface for cache keys
     }
 
     /**
      * CacheRecord
      */
-    class CacheRecord
-    {
+    class CacheRecord {
 
         private final ClassRealm realm;
 
@@ -56,35 +50,31 @@
 
         private final List<Artifact> artifacts;
 
-        CacheRecord( ClassRealm realm, ExtensionDescriptor descriptor, List<Artifact> artifacts )
-        {
+        CacheRecord(ClassRealm realm, ExtensionDescriptor descriptor, List<Artifact> artifacts) {
             this.realm = realm;
             this.descriptor = descriptor;
             this.artifacts = artifacts;
         }
 
-        public ClassRealm getRealm()
-        {
+        public ClassRealm getRealm() {
             return realm;
         }
 
-        public ExtensionDescriptor getDescriptor()
-        {
+        public ExtensionDescriptor getDescriptor() {
             return descriptor;
         }
 
-        public List<Artifact> getArtifacts()
-        {
+        public List<Artifact> getArtifacts() {
             return artifacts;
         }
     }
 
-    Key createKey( List<Artifact> extensionArtifacts );
+    Key createKey(List<Artifact> extensionArtifacts);
 
-    CacheRecord get( Key key );
+    CacheRecord get(Key key);
 
-    CacheRecord put( Key key, ClassRealm extensionRealm, ExtensionDescriptor extensionDescriptor,
-                     List<Artifact> artifacts );
+    CacheRecord put(
+            Key key, ClassRealm extensionRealm, ExtensionDescriptor extensionDescriptor, List<Artifact> artifacts);
 
     void flush();
 
@@ -96,6 +86,5 @@
      * @param project The project that employs the plugin realm, must not be {@code null}.
      * @param record The cache record being used for the project, must not be {@code null}.
      */
-    void register( MavenProject project, Key key, CacheRecord record );
-
+    void register(MavenProject project, Key key, CacheRecord record);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginDescriptorException.java b/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginDescriptorException.java
index 3a2e476..c93c6a3 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginDescriptorException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginDescriptorException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,30 +16,25 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 
 /**
  * InvalidPluginDescriptorException
  */
-public class InvalidPluginDescriptorException
-    extends Exception
-{
+public class InvalidPluginDescriptorException extends Exception {
 
-    public InvalidPluginDescriptorException( String message, List<String> errors )
-    {
-        super( toMessage( message, errors ) );
+    public InvalidPluginDescriptorException(String message, List<String> errors) {
+        super(toMessage(message, errors));
     }
 
-    private static String toMessage( String message, List<String> errors )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-        buffer.append( message );
-        for ( String error : errors )
-        {
-            buffer.append( ", " ).append( error );
+    private static String toMessage(String message, List<String> errors) {
+        StringBuilder buffer = new StringBuilder(256);
+        buffer.append(message);
+        for (String error : errors) {
+            buffer.append(", ").append(error);
         }
         return buffer.toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginException.java b/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginException.java
index b89fc86..4cc6e95 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/InvalidPluginException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.project.ProjectBuildingException;
 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
@@ -25,24 +24,17 @@
 /**
  * Thrown when a plugin is not internally consistent.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class InvalidPluginException
-    extends Exception
-{
-    public InvalidPluginException( String message, ProjectBuildingException e )
-    {
-        super( message, e );
+public class InvalidPluginException extends Exception {
+    public InvalidPluginException(String message, ProjectBuildingException e) {
+        super(message, e);
     }
 
-    public InvalidPluginException( String message, InvalidDependencyVersionException e )
-    {
-        super( message, e );
+    public InvalidPluginException(String message, InvalidDependencyVersionException e) {
+        super(message, e);
     }
 
-    public InvalidPluginException( String message )
-    {
-        super( message );
+    public InvalidPluginException(String message) {
+        super(message);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/LegacySupport.java b/maven-core/src/main/java/org/apache/maven/plugin/LegacySupport.java
index b246ed1..151d9be 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/LegacySupport.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/LegacySupport.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.execution.MavenSession;
 import org.eclipse.aether.RepositorySystemSession;
@@ -28,10 +27,8 @@
  * particular, this interface can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface LegacySupport
-{
+public interface LegacySupport {
 
     /**
      * Sets the currently active session. Some legacy components are basically stateful and their API is missing
@@ -40,7 +37,7 @@
      *
      * @param session The currently active session, may be {@code null}.
      */
-    void setSession( MavenSession session );
+    void setSession(MavenSession session);
 
     /**
      * Gets the currently active session.
@@ -55,5 +52,4 @@
      * @return The currently active repository session or {@code null} if none.
      */
     RepositorySystemSession getRepositorySession();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginManager.java
index 5616ad2..9812aa3 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginManager.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 
@@ -36,10 +35,8 @@
  * plugins as well as special purpose plugins like reports.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface MavenPluginManager
-{
+public interface MavenPluginManager {
 
     /**
      * Retrieves the descriptor for the specified plugin from its main artifact.
@@ -50,9 +47,9 @@
      * @param session The repository session to use for resolving the plugin's main artifact, must not be {@code null}.
      * @return The plugin descriptor, never {@code null}.
      */
-    PluginDescriptor getPluginDescriptor( Plugin plugin, List<RemoteRepository> repositories,
-                                          RepositorySystemSession session )
-        throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException;
+    PluginDescriptor getPluginDescriptor(
+            Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException;
 
     /**
      * Retrieves the descriptor for the specified plugin goal from the plugin's main artifact.
@@ -64,18 +61,27 @@
      * @param session The repository session to use for resolving the plugin's main artifact, must not be {@code null}.
      * @return The mojo descriptor, never {@code null}.
      */
-    MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
-                                      RepositorySystemSession session )
-        throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        InvalidPluginDescriptorException;
+    MojoDescriptor getMojoDescriptor(
+            Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    InvalidPluginDescriptorException;
 
     /**
      * Verifies the specified plugin is compatible with the current Maven runtime.
      *
      * @param pluginDescriptor The descriptor of the plugin to check, must not be {@code null}.
+     * @deprecated Use {@link #checkPrerequisites(PluginDescriptor)} instead.
      */
-    void checkRequiredMavenVersion( PluginDescriptor pluginDescriptor )
-        throws PluginIncompatibleException;
+    @Deprecated
+    void checkRequiredMavenVersion(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException;
+
+    /**
+     * Verifies that the specified plugin's prerequisites are met.
+     *
+     * @param pluginDescriptor The descriptor of the plugin to check, must not be {@code null}.
+     * @since 4.0.0
+     */
+    void checkPrerequisites(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException;
 
     /**
      * Sets up the class realm for the specified plugin. Both the class realm and the plugin artifacts that constitute
@@ -89,18 +95,21 @@
      * @param imports The packages/types to import from the parent realm, may be {@code null}.
      * @param filter The filter used to exclude certain plugin dependencies, may be {@code null}.
      */
-    void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent,
-                           List<String> imports, DependencyFilter filter )
-        throws PluginResolutionException, PluginContainerException;
+    void setupPluginRealm(
+            PluginDescriptor pluginDescriptor,
+            MavenSession session,
+            ClassLoader parent,
+            List<String> imports,
+            DependencyFilter filter)
+            throws PluginResolutionException, PluginContainerException;
 
     /**
      * Sets up class realm for the specified build extensions plugin.
      *
      * @since 3.3.0
      */
-    ExtensionRealmCache.CacheRecord setupExtensionsRealm( MavenProject project, Plugin plugin,
-                                                          RepositorySystemSession session )
-        throws PluginManagerException;
+    ExtensionRealmCache.CacheRecord setupExtensionsRealm(
+            MavenProject project, Plugin plugin, RepositorySystemSession session) throws PluginManagerException;
 
     /**
      * Looks up the mojo for the specified mojo execution and populates its parameters from the configuration given by
@@ -114,8 +123,8 @@
      * @param mojoExecution The mojo execution to retrieve the mojo for, must not be {@code null}.
      * @return The ready-to-execute mojo, never {@code null}.
      */
-    <T> T getConfiguredMojo( Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution )
-        throws PluginConfigurationException, PluginContainerException;
+    <T> T getConfiguredMojo(Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution)
+            throws PluginConfigurationException, PluginContainerException;
 
     /**
      * Releases the specified mojo back to the container.
@@ -123,6 +132,5 @@
      * @param mojo The mojo to release, may be {@code null}.
      * @param mojoExecution The mojo execution the mojo was originally retrieved for, must not be {@code null}.
      */
-    void releaseMojo( Object mojo, MojoExecution mojoExecution );
-
+    void releaseMojo(Object mojo, MojoExecution mojoExecution);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginPrerequisitesChecker.java b/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginPrerequisitesChecker.java
new file mode 100644
index 0000000..48cdda5
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/MavenPluginPrerequisitesChecker.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin;
+
+import java.util.function.Consumer;
+
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+
+/**
+ * Service responsible for checking if plugin's prerequisites are met.
+ */
+@FunctionalInterface
+public interface MavenPluginPrerequisitesChecker extends Consumer<PluginDescriptor> {
+    /**
+     *
+     * @param pluginDescriptor
+     * @throws IllegalStateException in case the checked prerequisites are not met
+     */
+    void accept(PluginDescriptor pluginDescriptor);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/MojoExecution.java b/maven-core/src/main/java/org/apache/maven/plugin/MojoExecution.java
index fa72c18..fd8835a 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/MojoExecution.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/MojoExecution.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,20 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * MojoExecution
  */
-public class MojoExecution
-{
+public class MojoExecution {
 
     private Plugin plugin;
 
@@ -41,13 +39,12 @@
 
     private MojoDescriptor mojoDescriptor;
 
-    private Xpp3Dom configuration;
+    private org.codehaus.plexus.util.xml.Xpp3Dom configuration;
 
     /**
      * Describes the source of an execution.
      */
-    public enum Source
-    {
+    public enum Source {
 
         /**
          * An execution that originates from the direct invocation of a goal from the CLI.
@@ -74,167 +71,148 @@
      */
     private Map<String, List<MojoExecution>> forkedExecutions = new LinkedHashMap<>();
 
-    public MojoExecution( Plugin plugin, String goal, String executionId )
-    {
+    public MojoExecution(Plugin plugin, String goal, String executionId) {
         this.plugin = plugin;
         this.goal = goal;
         this.executionId = executionId;
     }
 
-    public MojoExecution( MojoDescriptor mojoDescriptor )
-    {
+    public MojoExecution(MojoDescriptor mojoDescriptor) {
         this.mojoDescriptor = mojoDescriptor;
         this.executionId = null;
         this.configuration = null;
     }
 
-    public MojoExecution( MojoDescriptor mojoDescriptor, String executionId, Source source )
-    {
+    public MojoExecution(MojoDescriptor mojoDescriptor, String executionId, Source source) {
         this.mojoDescriptor = mojoDescriptor;
         this.executionId = executionId;
         this.configuration = null;
         this.source = source;
     }
 
-    public MojoExecution( MojoDescriptor mojoDescriptor, String executionId )
-    {
+    public MojoExecution(MojoDescriptor mojoDescriptor, String executionId) {
         this.mojoDescriptor = mojoDescriptor;
         this.executionId = executionId;
         this.configuration = null;
     }
 
-    public MojoExecution( MojoDescriptor mojoDescriptor, Xpp3Dom configuration )
-    {
+    public MojoExecution(MojoDescriptor mojoDescriptor, org.codehaus.plexus.util.xml.Xpp3Dom configuration) {
         this.mojoDescriptor = mojoDescriptor;
         this.configuration = configuration;
         this.executionId = null;
     }
 
+    public MojoExecution(MojoDescriptor mojoDescriptor, XmlNode configuration) {
+        this.mojoDescriptor = mojoDescriptor;
+        this.configuration = new org.codehaus.plexus.util.xml.Xpp3Dom(configuration);
+        this.executionId = null;
+    }
+
     /**
      * Gets the source of this execution.
      *
      * @return The source of this execution or {@code null} if unknown.
      */
-    public Source getSource()
-    {
+    public Source getSource() {
         return source;
     }
 
-    public String getExecutionId()
-    {
+    public String getExecutionId() {
         return executionId;
     }
 
-    public Plugin getPlugin()
-    {
-        if ( mojoDescriptor != null )
-        {
+    public Plugin getPlugin() {
+        if (mojoDescriptor != null) {
             return mojoDescriptor.getPluginDescriptor().getPlugin();
         }
 
         return plugin;
     }
 
-    public MojoDescriptor getMojoDescriptor()
-    {
+    public MojoDescriptor getMojoDescriptor() {
         return mojoDescriptor;
     }
 
-    public Xpp3Dom getConfiguration()
-    {
+    public org.codehaus.plexus.util.xml.Xpp3Dom getConfiguration() {
         return configuration;
     }
 
-    public void setConfiguration( Xpp3Dom configuration )
-    {
+    public void setConfiguration(org.codehaus.plexus.util.xml.Xpp3Dom configuration) {
         this.configuration = configuration;
     }
 
-    public String identify()
-    {
-        StringBuilder sb = new StringBuilder( 256 );
+    public void setConfiguration(XmlNode configuration) {
+        this.configuration = configuration != null ? new org.codehaus.plexus.util.xml.Xpp3Dom(configuration) : null;
+    }
 
-        sb.append( executionId );
-        sb.append( configuration.toString() );
+    public String identify() {
+        StringBuilder sb = new StringBuilder(256);
+
+        sb.append(executionId);
+        sb.append(configuration.toString());
 
         return sb.toString();
     }
 
-    public String getLifecyclePhase()
-    {
+    public String getLifecyclePhase() {
         return lifecyclePhase;
     }
 
-    public void setLifecyclePhase( String lifecyclePhase )
-    {
+    public void setLifecyclePhase(String lifecyclePhase) {
         this.lifecyclePhase = lifecyclePhase;
     }
 
     @Override
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder( 128 );
-        if ( mojoDescriptor != null )
-        {
-            buffer.append( mojoDescriptor.getId() );
+    public String toString() {
+        StringBuilder buffer = new StringBuilder(128);
+        if (mojoDescriptor != null) {
+            buffer.append(mojoDescriptor.getId());
         }
-        buffer.append( " {execution: " ).append( executionId ).append( '}' );
+        buffer.append(" {execution: ").append(executionId).append('}');
         return buffer.toString();
     }
 
-    public String getGroupId()
-    {
-        if ( mojoDescriptor != null )
-        {
+    public String getGroupId() {
+        if (mojoDescriptor != null) {
             return mojoDescriptor.getPluginDescriptor().getGroupId();
         }
 
         return plugin.getGroupId();
     }
 
-    public String getArtifactId()
-    {
-        if ( mojoDescriptor != null )
-        {
+    public String getArtifactId() {
+        if (mojoDescriptor != null) {
             return mojoDescriptor.getPluginDescriptor().getArtifactId();
         }
 
         return plugin.getArtifactId();
     }
 
-    public String getVersion()
-    {
-        if ( mojoDescriptor != null )
-        {
+    public String getVersion() {
+        if (mojoDescriptor != null) {
             return mojoDescriptor.getPluginDescriptor().getVersion();
         }
 
         return plugin.getVersion();
     }
 
-    public String getGoal()
-    {
-        if ( mojoDescriptor != null )
-        {
+    public String getGoal() {
+        if (mojoDescriptor != null) {
             return mojoDescriptor.getGoal();
         }
 
         return goal;
     }
 
-    public void setMojoDescriptor( MojoDescriptor mojoDescriptor )
-    {
+    public void setMojoDescriptor(MojoDescriptor mojoDescriptor) {
         this.mojoDescriptor = mojoDescriptor;
     }
 
-    public Map<String, List<MojoExecution>> getForkedExecutions()
-    {
+    public Map<String, List<MojoExecution>> getForkedExecutions() {
         return forkedExecutions;
     }
 
-    public void setForkedExecutions( String projectKey, List<MojoExecution> forkedExecutions )
-    {
-        this.forkedExecutions.put( projectKey, forkedExecutions );
+    public void setForkedExecutions(String projectKey, List<MojoExecution> forkedExecutions) {
+        this.forkedExecutions.put(projectKey, forkedExecutions);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/MojoExecutionRunner.java b/maven-core/src/main/java/org/apache/maven/plugin/MojoExecutionRunner.java
index eab5585..f48a469 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/MojoExecutionRunner.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/MojoExecutionRunner.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,19 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 
 /**
  * Provides context for mojo execution. Invocation of {@link #run(MojoExecution)} will result in actual execution
  */
-public interface MojoExecutionRunner
-{
+public interface MojoExecutionRunner {
     /**
      * Runs mojo execution
      *
      * @param execution mojo execution
      * @throws LifecycleExecutionException
      */
-    void run( MojoExecution execution ) throws LifecycleExecutionException;
+    void run(MojoExecution execution) throws LifecycleExecutionException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/MojosExecutionStrategy.java b/maven-core/src/main/java/org/apache/maven/plugin/MojosExecutionStrategy.java
index e4babf6..aa235eb 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/MojosExecutionStrategy.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/MojosExecutionStrategy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
+
+import java.util.List;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 
-import java.util.List;
-
 /**
  * Interface allows overriding default mojo execution strategy For example it is possible wrap some mojo execution to
  * decorate default functionality or skip some executions
  */
-public interface MojosExecutionStrategy
-{
+public interface MojosExecutionStrategy {
 
     /**
      * Entry point to the execution strategy
@@ -39,7 +37,6 @@
      * @param mojoExecutionRunner mojo execution task which must be invoked by a strategy to actually run it
      * @throws LifecycleExecutionException
      */
-    void execute( List<MojoExecution> mojos, MavenSession session, MojoExecutionRunner mojoExecutionRunner )
+    void execute(List<MojoExecution> mojos, MavenSession session, MojoExecutionRunner mojoExecutionRunner)
             throws LifecycleExecutionException;
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginArtifactsCache.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginArtifactsCache.java
index 11f5d70..6f14c17 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginArtifactsCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginArtifactsCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 
@@ -33,61 +32,55 @@
  * technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
  * prior notice.
  *
- * @author Igor Fedorenko
- * @author Benjamin Bentmann
  */
-public interface PluginArtifactsCache
-{
+public interface PluginArtifactsCache {
 
     /**
      * A cache key.
      */
-    interface Key
-    {
+    interface Key {
         // marker interface for cache keys
     }
 
     /**
      * CacheRecord
      */
-    class CacheRecord
-    {
+    class CacheRecord {
 
         private final List<Artifact> artifacts;
 
-        public List<Artifact> getArtifacts()
-        {
+        public List<Artifact> getArtifacts() {
             return artifacts;
         }
 
-        public PluginResolutionException getException()
-        {
+        public PluginResolutionException getException() {
             return exception;
         }
 
         private final PluginResolutionException exception;
 
-        public CacheRecord( List<Artifact> artifacts )
-        {
+        public CacheRecord(List<Artifact> artifacts) {
             this.artifacts = artifacts;
             this.exception = null;
         }
 
-        public CacheRecord( PluginResolutionException exception )
-        {
+        public CacheRecord(PluginResolutionException exception) {
             this.artifacts = null;
             this.exception = exception;
         }
     }
 
-    Key createKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepository> repositories,
-                   RepositorySystemSession session );
+    Key createKey(
+            Plugin plugin,
+            DependencyFilter extensionFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session);
 
-    CacheRecord get( Key key ) throws PluginResolutionException;
+    CacheRecord get(Key key) throws PluginResolutionException;
 
-    CacheRecord put( Key key, List<Artifact> pluginArtifacts );
+    CacheRecord put(Key key, List<Artifact> pluginArtifacts);
 
-    CacheRecord put( Key key, PluginResolutionException e );
+    CacheRecord put(Key key, PluginResolutionException e);
 
     void flush();
 
@@ -99,6 +92,5 @@
      * @param project The project that employs the plugin realm, must not be {@code null}.
      * @param record The cache record being used for the project, must not be {@code null}.
      */
-    void register( MavenProject project, Key cacheKey, CacheRecord record );
-
+    void register(MavenProject project, Key cacheKey, CacheRecord record);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginConfigurationException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginConfigurationException.java
index f4dcffc..408e9c7 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginConfigurationException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginConfigurationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.codehaus.plexus.component.configurator.ComponentConfigurationException;
@@ -25,49 +24,41 @@
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 
 /**
- * @author Jason van Zyl
  */
-public class PluginConfigurationException
-    extends Exception
-{
+public class PluginConfigurationException extends Exception {
     private PluginDescriptor pluginDescriptor;
 
     private String originalMessage;
 
-    public PluginConfigurationException( PluginDescriptor pluginDescriptor, String originalMessage )
-    {
-        super( originalMessage );
+    public PluginConfigurationException(PluginDescriptor pluginDescriptor, String originalMessage) {
+        super(originalMessage);
         this.pluginDescriptor = pluginDescriptor;
         this.originalMessage = originalMessage;
     }
 
-    public PluginConfigurationException( PluginDescriptor pluginDescriptor, String originalMessage, Throwable cause )
-    {
-        super( originalMessage, cause );
+    public PluginConfigurationException(PluginDescriptor pluginDescriptor, String originalMessage, Throwable cause) {
+        super(originalMessage, cause);
         this.pluginDescriptor = pluginDescriptor;
         this.originalMessage = originalMessage;
     }
 
-    public PluginConfigurationException( PluginDescriptor pluginDescriptor, String originalMessage,
-                                         ExpressionEvaluationException cause )
-    {
-        super( originalMessage, cause );
+    public PluginConfigurationException(
+            PluginDescriptor pluginDescriptor, String originalMessage, ExpressionEvaluationException cause) {
+        super(originalMessage, cause);
         this.pluginDescriptor = pluginDescriptor;
         this.originalMessage = originalMessage;
     }
 
-    public PluginConfigurationException( PluginDescriptor pluginDescriptor, String originalMessage,
-                                         ComponentConfigurationException cause )
-    {
-        super( originalMessage, cause );
+    public PluginConfigurationException(
+            PluginDescriptor pluginDescriptor, String originalMessage, ComponentConfigurationException cause) {
+        super(originalMessage, cause);
         this.pluginDescriptor = pluginDescriptor;
         this.originalMessage = originalMessage;
     }
 
-    public PluginConfigurationException( PluginDescriptor pluginDescriptor, String originalMessage,
-                                         ComponentLookupException cause )
-    {
-        super( originalMessage, cause );
+    public PluginConfigurationException(
+            PluginDescriptor pluginDescriptor, String originalMessage, ComponentLookupException cause) {
+        super(originalMessage, cause);
         this.pluginDescriptor = pluginDescriptor;
         this.originalMessage = originalMessage;
     }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java
index 91c49f2..27bde88 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginContainerException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
@@ -33,56 +32,47 @@
  * execution failed; a message detailing the problem; the ClassRealm used to
  * look up the plugin; and the Plexus exception that caused this error.
  *
- * @author jdcasey
  *
  */
-public class PluginContainerException
-    extends PluginManagerException
-{
+public class PluginContainerException extends PluginManagerException {
 
     private ClassRealm pluginRealm;
 
-    public PluginContainerException( MojoDescriptor mojoDescriptor, ClassRealm pluginRealm, String message,
-                                     Throwable e )
-    {
-        super( mojoDescriptor, message, e );
+    public PluginContainerException(
+            MojoDescriptor mojoDescriptor, ClassRealm pluginRealm, String message, Throwable e) {
+        super(mojoDescriptor, message, e);
 
         this.pluginRealm = pluginRealm;
     }
 
-    public PluginContainerException( MojoDescriptor mojoDescriptor, ClassRealm pluginRealm, String message,
-                                     ComponentLookupException e )
-    {
-        super( mojoDescriptor, message, e );
+    public PluginContainerException(
+            MojoDescriptor mojoDescriptor, ClassRealm pluginRealm, String message, ComponentLookupException e) {
+        super(mojoDescriptor, message, e);
 
         this.pluginRealm = pluginRealm;
     }
 
-    public PluginContainerException( Plugin plugin, ClassRealm pluginRealm, String message, Throwable e )
-    {
-        super( plugin, message, e );
+    public PluginContainerException(Plugin plugin, ClassRealm pluginRealm, String message, Throwable e) {
+        super(plugin, message, e);
 
         this.pluginRealm = pluginRealm;
     }
 
-    public PluginContainerException( Plugin plugin, ClassRealm pluginRealm, String message,
-                                     PlexusConfigurationException e )
-    {
-        super( plugin, message, e );
+    public PluginContainerException(
+            Plugin plugin, ClassRealm pluginRealm, String message, PlexusConfigurationException e) {
+        super(plugin, message, e);
 
         this.pluginRealm = pluginRealm;
     }
 
-    public PluginContainerException( Plugin plugin, ClassRealm pluginRealm, String message,
-                                     ComponentRepositoryException e )
-    {
-        super( plugin, message, e );
+    public PluginContainerException(
+            Plugin plugin, ClassRealm pluginRealm, String message, ComponentRepositoryException e) {
+        super(plugin, message, e);
 
         this.pluginRealm = pluginRealm;
     }
 
-    public ClassRealm getPluginRealm()
-    {
+    public ClassRealm getPluginRealm() {
         return pluginRealm;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java
index 08b4f1b..0761273 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 
@@ -34,25 +33,30 @@
  * prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginDescriptorCache
-{
+public interface PluginDescriptorCache {
 
     /**
      * A cache key.
      */
-    interface Key
-    {
+    interface Key {
         // marker interface for cache keys
     }
 
-    Key createKey( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session );
+    @FunctionalInterface
+    interface PluginDescriptorSupplier {
+        PluginDescriptor load()
+                throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException;
+    }
 
-    void put( Key key, PluginDescriptor pluginDescriptor );
+    Key createKey(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session);
 
-    PluginDescriptor get( Key key );
+    void put(Key key, PluginDescriptor pluginDescriptor);
+
+    PluginDescriptor get(Key key);
+
+    PluginDescriptor get(Key key, PluginDescriptorSupplier supplier)
+            throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException;
 
     void flush();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorParsingException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorParsingException.java
index 7d57b36..246adea 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorParsingException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginDescriptorParsingException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,41 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.model.Plugin;
 
 /**
- * @author Jason van Zyl
  */
-public class PluginDescriptorParsingException
-    extends Exception
-{
+public class PluginDescriptorParsingException extends Exception {
 
-    public PluginDescriptorParsingException( Plugin plugin, String descriptorLocation, Throwable e )
-    {
-        super( createMessage( plugin, descriptorLocation, e ), e );
+    public PluginDescriptorParsingException(Plugin plugin, String descriptorLocation, Throwable e) {
+        super(createMessage(plugin, descriptorLocation, e), e);
     }
 
-    private static String createMessage( Plugin plugin, String descriptorLocation, Throwable e )
-    {
+    private static String createMessage(Plugin plugin, String descriptorLocation, Throwable e) {
         String message = "Failed to parse plugin descriptor";
 
-        if ( plugin != null )
-        {
+        if (plugin != null) {
             message += " for " + plugin.getId();
         }
 
-        if ( descriptorLocation != null )
-        {
+        if (descriptorLocation != null) {
             message += " (" + descriptorLocation + ")";
         }
 
-        if ( e != null )
-        {
+        if (e != null) {
             message += ": " + e.getMessage();
         }
 
         return message;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginExecutionException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginExecutionException.java
index a99fbbc..63c77cb 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginExecutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginExecutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,76 +16,60 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.project.DuplicateArtifactAttachmentException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Exception in the plugin manager.
  */
-public class PluginExecutionException
-    extends PluginManagerException
-{
+public class PluginExecutionException extends PluginManagerException {
 
     private final MojoExecution mojoExecution;
 
-    public PluginExecutionException( MojoExecution mojoExecution, MavenProject project, String message )
-    {
-        super( mojoExecution.getMojoDescriptor(), project, message );
+    public PluginExecutionException(MojoExecution mojoExecution, MavenProject project, String message) {
+        super(mojoExecution.getMojoDescriptor(), project, message);
         this.mojoExecution = mojoExecution;
     }
 
-    public PluginExecutionException( MojoExecution mojoExecution, MavenProject project, String message,
-                                     Throwable cause )
-    {
-        super( mojoExecution.getMojoDescriptor(), project, message, cause );
+    public PluginExecutionException(
+            MojoExecution mojoExecution, MavenProject project, String message, Throwable cause) {
+        super(mojoExecution.getMojoDescriptor(), project, message, cause);
         this.mojoExecution = mojoExecution;
     }
 
-    public PluginExecutionException( MojoExecution mojoExecution, MavenProject project, Exception cause )
-    {
-        super( mojoExecution.getMojoDescriptor(), project, constructMessage( mojoExecution, cause ), cause );
+    public PluginExecutionException(MojoExecution mojoExecution, MavenProject project, Exception cause) {
+        super(mojoExecution.getMojoDescriptor(), project, constructMessage(mojoExecution, cause), cause);
         this.mojoExecution = mojoExecution;
     }
 
-    public PluginExecutionException( MojoExecution mojoExecution, MavenProject project,
-                                     DuplicateArtifactAttachmentException cause )
-    {
-        super( mojoExecution.getMojoDescriptor(), project, constructMessage( mojoExecution, cause ), cause );
+    public PluginExecutionException(
+            MojoExecution mojoExecution, MavenProject project, DuplicateArtifactAttachmentException cause) {
+        super(mojoExecution.getMojoDescriptor(), project, constructMessage(mojoExecution, cause), cause);
         this.mojoExecution = mojoExecution;
     }
 
-    public MojoExecution getMojoExecution()
-    {
+    public MojoExecution getMojoExecution() {
         return mojoExecution;
     }
 
-    private static String constructMessage( MojoExecution mojoExecution, Throwable cause )
-    {
+    private static String constructMessage(MojoExecution mojoExecution, Throwable cause) {
         String message;
 
-        if ( mojoExecution != null )
-        {
-            message =
-                "Execution " + mojoExecution.getExecutionId() + " of goal " + mojoExecution.getMojoDescriptor().getId()
-                    + " failed";
-        }
-        else
-        {
+        if (mojoExecution != null) {
+            message = "Execution " + mojoExecution.getExecutionId() + " of goal "
+                    + mojoExecution.getMojoDescriptor().getId() + " failed";
+        } else {
             message = "Mojo execution failed";
         }
 
-        if ( cause != null && StringUtils.isNotEmpty( cause.getMessage() ) )
-        {
+        if (cause != null && cause.getMessage() != null && !cause.getMessage().isEmpty()) {
             message += ": " + cause.getMessage();
-        }
-        else
-        {
+        } else {
             message += ".";
         }
 
         return message;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginIncompatibleException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginIncompatibleException.java
index f7b53eb..d3c5edb 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginIncompatibleException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginIncompatibleException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.model.Plugin;
 
 /**
  * Signals a plugin which is not compatible with the current Maven runtime.
  */
-public class PluginIncompatibleException
-    extends PluginManagerException
-{
+public class PluginIncompatibleException extends PluginManagerException {
 
-    public PluginIncompatibleException( Plugin plugin, String message )
-    {
-        super( plugin, message, (Throwable) null );
+    public PluginIncompatibleException(Plugin plugin, String message) {
+        this(plugin, message, null);
     }
 
+    public PluginIncompatibleException(Plugin plugin, String message, Throwable cause) {
+        super(plugin, message, cause);
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginLoaderException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginLoaderException.java
index 161e1c4..743aaec 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginLoaderException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginLoaderException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
 import org.apache.maven.artifact.resolver.ArtifactResolutionException;
@@ -31,94 +30,76 @@
  * Signifies a failure to load a plugin. This is used to abstract the specific errors which may be
  * encountered at lower levels, and provide a dependable interface to the plugin-loading framework.
  *
- * @author jdcasey
  *
  */
-public class PluginLoaderException
-    extends Exception
-{
+public class PluginLoaderException extends Exception {
 
     private String pluginKey;
 
-    public PluginLoaderException( Plugin plugin, String message, ArtifactResolutionException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, ArtifactResolutionException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message, ArtifactNotFoundException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, ArtifactNotFoundException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message, PluginNotFoundException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, PluginNotFoundException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message, PluginVersionResolutionException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, PluginVersionResolutionException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message, InvalidVersionSpecificationException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, InvalidVersionSpecificationException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message, InvalidPluginException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, InvalidPluginException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message, PluginManagerException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, PluginManagerException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message, PluginVersionNotFoundException cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(Plugin plugin, String message, PluginVersionNotFoundException cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( Plugin plugin, String message )
-    {
-        super( message );
+    public PluginLoaderException(Plugin plugin, String message) {
+        super(message);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( String message )
-    {
-        super( message );
+    public PluginLoaderException(String message) {
+        super(message);
     }
 
-    public PluginLoaderException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public PluginLoaderException( ReportPlugin plugin, String message, Throwable cause )
-    {
-        super( message, cause );
+    public PluginLoaderException(ReportPlugin plugin, String message, Throwable cause) {
+        super(message, cause);
         pluginKey = plugin.getKey();
     }
 
-    public PluginLoaderException( ReportPlugin plugin, String message )
-    {
-        super( message );
+    public PluginLoaderException(ReportPlugin plugin, String message) {
+        super(message);
         pluginKey = plugin.getKey();
     }
 
-    public String getPluginKey()
-    {
+    public String getPluginKey() {
         return pluginKey;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginManager.java
deleted file mode 100644
index 48b8e5e..0000000
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginManager.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package org.apache.maven.plugin;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.version.PluginVersionNotFoundException;
-import org.apache.maven.plugin.version.PluginVersionResolutionException;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.artifact.InvalidDependencyVersionException;
-import org.apache.maven.settings.Settings;
-import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
-
-import java.util.Map;
-
-/**
- * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
- */
-@Deprecated
-public interface PluginManager
-{
-    String ROLE = PluginManager.class.getName();
-
-    void executeMojo( MavenProject project, MojoExecution execution, MavenSession session )
-        throws MojoExecutionException, ArtifactResolutionException, MojoFailureException, ArtifactNotFoundException,
-        InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException;
-
-    PluginDescriptor getPluginDescriptorForPrefix( String prefix );
-
-    Plugin getPluginDefinitionForPrefix( String prefix, MavenSession session, MavenProject project );
-
-    PluginDescriptor verifyPlugin( Plugin plugin, MavenProject project, Settings settings,
-                                   ArtifactRepository localRepository )
-        throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
-        InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
-        PluginVersionNotFoundException;
-
-    Object getPluginComponent( Plugin plugin, String role, String roleHint )
-        throws PluginManagerException, ComponentLookupException;
-
-    Map<String, Object> getPluginComponents( Plugin plugin, String role )
-        throws ComponentLookupException, PluginManagerException;
-
-    /**
-     * @since 2.2.1
-     */
-    PluginDescriptor loadPluginDescriptor( Plugin plugin, MavenProject project, MavenSession session )
-        throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
-        InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
-        PluginVersionNotFoundException;
-
-    /**
-     * @since 2.2.1
-     */
-    PluginDescriptor loadPluginFully( Plugin plugin, MavenProject project, MavenSession session )
-        throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
-        InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
-        PluginVersionNotFoundException;
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java
index dc8f9a2..dd00d94 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginManagerException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 import org.apache.maven.model.Plugin;
@@ -32,11 +31,8 @@
 /**
  * Exception in the plugin manager.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class PluginManagerException
-    extends Exception
-{
+public class PluginManagerException extends Exception {
 
     private final String pluginGroupId;
 
@@ -48,9 +44,8 @@
 
     private MavenProject project;
 
-    protected PluginManagerException( Plugin plugin, String message, MavenProject project, Throwable cause )
-    {
-        super( message, cause );
+    protected PluginManagerException(Plugin plugin, String message, MavenProject project, Throwable cause) {
+        super(message, cause);
 
         this.project = project;
         pluginGroupId = plugin.getGroupId();
@@ -58,27 +53,24 @@
         pluginVersion = plugin.getVersion();
     }
 
-    public PluginManagerException( Plugin plugin, String message, Throwable cause )
-    {
-        super( message, cause );
+    public PluginManagerException(Plugin plugin, String message, Throwable cause) {
+        super(message, cause);
 
         pluginGroupId = plugin.getGroupId();
         pluginArtifactId = plugin.getArtifactId();
         pluginVersion = plugin.getVersion();
     }
 
-    protected PluginManagerException( MojoDescriptor mojoDescriptor, String message, Throwable cause )
-    {
-        super( message, cause );
+    protected PluginManagerException(MojoDescriptor mojoDescriptor, String message, Throwable cause) {
+        super(message, cause);
         pluginGroupId = mojoDescriptor.getPluginDescriptor().getGroupId();
         pluginArtifactId = mojoDescriptor.getPluginDescriptor().getArtifactId();
         pluginVersion = mojoDescriptor.getPluginDescriptor().getVersion();
         goal = mojoDescriptor.getGoal();
     }
 
-    protected PluginManagerException( MojoDescriptor mojoDescriptor, MavenProject project, String message )
-    {
-        super( message );
+    protected PluginManagerException(MojoDescriptor mojoDescriptor, MavenProject project, String message) {
+        super(message);
         this.project = project;
         pluginGroupId = mojoDescriptor.getPluginDescriptor().getGroupId();
         pluginArtifactId = mojoDescriptor.getPluginDescriptor().getArtifactId();
@@ -86,10 +78,9 @@
         goal = mojoDescriptor.getGoal();
     }
 
-    protected PluginManagerException( MojoDescriptor mojoDescriptor, MavenProject project, String message,
-                                      Throwable cause )
-    {
-        super( message, cause );
+    protected PluginManagerException(
+            MojoDescriptor mojoDescriptor, MavenProject project, String message, Throwable cause) {
+        super(message, cause);
         this.project = project;
         pluginGroupId = mojoDescriptor.getPluginDescriptor().getGroupId();
         pluginArtifactId = mojoDescriptor.getPluginDescriptor().getArtifactId();
@@ -97,37 +88,33 @@
         goal = mojoDescriptor.getGoal();
     }
 
-    public PluginManagerException( Plugin plugin, InvalidVersionSpecificationException cause )
-    {
-        super( cause );
+    public PluginManagerException(Plugin plugin, InvalidVersionSpecificationException cause) {
+        super(cause);
 
         pluginGroupId = plugin.getGroupId();
         pluginArtifactId = plugin.getArtifactId();
         pluginVersion = plugin.getVersion();
     }
 
-    public PluginManagerException( Plugin plugin, String message, PlexusConfigurationException cause )
-    {
-        super( message, cause );
+    public PluginManagerException(Plugin plugin, String message, PlexusConfigurationException cause) {
+        super(message, cause);
 
         pluginGroupId = plugin.getGroupId();
         pluginArtifactId = plugin.getArtifactId();
         pluginVersion = plugin.getVersion();
     }
 
-    public PluginManagerException( Plugin plugin, String message, ComponentRepositoryException cause )
-    {
-        super( message, cause );
+    public PluginManagerException(Plugin plugin, String message, ComponentRepositoryException cause) {
+        super(message, cause);
 
         pluginGroupId = plugin.getGroupId();
         pluginArtifactId = plugin.getArtifactId();
         pluginVersion = plugin.getVersion();
     }
 
-    public PluginManagerException( MojoDescriptor mojoDescriptor, MavenProject project, String message,
-                                   NoSuchRealmException cause )
-    {
-        super( message, cause );
+    public PluginManagerException(
+            MojoDescriptor mojoDescriptor, MavenProject project, String message, NoSuchRealmException cause) {
+        super(message, cause);
 
         this.project = project;
         pluginGroupId = mojoDescriptor.getPluginDescriptor().getGroupId();
@@ -136,10 +123,9 @@
         goal = mojoDescriptor.getGoal();
     }
 
-    public PluginManagerException( MojoDescriptor mojoDescriptor, String message, MavenProject project,
-                                   PlexusContainerException cause )
-    {
-        super( message, cause );
+    public PluginManagerException(
+            MojoDescriptor mojoDescriptor, String message, MavenProject project, PlexusContainerException cause) {
+        super(message, cause);
 
         this.project = project;
 
@@ -151,18 +137,16 @@
         goal = mojoDescriptor.getGoal();
     }
 
-    public PluginManagerException( Plugin plugin, String message, PlexusContainerException cause )
-    {
-        super( message, cause );
+    public PluginManagerException(Plugin plugin, String message, PlexusContainerException cause) {
+        super(message, cause);
 
         pluginGroupId = plugin.getGroupId();
         pluginArtifactId = plugin.getArtifactId();
         pluginVersion = plugin.getVersion();
     }
 
-    public PluginManagerException( Plugin plugin, String message, MavenProject project )
-    {
-        super( message );
+    public PluginManagerException(Plugin plugin, String message, MavenProject project) {
+        super(message);
 
         pluginGroupId = plugin.getGroupId();
         pluginArtifactId = plugin.getArtifactId();
@@ -170,28 +154,23 @@
         this.project = project;
     }
 
-    public String getPluginGroupId()
-    {
+    public String getPluginGroupId() {
         return pluginGroupId;
     }
 
-    public String getPluginArtifactId()
-    {
+    public String getPluginArtifactId() {
         return pluginArtifactId;
     }
 
-    public String getPluginVersion()
-    {
+    public String getPluginVersion() {
         return pluginVersion;
     }
 
-    public String getGoal()
-    {
+    public String getGoal() {
         return goal;
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginNotFoundException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginNotFoundException.java
index ef54e2d..8aa7fb3 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginNotFoundException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 
@@ -29,30 +28,39 @@
 /**
  * Exception occurring trying to resolve a plugin.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class PluginNotFoundException
-    extends AbstractArtifactResolutionException
-{
+public class PluginNotFoundException extends AbstractArtifactResolutionException {
     private Plugin plugin;
 
-    public PluginNotFoundException( Plugin plugin, ArtifactNotFoundException e )
-    {
-        super( "Plugin could not be found - check that the goal name is correct: " + e.getMessage(), e.getGroupId(),
-               e.getArtifactId(), e.getVersion(), "maven-plugin", null, e.getRemoteRepositories(), null, e.getCause() );
+    public PluginNotFoundException(Plugin plugin, ArtifactNotFoundException e) {
+        super(
+                "Plugin could not be found - check that the goal name is correct: " + e.getMessage(),
+                e.getGroupId(),
+                e.getArtifactId(),
+                e.getVersion(),
+                "maven-plugin",
+                null,
+                e.getRemoteRepositories(),
+                null,
+                e.getCause());
         this.plugin = plugin;
     }
 
-    public PluginNotFoundException( Plugin plugin, List<ArtifactRepository> remoteRepositories )
-    {
-        super( "Plugin could not be found, please check its coordinates for typos and ensure the required"
-            + " plugin repositories are defined in the POM", plugin.getGroupId(), plugin.getArtifactId(),
-               plugin.getVersion(), "maven-plugin", null, remoteRepositories, null );
+    public PluginNotFoundException(Plugin plugin, List<ArtifactRepository> remoteRepositories) {
+        super(
+                "Plugin could not be found, please check its coordinates for typos and ensure the required"
+                        + " plugin repositories are defined in the POM",
+                plugin.getGroupId(),
+                plugin.getArtifactId(),
+                plugin.getVersion(),
+                "maven-plugin",
+                null,
+                remoteRepositories,
+                null);
         this.plugin = plugin;
     }
 
-    public Plugin getPlugin()
-    {
+    public Plugin getPlugin() {
         return plugin;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterException.java
index d1fa98d..73a1925 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.Collection;
 import java.util.Iterator;
@@ -27,14 +26,11 @@
 
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * PluginParameterException
  */
-public class PluginParameterException
-    extends PluginConfigurationException
-{
+public class PluginParameterException extends PluginConfigurationException {
 
     private static final String LS = System.lineSeparator();
 
@@ -42,157 +38,143 @@
 
     private final MojoDescriptor mojo;
 
-    public PluginParameterException( MojoDescriptor mojo, List<Parameter> parameters )
-    {
-        super( mojo.getPluginDescriptor(), "The parameters " + format( parameters ) + " for goal "
-            + mojo.getRoleHint() + " are missing or invalid" );
+    public PluginParameterException(MojoDescriptor mojo, List<Parameter> parameters) {
+        super(
+                mojo.getPluginDescriptor(),
+                "The parameters " + format(parameters) + " for goal " + mojo.getRoleHint() + " are missing or invalid");
 
         this.mojo = mojo;
 
         this.parameters = parameters;
     }
 
-    private static String format( List<Parameter> parameters )
-    {
-        StringBuilder buffer = new StringBuilder( 128 );
-        if ( parameters != null )
-        {
-            for ( Parameter parameter : parameters )
-            {
-                if ( buffer.length() > 0 )
-                {
-                    buffer.append( ", " );
+    private static String format(List<Parameter> parameters) {
+        StringBuilder buffer = new StringBuilder(128);
+        if (parameters != null) {
+            for (Parameter parameter : parameters) {
+                if (buffer.length() > 0) {
+                    buffer.append(", ");
                 }
-                buffer.append( '\'' ).append( parameter.getName() ).append( '\'' );
+                buffer.append('\'').append(parameter.getName()).append('\'');
             }
         }
         return buffer.toString();
     }
 
-    public MojoDescriptor getMojoDescriptor()
-    {
+    public MojoDescriptor getMojoDescriptor() {
         return mojo;
     }
 
-    public List<Parameter> getParameters()
-    {
+    public List<Parameter> getParameters() {
         return parameters;
     }
 
-    private static void decomposeParameterIntoUserInstructions( MojoDescriptor mojo, Parameter param,
-                                                                StringBuilder messageBuffer )
-    {
+    private static void decomposeParameterIntoUserInstructions(
+            MojoDescriptor mojo, Parameter param, StringBuilder messageBuffer) {
         String expression = param.getExpression();
 
-        if ( param.isEditable() )
-        {
-            boolean isArray = param.getType().endsWith( "[]" );
+        if (param.isEditable()) {
+            boolean isArray = param.getType().endsWith("[]");
             boolean isCollection = false;
             boolean isMap = false;
             boolean isProperties = false;
-            if ( !isArray )
-            {
-                try
-                {
-                    //assuming Type is available in current ClassLoader
-                    isCollection = Collection.class.isAssignableFrom( Class.forName( param.getType() ) );
-                    isMap = Map.class.isAssignableFrom( Class.forName( param.getType() ) );
-                    isProperties = Properties.class.isAssignableFrom( Class.forName( param.getType() ) );
-                }
-                catch ( ClassNotFoundException e )
-                {
+            if (!isArray) {
+                try {
+                    // assuming Type is available in current ClassLoader
+                    isCollection = Collection.class.isAssignableFrom(Class.forName(param.getType()));
+                    isMap = Map.class.isAssignableFrom(Class.forName(param.getType()));
+                    isProperties = Properties.class.isAssignableFrom(Class.forName(param.getType()));
+                } catch (ClassNotFoundException e) {
                     // assume it is not assignable from Collection or Map
                 }
             }
 
-            messageBuffer.append( "Inside the definition for plugin '" );
-            messageBuffer.append( mojo.getPluginDescriptor().getArtifactId() );
-            messageBuffer.append( "', specify the following:" ).append( LS ).append( LS );
-            messageBuffer.append( "<configuration>" ).append( LS ).append( "  ..." ).append( LS );
-            messageBuffer.append( "  <" ).append( param.getName() ).append( '>' );
-            if ( isArray || isCollection )
-            {
-                messageBuffer.append( LS );
-                messageBuffer.append( "    <item>" );
+            messageBuffer.append("Inside the definition for plugin '");
+            messageBuffer.append(mojo.getPluginDescriptor().getArtifactId());
+            messageBuffer.append("', specify the following:").append(LS).append(LS);
+            messageBuffer.append("<configuration>").append(LS).append("  ...").append(LS);
+            messageBuffer.append("  <").append(param.getName()).append('>');
+            if (isArray || isCollection) {
+                messageBuffer.append(LS);
+                messageBuffer.append("    <item>");
+            } else if (isProperties) {
+                messageBuffer.append(LS);
+                messageBuffer.append("    <property>").append(LS);
+                messageBuffer.append("      <name>KEY</name>").append(LS);
+                messageBuffer.append("      <value>");
+            } else if (isMap) {
+                messageBuffer.append(LS);
+                messageBuffer.append("    <KEY>");
             }
-            else if ( isProperties )
-            {
-                messageBuffer.append( LS );
-                messageBuffer.append( "    <property>" ).append( LS );
-                messageBuffer.append( "      <name>KEY</name>" ).append( LS );
-                messageBuffer.append( "      <value>" );
+            messageBuffer.append("VALUE");
+            if (isArray || isCollection) {
+                messageBuffer.append("</item>").append(LS);
+                messageBuffer.append("  ");
+            } else if (isProperties) {
+                messageBuffer.append("</value>").append(LS);
+                messageBuffer.append("    </property>").append(LS);
+                messageBuffer.append("  ");
+            } else if (isMap) {
+                messageBuffer.append("</KEY>").append(LS);
+                messageBuffer.append("  ");
             }
-            else if ( isMap )
-            {
-                messageBuffer.append( LS );
-                messageBuffer.append( "    <KEY>" );
-            }
-            messageBuffer.append( "VALUE" );
-            if ( isArray || isCollection )
-            {
-                messageBuffer.append( "</item>" ).append( LS );
-                messageBuffer.append( "  " );
-            }
-            else if ( isProperties )
-            {
-                messageBuffer.append( "</value>" ).append( LS );
-                messageBuffer.append( "    </property>" ).append( LS );
-                messageBuffer.append( "  " );
-            }
-            else if ( isMap )
-            {
-                messageBuffer.append( "</KEY>" ).append( LS );
-                messageBuffer.append( "  " );
-            }
-            messageBuffer.append( "</" ).append( param.getName() ).append( ">" ).append( LS );
-            messageBuffer.append( "</configuration>" );
+            messageBuffer.append("</").append(param.getName()).append(">").append(LS);
+            messageBuffer.append("</configuration>");
 
             String alias = param.getAlias();
-            if ( StringUtils.isNotEmpty( alias ) && !alias.equals( param.getName() ) )
-            {
-                messageBuffer.append( LS ).append( LS ).append( "-OR-" ).append( LS ).append( LS );
-                messageBuffer.append( "<configuration>" ).append( LS ).append( "  ..." ).append( LS );
-                messageBuffer.append( "  <" ).append( alias ).append(
-                    ">VALUE</" ).append( alias ).append( ">" ).append( LS ).append( "</configuration>" ).append( LS );
+            if ((alias != null && !alias.isEmpty()) && !alias.equals(param.getName())) {
+                messageBuffer.append(LS).append(LS).append("-OR-").append(LS).append(LS);
+                messageBuffer
+                        .append("<configuration>")
+                        .append(LS)
+                        .append("  ...")
+                        .append(LS);
+                messageBuffer
+                        .append("  <")
+                        .append(alias)
+                        .append(">VALUE</")
+                        .append(alias)
+                        .append(">")
+                        .append(LS)
+                        .append("</configuration>")
+                        .append(LS);
             }
         }
 
-        if ( StringUtils.isEmpty( expression ) )
-        {
-            messageBuffer.append( '.' );
-        }
-        else
-        {
-            if ( param.isEditable() )
-            {
-                messageBuffer.append( LS ).append( LS ).append( "-OR-" ).append( LS ).append( LS );
+        if (expression == null || expression.isEmpty()) {
+            messageBuffer.append('.');
+        } else {
+            if (param.isEditable()) {
+                messageBuffer.append(LS).append(LS).append("-OR-").append(LS).append(LS);
             }
 
-            //addParameterUsageInfo( expression, messageBuffer );
+            // addParameterUsageInfo( expression, messageBuffer );
         }
     }
 
-    public String buildDiagnosticMessage()
-    {
-        StringBuilder messageBuffer = new StringBuilder( 256 );
+    public String buildDiagnosticMessage() {
+        StringBuilder messageBuffer = new StringBuilder(256);
 
         List<Parameter> params = getParameters();
         MojoDescriptor mojo = getMojoDescriptor();
 
-        messageBuffer.append( "One or more required plugin parameters are invalid/missing for '" )
-            .append( mojo.getPluginDescriptor().getGoalPrefix() ).append( ':' ).append( mojo.getGoal() )
-            .append( "'" ).append( LS );
+        messageBuffer
+                .append("One or more required plugin parameters are invalid/missing for '")
+                .append(mojo.getPluginDescriptor().getGoalPrefix())
+                .append(':')
+                .append(mojo.getGoal())
+                .append("'")
+                .append(LS);
 
         int idx = 0;
-        for ( Iterator<Parameter> it = params.iterator(); it.hasNext(); idx++ )
-        {
+        for (Iterator<Parameter> it = params.iterator(); it.hasNext(); idx++) {
             Parameter param = it.next();
 
-            messageBuffer.append( LS ).append( "[" ).append( idx ).append( "] " );
+            messageBuffer.append(LS).append("[").append(idx).append("] ");
 
-            decomposeParameterIntoUserInstructions( mojo, param, messageBuffer );
+            decomposeParameterIntoUserInstructions(mojo, param, messageBuffer);
 
-            messageBuffer.append( LS );
+            messageBuffer.append(LS);
         }
 
         return messageBuffer.toString();
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java
index f621b63..07dd224 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.Properties;
 
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.interpolation.reflection.ReflectionValueExtractor;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
-import org.codehaus.plexus.util.introspection.ReflectionValueExtractor;
 
 /**
  * Evaluator for plugin parameters expressions. Content surrounded by <code>${</code> and <code>}</code> is evaluated.
@@ -39,7 +39,7 @@
  * <tr><td><code>session</code></td>           <td></td>               <td>the actual {@link MavenSession}</td></tr>
  * <tr><td><code>session.*</code></td>         <td>(since Maven 3)</td><td></td></tr>
  * <tr><td><code>localRepository</code></td>   <td></td>
- *                                             <td>{@link MavenSession#getLocalRepository()}</td></tr>
+ *                                             <td>{@link MavenSession#getLocalRepository()} DEPRECATED: Avoid use of {@link org.apache.maven.artifact.repository.ArtifactRepository} type. If you need access to local repository, switch to '${repositorySystemSession}' expression and get LRM from it instead. See <a href="https://issues.apache.org/jira/browse/MNG-7706">MNG-7706</a></td></tr>
  * <tr><td><code>reactorProjects</code></td>   <td></td>               <td>{@link MavenSession#getProjects()}</td></tr>
  * <tr><td><code>repositorySystemSession</code></td><td> (since Maven 3)</td>
  *                                             <td>{@link MavenSession#getRepositorySession()}</td></tr>
@@ -61,18 +61,16 @@
  *                             <td>{@link MojoExecution#getMojoDescriptor()}.{@link MojoDescriptor#getPluginDescriptor()
  *                                 getPluginDescriptor()}</td></tr>
  * <tr><td><code>plugin.*</code></td>          <td></td>               <td></td></tr>
- * <tr><td><code>*</code></td>                 <td></td>               <td>system properties</td></tr>
+ * <tr><td><code>*</code></td>                 <td></td>               <td>user properties</td></tr>
  * <tr><td><code>*</code></td>                 <td></td>               <td>project properties</td></tr>
+ * <tr><td><code>*</code></td>                 <td></td>               <td>system properties</td></tr>
  * </table>
  * <i>Notice:</i> <code>reports</code> was supported in Maven 2.x but was removed in Maven 3
  *
- * @author Jason van Zyl
  * @see MavenSession
  * @see MojoExecution
  */
-public class PluginParameterExpressionEvaluator
-    implements TypeAwareExpressionEvaluator
-{
+public class PluginParameterExpressionEvaluator implements TypeAwareExpressionEvaluator {
     private MavenSession session;
 
     private MojoExecution mojoExecution;
@@ -83,13 +81,11 @@
 
     private Properties properties;
 
-    public PluginParameterExpressionEvaluator( MavenSession session )
-    {
-        this( session, null );
+    public PluginParameterExpressionEvaluator(MavenSession session) {
+        this(session, null);
     }
 
-    public PluginParameterExpressionEvaluator( MavenSession session, MojoExecution mojoExecution )
-    {
+    public PluginParameterExpressionEvaluator(MavenSession session, MojoExecution mojoExecution) {
         this.session = session;
         this.mojoExecution = mojoExecution;
         this.properties = new Properties();
@@ -99,327 +95,232 @@
         // Maven4: We may want to evaluate how this is used but we add these separate as the
         // getExecutionProperties is deprecated in MavenSession.
         //
-        this.properties.putAll( session.getUserProperties() );
-        this.properties.putAll( session.getSystemProperties() );
+        this.properties.putAll(session.getUserProperties());
+        this.properties.putAll(session.getSystemProperties());
 
         String basedir = null;
 
-        if ( project != null )
-        {
+        if (project != null) {
             File projectFile = project.getBasedir();
 
             // this should always be the case for non-super POM instances...
-            if ( projectFile != null )
-            {
+            if (projectFile != null) {
                 basedir = projectFile.getAbsolutePath();
             }
         }
 
-        if ( basedir == null )
-        {
+        if (basedir == null) {
             basedir = session.getExecutionRootDirectory();
         }
 
-        if ( basedir == null )
-        {
-            basedir = System.getProperty( "user.dir" );
+        if (basedir == null) {
+            basedir = System.getProperty("user.dir");
         }
 
         this.basedir = basedir;
     }
 
     @Override
-    public Object evaluate( String expr )
-        throws ExpressionEvaluationException
-    {
-        return evaluate( expr, null );
+    public Object evaluate(String expr) throws ExpressionEvaluationException {
+        return evaluate(expr, null);
     }
 
     @Override
-    @SuppressWarnings( "checkstyle:methodlength" )
-    public Object evaluate( String expr, Class<?> type )
-        throws ExpressionEvaluationException
-    {
+    @SuppressWarnings("checkstyle:methodlength")
+    public Object evaluate(String expr, Class<?> type) throws ExpressionEvaluationException {
         Object value = null;
 
-        if ( expr == null )
-        {
+        if (expr == null) {
             return null;
         }
 
-        String expression = stripTokens( expr );
-        if ( expression.equals( expr ) )
-        {
-            int index = expr.indexOf( "${" );
-            if ( index >= 0 )
-            {
-                int lastIndex = expr.indexOf( '}', index );
-                if ( lastIndex >= 0 )
-                {
-                    String retVal = expr.substring( 0, index );
+        String expression = stripTokens(expr);
+        if (expression.equals(expr)) {
+            int index = expr.indexOf("${");
+            if (index >= 0) {
+                int lastIndex = expr.indexOf('}', index);
+                if (lastIndex >= 0) {
+                    String retVal = expr.substring(0, index);
 
-                    if ( ( index > 0 ) && ( expr.charAt( index - 1 ) == '$' ) )
-                    {
-                        retVal += expr.substring( index + 1, lastIndex + 1 );
-                    }
-                    else
-                    {
-                        Object subResult = evaluate( expr.substring( index, lastIndex + 1 ) );
+                    if ((index > 0) && (expr.charAt(index - 1) == '$')) {
+                        retVal += expr.substring(index + 1, lastIndex + 1);
+                    } else {
+                        Object subResult = evaluate(expr.substring(index, lastIndex + 1));
 
-                        if ( subResult != null )
-                        {
+                        if (subResult != null) {
                             retVal += subResult;
-                        }
-                        else
-                        {
-                            retVal += "$" + expr.substring( index + 1, lastIndex + 1 );
+                        } else {
+                            retVal += "$" + expr.substring(index + 1, lastIndex + 1);
                         }
                     }
 
-                    retVal += evaluate( expr.substring( lastIndex + 1 ) );
+                    retVal += evaluate(expr.substring(lastIndex + 1));
                     return retVal;
                 }
             }
 
             // Was not an expression
-            if ( expression.contains( "$$" ) )
-            {
-                return expression.replaceAll( "\\$\\$", "\\$" );
-            }
-            else
-            {
-                return expression;
-            }
+            return expression.replace("$$", "$");
         }
 
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
-        if ( "localRepository".equals( expression ) )
-        {
+        if ("localRepository".equals(expression)) {
             value = session.getLocalRepository();
-        }
-        else if ( "session".equals( expression ) )
-        {
+        } else if ("session".equals(expression)) {
             value = session;
-        }
-        else if ( expression.startsWith( "session" ) )
-        {
-            try
-            {
-                int pathSeparator = expression.indexOf( '/' );
+        } else if (expression.startsWith("session")) {
+            try {
+                int pathSeparator = expression.indexOf('/');
 
-                if ( pathSeparator > 0 )
-                {
-                    String pathExpression = expression.substring( 1, pathSeparator );
-                    value = ReflectionValueExtractor.evaluate( pathExpression, session );
-                    value = value + expression.substring( pathSeparator );
+                if (pathSeparator > 0) {
+                    String pathExpression = expression.substring(0, pathSeparator);
+                    value = ReflectionValueExtractor.evaluate(pathExpression, session);
+                    if (pathSeparator < expression.length() - 1) {
+                        if (value instanceof Path) {
+                            value = ((Path) value).resolve(expression.substring(pathSeparator + 1));
+                        } else {
+                            value = value + expression.substring(pathSeparator);
+                        }
+                    }
+                } else {
+                    value = ReflectionValueExtractor.evaluate(expression, session);
                 }
-                else
-                {
-                    value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), session );
-                }
-            }
-            catch ( Exception e )
-            {
+            } catch (Exception e) {
                 // TODO don't catch exception
-                throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
-                                                         e );
+                throw new ExpressionEvaluationException(
+                        "Error evaluating plugin parameter expression: " + expression, e);
             }
-        }
-        else if ( "reactorProjects".equals( expression ) )
-        {
+        } else if ("reactorProjects".equals(expression)) {
             value = session.getProjects();
-        }
-        else if ( "mojoExecution".equals( expression ) )
-        {
-            value = mojoExecution;
-        }
-        else if ( "project".equals( expression ) )
-        {
+        } else if ("project".equals(expression)) {
             value = project;
-        }
-        else if ( "executedProject".equals( expression ) )
-        {
+        } else if ("executedProject".equals(expression)) {
             value = project.getExecutionProject();
-        }
-        else if ( expression.startsWith( "project" ) || expression.startsWith( "pom" ) )
-        {
-            try
-            {
-                int pathSeparator = expression.indexOf( '/' );
+        } else if (expression.startsWith("project") || expression.startsWith("pom")) {
+            try {
+                int pathSeparator = expression.indexOf('/');
 
-                if ( pathSeparator > 0 )
-                {
-                    String pathExpression = expression.substring( 0, pathSeparator );
-                    value = ReflectionValueExtractor.evaluate( pathExpression, project );
-                    value = value + expression.substring( pathSeparator );
+                if (pathSeparator > 0) {
+                    String pathExpression = expression.substring(0, pathSeparator);
+                    value = ReflectionValueExtractor.evaluate(pathExpression, project);
+                    value = value + expression.substring(pathSeparator);
+                } else {
+                    value = ReflectionValueExtractor.evaluate(expression, project);
                 }
-                else
-                {
-                    value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), project );
-                }
-            }
-            catch ( Exception e )
-            {
+            } catch (Exception e) {
                 // TODO don't catch exception
-                throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
-                                                         e );
+                throw new ExpressionEvaluationException(
+                        "Error evaluating plugin parameter expression: " + expression, e);
             }
-        }
-        else if ( expression.equals( "repositorySystemSession" ) )
-        {
+        } else if (expression.equals("repositorySystemSession")) {
             value = session.getRepositorySession();
-        }
-        else if ( expression.equals( "mojo" ) )
-        {
+        } else if (expression.equals("mojo") || expression.equals("mojoExecution")) {
             value = mojoExecution;
-        }
-        else if ( expression.startsWith( "mojo" ) )
-        {
-            try
-            {
-                int pathSeparator = expression.indexOf( '/' );
+        } else if (expression.startsWith("mojo")) {
+            try {
+                int pathSeparator = expression.indexOf('/');
 
-                if ( pathSeparator > 0 )
-                {
-                    String pathExpression = expression.substring( 1, pathSeparator );
-                    value = ReflectionValueExtractor.evaluate( pathExpression, mojoExecution );
-                    value = value + expression.substring( pathSeparator );
+                if (pathSeparator > 0) {
+                    String pathExpression = expression.substring(0, pathSeparator);
+                    value = ReflectionValueExtractor.evaluate(pathExpression, mojoExecution);
+                    value = value + expression.substring(pathSeparator);
+                } else {
+                    value = ReflectionValueExtractor.evaluate(expression, mojoExecution);
                 }
-                else
-                {
-                    value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), mojoExecution );
-                }
-            }
-            catch ( Exception e )
-            {
+            } catch (Exception e) {
                 // TODO don't catch exception
-                throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
-                                                         e );
+                throw new ExpressionEvaluationException(
+                        "Error evaluating plugin parameter expression: " + expression, e);
             }
-        }
-        else if ( expression.equals( "plugin" ) )
-        {
+        } else if (expression.equals("plugin")) {
             value = mojoDescriptor.getPluginDescriptor();
-        }
-        else if ( expression.startsWith( "plugin" ) )
-        {
-            try
-            {
-                int pathSeparator = expression.indexOf( '/' );
+        } else if (expression.startsWith("plugin")) {
+            try {
+                int pathSeparator = expression.indexOf('/');
 
                 PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
 
-                if ( pathSeparator > 0 )
-                {
-                    String pathExpression = expression.substring( 1, pathSeparator );
-                    value = ReflectionValueExtractor.evaluate( pathExpression, pluginDescriptor );
-                    value = value + expression.substring( pathSeparator );
+                if (pathSeparator > 0) {
+                    String pathExpression = expression.substring(0, pathSeparator);
+                    value = ReflectionValueExtractor.evaluate(pathExpression, pluginDescriptor);
+                    value = value + expression.substring(pathSeparator);
+                } else {
+                    value = ReflectionValueExtractor.evaluate(expression, pluginDescriptor);
                 }
-                else
-                {
-                    value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), pluginDescriptor );
-                }
+            } catch (Exception e) {
+                throw new ExpressionEvaluationException(
+                        "Error evaluating plugin parameter expression: " + expression, e);
             }
-            catch ( Exception e )
-            {
-                throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
-                                                         e );
-            }
-        }
-        else if ( "settings".equals( expression ) )
-        {
+        } else if ("settings".equals(expression)) {
             value = session.getSettings();
-        }
-        else if ( expression.startsWith( "settings" ) )
-        {
-            try
-            {
-                int pathSeparator = expression.indexOf( '/' );
+        } else if (expression.startsWith("settings")) {
+            try {
+                int pathSeparator = expression.indexOf('/');
 
-                if ( pathSeparator > 0 )
-                {
-                    String pathExpression = expression.substring( 1, pathSeparator );
-                    value = ReflectionValueExtractor.evaluate( pathExpression, session.getSettings() );
-                    value = value + expression.substring( pathSeparator );
+                if (pathSeparator > 0) {
+                    String pathExpression = expression.substring(0, pathSeparator);
+                    value = ReflectionValueExtractor.evaluate(pathExpression, session.getSettings());
+                    value = value + expression.substring(pathSeparator);
+                } else {
+                    value = ReflectionValueExtractor.evaluate(expression, session.getSettings());
                 }
-                else
-                {
-                    value = ReflectionValueExtractor.evaluate( expression.substring( 1 ), session.getSettings() );
-                }
-            }
-            catch ( Exception e )
-            {
+            } catch (Exception e) {
                 // TODO don't catch exception
-                throw new ExpressionEvaluationException( "Error evaluating plugin parameter expression: " + expression,
-                                                         e );
+                throw new ExpressionEvaluationException(
+                        "Error evaluating plugin parameter expression: " + expression, e);
             }
-        }
-        else if ( "basedir".equals( expression ) )
-        {
+        } else if ("basedir".equals(expression)) {
             value = basedir;
-        }
-        else if ( expression.startsWith( "basedir" ) )
-        {
-            int pathSeparator = expression.indexOf( '/' );
+        } else if (expression.startsWith("basedir")) {
+            int pathSeparator = expression.indexOf('/');
 
-            if ( pathSeparator > 0 )
-            {
-                value = basedir + expression.substring( pathSeparator );
+            if (pathSeparator > 0) {
+                value = basedir + expression.substring(pathSeparator);
             }
         }
 
         /*
          * MNG-4312: We neither have reserved all of the above magic expressions nor is their set fixed/well-known (it
          * gets occasionally extended by newer Maven versions). This imposes the risk for existing plugins to
-         * unintentionally use such a magic expression for an ordinary system property. So here we check whether we
+         * unintentionally use such a magic expression for an ordinary property. So here we check whether we
          * ended up with a magic value that is not compatible with the type of the configured mojo parameter (a string
          * could still be converted by the configurator so we leave those alone). If so, back off to evaluating the
          * expression from properties only.
          */
-        if ( value != null && type != null && !( value instanceof String ) && !isTypeCompatible( type, value ) )
-        {
+        if (value != null && type != null && !(value instanceof String) && !isTypeCompatible(type, value)) {
             value = null;
         }
 
-        if ( value == null )
-        {
+        if (value == null) {
             // The CLI should win for defining properties
 
-            if ( properties != null )
-            {
-                // We will attempt to get nab a system property as a way to specify a
-                // parameter to a plugins. My particular case here is allowing the surefire
-                // plugin to run a single test so I want to specify that class on the cli
-                // as a parameter.
+            if (properties != null) {
+                // We will attempt to get nab a property as a way to specify a parameter
+                // to a plugin. My particular case here is allowing the surefire plugin
+                // to run a single test so I want to specify that class on the cli as
+                // a parameter.
 
-                value = properties.getProperty( expression );
+                value = properties.getProperty(expression);
             }
 
-            if ( ( value == null ) && ( ( project != null ) && ( project.getProperties() != null ) ) )
-            {
-                value = project.getProperties().getProperty( expression );
+            if ((value == null) && ((project != null) && (project.getProperties() != null))) {
+                value = project.getProperties().getProperty(expression);
             }
-
         }
 
-        if ( value instanceof String )
-        {
+        if (value instanceof String) {
             // TODO without #, this could just be an evaluate call...
 
             String val = (String) value;
 
-            int exprStartDelimiter = val.indexOf( "${" );
+            int exprStartDelimiter = val.indexOf("${");
 
-            if ( exprStartDelimiter >= 0 )
-            {
-                if ( exprStartDelimiter > 0 )
-                {
-                    value = val.substring( 0, exprStartDelimiter ) + evaluate( val.substring( exprStartDelimiter ) );
-                }
-                else
-                {
-                    value = evaluate( val.substring( exprStartDelimiter ) );
+            if (exprStartDelimiter >= 0) {
+                if (exprStartDelimiter > 0) {
+                    value = val.substring(0, exprStartDelimiter) + evaluate(val.substring(exprStartDelimiter));
+                } else {
+                    value = evaluate(val.substring(exprStartDelimiter));
                 }
             }
         }
@@ -427,49 +328,37 @@
         return value;
     }
 
-    private static boolean isTypeCompatible( Class<?> type, Object value )
-    {
-        if ( type.isInstance( value ) )
-        {
+    private static boolean isTypeCompatible(Class<?> type, Object value) {
+        if (type.isInstance(value)) {
             return true;
         }
         // likely Boolean -> boolean, Short -> int etc. conversions, it's not the problem case we try to avoid
-        return ( ( type.isPrimitive() || type.getName().startsWith( "java.lang." ) )
-                        && value.getClass().getName().startsWith( "java.lang." ) );
+        return ((type.isPrimitive() || type.getName().startsWith("java.lang."))
+                && value.getClass().getName().startsWith("java.lang."));
     }
 
-    private String stripTokens( String expr )
-    {
-        if ( expr.startsWith( "${" ) && ( expr.indexOf( '}' ) == expr.length() - 1 ) )
-        {
-            expr = expr.substring( 2, expr.length() - 1 );
+    private String stripTokens(String expr) {
+        if (expr.startsWith("${") && (expr.indexOf('}') == expr.length() - 1)) {
+            expr = expr.substring(2, expr.length() - 1);
         }
         return expr;
     }
 
     @Override
-    public File alignToBaseDirectory( File file )
-    {
+    public File alignToBaseDirectory(File file) {
         // TODO Copied from the DefaultInterpolator. We likely want to resurrect the PathTranslator or at least a
         // similar component for re-usage
-        if ( file != null )
-        {
-            if ( file.isAbsolute() )
-            {
+        if (file != null) {
+            if (file.isAbsolute()) {
                 // path was already absolute, just normalize file separator and we're done
-            }
-            else if ( file.getPath().startsWith( File.separator ) )
-            {
+            } else if (file.getPath().startsWith(File.separator)) {
                 // drive-relative Windows path, don't align with project directory but with drive root
                 file = file.getAbsoluteFile();
-            }
-            else
-            {
+            } else {
                 // an ordinary relative path, align with project directory
-                file = new File( new File( basedir, file.getPath() ).toURI().normalize() ).getAbsoluteFile();
+                file = new File(new File(basedir, file.getPath()).toURI().normalize()).getAbsoluteFile();
             }
         }
         return file;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java
new file mode 100644
index 0000000..d3620c6
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4.java
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+
+import org.apache.maven.api.MojoExecution;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.Session;
+import org.apache.maven.model.interpolation.reflection.ReflectionValueExtractor;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
+import org.codehaus.plexus.component.configurator.expression.TypeAwareExpressionEvaluator;
+
+/**
+ * Evaluator for plugin parameters expressions. Content surrounded by <code>${</code> and <code>}</code> is evaluated.
+ * Recognized values are:
+ * <table border="1">
+ * <caption>Expression matrix</caption>
+ * <tr><th>expression</th>                     <th></th>               <th>evaluation result</th></tr>
+ * <tr><td><code>session.*</code></td>         <td></td>               <td></td></tr>
+ * <tr><td><code>project.*</code></td>         <td></td>               <td></td></tr>
+ * <tr><td><code>settings.*</code></td>        <td></td>               <td></td></tr>
+ * <tr><td><code>mojo.*</code></td>            <td></td>               <td>the actual {@link MojoExecution}</td></tr>
+ * <tr><td><code>*</code></td>                 <td></td>               <td>user properties</td></tr>
+ * <tr><td><code>*</code></td>                 <td></td>               <td>system properties</td></tr>
+ * <tr><td><code>*</code></td>                 <td></td>               <td>project properties</td></tr>
+ * </table>
+ *
+ * @see Session
+ * @see Project
+ * @see org.apache.maven.api.settings.Settings
+ * @see MojoExecution
+ */
+public class PluginParameterExpressionEvaluatorV4 implements TypeAwareExpressionEvaluator {
+    private Session session;
+
+    private MojoExecution mojoExecution;
+
+    private Project project;
+
+    private Path basedir;
+
+    private Properties properties;
+
+    public PluginParameterExpressionEvaluatorV4(Session session, Project project) {
+        this(session, project, null);
+    }
+
+    public PluginParameterExpressionEvaluatorV4(Session session, Project project, MojoExecution mojoExecution) {
+        this.session = session;
+        this.mojoExecution = mojoExecution;
+        this.properties = new Properties();
+        this.project = project;
+
+        //
+        // Maven4: We may want to evaluate how this is used but we add these separate as the
+        // getExecutionProperties is deprecated in MavenSession.
+        //
+        this.properties.putAll(session.getUserProperties());
+        this.properties.putAll(session.getSystemProperties());
+
+        Path basedir = null;
+
+        if (project != null) {
+            Optional<Path> projectFile = project.getBasedir();
+
+            // this should always be the case for non-super POM instances...
+            if (projectFile.isPresent()) {
+                basedir = projectFile.get().toAbsolutePath();
+            }
+        }
+
+        if (basedir == null) {
+            basedir = session.getTopDirectory();
+        }
+
+        if (basedir == null) {
+            basedir = Paths.get(System.getProperty("user.dir"));
+        }
+
+        this.basedir = basedir;
+    }
+
+    @Override
+    public Object evaluate(String expr) throws ExpressionEvaluationException {
+        return evaluate(expr, null);
+    }
+
+    @Override
+    @SuppressWarnings("checkstyle:methodlength")
+    public Object evaluate(String expr, Class<?> type) throws ExpressionEvaluationException {
+        Object value = null;
+
+        if (expr == null) {
+            return null;
+        }
+
+        String expression = stripTokens(expr);
+        if (expression.equals(expr)) {
+            int index = expr.indexOf("${");
+            if (index >= 0) {
+                int lastIndex = expr.indexOf('}', index);
+                if (lastIndex >= 0) {
+                    String retVal = expr.substring(0, index);
+
+                    if ((index > 0) && (expr.charAt(index - 1) == '$')) {
+                        retVal += expr.substring(index + 1, lastIndex + 1);
+                    } else {
+                        Object subResult = evaluate(expr.substring(index, lastIndex + 1));
+
+                        if (subResult != null) {
+                            retVal += subResult;
+                        } else {
+                            retVal += "$" + expr.substring(index + 1, lastIndex + 1);
+                        }
+                    }
+
+                    retVal += evaluate(expr.substring(lastIndex + 1));
+                    return retVal;
+                }
+            }
+
+            // Was not an expression
+            return expression.replace("$$", "$");
+        }
+
+        Map<String, Object> objects = new HashMap<>();
+        objects.put("session.", session);
+        objects.put("project.", project);
+        objects.put("mojo.", mojoExecution);
+        objects.put("settings.", session.getSettings());
+        for (Map.Entry<String, Object> ctx : objects.entrySet()) {
+            if (expression.startsWith(ctx.getKey())) {
+                try {
+                    int pathSeparator = expression.indexOf('/');
+                    if (pathSeparator > 0) {
+                        String pathExpression = expression.substring(0, pathSeparator);
+                        value = ReflectionValueExtractor.evaluate(pathExpression, ctx.getValue());
+                        if (pathSeparator < expression.length() - 1) {
+                            if (value instanceof Path) {
+                                value = ((Path) value).resolve(expression.substring(pathSeparator + 1));
+                            } else {
+                                value = value + expression.substring(pathSeparator);
+                            }
+                        }
+                    } else {
+                        value = ReflectionValueExtractor.evaluate(expression, ctx.getValue());
+                    }
+                    break;
+                } catch (Exception e) {
+                    // TODO don't catch exception
+                    throw new ExpressionEvaluationException(
+                            "Error evaluating plugin parameter expression: " + expression, e);
+                }
+            }
+        }
+
+        /*
+         * MNG-4312: We neither have reserved all of the above magic expressions nor is their set fixed/well-known (it
+         * gets occasionally extended by newer Maven versions). This imposes the risk for existing plugins to
+         * unintentionally use such a magic expression for an ordinary property. So here we check whether we
+         * ended up with a magic value that is not compatible with the type of the configured mojo parameter (a string
+         * could still be converted by the configurator so we leave those alone). If so, back off to evaluating the
+         * expression from properties only.
+         */
+        if (value != null && type != null && !(value instanceof String) && !isTypeCompatible(type, value)) {
+            value = null;
+        }
+
+        if (value == null) {
+            // The CLI should win for defining properties
+
+            if (properties != null) {
+                // We will attempt to get nab a property as a way to specify a parameter
+                // to a plugin. My particular case here is allowing the surefire plugin
+                // to run a single test so I want to specify that class on the cli as
+                // a parameter.
+
+                value = properties.getProperty(expression);
+            }
+
+            if ((value == null) && ((project != null) && (project.getModel().getProperties() != null))) {
+                value = project.getModel().getProperties().get(expression);
+            }
+        }
+
+        if (value instanceof String) {
+            // TODO without #, this could just be an evaluate call...
+
+            String val = (String) value;
+
+            int exprStartDelimiter = val.indexOf("${");
+
+            if (exprStartDelimiter >= 0) {
+                if (exprStartDelimiter > 0) {
+                    value = val.substring(0, exprStartDelimiter) + evaluate(val.substring(exprStartDelimiter));
+                } else {
+                    value = evaluate(val.substring(exprStartDelimiter));
+                }
+            }
+        }
+
+        return value;
+    }
+
+    private static boolean isTypeCompatible(Class<?> type, Object value) {
+        if (type.isInstance(value)) {
+            return true;
+        }
+        // likely Boolean -> boolean, Short -> int etc. conversions, it's not the problem case we try to avoid
+        return ((type.isPrimitive() || type.getName().startsWith("java.lang."))
+                && value.getClass().getName().startsWith("java.lang."));
+    }
+
+    private String stripTokens(String expr) {
+        if (expr.startsWith("${") && (expr.indexOf('}') == expr.length() - 1)) {
+            expr = expr.substring(2, expr.length() - 1);
+        }
+        return expr;
+    }
+
+    @Override
+    public File alignToBaseDirectory(File file) {
+        // TODO Copied from the DefaultInterpolator. We likely want to resurrect the PathTranslator or at least a
+        // similar component for re-usage
+        if (file != null) {
+            if (file.isAbsolute()) {
+                // path was already absolute, just normalize file separator and we're done
+            } else if (file.getPath().startsWith(File.separator)) {
+                // drive-relative Windows path, don't align with project directory but with drive root
+                file = file.getAbsoluteFile();
+            } else {
+                // an ordinary relative path, align with project directory
+                file = basedir.resolve(file.getPath())
+                        .normalize()
+                        .toAbsolutePath()
+                        .toFile();
+            }
+        }
+        return file;
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java
index 78c3ae6..2c73a00 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginRealmCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.List;
 import java.util.Map;
@@ -35,23 +34,17 @@
  * technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
  * prior notice.
  *
- * @author Igor Fedorenko
- * @author Benjamin Bentmann
  */
-public interface PluginRealmCache
-{
+public interface PluginRealmCache {
     /**
      * CacheRecord
      */
-    class CacheRecord
-    {
-        public ClassRealm getRealm()
-        {
+    class CacheRecord {
+        public ClassRealm getRealm() {
             return realm;
         }
 
-        public List<Artifact> getArtifacts()
-        {
+        public List<Artifact> getArtifacts() {
             return artifacts;
         }
 
@@ -59,8 +52,7 @@
 
         private final List<Artifact> artifacts;
 
-        public CacheRecord( ClassRealm realm, List<Artifact> artifacts )
-        {
+        public CacheRecord(ClassRealm realm, List<Artifact> artifacts) {
             this.realm = realm;
             this.artifacts = artifacts;
         }
@@ -69,18 +61,28 @@
     /**
      * A cache key.
      */
-    interface Key
-    {
+    interface Key {
         // marker interface for cache keys
     }
 
-    Key createKey( Plugin plugin, ClassLoader parentRealm, Map<String, ClassLoader> foreignImports,
-                   DependencyFilter dependencyFilter, List<RemoteRepository> repositories,
-                   RepositorySystemSession session );
+    @FunctionalInterface
+    interface PluginRealmSupplier {
+        CacheRecord load() throws PluginResolutionException, PluginContainerException;
+    }
 
-    CacheRecord get( Key key );
+    Key createKey(
+            Plugin plugin,
+            ClassLoader parentRealm,
+            Map<String, ClassLoader> foreignImports,
+            DependencyFilter dependencyFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session);
 
-    CacheRecord put( Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts );
+    CacheRecord get(Key key);
+
+    CacheRecord get(Key key, PluginRealmSupplier supplier) throws PluginResolutionException, PluginContainerException;
+
+    CacheRecord put(Key key, ClassRealm pluginRealm, List<Artifact> pluginArtifacts);
 
     void flush();
 
@@ -92,6 +94,5 @@
      * @param project The project that employs the plugin realm, must not be {@code null}.
      * @param record The cache record being used for the project, must not be {@code null}.
      */
-    void register( MavenProject project, Key key, CacheRecord record );
-
+    void register(MavenProject project, Key key, CacheRecord record);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginResolutionException.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginResolutionException.java
index ab28064..048444d 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/PluginResolutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,30 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.model.Plugin;
 
 /**
  * Exception occurring trying to resolve a plugin.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class PluginResolutionException
-    extends Exception
-{
+public class PluginResolutionException extends Exception {
 
     private final Plugin plugin;
 
-    public PluginResolutionException( Plugin plugin, Throwable cause )
-    {
-        super( "Plugin " + plugin.getId() + " or one of its dependencies could not be resolved: " + cause.getMessage(),
-               cause );
+    public PluginResolutionException(Plugin plugin, Throwable cause) {
+        super(
+                "Plugin " + plugin.getId() + " or one of its dependencies could not be resolved: " + cause.getMessage(),
+                cause);
         this.plugin = plugin;
     }
 
-    public Plugin getPlugin()
-    {
+    public Plugin getPlugin() {
         return plugin;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/PluginValidationManager.java b/maven-core/src/main/java/org/apache/maven/plugin/PluginValidationManager.java
new file mode 100644
index 0000000..d65f8da
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/PluginValidationManager.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+
+/**
+ * Component collecting plugin validation issues and reporting them.
+ *
+ * @since 3.9.2
+ */
+public interface PluginValidationManager {
+    enum IssueLocality {
+        /**
+         * Issue is "user actionable", is internal to the currently built project and is reparable from scope of it
+         * by doing some change (for example by changing POM and fixing the problematic plugin configuration).
+         */
+        INTERNAL,
+
+        /**
+         * Issue (present in some plugin) is "developer actionable" (of given plugin, by changing code and doing
+         * new release), is NOT local to the currently built project. It may be reparable by updating given plugin
+         * to new fixed version, or by dropping plugin use from currently built project.
+         * <p>
+         * Note: if a reactor build contains a plugin (with issues) and later that built plugin is used in build,
+         * it will be reported as "external". It is up to developer to correctly interpret output (GAV) of issues
+         * and realize that in this case he wears two hats:" "user" and "(plugin) developer".
+         */
+        EXTERNAL
+    }
+
+    /**
+     * Reports plugin issues applicable to the plugin as a whole.
+     * <p>
+     * This method should be used in "early" phase of plugin execution, possibly even when plugin or mojo descriptor
+     * does not exist yet. In turn, this method will not record extra information like plugin occurrence or declaration
+     * location as those are not yet available.
+     */
+    void reportPluginValidationIssue(
+            IssueLocality locality, RepositorySystemSession session, Artifact pluginArtifact, String issue);
+
+    /**
+     * Reports plugin issues applicable to the plugin as a whole.
+     * <p>
+     * This method will record extra information as well, like plugin occurrence or declaration location.
+     */
+    void reportPluginValidationIssue(
+            IssueLocality locality, MavenSession mavenSession, MojoDescriptor mojoDescriptor, String issue);
+
+    /**
+     * Reports plugin Mojo issues applicable to the Mojo itself.
+     * <p>
+     * This method will record extra information as well, like plugin occurrence or declaration location.
+     */
+    void reportPluginMojoValidationIssue(
+            IssueLocality locality,
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            String issue);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginDependenciesValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginDependenciesValidator.java
new file mode 100644
index 0000000..43421ce
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginDependenciesValidator.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import org.apache.maven.plugin.PluginValidationManager;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Service responsible for validating plugin dependencies.
+ *
+ * @since 3.9.2
+ */
+abstract class AbstractMavenPluginDependenciesValidator implements MavenPluginDependenciesValidator {
+
+    protected final PluginValidationManager pluginValidationManager;
+
+    protected AbstractMavenPluginDependenciesValidator(PluginValidationManager pluginValidationManager) {
+        this.pluginValidationManager = requireNonNull(pluginValidationManager);
+    }
+
+    @Override
+    public void validate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult) {
+        if (artifactDescriptorResult.getDependencies() != null) {
+            doValidate(session, pluginArtifact, artifactDescriptorResult);
+        }
+    }
+
+    protected abstract void doValidate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginDescriptorSourcedParametersValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginDescriptorSourcedParametersValidator.java
new file mode 100644
index 0000000..e088eea
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginDescriptorSourcedParametersValidator.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.maven.plugin.PluginValidationManager;
+
+/**
+ * Common implementations for plugin parameters configuration validation that relies on Mojo descriptor (leaves out
+ * core parameters by default).
+ *
+ */
+abstract class AbstractMavenPluginDescriptorSourcedParametersValidator extends AbstractMavenPluginParametersValidator {
+
+    // plugin author can provide @Parameter( property = "session" ) in this case property will always evaluate
+    // so, we need ignore those
+
+    // source org.apache.maven.plugin.PluginParameterExpressionEvaluator
+    private static final List<String> IGNORED_PROPERTY_VALUES = Arrays.asList(
+            "basedir",
+            "executedProject",
+            "localRepository",
+            "mojo",
+            "mojoExecution",
+            "plugin",
+            "project",
+            "reactorProjects",
+            "session",
+            "settings");
+
+    private static final List<String> IGNORED_PROPERTY_PREFIX =
+            Arrays.asList("mojo.", "pom.", "plugin.", "project.", "session.", "settings.");
+
+    protected AbstractMavenPluginDescriptorSourcedParametersValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
+    }
+
+    @Override
+    protected boolean isIgnoredProperty(String strValue) {
+        if (!strValue.startsWith("${")) {
+            return false;
+        }
+
+        String propertyName = strValue.replace("${", "").replace("}", "");
+
+        if (IGNORED_PROPERTY_VALUES.contains(propertyName)) {
+            return true;
+        }
+
+        return IGNORED_PROPERTY_PREFIX.stream().anyMatch(propertyName::startsWith);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator.java
index d0fb15d..9e7426b 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/AbstractMavenPluginParametersValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,88 +16,56 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
-import java.util.Arrays;
-import java.util.List;
-
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.PluginValidationManager;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.apache.maven.shared.utils.logging.MessageUtils;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
-import org.slf4j.Logger;
+
+import static java.util.Objects.requireNonNull;
 
 /**
  * Common implementations for plugin parameters configuration validation.
  *
- * @author Slawomir Jaranowski
  */
-abstract class AbstractMavenPluginParametersValidator implements MavenPluginConfigurationValidator
-{
+abstract class AbstractMavenPluginParametersValidator implements MavenPluginConfigurationValidator {
 
-    // plugin author can provide @Parameter( property = "session" ) in this case property will always evaluate
-    // so, we need ignore those
+    protected final PluginValidationManager pluginValidationManager;
 
-    // source org.apache.maven.plugin.PluginParameterExpressionEvaluator
-    private static final List<String> IGNORED_PROPERTY_VALUES = Arrays.asList(
-        "basedir",
-        "executedProject",
-        "localRepository",
-        "mojo",
-        "mojoExecution",
-        "plugin",
-        "project",
-        "reactorProjects",
-        "session",
-        "settings"
-    );
+    protected AbstractMavenPluginParametersValidator(PluginValidationManager pluginValidationManager) {
+        this.pluginValidationManager = requireNonNull(pluginValidationManager);
+    }
 
-    private static final List<String> IGNORED_PROPERTY_PREFIX = Arrays.asList(
-        "mojo.",
-        "plugin.",
-        "project.",
-        "session.",
-        "settings."
-    );
-
-    protected abstract Logger getLogger();
-
-    protected static boolean isValueSet( PlexusConfiguration config,
-                                         ExpressionEvaluator expressionEvaluator )
-    {
-        if ( config == null )
-        {
+    protected boolean isValueSet(PlexusConfiguration config, ExpressionEvaluator expressionEvaluator) {
+        if (config == null) {
             return false;
         }
 
         // there are sub items ... so configuration is declared
-        if ( config.getChildCount() > 0 )
-        {
+        if (config.getChildCount() > 0) {
             return true;
         }
 
         String strValue = config.getValue();
 
-        if ( strValue == null || strValue.isEmpty() )
-        {
+        if (strValue == null || strValue.isEmpty()) {
             return false;
         }
 
-        if ( isIgnoredProperty( strValue ) )
-        {
+        if (isIgnoredProperty(strValue)) {
             return false;
         }
 
         // for declaration like @Parameter( property = "config.property" )
         // the value will contain ${config.property}
 
-        try
-        {
-            return expressionEvaluator.evaluate( strValue ) != null;
-        }
-        catch ( ExpressionEvaluationException e )
-        {
+        try {
+            return expressionEvaluator.evaluate(strValue) != null;
+        } catch (ExpressionEvaluationException e) {
             // not important
             // will be reported during Mojo fields populate
         }
@@ -108,45 +74,42 @@
         return false;
     }
 
-    private static boolean isIgnoredProperty( String strValue )
-    {
-        if ( !strValue.startsWith( "${" ) )
-        {
-            return false;
-        }
-
-        String propertyName = strValue.replace( "${", "" ).replace( "}", "" );
-
-        if ( IGNORED_PROPERTY_VALUES.contains( propertyName ) )
-        {
-            return true;
-        }
-
-        return IGNORED_PROPERTY_PREFIX.stream().anyMatch( propertyName::startsWith );
+    @Override
+    public final void validate(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator) {
+        doValidate(mavenSession, mojoDescriptor, mojoClass, pomConfiguration, expressionEvaluator);
     }
 
-    protected abstract String getParameterLogReason( Parameter parameter );
+    protected abstract void doValidate(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator);
 
-    protected void logParameter( Parameter parameter )
-    {
-        MessageBuilder messageBuilder = MessageUtils.buffer()
-            .warning( "Parameter '" )
-            .warning( parameter.getName() )
-            .warning( '\'' );
+    protected boolean isIgnoredProperty(String strValue) {
+        return false;
+    }
 
-        if ( parameter.getExpression() != null )
-        {
-            String userProperty = parameter.getExpression().replace( "${", "'" ).replace( '}', '\'' );
-            messageBuilder
-                .warning( " (user property " )
-                .warning( userProperty )
-                .warning( ")" );
+    protected abstract String getParameterLogReason(Parameter parameter);
+
+    protected String formatParameter(Parameter parameter) {
+        StringBuilder stringBuilder = new StringBuilder()
+                .append("Parameter '")
+                .append(parameter.getName())
+                .append('\'');
+
+        if (parameter.getExpression() != null) {
+            String userProperty = parameter.getExpression().replace("${", "'").replace('}', '\'');
+            stringBuilder.append(" (user property ").append(userProperty).append(")");
         }
 
-        messageBuilder
-            .warning( " " )
-            .warning( getParameterLogReason( parameter ) );
+        stringBuilder.append(" ").append(getParameterLogReason(parameter));
 
-        getLogger().warn( messageBuilder.toString() );
+        return stringBuilder.toString();
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultLegacySupport.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultLegacySupport.java
index bc02e1f..79acd24 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultLegacySupport.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultLegacySupport.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.concurrent.atomic.AtomicReference;
+package org.apache.maven.plugin.internal;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.concurrent.atomic.AtomicReference;
+
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.LegacySupport;
 import org.eclipse.aether.RepositorySystemSession;
@@ -34,45 +33,33 @@
  * particular, this component can be changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultLegacySupport
-    implements LegacySupport
-{
+public class DefaultLegacySupport implements LegacySupport {
 
-    private static final ThreadLocal<AtomicReference<MavenSession>> SESSION =
-        new InheritableThreadLocal<>();
+    private static final ThreadLocal<AtomicReference<MavenSession>> SESSION = new InheritableThreadLocal<>();
 
-    public void setSession( MavenSession session )
-    {
+    public void setSession(MavenSession session) {
         AtomicReference<MavenSession> reference = DefaultLegacySupport.SESSION.get();
-        if ( reference != null )
-        {
-            reference.set( null );
+        if (reference != null) {
+            reference.set(null);
         }
 
-        if ( session == null && reference != null )
-        {
+        if (session == null && reference != null) {
             DefaultLegacySupport.SESSION.remove();
-        }
-        else
-        {
-            DefaultLegacySupport.SESSION.set( new AtomicReference<>( session ) );
+        } else {
+            DefaultLegacySupport.SESSION.set(new AtomicReference<>(session));
         }
     }
 
-    public MavenSession getSession()
-    {
+    public MavenSession getSession() {
         AtomicReference<MavenSession> currentSession = DefaultLegacySupport.SESSION.get();
         return currentSession != null ? currentSession.get() : null;
     }
 
-    public RepositorySystemSession getRepositorySession()
-    {
+    public RepositorySystemSession getRepositorySession() {
         MavenSession session = getSession();
-        return ( session != null ) ? session.getRepositorySession() : null;
+        return (session != null) ? session.getRepositorySession() : null;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
index 71c355a..6fa005b 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,46 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.jar.JarFile;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.name.Names;
 import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.classrealm.ClassRealmManager;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
+import org.apache.maven.internal.impl.DefaultMojoExecution;
+import org.apache.maven.internal.impl.InternalSession;
+import org.apache.maven.internal.xml.XmlPlexusConfiguration;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.ContextEnabled;
 import org.apache.maven.plugin.DebugConfigurationListener;
 import org.apache.maven.plugin.ExtensionRealmCache;
 import org.apache.maven.plugin.InvalidPluginDescriptorException;
 import org.apache.maven.plugin.MavenPluginManager;
+import org.apache.maven.plugin.MavenPluginPrerequisitesChecker;
 import org.apache.maven.plugin.Mojo;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.MojoNotFoundException;
@@ -42,8 +68,10 @@
 import org.apache.maven.plugin.PluginManagerException;
 import org.apache.maven.plugin.PluginParameterException;
 import org.apache.maven.plugin.PluginParameterExpressionEvaluator;
+import org.apache.maven.plugin.PluginParameterExpressionEvaluatorV4;
 import org.apache.maven.plugin.PluginRealmCache;
 import org.apache.maven.plugin.PluginResolutionException;
+import org.apache.maven.plugin.PluginValidationManager;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
@@ -69,12 +97,10 @@
 import org.codehaus.plexus.component.repository.ComponentDescriptor;
 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
 import org.codehaus.plexus.configuration.PlexusConfigurationException;
-import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.graph.DependencyFilter;
 import org.eclipse.aether.graph.DependencyNode;
@@ -84,41 +110,16 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.BufferedInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.jar.JarFile;
-import java.util.zip.ZipEntry;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 /**
  * Provides basic services to manage Maven plugins and their mojos. This component is kept general in its design such
  * that the plugins/mojos can be used in arbitrary contexts. In particular, the mojos can be used for ordinary build
  * plugins as well as special purpose plugins like reports.
  *
- * @author Benjamin Bentmann
  * @since 3.0
  */
 @Named
 @Singleton
-public class DefaultMavenPluginManager
-    implements MavenPluginManager
-{
+public class DefaultMavenPluginManager implements MavenPluginManager {
 
     /**
      * <p>
@@ -131,7 +132,7 @@
      */
     public static final String KEY_EXTENSIONS_REALMS = DefaultMavenPluginManager.class.getName() + "/extensionsRealms";
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private PlexusContainer container;
     private ClassRealmManager classRealmManager;
@@ -144,11 +145,13 @@
     private PluginArtifactsCache pluginArtifactsCache;
     private MavenPluginValidator pluginValidator;
     private List<MavenPluginConfigurationValidator> configurationValidators;
-
+    private PluginValidationManager pluginValidationManager;
+    private List<MavenPluginPrerequisitesChecker> prerequisitesCheckers;
     private final ExtensionDescriptorBuilder extensionDescriptorBuilder = new ExtensionDescriptorBuilder();
     private final PluginDescriptorBuilder builder = new PluginDescriptorBuilder();
 
     @Inject
+    @SuppressWarnings("checkstyle:ParameterNumber")
     public DefaultMavenPluginManager(
             PlexusContainer container,
             ClassRealmManager classRealmManager,
@@ -160,8 +163,9 @@
             PluginVersionResolver pluginVersionResolver,
             PluginArtifactsCache pluginArtifactsCache,
             MavenPluginValidator pluginValidator,
-            List<MavenPluginConfigurationValidator> configurationValidators )
-    {
+            List<MavenPluginConfigurationValidator> configurationValidators,
+            PluginValidationManager pluginValidationManager,
+            List<MavenPluginPrerequisitesChecker> prerequisitesCheckers) {
         this.container = container;
         this.classRealmManager = classRealmManager;
         this.pluginDescriptorCache = pluginDescriptorCache;
@@ -173,227 +177,215 @@
         this.pluginArtifactsCache = pluginArtifactsCache;
         this.pluginValidator = pluginValidator;
         this.configurationValidators = configurationValidators;
+        this.pluginValidationManager = pluginValidationManager;
+        this.prerequisitesCheckers = prerequisitesCheckers;
     }
 
-    public synchronized PluginDescriptor getPluginDescriptor( Plugin plugin, List<RemoteRepository> repositories,
-                                                             RepositorySystemSession session )
-        throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException
-    {
-        PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey( plugin, repositories, session );
+    public PluginDescriptor getPluginDescriptor(
+            Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginResolutionException, PluginDescriptorParsingException, InvalidPluginDescriptorException {
+        PluginDescriptorCache.Key cacheKey = pluginDescriptorCache.createKey(plugin, repositories, session);
 
-        PluginDescriptor pluginDescriptor = pluginDescriptorCache.get( cacheKey );
-
-        if ( pluginDescriptor == null )
-        {
+        PluginDescriptor pluginDescriptor = pluginDescriptorCache.get(cacheKey, () -> {
             org.eclipse.aether.artifact.Artifact artifact =
-                pluginDependenciesResolver.resolve( plugin, repositories, session );
+                    pluginDependenciesResolver.resolve(plugin, repositories, session);
 
-            Artifact pluginArtifact = RepositoryUtils.toArtifact( artifact );
+            Artifact pluginArtifact = RepositoryUtils.toArtifact(artifact);
 
-            pluginDescriptor = extractPluginDescriptor( pluginArtifact, plugin );
+            PluginDescriptor descriptor = extractPluginDescriptor(pluginArtifact, plugin);
 
-            pluginDescriptor.setRequiredMavenVersion( artifact.getProperty( "requiredMavenVersion", null ) );
+            boolean isBlankVersion = descriptor.getRequiredMavenVersion() == null
+                    || descriptor.getRequiredMavenVersion().trim().isEmpty();
 
-            pluginDescriptorCache.put( cacheKey, pluginDescriptor );
-        }
+            if (isBlankVersion) {
+                // only take value from underlying POM if plugin descriptor has no explicit Maven requirement
+                descriptor.setRequiredMavenVersion(artifact.getProperty("requiredMavenVersion", null));
+            }
 
-        pluginDescriptor.setPlugin( plugin );
+            return descriptor;
+        });
+
+        pluginDescriptor.setPlugin(plugin);
 
         return pluginDescriptor;
     }
 
-    private PluginDescriptor extractPluginDescriptor( Artifact pluginArtifact, Plugin plugin )
-        throws PluginDescriptorParsingException, InvalidPluginDescriptorException
-    {
+    private PluginDescriptor extractPluginDescriptor(Artifact pluginArtifact, Plugin plugin)
+            throws PluginDescriptorParsingException, InvalidPluginDescriptorException {
         PluginDescriptor pluginDescriptor = null;
 
         File pluginFile = pluginArtifact.getFile();
 
-        try
-        {
-            if ( pluginFile.isFile() )
-            {
-                try ( JarFile pluginJar = new JarFile( pluginFile, false ) )
-                {
-                    ZipEntry pluginDescriptorEntry = pluginJar.getEntry( getPluginDescriptorLocation() );
+        try {
+            if (pluginFile.isFile()) {
+                try (JarFile pluginJar = new JarFile(pluginFile, false)) {
+                    ZipEntry pluginDescriptorEntry = pluginJar.getEntry(getPluginDescriptorLocation());
 
-                    if ( pluginDescriptorEntry != null )
-                    {
-                        InputStream is = pluginJar.getInputStream( pluginDescriptorEntry );
-
-                        pluginDescriptor = parsePluginDescriptor( is, plugin, pluginFile.getAbsolutePath() );
+                    if (pluginDescriptorEntry != null) {
+                        pluginDescriptor = parsePluginDescriptor(
+                                () -> pluginJar.getInputStream(pluginDescriptorEntry),
+                                plugin,
+                                pluginFile.getAbsolutePath());
                     }
                 }
-            }
-            else
-            {
-                File pluginXml = new File( pluginFile, getPluginDescriptorLocation() );
+            } else {
+                File pluginXml = new File(pluginFile, getPluginDescriptorLocation());
 
-                if ( pluginXml.isFile() )
-                {
-                    try ( InputStream is = new BufferedInputStream( new FileInputStream( pluginXml ) ) )
-                    {
-                        pluginDescriptor = parsePluginDescriptor( is, plugin, pluginXml.getAbsolutePath() );
-                    }
+                if (pluginXml.isFile()) {
+                    pluginDescriptor = parsePluginDescriptor(
+                            () -> Files.newInputStream(pluginXml.toPath()), plugin, pluginXml.getAbsolutePath());
                 }
             }
 
-            if ( pluginDescriptor == null )
-            {
-                throw new IOException( "No plugin descriptor found at " + getPluginDescriptorLocation() );
+            if (pluginDescriptor == null) {
+                throw new IOException("No plugin descriptor found at " + getPluginDescriptorLocation());
             }
-        }
-        catch ( IOException e )
-        {
-            throw new PluginDescriptorParsingException( plugin, pluginFile.getAbsolutePath(), e );
+        } catch (IOException e) {
+            throw new PluginDescriptorParsingException(plugin, pluginFile.getAbsolutePath(), e);
         }
 
         List<String> errors = new ArrayList<>();
-        pluginValidator.validate( pluginArtifact, pluginDescriptor, errors );
+        pluginValidator.validate(pluginArtifact, pluginDescriptor, errors);
 
-        if ( !errors.isEmpty() )
-        {
+        if (!errors.isEmpty()) {
             throw new InvalidPluginDescriptorException(
-                "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", errors );
+                    "Invalid plugin descriptor for " + plugin.getId() + " (" + pluginFile + ")", errors);
         }
 
-        pluginDescriptor.setPluginArtifact( pluginArtifact );
+        pluginDescriptor.setPluginArtifact(pluginArtifact);
 
         return pluginDescriptor;
     }
 
-    private String getPluginDescriptorLocation()
-    {
+    private String getPluginDescriptorLocation() {
         return "META-INF/maven/plugin.xml";
     }
 
-    private PluginDescriptor parsePluginDescriptor( InputStream is, Plugin plugin, String descriptorLocation )
-        throws PluginDescriptorParsingException
-    {
-        try
-        {
-            Reader reader = ReaderFactory.newXmlReader( is );
-
-            return builder.build( reader, descriptorLocation );
-        }
-        catch ( IOException | PlexusConfigurationException e )
-        {
-            throw new PluginDescriptorParsingException( plugin, descriptorLocation, e );
+    private PluginDescriptor parsePluginDescriptor(
+            PluginDescriptorBuilder.StreamSupplier is, Plugin plugin, String descriptorLocation)
+            throws PluginDescriptorParsingException {
+        try {
+            return builder.build(is, descriptorLocation);
+        } catch (PlexusConfigurationException e) {
+            throw new PluginDescriptorParsingException(plugin, descriptorLocation, e);
         }
     }
 
-    public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
-                                             RepositorySystemSession session )
-        throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        InvalidPluginDescriptorException
-    {
-        PluginDescriptor pluginDescriptor = getPluginDescriptor( plugin, repositories, session );
+    public MojoDescriptor getMojoDescriptor(
+            Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws MojoNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    InvalidPluginDescriptorException {
+        PluginDescriptor pluginDescriptor = getPluginDescriptor(plugin, repositories, session);
 
-        MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo( goal );
+        MojoDescriptor mojoDescriptor = pluginDescriptor.getMojo(goal);
 
-        if ( mojoDescriptor == null )
-        {
-            throw new MojoNotFoundException( goal, pluginDescriptor );
+        if (mojoDescriptor == null) {
+            throw new MojoNotFoundException(goal, pluginDescriptor);
         }
 
         return mojoDescriptor;
     }
 
-    public void checkRequiredMavenVersion( PluginDescriptor pluginDescriptor )
-        throws PluginIncompatibleException
-    {
-        String requiredMavenVersion = pluginDescriptor.getRequiredMavenVersion();
-        if ( StringUtils.isNotBlank( requiredMavenVersion ) )
-        {
-            try
-            {
-                if ( !runtimeInformation.isMavenVersion( requiredMavenVersion ) )
-                {
-                    throw new PluginIncompatibleException( pluginDescriptor.getPlugin(),
-                                                           "The plugin " + pluginDescriptor.getId()
-                                                               + " requires Maven version " + requiredMavenVersion );
-                }
+    @Override
+    public void checkPrerequisites(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException {
+        List<IllegalStateException> prerequisiteExceptions = new ArrayList<>();
+        prerequisitesCheckers.forEach(c -> {
+            try {
+                c.accept(pluginDescriptor);
+            } catch (IllegalStateException e) {
+                prerequisiteExceptions.add(e);
             }
-            catch ( RuntimeException e )
-            {
-                logger.warn( "Could not verify plugin's Maven prerequisite: " + e.getMessage() );
-            }
+        });
+        // aggregate all exceptions
+        if (!prerequisiteExceptions.isEmpty()) {
+            String messages = prerequisiteExceptions.stream()
+                    .map(IllegalStateException::getMessage)
+                    .collect(Collectors.joining(", "));
+            PluginIncompatibleException pie = new PluginIncompatibleException(
+                    pluginDescriptor.getPlugin(),
+                    "The plugin " + pluginDescriptor.getId() + " has unmet prerequisites: " + messages,
+                    prerequisiteExceptions.get(0));
+            // the first exception is added as cause, all other ones as suppressed exceptions
+            prerequisiteExceptions.stream().skip(1).forEach(pie::addSuppressed);
+            throw pie;
         }
     }
 
-    public synchronized void setupPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session,
-                                               ClassLoader parent, List<String> imports, DependencyFilter filter )
-        throws PluginResolutionException, PluginContainerException
-    {
+    @Override
+    @Deprecated
+    public void checkRequiredMavenVersion(PluginDescriptor pluginDescriptor) throws PluginIncompatibleException {
+        checkPrerequisites(pluginDescriptor);
+    }
+
+    public void setupPluginRealm(
+            PluginDescriptor pluginDescriptor,
+            MavenSession session,
+            ClassLoader parent,
+            List<String> imports,
+            DependencyFilter filter)
+            throws PluginResolutionException, PluginContainerException {
         Plugin plugin = pluginDescriptor.getPlugin();
         MavenProject project = session.getCurrentProject();
 
-        if ( plugin.isExtensions() )
-        {
+        if (plugin.isExtensions()) {
             ExtensionRealmCache.CacheRecord extensionRecord;
-            try
-            {
+            try {
                 RepositorySystemSession repositorySession = session.getRepositorySession();
-                extensionRecord = setupExtensionsRealm( project, plugin, repositorySession );
-            }
-            catch ( PluginManagerException e )
-            {
+                extensionRecord = setupExtensionsRealm(project, plugin, repositorySession);
+            } catch (PluginManagerException e) {
                 // extensions realm is expected to be fully setup at this point
                 // any exception means a problem in maven code, not a user error
-                throw new IllegalStateException( e );
+                throw new IllegalStateException(e);
             }
 
             ClassRealm pluginRealm = extensionRecord.getRealm();
             List<Artifact> pluginArtifacts = extensionRecord.getArtifacts();
 
-            for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
-            {
-                componentDescriptor.setRealm( pluginRealm );
+            for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
+                componentDescriptor.setRealm(pluginRealm);
             }
 
-            pluginDescriptor.setClassRealm( pluginRealm );
-            pluginDescriptor.setArtifacts( pluginArtifacts );
-        }
-        else
-        {
-            Map<String, ClassLoader> foreignImports = calcImports( project, parent, imports );
+            pluginDescriptor.setClassRealm(pluginRealm);
+            pluginDescriptor.setArtifacts(pluginArtifacts);
+        } else {
+            Map<String, ClassLoader> foreignImports = calcImports(project, parent, imports);
 
-            PluginRealmCache.Key cacheKey = pluginRealmCache.createKey( plugin, parent, foreignImports, filter,
-                                                                        project.getRemotePluginRepositories(),
-                                                                        session.getRepositorySession() );
+            PluginRealmCache.Key cacheKey = pluginRealmCache.createKey(
+                    plugin,
+                    parent,
+                    foreignImports,
+                    filter,
+                    project.getRemotePluginRepositories(),
+                    session.getRepositorySession());
 
-            PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get( cacheKey );
+            PluginRealmCache.CacheRecord cacheRecord = pluginRealmCache.get(cacheKey, () -> {
+                createPluginRealm(pluginDescriptor, session, parent, foreignImports, filter);
 
-            if ( cacheRecord != null )
-            {
-                pluginDescriptor.setClassRealm( cacheRecord.getRealm() );
-                pluginDescriptor.setArtifacts( new ArrayList<>( cacheRecord.getArtifacts() ) );
-                for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
-                {
-                    componentDescriptor.setRealm( cacheRecord.getRealm() );
-                }
-            }
-            else
-            {
-                createPluginRealm( pluginDescriptor, session, parent, foreignImports, filter );
+                return new PluginRealmCache.CacheRecord(
+                        pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts());
+            });
 
-                cacheRecord =
-                    pluginRealmCache.put( cacheKey, pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts() );
+            pluginDescriptor.setClassRealm(cacheRecord.getRealm());
+            pluginDescriptor.setArtifacts(new ArrayList<>(cacheRecord.getArtifacts()));
+            for (ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents()) {
+                componentDescriptor.setRealm(cacheRecord.getRealm());
             }
 
-            pluginRealmCache.register( project, cacheKey, cacheRecord );
+            pluginRealmCache.register(project, cacheKey, cacheRecord);
         }
     }
 
-    private void createPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent,
-                                    Map<String, ClassLoader> foreignImports, DependencyFilter filter )
-        throws PluginResolutionException, PluginContainerException
-    {
-        Plugin plugin =
-            Objects.requireNonNull( pluginDescriptor.getPlugin(), "pluginDescriptor.plugin cannot be null" );
+    private void createPluginRealm(
+            PluginDescriptor pluginDescriptor,
+            MavenSession session,
+            ClassLoader parent,
+            Map<String, ClassLoader> foreignImports,
+            DependencyFilter filter)
+            throws PluginResolutionException, PluginContainerException {
+        Plugin plugin = Objects.requireNonNull(pluginDescriptor.getPlugin(), "pluginDescriptor.plugin cannot be null");
 
-        Artifact pluginArtifact = Objects.requireNonNull( pluginDescriptor.getPluginArtifact(),
-                                                          "pluginDescriptor.pluginArtifact cannot be null" );
+        Artifact pluginArtifact = Objects.requireNonNull(
+                pluginDescriptor.getPluginArtifact(), "pluginDescriptor.pluginArtifact cannot be null");
 
         MavenProject project = session.getCurrentProject();
 
@@ -402,535 +394,506 @@
 
         RepositorySystemSession repositorySession = session.getRepositorySession();
         DependencyFilter dependencyFilter = project.getExtensionDependencyFilter();
-        dependencyFilter = AndDependencyFilter.newInstance( dependencyFilter, filter );
+        dependencyFilter = AndDependencyFilter.newInstance(dependencyFilter, filter);
 
-        DependencyNode root =
-            pluginDependenciesResolver.resolve( plugin, RepositoryUtils.toArtifact( pluginArtifact ), dependencyFilter,
-                                                project.getRemotePluginRepositories(), repositorySession );
+        DependencyNode root = pluginDependenciesResolver.resolve(
+                plugin,
+                RepositoryUtils.toArtifact(pluginArtifact),
+                dependencyFilter,
+                project.getRemotePluginRepositories(),
+                repositorySession);
 
         PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
-        root.accept( nlg );
+        root.accept(nlg);
 
-        pluginArtifacts = toMavenArtifacts( root, nlg );
+        pluginArtifacts = toMavenArtifacts(root, nlg);
 
-        pluginRealm = classRealmManager.createPluginRealm( plugin, parent, null, foreignImports,
-                                                           toAetherArtifacts( pluginArtifacts ) );
+        pluginRealm = classRealmManager.createPluginRealm(
+                plugin, parent, null, foreignImports, toAetherArtifacts(pluginArtifacts));
 
-        discoverPluginComponents( pluginRealm, plugin, pluginDescriptor );
+        discoverPluginComponents(pluginRealm, plugin, pluginDescriptor);
 
-        pluginDescriptor.setClassRealm( pluginRealm );
-        pluginDescriptor.setArtifacts( pluginArtifacts );
+        pluginDescriptor.setDependencyNode(root);
+        pluginDescriptor.setClassRealm(pluginRealm);
+        pluginDescriptor.setArtifacts(pluginArtifacts);
     }
 
-    private void discoverPluginComponents( final ClassRealm pluginRealm, Plugin plugin,
-                                           PluginDescriptor pluginDescriptor )
-        throws PluginContainerException
-    {
-        try
-        {
-            if ( pluginDescriptor != null )
-            {
-                for ( ComponentDescriptor<?> componentDescriptor : pluginDescriptor.getComponents() )
-                {
-                    componentDescriptor.setRealm( pluginRealm );
-                    container.addComponentDescriptor( componentDescriptor );
+    private void discoverPluginComponents(
+            final ClassRealm pluginRealm, Plugin plugin, PluginDescriptor pluginDescriptor)
+            throws PluginContainerException {
+        try {
+            if (pluginDescriptor != null) {
+                for (MojoDescriptor mojo : pluginDescriptor.getMojos()) {
+                    if (!mojo.isV4Api()) {
+                        mojo.setRealm(pluginRealm);
+                        container.addComponentDescriptor(mojo);
+                    }
                 }
             }
 
-            ( (DefaultPlexusContainer) container ).discoverComponents( pluginRealm, new SessionScopeModule( container ),
-                                                                       new MojoExecutionScopeModule( container ) );
-        }
-        catch ( ComponentLookupException | CycleDetectedInComponentGraphException e )
-        {
-            throw new PluginContainerException( plugin, pluginRealm,
-                                                "Error in component graph of plugin " + plugin.getId() + ": "
-                                                    + e.getMessage(), e );
+            ((DefaultPlexusContainer) container)
+                    .discoverComponents(
+                            pluginRealm,
+                            new AbstractModule() {
+                                @Override
+                                protected void configure() {
+                                    if (pluginDescriptor != null) {
+                                        for (MojoDescriptor mojo : pluginDescriptor.getMojos()) {
+                                            if (mojo.isV4Api()) {
+                                                try {
+                                                    mojo.setRealm(pluginRealm);
+                                                    Class<?> cl = mojo.getImplementationClass();
+                                                    if (cl == null) {
+                                                        cl = pluginRealm.loadClass(mojo.getImplementation());
+                                                    }
+                                                    bind(org.apache.maven.api.plugin.Mojo.class)
+                                                            .annotatedWith(Names.named(mojo.getId()))
+                                                            .to((Class) cl);
+                                                } catch (ClassNotFoundException e) {
+                                                    throw new IllegalStateException("Unable to load mojo class", e);
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                            },
+                            new SessionScopeModule(container),
+                            new MojoExecutionScopeModule(container),
+                            new PluginConfigurationModule(plugin.getDelegate()));
+        } catch (ComponentLookupException | CycleDetectedInComponentGraphException e) {
+            throw new PluginContainerException(
+                    plugin,
+                    pluginRealm,
+                    "Error in component graph of plugin " + plugin.getId() + ": " + e.getMessage(),
+                    e);
         }
     }
 
-    private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts( final List<Artifact> pluginArtifacts )
-    {
-        return new ArrayList<>( RepositoryUtils.toArtifacts( pluginArtifacts ) );
+    private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts(final List<Artifact> pluginArtifacts) {
+        return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts));
     }
 
-    private List<Artifact> toMavenArtifacts( DependencyNode root, PreorderNodeListGenerator nlg )
-    {
-        List<Artifact> artifacts = new ArrayList<>( nlg.getNodes().size() );
-        RepositoryUtils.toArtifacts( artifacts, Collections.singleton( root ), Collections.emptyList(), null );
-        artifacts.removeIf( artifact -> artifact.getFile() == null );
-        return Collections.unmodifiableList( artifacts );
+    private List<Artifact> toMavenArtifacts(DependencyNode root, PreorderNodeListGenerator nlg) {
+        List<Artifact> artifacts = new ArrayList<>(nlg.getNodes().size());
+        RepositoryUtils.toArtifacts(artifacts, Collections.singleton(root), Collections.emptyList(), null);
+        artifacts.removeIf(artifact -> artifact.getFile() == null);
+        return Collections.unmodifiableList(artifacts);
     }
 
-    private Map<String, ClassLoader> calcImports( MavenProject project, ClassLoader parent, List<String> imports )
-    {
+    private Map<String, ClassLoader> calcImports(MavenProject project, ClassLoader parent, List<String> imports) {
         Map<String, ClassLoader> foreignImports = new HashMap<>();
 
         ClassLoader projectRealm = project.getClassRealm();
-        if ( projectRealm != null )
-        {
-            foreignImports.put( "", projectRealm );
-        }
-        else
-        {
-            foreignImports.put( "", classRealmManager.getMavenApiRealm() );
+        if (projectRealm != null) {
+            foreignImports.put("", projectRealm);
+        } else {
+            foreignImports.put("", classRealmManager.getMavenApiRealm());
         }
 
-        if ( parent != null && imports != null )
-        {
-            for ( String parentImport : imports )
-            {
-                foreignImports.put( parentImport, parent );
+        if (parent != null && imports != null) {
+            for (String parentImport : imports) {
+                foreignImports.put(parentImport, parent);
             }
         }
 
         return foreignImports;
     }
 
-    public <T> T getConfiguredMojo( Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution )
-        throws PluginConfigurationException, PluginContainerException
-    {
+    public <T> T getConfiguredMojo(Class<T> mojoInterface, MavenSession session, MojoExecution mojoExecution)
+            throws PluginConfigurationException, PluginContainerException {
         MojoDescriptor mojoDescriptor = mojoExecution.getMojoDescriptor();
 
         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
 
         ClassRealm pluginRealm = pluginDescriptor.getClassRealm();
 
-        if ( pluginRealm == null )
-        {
-            try
-            {
-                setupPluginRealm( pluginDescriptor, session, null, null, null );
-            }
-            catch ( PluginResolutionException e )
-            {
+        if (pluginRealm == null) {
+            try {
+                setupPluginRealm(pluginDescriptor, session, null, null, null);
+            } catch (PluginResolutionException e) {
                 String msg = "Cannot setup plugin realm [mojoDescriptor=" + mojoDescriptor.getId()
                         + ", pluginDescriptor=" + pluginDescriptor.getId() + "]";
-                throw new PluginConfigurationException( pluginDescriptor, msg, e );
+                throw new PluginConfigurationException(pluginDescriptor, msg, e);
             }
             pluginRealm = pluginDescriptor.getClassRealm();
         }
 
-        if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "Loading mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm );
+        if (logger.isDebugEnabled()) {
+            logger.debug("Loading mojo " + mojoDescriptor.getId() + " from plugin realm " + pluginRealm);
         }
 
         // We are forcing the use of the plugin realm for all lookups that might occur during
         // the lifecycle that is part of the lookup. Here we are specifically trying to keep
         // lookups that occur in contextualize calls in line with the right realm.
-        ClassRealm oldLookupRealm = container.setLookupRealm( pluginRealm );
+        ClassRealm oldLookupRealm = container.setLookupRealm(pluginRealm);
 
         ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
-        Thread.currentThread().setContextClassLoader( pluginRealm );
+        Thread.currentThread().setContextClassLoader(pluginRealm);
 
-        try
-        {
+        try {
             T mojo;
 
-            try
-            {
-                mojo = container.lookup( mojoInterface, mojoDescriptor.getRoleHint() );
-            }
-            catch ( ComponentLookupException e )
-            {
+            try {
+                mojo = container.lookup(mojoInterface, mojoDescriptor.getRoleHint());
+            } catch (ComponentLookupException e) {
                 Throwable cause = e.getCause();
-                while ( cause != null && !( cause instanceof LinkageError )
-                    && !( cause instanceof ClassNotFoundException ) )
-                {
+                while (cause != null
+                        && !(cause instanceof LinkageError)
+                        && !(cause instanceof ClassNotFoundException)) {
                     cause = cause.getCause();
                 }
 
-                if ( ( cause instanceof NoClassDefFoundError ) || ( cause instanceof ClassNotFoundException ) )
-                {
-                    ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
-                    PrintStream ps = new PrintStream( os );
-                    ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
-                                    + pluginDescriptor.getId() + "'. A required class is missing: "
-                                    + cause.getMessage() );
-                    pluginRealm.display( ps );
+                if ((cause instanceof NoClassDefFoundError) || (cause instanceof ClassNotFoundException)) {
+                    ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
+                    PrintStream ps = new PrintStream(os);
+                    ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
+                            + pluginDescriptor.getId() + "'. A required class is missing: "
+                            + cause.getMessage());
+                    pluginRealm.display(ps);
 
-                    throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause );
-                }
-                else if ( cause instanceof LinkageError )
-                {
-                    ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
-                    PrintStream ps = new PrintStream( os );
-                    ps.println( "Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
-                                    + pluginDescriptor.getId() + "' due to an API incompatibility: "
-                                    + e.getClass().getName() + ": " + cause.getMessage() );
-                    pluginRealm.display( ps );
+                    throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
+                } else if (cause instanceof LinkageError) {
+                    ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
+                    PrintStream ps = new PrintStream(os);
+                    ps.println("Unable to load the mojo '" + mojoDescriptor.getGoal() + "' in the plugin '"
+                            + pluginDescriptor.getId() + "' due to an API incompatibility: "
+                            + e.getClass().getName() + ": " + cause.getMessage());
+                    pluginRealm.display(ps);
 
-                    throw new PluginContainerException( mojoDescriptor, pluginRealm, os.toString(), cause );
+                    throw new PluginContainerException(mojoDescriptor, pluginRealm, os.toString(), cause);
                 }
 
-                throw new PluginContainerException( mojoDescriptor, pluginRealm,
-                                                    "Unable to load the mojo '" + mojoDescriptor.getGoal()
-                                                        + "' (or one of its required components) from the plugin '"
-                                                        + pluginDescriptor.getId() + "'", e );
+                throw new PluginContainerException(
+                        mojoDescriptor,
+                        pluginRealm,
+                        "Unable to load the mojo '" + mojoDescriptor.getGoal()
+                                + "' (or one of its required components) from the plugin '"
+                                + pluginDescriptor.getId() + "'",
+                        e);
             }
 
-            if ( mojo instanceof ContextEnabled )
-            {
+            if (mojo instanceof ContextEnabled) {
                 MavenProject project = session.getCurrentProject();
 
-                Map<String, Object> pluginContext = session.getPluginContext( pluginDescriptor, project );
+                Map<String, Object> pluginContext = session.getPluginContext(pluginDescriptor, project);
 
-                if ( pluginContext != null )
-                {
-                    pluginContext.put( "project", project );
+                if (pluginContext != null) {
+                    pluginContext.put("project", project);
 
-                    pluginContext.put( "pluginDescriptor", pluginDescriptor );
+                    pluginContext.put("pluginDescriptor", pluginDescriptor);
 
-                    ( (ContextEnabled) mojo ).setPluginContext( pluginContext );
+                    ((ContextEnabled) mojo).setPluginContext(pluginContext);
                 }
             }
 
-            if ( mojo instanceof Mojo )
-            {
-                Logger mojoLogger = LoggerFactory.getLogger( mojoDescriptor.getImplementation() );
-                ( (Mojo) mojo ).setLog( new MojoLogWrapper( mojoLogger ) );
+            if (mojo instanceof Mojo) {
+                Logger mojoLogger = LoggerFactory.getLogger(mojoDescriptor.getImplementation());
+                ((Mojo) mojo).setLog(new MojoLogWrapper(mojoLogger));
             }
 
-            Xpp3Dom dom = mojoExecution.getConfiguration();
+            if (mojo instanceof Contextualizable) {
+                pluginValidationManager.reportPluginMojoValidationIssue(
+                        PluginValidationManager.IssueLocality.EXTERNAL,
+                        session,
+                        mojoDescriptor,
+                        mojo.getClass(),
+                        "Mojo implements `Contextualizable` interface from Plexus Container, which is EOL.");
+            }
+
+            XmlNode dom = mojoExecution.getConfiguration() != null
+                    ? mojoExecution.getConfiguration().getDom()
+                    : null;
 
             PlexusConfiguration pomConfiguration;
 
-            if ( dom == null )
-            {
-                pomConfiguration = new XmlPlexusConfiguration( "configuration" );
-            }
-            else
-            {
-                pomConfiguration = new XmlPlexusConfiguration( dom );
+            if (dom == null) {
+                pomConfiguration = new DefaultPlexusConfiguration("configuration");
+            } else {
+                pomConfiguration = XmlPlexusConfiguration.toPlexusConfiguration(dom);
             }
 
-            ExpressionEvaluator expressionEvaluator = new PluginParameterExpressionEvaluator( session, mojoExecution );
-
-            for ( MavenPluginConfigurationValidator validator: configurationValidators )
-            {
-                validator.validate( mojoDescriptor, pomConfiguration, expressionEvaluator );
+            ExpressionEvaluator expressionEvaluator;
+            InternalSession sessionV4 = InternalSession.from(session.getSession());
+            if (mojoDescriptor.isV4Api()) {
+                expressionEvaluator = new PluginParameterExpressionEvaluatorV4(
+                        sessionV4,
+                        sessionV4.getProject(session.getCurrentProject()),
+                        new DefaultMojoExecution(sessionV4, mojoExecution));
+            } else {
+                expressionEvaluator = new PluginParameterExpressionEvaluator(session, mojoExecution);
             }
 
-            populateMojoExecutionFields( mojo, mojoExecution.getExecutionId(), mojoDescriptor, pluginRealm,
-                                         pomConfiguration, expressionEvaluator );
+            for (MavenPluginConfigurationValidator validator : configurationValidators) {
+                validator.validate(session, mojoDescriptor, mojo.getClass(), pomConfiguration, expressionEvaluator);
+            }
+
+            populateMojoExecutionFields(
+                    mojo,
+                    mojoExecution.getExecutionId(),
+                    mojoDescriptor,
+                    pluginRealm,
+                    pomConfiguration,
+                    expressionEvaluator);
 
             return mojo;
-        }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( oldClassLoader );
-            container.setLookupRealm( oldLookupRealm );
+        } finally {
+            Thread.currentThread().setContextClassLoader(oldClassLoader);
+            container.setLookupRealm(oldLookupRealm);
         }
     }
 
-    private void populateMojoExecutionFields( Object mojo, String executionId, MojoDescriptor mojoDescriptor,
-                                              ClassRealm pluginRealm, PlexusConfiguration configuration,
-                                              ExpressionEvaluator expressionEvaluator )
-        throws PluginConfigurationException
-    {
+    private void populateMojoExecutionFields(
+            Object mojo,
+            String executionId,
+            MojoDescriptor mojoDescriptor,
+            ClassRealm pluginRealm,
+            PlexusConfiguration configuration,
+            ExpressionEvaluator expressionEvaluator)
+            throws PluginConfigurationException {
         ComponentConfigurator configurator = null;
 
         String configuratorId = mojoDescriptor.getComponentConfigurator();
 
-        if ( StringUtils.isEmpty( configuratorId ) )
-        {
-            configuratorId = "basic";
+        if (configuratorId == null || configuratorId.isEmpty()) {
+            configuratorId = mojoDescriptor.isV4Api() ? "enhanced" : "basic";
         }
 
-        try
-        {
+        try {
             // TODO could the configuration be passed to lookup and the configurator known to plexus via the descriptor
             // so that this method could entirely be handled by a plexus lookup?
-            configurator = container.lookup( ComponentConfigurator.class, configuratorId );
+            configurator = container.lookup(ComponentConfigurator.class, configuratorId);
 
-            ConfigurationListener listener = new DebugConfigurationListener( logger );
+            ConfigurationListener listener = new DebugConfigurationListener(logger);
 
             ValidatingConfigurationListener validator =
-                new ValidatingConfigurationListener( mojo, mojoDescriptor, listener );
+                    new ValidatingConfigurationListener(mojo, mojoDescriptor, listener);
 
-            logger.debug( "Configuring mojo execution '" + mojoDescriptor.getId() + ':' + executionId + "' with "
-                + configuratorId + " configurator -->" );
+            if (logger.isDebugEnabled()) {
+                logger.debug("Configuring mojo execution '" + mojoDescriptor.getId() + ':' + executionId + "' with "
+                        + configuratorId + " configurator -->");
+            }
 
-            configurator.configureComponent( mojo, configuration, expressionEvaluator, pluginRealm, validator );
+            configurator.configureComponent(mojo, configuration, expressionEvaluator, pluginRealm, validator);
 
-            logger.debug( "-- end configuration --" );
+            logger.debug("-- end configuration --");
 
             Collection<Parameter> missingParameters = validator.getMissingParameters();
-            if ( !missingParameters.isEmpty() )
-            {
-                if ( "basic".equals( configuratorId ) )
-                {
-                    throw new PluginParameterException( mojoDescriptor, new ArrayList<>( missingParameters ) );
-                }
-                else
-                {
+            if (!missingParameters.isEmpty()) {
+                if ("basic".equals(configuratorId)) {
+                    throw new PluginParameterException(mojoDescriptor, new ArrayList<>(missingParameters));
+                } else {
                     /*
                      * NOTE: Other configurators like the map-oriented one don't call into the listener, so do it the
                      * hard way.
                      */
-                    validateParameters( mojoDescriptor, configuration, expressionEvaluator );
+                    validateParameters(mojoDescriptor, configuration, expressionEvaluator);
                 }
             }
-        }
-        catch ( ComponentConfigurationException e )
-        {
+        } catch (ComponentConfigurationException e) {
             String message = "Unable to parse configuration of mojo " + mojoDescriptor.getId();
-            if ( e.getFailedConfiguration() != null )
-            {
+            if (e.getFailedConfiguration() != null) {
                 message += " for parameter " + e.getFailedConfiguration().getName();
             }
             message += ": " + e.getMessage();
 
-            throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), message, e );
-        }
-        catch ( ComponentLookupException e )
-        {
-            throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(),
-                                                    "Unable to retrieve component configurator " + configuratorId
-                                                        + " for configuration of mojo " + mojoDescriptor.getId(), e );
-        }
-        catch ( NoClassDefFoundError e )
-        {
-            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
-            PrintStream ps = new PrintStream( os );
-            ps.println( "A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": "
-                            + e.getMessage() );
-            pluginRealm.display( ps );
+            throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), message, e);
+        } catch (ComponentLookupException e) {
+            throw new PluginConfigurationException(
+                    mojoDescriptor.getPluginDescriptor(),
+                    "Unable to retrieve component configurator " + configuratorId + " for configuration of mojo "
+                            + mojoDescriptor.getId(),
+                    e);
+        } catch (NoClassDefFoundError e) {
+            ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
+            PrintStream ps = new PrintStream(os);
+            ps.println("A required class was missing during configuration of mojo " + mojoDescriptor.getId() + ": "
+                    + e.getMessage());
+            pluginRealm.display(ps);
 
-            throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
-        }
-        catch ( LinkageError e )
-        {
-            ByteArrayOutputStream os = new ByteArrayOutputStream( 1024 );
-            PrintStream ps = new PrintStream( os );
-            ps.println(
-                "An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId() + ": "
-                    + e.getClass().getName() + ": " + e.getMessage() );
-            pluginRealm.display( ps );
+            throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e);
+        } catch (LinkageError e) {
+            ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
+            PrintStream ps = new PrintStream(os);
+            ps.println("An API incompatibility was encountered during configuration of mojo " + mojoDescriptor.getId()
+                    + ": " + e.getClass().getName() + ": " + e.getMessage());
+            pluginRealm.display(ps);
 
-            throw new PluginConfigurationException( mojoDescriptor.getPluginDescriptor(), os.toString(), e );
-        }
-        finally
-        {
-            if ( configurator != null )
-            {
-                try
-                {
-                    container.release( configurator );
-                }
-                catch ( ComponentLifecycleException e )
-                {
-                    logger.debug( "Failed to release mojo configurator - ignoring." );
+            throw new PluginConfigurationException(mojoDescriptor.getPluginDescriptor(), os.toString(), e);
+        } finally {
+            if (configurator != null) {
+                try {
+                    container.release(configurator);
+                } catch (ComponentLifecycleException e) {
+                    logger.debug("Failed to release mojo configurator - ignoring.");
                 }
             }
         }
     }
 
-    private void validateParameters( MojoDescriptor mojoDescriptor, PlexusConfiguration configuration,
-                                     ExpressionEvaluator expressionEvaluator )
-        throws ComponentConfigurationException, PluginParameterException
-    {
-        if ( mojoDescriptor.getParameters() == null )
-        {
+    private void validateParameters(
+            MojoDescriptor mojoDescriptor, PlexusConfiguration configuration, ExpressionEvaluator expressionEvaluator)
+            throws ComponentConfigurationException, PluginParameterException {
+        if (mojoDescriptor.getParameters() == null) {
             return;
         }
 
         List<Parameter> invalidParameters = new ArrayList<>();
 
-        for ( Parameter parameter : mojoDescriptor.getParameters() )
-        {
-            if ( !parameter.isRequired() )
-            {
+        for (Parameter parameter : mojoDescriptor.getParameters()) {
+            if (!parameter.isRequired()) {
                 continue;
             }
 
             Object value = null;
 
-            PlexusConfiguration config = configuration.getChild( parameter.getName(), false );
-            if ( config != null )
-            {
-                String expression = config.getValue( null );
+            PlexusConfiguration config = configuration.getChild(parameter.getName(), false);
+            if (config != null) {
+                String expression = config.getValue(null);
 
-                try
-                {
-                    value = expressionEvaluator.evaluate( expression );
+                try {
+                    value = expressionEvaluator.evaluate(expression);
 
-                    if ( value == null )
-                    {
-                        value = config.getAttribute( "default-value", null );
+                    if (value == null) {
+                        value = config.getAttribute("default-value", null);
                     }
-                }
-                catch ( ExpressionEvaluationException e )
-                {
+                } catch (ExpressionEvaluationException e) {
                     String msg = "Error evaluating the expression '" + expression + "' for configuration value '"
-                        + configuration.getName() + "'";
-                    throw new ComponentConfigurationException( configuration, msg, e );
+                            + configuration.getName() + "'";
+                    throw new ComponentConfigurationException(configuration, msg, e);
                 }
             }
 
-            if ( value == null && ( config == null || config.getChildCount() <= 0 ) )
-            {
-                invalidParameters.add( parameter );
+            if (value == null && (config == null || config.getChildCount() <= 0)) {
+                invalidParameters.add(parameter);
             }
         }
 
-        if ( !invalidParameters.isEmpty() )
-        {
-            throw new PluginParameterException( mojoDescriptor, invalidParameters );
+        if (!invalidParameters.isEmpty()) {
+            throw new PluginParameterException(mojoDescriptor, invalidParameters);
         }
     }
 
-    public void releaseMojo( Object mojo, MojoExecution mojoExecution )
-    {
-        if ( mojo != null )
-        {
-            try
-            {
-                container.release( mojo );
-            }
-            catch ( ComponentLifecycleException e )
-            {
+    public void releaseMojo(Object mojo, MojoExecution mojoExecution) {
+        if (mojo != null) {
+            try {
+                container.release(mojo);
+            } catch (ComponentLifecycleException e) {
                 String goalExecId = mojoExecution.getGoal();
 
-                if ( mojoExecution.getExecutionId() != null )
-                {
-                    goalExecId += " {execution: " + mojoExecution.getExecutionId() + "}";
+                if (mojoExecution.getExecutionId() != null) {
+                    logger.debug(
+                            "Error releasing mojo for {} {execution: {}}",
+                            goalExecId,
+                            mojoExecution.getExecutionId(),
+                            e);
+                } else {
+                    logger.debug("Error releasing mojo for {}", goalExecId, e);
                 }
-
-                logger.debug( "Error releasing mojo for " + goalExecId, e );
             }
         }
     }
 
-    public ExtensionRealmCache.CacheRecord setupExtensionsRealm( MavenProject project, Plugin plugin,
-                                                                 RepositorySystemSession session )
-        throws PluginManagerException
-    {
-        @SuppressWarnings( "unchecked" ) Map<String, ExtensionRealmCache.CacheRecord> pluginRealms =
-            (Map<String, ExtensionRealmCache.CacheRecord>) project.getContextValue( KEY_EXTENSIONS_REALMS );
-        if ( pluginRealms == null )
-        {
+    public ExtensionRealmCache.CacheRecord setupExtensionsRealm(
+            MavenProject project, Plugin plugin, RepositorySystemSession session) throws PluginManagerException {
+        @SuppressWarnings("unchecked")
+        Map<String, ExtensionRealmCache.CacheRecord> pluginRealms =
+                (Map<String, ExtensionRealmCache.CacheRecord>) project.getContextValue(KEY_EXTENSIONS_REALMS);
+        if (pluginRealms == null) {
             pluginRealms = new HashMap<>();
-            project.setContextValue( KEY_EXTENSIONS_REALMS, pluginRealms );
+            project.setContextValue(KEY_EXTENSIONS_REALMS, pluginRealms);
         }
 
         final String pluginKey = plugin.getId();
 
-        ExtensionRealmCache.CacheRecord extensionRecord = pluginRealms.get( pluginKey );
-        if ( extensionRecord != null )
-        {
+        ExtensionRealmCache.CacheRecord extensionRecord = pluginRealms.get(pluginKey);
+        if (extensionRecord != null) {
             return extensionRecord;
         }
 
         final List<RemoteRepository> repositories = project.getRemotePluginRepositories();
 
         // resolve plugin version as necessary
-        if ( plugin.getVersion() == null )
-        {
-            PluginVersionRequest versionRequest = new DefaultPluginVersionRequest( plugin, session, repositories );
-            try
-            {
-                plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
-            }
-            catch ( PluginVersionResolutionException e )
-            {
-                throw new PluginManagerException( plugin, e.getMessage(), e );
+        if (plugin.getVersion() == null) {
+            PluginVersionRequest versionRequest = new DefaultPluginVersionRequest(plugin, session, repositories);
+            try {
+                plugin.setVersion(pluginVersionResolver.resolve(versionRequest).getVersion());
+            } catch (PluginVersionResolutionException e) {
+                throw new PluginManagerException(plugin, e.getMessage(), e);
             }
         }
 
+        // TODO: store plugin version
+
         // resolve plugin artifacts
         List<Artifact> artifacts;
-        PluginArtifactsCache.Key cacheKey = pluginArtifactsCache.createKey( plugin, null, repositories, session );
+        PluginArtifactsCache.Key cacheKey = pluginArtifactsCache.createKey(plugin, null, repositories, session);
         PluginArtifactsCache.CacheRecord recordArtifacts;
-        try
-        {
-            recordArtifacts = pluginArtifactsCache.get( cacheKey );
+        try {
+            recordArtifacts = pluginArtifactsCache.get(cacheKey);
+        } catch (PluginResolutionException e) {
+            throw new PluginManagerException(plugin, e.getMessage(), e);
         }
-        catch ( PluginResolutionException e )
-        {
-            throw new PluginManagerException( plugin, e.getMessage(), e );
-        }
-        if ( recordArtifacts != null )
-        {
+        if (recordArtifacts != null) {
             artifacts = recordArtifacts.getArtifacts();
-        }
-        else
-        {
-            try
-            {
-                artifacts = resolveExtensionArtifacts( plugin, repositories, session );
-                recordArtifacts = pluginArtifactsCache.put( cacheKey, artifacts );
-            }
-            catch ( PluginResolutionException e )
-            {
-                pluginArtifactsCache.put( cacheKey, e );
-                pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
-                throw new PluginManagerException( plugin, e.getMessage(), e );
+        } else {
+            try {
+                artifacts = resolveExtensionArtifacts(plugin, repositories, session);
+                recordArtifacts = pluginArtifactsCache.put(cacheKey, artifacts);
+            } catch (PluginResolutionException e) {
+                pluginArtifactsCache.put(cacheKey, e);
+                pluginArtifactsCache.register(project, cacheKey, recordArtifacts);
+                throw new PluginManagerException(plugin, e.getMessage(), e);
             }
         }
-        pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
+        pluginArtifactsCache.register(project, cacheKey, recordArtifacts);
 
         // create and cache extensions realms
-        final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey( artifacts );
-        extensionRecord = extensionRealmCache.get( extensionKey );
-        if ( extensionRecord == null )
-        {
-            ClassRealm extensionRealm =
-                classRealmManager.createExtensionRealm( plugin, toAetherArtifacts( artifacts ) );
+        final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey(artifacts);
+        extensionRecord = extensionRealmCache.get(extensionKey);
+        if (extensionRecord == null) {
+            ClassRealm extensionRealm = classRealmManager.createExtensionRealm(plugin, toAetherArtifacts(artifacts));
 
             // TODO figure out how to use the same PluginDescriptor when running mojos
 
             PluginDescriptor pluginDescriptor = null;
-            if ( plugin.isExtensions() && !artifacts.isEmpty() )
-            {
+            if (plugin.isExtensions() && !artifacts.isEmpty()) {
                 // ignore plugin descriptor parsing errors at this point
                 // these errors will reported during calculation of project build execution plan
-                try
-                {
-                    pluginDescriptor = extractPluginDescriptor( artifacts.get( 0 ), plugin );
-                }
-                catch ( PluginDescriptorParsingException | InvalidPluginDescriptorException e )
-                {
+                try {
+                    pluginDescriptor = extractPluginDescriptor(artifacts.get(0), plugin);
+                } catch (PluginDescriptorParsingException | InvalidPluginDescriptorException e) {
                     // ignore, see above
                 }
             }
 
-            discoverPluginComponents( extensionRealm, plugin, pluginDescriptor );
+            discoverPluginComponents(extensionRealm, plugin, pluginDescriptor);
 
             ExtensionDescriptor extensionDescriptor = null;
-            Artifact extensionArtifact = artifacts.get( 0 );
-            try
-            {
-                extensionDescriptor = extensionDescriptorBuilder.build( extensionArtifact.getFile() );
-            }
-            catch ( IOException e )
-            {
+            Artifact extensionArtifact = artifacts.get(0);
+            try {
+                extensionDescriptor = extensionDescriptorBuilder.build(extensionArtifact.getFile());
+            } catch (IOException e) {
                 String message = "Invalid extension descriptor for " + plugin.getId() + ": " + e.getMessage();
-                if ( logger.isDebugEnabled() )
-                {
-                    logger.error( message, e );
-                }
-                else
-                {
-                    logger.error( message );
+                if (logger.isDebugEnabled()) {
+                    logger.error(message, e);
+                } else {
+                    logger.error(message);
                 }
             }
-            extensionRecord = extensionRealmCache.put( extensionKey, extensionRealm, extensionDescriptor, artifacts );
+            extensionRecord = extensionRealmCache.put(extensionKey, extensionRealm, extensionDescriptor, artifacts);
         }
-        extensionRealmCache.register( project, extensionKey, extensionRecord );
-        pluginRealms.put( pluginKey, extensionRecord );
+        extensionRealmCache.register(project, extensionKey, extensionRecord);
+        pluginRealms.put(pluginKey, extensionRecord);
 
         return extensionRecord;
     }
 
-    private List<Artifact> resolveExtensionArtifacts( Plugin extensionPlugin, List<RemoteRepository> repositories,
-                                                      RepositorySystemSession session )
-        throws PluginResolutionException
-    {
-        DependencyNode root = pluginDependenciesResolver.resolve( extensionPlugin, null, null, repositories, session );
+    private List<Artifact> resolveExtensionArtifacts(
+            Plugin extensionPlugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginResolutionException {
+        DependencyNode root = pluginDependenciesResolver.resolve(extensionPlugin, null, null, repositories, session);
         PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
-        root.accept( nlg );
-        return toMavenArtifacts( root, nlg );
+        root.accept(nlg);
+        return toMavenArtifacts(root, nlg);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginValidator.java
index da7c4b6..4d7e40d 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginValidator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultMavenPluginValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,40 +16,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.List;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 /**
  * DefaultMavenPluginValidator
  */
 @Named
 @Singleton
-class DefaultMavenPluginValidator
-        implements MavenPluginValidator
-{
+class DefaultMavenPluginValidator implements MavenPluginValidator {
 
     @Override
-    public void validate( Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List<String> errors )
-    {
-        if ( !pluginArtifact.getGroupId().equals( pluginDescriptor.getGroupId() ) )
-        {
-            errors.add( "Plugin's descriptor contains the wrong group ID: " + pluginDescriptor.getGroupId() );
+    public void validate(Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List<String> errors) {
+        if (!pluginArtifact.getGroupId().equals(pluginDescriptor.getGroupId())) {
+            errors.add("Plugin's descriptor contains the wrong group ID: " + pluginDescriptor.getGroupId());
         }
 
-        if ( !pluginArtifact.getArtifactId().equals( pluginDescriptor.getArtifactId() ) )
-        {
-            errors.add( "Plugin's descriptor contains the wrong artifact ID: " + pluginDescriptor.getArtifactId() );
+        if (!pluginArtifact.getArtifactId().equals(pluginDescriptor.getArtifactId())) {
+            errors.add("Plugin's descriptor contains the wrong artifact ID: " + pluginDescriptor.getArtifactId());
         }
 
-        if ( !pluginArtifact.getBaseVersion().equals( pluginDescriptor.getVersion() ) )
-        {
-            errors.add( "Plugin's descriptor contains the wrong version: " + pluginDescriptor.getVersion() );
+        if (!pluginArtifact.getBaseVersion().equals(pluginDescriptor.getVersion())) {
+            errors.add("Plugin's descriptor contains the wrong version: " + pluginDescriptor.getVersion());
         }
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
index a31ca62..2f7cb9a 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginDependenciesResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Collection;
 import java.util.LinkedHashMap;
@@ -25,15 +28,10 @@
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.PluginResolutionException;
-import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
@@ -67,84 +65,83 @@
  * deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultPluginDependenciesResolver
-    implements PluginDependenciesResolver
-{
+public class DefaultPluginDependenciesResolver implements PluginDependenciesResolver {
     private static final String REPOSITORY_CONTEXT = "plugin";
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final RepositorySystem repoSystem;
 
+    private final List<MavenPluginDependenciesValidator> dependenciesValidators;
+
     @Inject
-    public DefaultPluginDependenciesResolver( RepositorySystem repoSystem )
-    {
+    public DefaultPluginDependenciesResolver(
+            RepositorySystem repoSystem, List<MavenPluginDependenciesValidator> dependenciesValidators) {
         this.repoSystem = repoSystem;
+        this.dependenciesValidators = dependenciesValidators;
     }
 
-    private Artifact toArtifact( Plugin plugin, RepositorySystemSession session )
-    {
-        return new DefaultArtifact( plugin.getGroupId(), plugin.getArtifactId(), null, "jar", plugin.getVersion(),
-                                    session.getArtifactTypeRegistry().get( "maven-plugin" ) );
+    private Artifact toArtifact(Plugin plugin, RepositorySystemSession session) {
+        return new DefaultArtifact(
+                plugin.getGroupId(),
+                plugin.getArtifactId(),
+                null,
+                "jar",
+                plugin.getVersion(),
+                session.getArtifactTypeRegistry().get("maven-plugin"));
     }
 
-    public Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
-        throws PluginResolutionException
-    {
-        RequestTrace trace = RequestTrace.newChild( null, plugin );
+    public Artifact resolve(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginResolutionException {
+        RequestTrace trace = RequestTrace.newChild(null, plugin);
 
-        Artifact pluginArtifact = toArtifact( plugin, session );
+        Artifact pluginArtifact = toArtifact(plugin, session);
 
-        try
-        {
-            DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
-            pluginSession.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, false ) );
+        try {
+            DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession(session);
+            pluginSession.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(true, false));
 
             ArtifactDescriptorRequest request =
-                new ArtifactDescriptorRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
-            request.setTrace( trace );
-            ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor( pluginSession, request );
+                    new ArtifactDescriptorRequest(pluginArtifact, repositories, REPOSITORY_CONTEXT);
+            request.setTrace(trace);
+            ArtifactDescriptorResult result = repoSystem.readArtifactDescriptor(pluginSession, request);
+
+            for (MavenPluginDependenciesValidator dependenciesValidator : dependenciesValidators) {
+                dependenciesValidator.validate(session, pluginArtifact, result);
+            }
 
             pluginArtifact = result.getArtifact();
 
-            if ( logger.isWarnEnabled() )
-            {
-                if ( !result.getRelocations().isEmpty() )
-                {
-                    String message = pluginArtifact instanceof org.apache.maven.repository.internal.RelocatedArtifact
-                            ? ( ( org.apache.maven.repository.internal.RelocatedArtifact ) pluginArtifact ).getMessage()
-                            : null;
-                    logger.warn( "The artifact " + result.getRelocations().get( 0 ) + " has been relocated to "
-                            + pluginArtifact + ( message != null ? ": " + message : "" ) );
-                }
+            if (logger.isWarnEnabled() && !result.getRelocations().isEmpty()) {
+                String message = pluginArtifact instanceof org.apache.maven.repository.internal.RelocatedArtifact
+                        ? ": " + ((org.apache.maven.repository.internal.RelocatedArtifact) pluginArtifact).getMessage()
+                        : "";
+                logger.warn(
+                        "The artifact {} has been relocated to {}{}",
+                        result.getRelocations().get(0),
+                        pluginArtifact,
+                        message);
             }
 
-            String requiredMavenVersion = (String) result.getProperties().get( "prerequisites.maven" );
-            if ( requiredMavenVersion != null )
-            {
-                Map<String, String> props = new LinkedHashMap<>( pluginArtifact.getProperties() );
-                props.put( "requiredMavenVersion", requiredMavenVersion );
-                pluginArtifact = pluginArtifact.setProperties( props );
+            String requiredMavenVersion = (String) result.getProperties().get("prerequisites.maven");
+            if (requiredMavenVersion != null) {
+                Map<String, String> props = new LinkedHashMap<>(pluginArtifact.getProperties());
+                props.put("requiredMavenVersion", requiredMavenVersion);
+                pluginArtifact = pluginArtifact.setProperties(props);
             }
-        }
-        catch ( ArtifactDescriptorException e )
-        {
-            throw new PluginResolutionException( plugin, e );
+        } catch (ArtifactDescriptorException e) {
+            throw new PluginResolutionException(plugin, e);
         }
 
-        try
-        {
-            ArtifactRequest request = new ArtifactRequest( pluginArtifact, repositories, REPOSITORY_CONTEXT );
-            request.setTrace( trace );
-            pluginArtifact = repoSystem.resolveArtifact( session, request ).getArtifact();
-        }
-        catch ( ArtifactResolutionException e )
-        {
-            throw new PluginResolutionException( plugin, e );
+        try {
+            ArtifactRequest request = new ArtifactRequest(pluginArtifact, repositories, REPOSITORY_CONTEXT);
+            request.setTrace(trace);
+            pluginArtifact = repoSystem.resolveArtifact(session, request).getArtifact();
+        } catch (ArtifactResolutionException e) {
+            throw new PluginResolutionException(plugin, e);
         }
 
         return pluginArtifact;
@@ -153,174 +150,155 @@
     /**
      * @since 3.3.0
      */
-    public DependencyNode resolveCoreExtension( Plugin plugin, DependencyFilter dependencyFilter,
-                                                List<RemoteRepository> repositories, RepositorySystemSession session )
-        throws PluginResolutionException
-    {
-        return resolveInternal( plugin, null /* pluginArtifact */, dependencyFilter,
-                                repositories, session );
+    public DependencyNode resolveCoreExtension(
+            Plugin plugin,
+            DependencyFilter dependencyFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session)
+            throws PluginResolutionException {
+        return resolveInternal(plugin, null /* pluginArtifact */, dependencyFilter, repositories, session);
     }
 
-    public DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
-                                   List<RemoteRepository> repositories, RepositorySystemSession session )
-        throws PluginResolutionException
-    {
-        return resolveInternal( plugin, pluginArtifact, dependencyFilter, repositories,
-                                session );
+    public DependencyNode resolve(
+            Plugin plugin,
+            Artifact pluginArtifact,
+            DependencyFilter dependencyFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session)
+            throws PluginResolutionException {
+        return resolveInternal(plugin, pluginArtifact, dependencyFilter, repositories, session);
     }
 
-    private DependencyNode resolveInternal( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
-                                            List<RemoteRepository> repositories, RepositorySystemSession session )
-        throws PluginResolutionException
-    {
-        RequestTrace trace = RequestTrace.newChild( null, plugin );
+    private DependencyNode resolveInternal(
+            Plugin plugin,
+            Artifact pluginArtifact,
+            DependencyFilter dependencyFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session)
+            throws PluginResolutionException {
+        RequestTrace trace = RequestTrace.newChild(null, plugin);
 
-        if ( pluginArtifact == null )
-        {
-            pluginArtifact = toArtifact( plugin, session );
+        if (pluginArtifact == null) {
+            pluginArtifact = toArtifact(plugin, session);
         }
 
-        DependencyFilter collectionFilter = new ScopeDependencyFilter( "provided", "test" );
-        DependencyFilter resolutionFilter = AndDependencyFilter.newInstance( collectionFilter, dependencyFilter );
+        DependencyFilter collectionFilter = new ScopeDependencyFilter("provided", "test");
+        DependencyFilter resolutionFilter = AndDependencyFilter.newInstance(collectionFilter, dependencyFilter);
 
         DependencyNode node;
 
-        try
-        {
-            DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession( session );
-            pluginSession.setDependencySelector( session.getDependencySelector() );
-            pluginSession.setDependencyGraphTransformer( session.getDependencyGraphTransformer() );
+        try {
+            DefaultRepositorySystemSession pluginSession = new DefaultRepositorySystemSession(session);
+            pluginSession.setDependencySelector(session.getDependencySelector());
+            pluginSession.setDependencyGraphTransformer(session.getDependencyGraphTransformer());
 
             CollectRequest request = new CollectRequest();
-            request.setRequestContext( REPOSITORY_CONTEXT );
-            request.setRepositories( repositories );
-            request.setRoot( new org.eclipse.aether.graph.Dependency( pluginArtifact, null ) );
-            for ( Dependency dependency : plugin.getDependencies() )
-            {
+            request.setRequestContext(REPOSITORY_CONTEXT);
+            request.setRepositories(repositories);
+            request.setRoot(new org.eclipse.aether.graph.Dependency(pluginArtifact, null));
+            for (Dependency dependency : plugin.getDependencies()) {
                 org.eclipse.aether.graph.Dependency pluginDep =
-                    RepositoryUtils.toDependency( dependency, session.getArtifactTypeRegistry() );
-                if ( !JavaScopes.SYSTEM.equals( pluginDep.getScope() ) )
-                {
-                    pluginDep = pluginDep.setScope( JavaScopes.RUNTIME );
+                        RepositoryUtils.toDependency(dependency, session.getArtifactTypeRegistry());
+                if (!JavaScopes.SYSTEM.equals(pluginDep.getScope())) {
+                    pluginDep = pluginDep.setScope(JavaScopes.RUNTIME);
                 }
-                request.addDependency( pluginDep );
+                request.addDependency(pluginDep);
             }
 
-            DependencyRequest depRequest = new DependencyRequest( request, resolutionFilter );
-            depRequest.setTrace( trace );
+            DependencyRequest depRequest = new DependencyRequest(request, resolutionFilter);
+            depRequest.setTrace(trace);
 
-            request.setTrace( RequestTrace.newChild( trace, depRequest ) );
+            request.setTrace(RequestTrace.newChild(trace, depRequest));
 
-            node = repoSystem.collectDependencies( pluginSession, request ).getRoot();
+            node = repoSystem.collectDependencies(pluginSession, request).getRoot();
 
-            if ( logger.isDebugEnabled() )
-            {
-                node.accept( new GraphLogger() );
+            if (logger.isDebugEnabled()) {
+                node.accept(new GraphLogger());
             }
 
-            depRequest.setRoot( node );
-            repoSystem.resolveDependencies( session, depRequest );
-        }
-        catch ( DependencyCollectionException e )
-        {
-            throw new PluginResolutionException( plugin, e );
-        }
-        catch ( DependencyResolutionException e )
-        {
-            throw new PluginResolutionException( plugin, e.getCause() );
+            depRequest.setRoot(node);
+            repoSystem.resolveDependencies(session, depRequest);
+        } catch (DependencyCollectionException e) {
+            throw new PluginResolutionException(plugin, e);
+        } catch (DependencyResolutionException e) {
+            throw new PluginResolutionException(plugin, e.getCause());
         }
 
         return node;
     }
 
     // Keep this class in sync with org.apache.maven.project.DefaultProjectDependenciesResolver.GraphLogger
-    class GraphLogger
-        implements DependencyVisitor
-    {
+    class GraphLogger implements DependencyVisitor {
 
         private String indent = "";
 
-        public boolean visitEnter( DependencyNode node )
-        {
-            StringBuilder buffer = new StringBuilder( 128 );
-            buffer.append( indent );
+        public boolean visitEnter(DependencyNode node) {
+            StringBuilder buffer = new StringBuilder(128);
+            buffer.append(indent);
             org.eclipse.aether.graph.Dependency dep = node.getDependency();
-            if ( dep != null )
-            {
+            if (dep != null) {
                 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
 
-                buffer.append( art );
-                if ( StringUtils.isNotEmpty( dep.getScope() ) )
-                {
-                    buffer.append( ':' ).append( dep.getScope() );
+                buffer.append(art);
+                if (dep.getScope() != null && !dep.getScope().isEmpty()) {
+                    buffer.append(':').append(dep.getScope());
                 }
 
-                if ( dep.isOptional() )
-                {
-                    buffer.append( " (optional)" );
+                if (dep.isOptional()) {
+                    buffer.append(" (optional)");
                 }
 
                 // TODO We currently cannot tell which <dependencyManagement> section contained the management
                 //      information. When the resolver provides this information, these log messages should be updated
                 //      to contain it.
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) == DependencyNode.MANAGED_SCOPE )
-                {
-                    final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node );
-                    buffer.append( " (scope managed from " );
-                    buffer.append( Objects.toString( premanagedScope, "default" ) );
-                    buffer.append( ')' );
+                if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) == DependencyNode.MANAGED_SCOPE) {
+                    final String premanagedScope = DependencyManagerUtils.getPremanagedScope(node);
+                    buffer.append(" (scope managed from ");
+                    buffer.append(Objects.toString(premanagedScope, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_VERSION ) == DependencyNode.MANAGED_VERSION )
-                {
-                    final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node );
-                    buffer.append( " (version managed from " );
-                    buffer.append( Objects.toString( premanagedVersion, "default" ) );
-                    buffer.append( ')' );
+                if ((node.getManagedBits() & DependencyNode.MANAGED_VERSION) == DependencyNode.MANAGED_VERSION) {
+                    final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
+                    buffer.append(" (version managed from ");
+                    buffer.append(Objects.toString(premanagedVersion, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) == DependencyNode.MANAGED_OPTIONAL )
-                {
-                    final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node );
-                    buffer.append( " (optionality managed from " );
-                    buffer.append( Objects.toString( premanagedOptional, "default" ) );
-                    buffer.append( ')' );
+                if ((node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) == DependencyNode.MANAGED_OPTIONAL) {
+                    final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional(node);
+                    buffer.append(" (optionality managed from ");
+                    buffer.append(Objects.toString(premanagedOptional, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS )
-                         == DependencyNode.MANAGED_EXCLUSIONS )
-                {
+                if ((node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS) == DependencyNode.MANAGED_EXCLUSIONS) {
                     final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
-                        DependencyManagerUtils.getPremanagedExclusions( node );
+                            DependencyManagerUtils.getPremanagedExclusions(node);
 
-                    buffer.append( " (exclusions managed from " );
-                    buffer.append( Objects.toString( premanagedExclusions, "default" ) );
-                    buffer.append( ')' );
+                    buffer.append(" (exclusions managed from ");
+                    buffer.append(Objects.toString(premanagedExclusions, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES )
-                         == DependencyNode.MANAGED_PROPERTIES )
-                {
+                if ((node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES) == DependencyNode.MANAGED_PROPERTIES) {
                     final Map<String, String> premanagedProperties =
-                        DependencyManagerUtils.getPremanagedProperties( node );
+                            DependencyManagerUtils.getPremanagedProperties(node);
 
-                    buffer.append( " (properties managed from " );
-                    buffer.append( Objects.toString( premanagedProperties, "default" ) );
-                    buffer.append( ')' );
+                    buffer.append(" (properties managed from ");
+                    buffer.append(Objects.toString(premanagedProperties, "default"));
+                    buffer.append(')');
                 }
             }
 
-            logger.debug( buffer.toString() );
+            logger.debug(buffer.toString());
             indent += "   ";
             return true;
         }
 
-        public boolean visitLeave( DependencyNode node )
-        {
-            indent = indent.substring( 0, indent.length() - 3 );
+        public boolean visitLeave(DependencyNode node) {
+            indent = indent.substring(0, indent.length() - 3);
             return true;
         }
-
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java
deleted file mode 100644
index 24f7135..0000000
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginManager.java
+++ /dev/null
@@ -1,266 +0,0 @@
-package org.apache.maven.plugin.internal;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.plugin.InvalidPluginDescriptorException;
-import org.apache.maven.plugin.InvalidPluginException;
-import org.apache.maven.plugin.LegacySupport;
-import org.apache.maven.plugin.MavenPluginManager;
-import org.apache.maven.plugin.MojoExecution;
-import org.apache.maven.plugin.MojoExecutionException;
-import org.apache.maven.plugin.MojoFailureException;
-import org.apache.maven.plugin.PluginConfigurationException;
-import org.apache.maven.plugin.PluginDescriptorParsingException;
-import org.apache.maven.plugin.PluginManager;
-import org.apache.maven.plugin.PluginManagerException;
-import org.apache.maven.plugin.PluginNotFoundException;
-import org.apache.maven.plugin.PluginResolutionException;
-import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.prefix.DefaultPluginPrefixRequest;
-import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
-import org.apache.maven.plugin.prefix.PluginPrefixRequest;
-import org.apache.maven.plugin.prefix.PluginPrefixResolver;
-import org.apache.maven.plugin.prefix.PluginPrefixResult;
-import org.apache.maven.plugin.version.DefaultPluginVersionRequest;
-import org.apache.maven.plugin.version.PluginVersionNotFoundException;
-import org.apache.maven.plugin.version.PluginVersionRequest;
-import org.apache.maven.plugin.version.PluginVersionResolutionException;
-import org.apache.maven.plugin.version.PluginVersionResolver;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.artifact.InvalidDependencyVersionException;
-import org.apache.maven.settings.Settings;
-import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
-
-/**
- * @author Benjamin Bentmann
- */
-@Named
-@Singleton
-public class DefaultPluginManager
-    implements PluginManager
-{
-
-    private final PlexusContainer container;
-    private final MavenPluginManager pluginManager;
-    private final PluginVersionResolver pluginVersionResolver;
-    private final PluginPrefixResolver pluginPrefixResolver;
-    private final LegacySupport legacySupport;
-
-    @Inject
-    public DefaultPluginManager(
-            PlexusContainer container,
-            MavenPluginManager pluginManager,
-            PluginVersionResolver pluginVersionResolver,
-            PluginPrefixResolver pluginPrefixResolver,
-            LegacySupport legacySupport )
-    {
-        this.container = container;
-        this.pluginManager = pluginManager;
-        this.pluginVersionResolver = pluginVersionResolver;
-        this.pluginPrefixResolver = pluginPrefixResolver;
-        this.legacySupport = legacySupport;
-    }
-
-    public void executeMojo( MavenProject project, MojoExecution execution, MavenSession session )
-        throws MojoExecutionException, ArtifactResolutionException, MojoFailureException, ArtifactNotFoundException,
-        InvalidDependencyVersionException, PluginManagerException, PluginConfigurationException
-    {
-        throw new UnsupportedOperationException();
-    }
-
-    public Object getPluginComponent( Plugin plugin, String role, String roleHint )
-        throws PluginManagerException, ComponentLookupException
-    {
-        MavenSession session = legacySupport.getSession();
-
-        PluginDescriptor pluginDescriptor;
-        try
-        {
-            pluginDescriptor =
-                pluginManager.getPluginDescriptor( plugin, session.getCurrentProject().getRemotePluginRepositories(),
-                                                   session.getRepositorySession() );
-
-            pluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
-        }
-        catch ( Exception e )
-        {
-            throw new PluginManagerException( plugin, e.getMessage(), e );
-        }
-
-        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
-        try
-        {
-            Thread.currentThread().setContextClassLoader( pluginDescriptor.getClassRealm() );
-
-            return container.lookup( role, roleHint );
-        }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( oldClassLoader );
-        }
-    }
-
-    public Map<String, Object> getPluginComponents( Plugin plugin, String role )
-        throws ComponentLookupException, PluginManagerException
-    {
-        MavenSession session = legacySupport.getSession();
-
-        PluginDescriptor pluginDescriptor;
-        try
-        {
-            pluginDescriptor =
-                pluginManager.getPluginDescriptor( plugin, session.getCurrentProject().getRemotePluginRepositories(),
-                                                   session.getRepositorySession() );
-
-            pluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
-        }
-        catch ( Exception e )
-        {
-            throw new PluginManagerException( plugin, e.getMessage(), e );
-        }
-
-        ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
-        try
-        {
-            Thread.currentThread().setContextClassLoader( pluginDescriptor.getClassRealm() );
-
-            return container.lookupMap( role );
-        }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( oldClassLoader );
-        }
-    }
-
-    public Plugin getPluginDefinitionForPrefix( String prefix, MavenSession session, MavenProject project )
-    {
-        PluginPrefixRequest request = new DefaultPluginPrefixRequest( prefix, session );
-        request.setPom( project.getModel() );
-
-        try
-        {
-            PluginPrefixResult result = pluginPrefixResolver.resolve( request );
-
-            Plugin plugin = new Plugin();
-            plugin.setGroupId( result.getGroupId() );
-            plugin.setArtifactId( result.getArtifactId() );
-
-            return plugin;
-        }
-        catch ( NoPluginFoundForPrefixException e )
-        {
-            return null;
-        }
-    }
-
-    public PluginDescriptor getPluginDescriptorForPrefix( String prefix )
-    {
-        MavenSession session = legacySupport.getSession();
-
-        PluginPrefixRequest request = new DefaultPluginPrefixRequest( prefix, session );
-
-        try
-        {
-            PluginPrefixResult result = pluginPrefixResolver.resolve( request );
-
-            Plugin plugin = new Plugin();
-            plugin.setGroupId( result.getGroupId() );
-            plugin.setArtifactId( result.getArtifactId() );
-
-            return loadPluginDescriptor( plugin, session.getCurrentProject(), session );
-        }
-        catch ( Exception e )
-        {
-            return null;
-        }
-    }
-
-    public PluginDescriptor loadPluginDescriptor( Plugin plugin, MavenProject project, MavenSession session )
-        throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
-        InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
-        PluginVersionNotFoundException
-    {
-        return verifyPlugin( plugin, project, session.getSettings(), session.getLocalRepository() );
-    }
-
-    public PluginDescriptor loadPluginFully( Plugin plugin, MavenProject project, MavenSession session )
-        throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
-        InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
-        PluginVersionNotFoundException
-    {
-        PluginDescriptor pluginDescriptor = loadPluginDescriptor( plugin, project, session );
-
-        try
-        {
-            pluginManager.setupPluginRealm( pluginDescriptor, session, null, null, null );
-        }
-        catch ( PluginResolutionException e )
-        {
-            throw new PluginManagerException( plugin, e.getMessage(), e );
-        }
-
-        return pluginDescriptor;
-    }
-
-    public PluginDescriptor verifyPlugin( Plugin plugin, MavenProject project, Settings settings,
-                                          ArtifactRepository localRepository )
-        throws ArtifactResolutionException, PluginVersionResolutionException, ArtifactNotFoundException,
-        InvalidVersionSpecificationException, InvalidPluginException, PluginManagerException, PluginNotFoundException,
-        PluginVersionNotFoundException
-    {
-        MavenSession session = legacySupport.getSession();
-
-        if ( plugin.getVersion() == null )
-        {
-            PluginVersionRequest versionRequest =
-                new DefaultPluginVersionRequest( plugin, session.getRepositorySession(),
-                                                 project.getRemotePluginRepositories() );
-            plugin.setVersion( pluginVersionResolver.resolve( versionRequest ).getVersion() );
-        }
-
-        try
-        {
-            return pluginManager.getPluginDescriptor( plugin, project.getRemotePluginRepositories(),
-                                                      session.getRepositorySession() );
-        }
-        catch ( PluginResolutionException e )
-        {
-            throw new PluginNotFoundException( plugin, project.getPluginArtifactRepositories() );
-        }
-        catch ( PluginDescriptorParsingException | InvalidPluginDescriptorException e )
-        {
-            throw new PluginManagerException( plugin, e.getMessage(), e );
-        }
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginValidationManager.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginValidationManager.java
new file mode 100644
index 0000000..0794a54
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DefaultPluginValidationManager.java
@@ -0,0 +1,372 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+import org.apache.maven.eventspy.AbstractEventSpy;
+import org.apache.maven.execution.ExecutionEvent;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.plugin.PluginValidationManager;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.util.ConfigUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Singleton
+@Named
+public final class DefaultPluginValidationManager extends AbstractEventSpy implements PluginValidationManager {
+    /**
+     * The collection of "G:A" combinations that do NOT belong to Maven Core, hence, should be excluded from
+     * "expected in provided scope" type of checks.
+     */
+    static final Collection<String> EXPECTED_PROVIDED_SCOPE_EXCLUSIONS_GA =
+            Collections.unmodifiableCollection(Arrays.asList(
+                    "org.apache.maven:maven-archiver", "org.apache.maven:maven-jxr", "org.apache.maven:plexus-utils"));
+
+    private static final String ISSUES_KEY = DefaultPluginValidationManager.class.getName() + ".issues";
+
+    private static final String PLUGIN_EXCLUDES_KEY = DefaultPluginValidationManager.class.getName() + ".excludes";
+
+    private static final String MAVEN_PLUGIN_VALIDATION_KEY = "maven.plugin.validation";
+
+    private static final String MAVEN_PLUGIN_VALIDATION_EXCLUDES_KEY = "maven.plugin.validation.excludes";
+
+    private static final ValidationReportLevel DEFAULT_VALIDATION_LEVEL = ValidationReportLevel.INLINE;
+
+    private static final Collection<ValidationReportLevel> INLINE_VALIDATION_LEVEL = Collections.unmodifiableCollection(
+            Arrays.asList(ValidationReportLevel.INLINE, ValidationReportLevel.BRIEF));
+
+    private enum ValidationReportLevel {
+        NONE, // mute validation completely (validation issue collection still happens, it is just not reported!)
+        INLINE, // inline, each "internal" problem one line next to mojo invocation
+        SUMMARY, // at end, list of plugin GAVs along with ANY validation issues
+        BRIEF, // each "internal" problem one line next to mojo invocation
+        // and at end list of plugin GAVs along with "external" issues
+        VERBOSE // at end, list of plugin GAVs along with detailed report of ANY validation issues
+    }
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Override
+    public void onEvent(Object event) {
+        if (event instanceof ExecutionEvent) {
+            ExecutionEvent executionEvent = (ExecutionEvent) event;
+            if (executionEvent.getType() == ExecutionEvent.Type.SessionStarted) {
+                RepositorySystemSession repositorySystemSession =
+                        executionEvent.getSession().getRepositorySession();
+                validationReportLevel(repositorySystemSession); // this will parse and store it in session.data
+                validationPluginExcludes(repositorySystemSession);
+            } else if (executionEvent.getType() == ExecutionEvent.Type.SessionEnded) {
+                reportSessionCollectedValidationIssues(executionEvent.getSession());
+            }
+        }
+    }
+
+    private List<?> validationPluginExcludes(RepositorySystemSession session) {
+        return (List<?>) session.getData().computeIfAbsent(PLUGIN_EXCLUDES_KEY, () -> parsePluginExcludes(session));
+    }
+
+    private List<String> parsePluginExcludes(RepositorySystemSession session) {
+        String excludes = ConfigUtils.getString(session, null, MAVEN_PLUGIN_VALIDATION_EXCLUDES_KEY);
+        if (excludes == null || excludes.isEmpty()) {
+            return Collections.emptyList();
+        }
+        return Arrays.stream(excludes.split(","))
+                .map(String::trim)
+                .filter(s -> !s.isEmpty())
+                .collect(Collectors.toList());
+    }
+
+    private ValidationReportLevel validationReportLevel(RepositorySystemSession session) {
+        return (ValidationReportLevel) session.getData()
+                .computeIfAbsent(ValidationReportLevel.class, () -> parseValidationReportLevel(session));
+    }
+
+    private ValidationReportLevel parseValidationReportLevel(RepositorySystemSession session) {
+        String level = ConfigUtils.getString(session, null, MAVEN_PLUGIN_VALIDATION_KEY);
+        if (level == null || level.isEmpty()) {
+            return DEFAULT_VALIDATION_LEVEL;
+        }
+        try {
+            return ValidationReportLevel.valueOf(level.toUpperCase(Locale.ENGLISH));
+        } catch (IllegalArgumentException e) {
+            logger.warn(
+                    "Invalid value specified for property {}: '{}'. Supported values are (case insensitive): {}",
+                    MAVEN_PLUGIN_VALIDATION_KEY,
+                    level,
+                    Arrays.toString(ValidationReportLevel.values()));
+            return DEFAULT_VALIDATION_LEVEL;
+        }
+    }
+
+    private String pluginKey(String groupId, String artifactId, String version) {
+        return groupId + ":" + artifactId + ":" + version;
+    }
+
+    private String pluginKey(MojoDescriptor mojoDescriptor) {
+        PluginDescriptor pd = mojoDescriptor.getPluginDescriptor();
+        return pluginKey(pd.getGroupId(), pd.getArtifactId(), pd.getVersion());
+    }
+
+    private String pluginKey(Artifact pluginArtifact) {
+        return pluginKey(pluginArtifact.getGroupId(), pluginArtifact.getArtifactId(), pluginArtifact.getVersion());
+    }
+
+    private void mayReportInline(RepositorySystemSession session, IssueLocality locality, String issue) {
+        if (locality == IssueLocality.INTERNAL) {
+            ValidationReportLevel validationReportLevel = validationReportLevel(session);
+            if (INLINE_VALIDATION_LEVEL.contains(validationReportLevel)) {
+                logger.warn(" {}", issue);
+            }
+        }
+    }
+
+    @Override
+    public void reportPluginValidationIssue(
+            IssueLocality locality, RepositorySystemSession session, Artifact pluginArtifact, String issue) {
+        String pluginKey = pluginKey(pluginArtifact);
+        if (validationPluginExcludes(session).contains(pluginKey)) {
+            return;
+        }
+        PluginValidationIssues pluginIssues =
+                pluginIssues(session).computeIfAbsent(pluginKey, k -> new PluginValidationIssues());
+        pluginIssues.reportPluginIssue(locality, null, issue);
+        mayReportInline(session, locality, issue);
+    }
+
+    @Override
+    public void reportPluginValidationIssue(
+            IssueLocality locality, MavenSession mavenSession, MojoDescriptor mojoDescriptor, String issue) {
+        String pluginKey = pluginKey(mojoDescriptor);
+        if (validationPluginExcludes(mavenSession.getRepositorySession()).contains(pluginKey)) {
+            return;
+        }
+        PluginValidationIssues pluginIssues = pluginIssues(mavenSession.getRepositorySession())
+                .computeIfAbsent(pluginKey, k -> new PluginValidationIssues());
+        pluginIssues.reportPluginIssue(locality, pluginDeclaration(mavenSession, mojoDescriptor), issue);
+        mayReportInline(mavenSession.getRepositorySession(), locality, issue);
+    }
+
+    @Override
+    public void reportPluginMojoValidationIssue(
+            IssueLocality locality,
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            String issue) {
+        String pluginKey = pluginKey(mojoDescriptor);
+        if (validationPluginExcludes(mavenSession.getRepositorySession()).contains(pluginKey)) {
+            return;
+        }
+        PluginValidationIssues pluginIssues = pluginIssues(mavenSession.getRepositorySession())
+                .computeIfAbsent(pluginKey, k -> new PluginValidationIssues());
+        pluginIssues.reportPluginMojoIssue(
+                locality, pluginDeclaration(mavenSession, mojoDescriptor), mojoInfo(mojoDescriptor, mojoClass), issue);
+        mayReportInline(mavenSession.getRepositorySession(), locality, issue);
+    }
+
+    private void reportSessionCollectedValidationIssues(MavenSession mavenSession) {
+        if (!logger.isWarnEnabled()) {
+            return; // nothing can be reported
+        }
+        ValidationReportLevel validationReportLevel = validationReportLevel(mavenSession.getRepositorySession());
+        if (validationReportLevel == ValidationReportLevel.NONE
+                || validationReportLevel == ValidationReportLevel.INLINE) {
+            return; // we were asked to not report anything OR reporting already happened inline
+        }
+        ConcurrentHashMap<String, PluginValidationIssues> issuesMap = pluginIssues(mavenSession.getRepositorySession());
+        EnumSet<IssueLocality> issueLocalitiesToReport = validationReportLevel == ValidationReportLevel.SUMMARY
+                        || validationReportLevel == ValidationReportLevel.VERBOSE
+                ? EnumSet.allOf(IssueLocality.class)
+                : EnumSet.of(IssueLocality.EXTERNAL);
+
+        if (hasAnythingToReport(issuesMap, issueLocalitiesToReport)) {
+            logger.warn("");
+            logger.warn("Plugin {} validation issues were detected in following plugin(s)", issueLocalitiesToReport);
+            logger.warn("");
+            for (Map.Entry<String, PluginValidationIssues> entry : issuesMap.entrySet()) {
+                PluginValidationIssues issues = entry.getValue();
+                if (!hasAnythingToReport(issues, issueLocalitiesToReport)) {
+                    continue;
+                }
+                logger.warn(" * {}", entry.getKey());
+                if (validationReportLevel == ValidationReportLevel.VERBOSE) {
+                    if (!issues.pluginDeclarations.isEmpty()) {
+                        logger.warn("  Declared at location(s):");
+                        for (String pluginDeclaration : issues.pluginDeclarations) {
+                            logger.warn("   * {}", pluginDeclaration);
+                        }
+                    }
+                    if (!issues.pluginIssues.isEmpty()) {
+                        for (IssueLocality issueLocality : issueLocalitiesToReport) {
+                            Set<String> pluginIssues = issues.pluginIssues.get(issueLocality);
+                            if (pluginIssues != null && !pluginIssues.isEmpty()) {
+                                logger.warn("  Plugin {} issue(s):", issueLocality);
+                                for (String pluginIssue : pluginIssues) {
+                                    logger.warn("   * {}", pluginIssue);
+                                }
+                            }
+                        }
+                    }
+                    if (!issues.mojoIssues.isEmpty()) {
+                        for (IssueLocality issueLocality : issueLocalitiesToReport) {
+                            Map<String, LinkedHashSet<String>> mojoIssues = issues.mojoIssues.get(issueLocality);
+                            if (mojoIssues != null && !mojoIssues.isEmpty()) {
+                                logger.warn("  Mojo {} issue(s):", issueLocality);
+                                for (String mojoInfo : mojoIssues.keySet()) {
+                                    logger.warn("   * Mojo {}", mojoInfo);
+                                    for (String mojoIssue : mojoIssues.get(mojoInfo)) {
+                                        logger.warn("     - {}", mojoIssue);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    logger.warn("");
+                }
+            }
+            logger.warn("");
+            if (validationReportLevel == ValidationReportLevel.VERBOSE) {
+                logger.warn(
+                        "Fix reported issues by adjusting plugin configuration or by upgrading above listed plugins. If no upgrade available, please notify plugin maintainers about reported issues.");
+            }
+            logger.warn(
+                    "For more or less details, use 'maven.plugin.validation' property with one of the values (case insensitive): {}",
+                    Arrays.toString(ValidationReportLevel.values()));
+            logger.warn("");
+        }
+    }
+
+    private boolean hasAnythingToReport(
+            Map<String, PluginValidationIssues> issuesMap, EnumSet<IssueLocality> issueLocalitiesToReport) {
+        for (PluginValidationIssues issues : issuesMap.values()) {
+            if (hasAnythingToReport(issues, issueLocalitiesToReport)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean hasAnythingToReport(PluginValidationIssues issues, EnumSet<IssueLocality> issueLocalitiesToReport) {
+        for (IssueLocality issueLocality : issueLocalitiesToReport) {
+            Set<String> pluginIssues = issues.pluginIssues.get(issueLocality);
+            if (pluginIssues != null && !pluginIssues.isEmpty()) {
+                return true;
+            }
+            Map<String, LinkedHashSet<String>> mojoIssues = issues.mojoIssues.get(issueLocality);
+            if (mojoIssues != null && !mojoIssues.isEmpty()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String pluginDeclaration(MavenSession mavenSession, MojoDescriptor mojoDescriptor) {
+        InputLocation inputLocation =
+                mojoDescriptor.getPluginDescriptor().getPlugin().getLocation("");
+        if (inputLocation != null && inputLocation.getSource() != null) {
+            StringBuilder stringBuilder = new StringBuilder();
+            stringBuilder.append(inputLocation.getSource().getModelId());
+            String location = inputLocation.getSource().getLocation();
+            if (location != null) {
+                if (location.contains("://")) {
+                    stringBuilder.append(" (").append(location).append(")");
+                } else {
+                    Path topDirectory = mavenSession.getTopDirectory();
+                    Path locationPath = Paths.get(location).toAbsolutePath().normalize();
+                    if (locationPath.startsWith(topDirectory)) {
+                        locationPath = topDirectory.relativize(locationPath);
+                    }
+                    stringBuilder.append(" (").append(locationPath).append(")");
+                }
+            }
+            stringBuilder.append(" @ line ").append(inputLocation.getLineNumber());
+            return stringBuilder.toString();
+        } else {
+            return "unknown";
+        }
+    }
+
+    private String mojoInfo(MojoDescriptor mojoDescriptor, Class<?> mojoClass) {
+        return mojoDescriptor.getFullGoalName() + " (" + mojoClass.getName() + ")";
+    }
+
+    @SuppressWarnings("unchecked")
+    private ConcurrentHashMap<String, PluginValidationIssues> pluginIssues(RepositorySystemSession session) {
+        return (ConcurrentHashMap<String, PluginValidationIssues>)
+                session.getData().computeIfAbsent(ISSUES_KEY, ConcurrentHashMap::new);
+    }
+
+    private static class PluginValidationIssues {
+        private final LinkedHashSet<String> pluginDeclarations;
+
+        private final HashMap<IssueLocality, LinkedHashSet<String>> pluginIssues;
+
+        private final HashMap<IssueLocality, LinkedHashMap<String, LinkedHashSet<String>>> mojoIssues;
+
+        private PluginValidationIssues() {
+            this.pluginDeclarations = new LinkedHashSet<>();
+            this.pluginIssues = new HashMap<>();
+            this.mojoIssues = new HashMap<>();
+        }
+
+        private synchronized void reportPluginIssue(
+                IssueLocality issueLocality, String pluginDeclaration, String issue) {
+            if (pluginDeclaration != null) {
+                pluginDeclarations.add(pluginDeclaration);
+            }
+            pluginIssues
+                    .computeIfAbsent(issueLocality, k -> new LinkedHashSet<>())
+                    .add(issue);
+        }
+
+        private synchronized void reportPluginMojoIssue(
+                IssueLocality issueLocality, String pluginDeclaration, String mojoInfo, String issue) {
+            if (pluginDeclaration != null) {
+                pluginDeclarations.add(pluginDeclaration);
+            }
+            mojoIssues
+                    .computeIfAbsent(issueLocality, k -> new LinkedHashMap<>())
+                    .computeIfAbsent(mojoInfo, k -> new LinkedHashSet<>())
+                    .add(issue);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator.java
new file mode 100644
index 0000000..faaac5c
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedCoreExpressionValidator.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.HashMap;
+import java.util.Objects;
+
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.PluginValidationManager;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.Parameter;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+
+/**
+ * Print warnings if deprecated core parameters are used in mojo.
+ *
+ * @since 3.9.1
+ */
+@Singleton
+@Named
+class DeprecatedCoreExpressionValidator extends AbstractMavenPluginParametersValidator {
+    private static final HashMap<String, String> DEPRECATED_CORE_PARAMETERS;
+
+    private static final String ARTIFACT_REPOSITORY_REASON =
+            "ArtifactRepository type is deprecated and its use in Mojos should be avoided.";
+
+    static {
+        HashMap<String, String> deprecatedCoreParameters = new HashMap<>();
+        deprecatedCoreParameters.put("${localRepository}", ARTIFACT_REPOSITORY_REASON);
+        deprecatedCoreParameters.put("${session.localRepository}", ARTIFACT_REPOSITORY_REASON);
+        DEPRECATED_CORE_PARAMETERS = deprecatedCoreParameters;
+    }
+
+    @Inject
+    DeprecatedCoreExpressionValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
+    }
+
+    @Override
+    protected String getParameterLogReason(Parameter parameter) {
+        return "uses deprecated parameter expression '" + parameter.getDefaultValue() + "': "
+                + DEPRECATED_CORE_PARAMETERS.get(parameter.getDefaultValue());
+    }
+
+    @Override
+    protected void doValidate(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator) {
+        if (mojoDescriptor.getParameters() == null) {
+            return;
+        }
+
+        mojoDescriptor.getParameters().stream()
+                .filter(this::isDeprecated)
+                .map(this::formatParameter)
+                .forEach(m -> pluginValidationManager.reportPluginMojoValidationIssue(
+                        PluginValidationManager.IssueLocality.EXTERNAL, mavenSession, mojoDescriptor, mojoClass, m));
+    }
+
+    private boolean isDeprecated(Parameter parameter) {
+        return Objects.equals(
+                        org.apache.maven.artifact.repository.ArtifactRepository.class.getName(), parameter.getType())
+                && DEPRECATED_CORE_PARAMETERS.containsKey(parameter.getDefaultValue());
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java
index 2f1291d..a4d784c 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,83 +16,93 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import org.apache.maven.api.services.MessageBuilderFactory;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.PluginValidationManager;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
-import org.apache.maven.shared.utils.logging.MessageUtils;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Print warnings if deprecated mojo or parameters of plugin are used in configuration.
  *
- * @author Slawomir Jaranowski
  */
-@Named
 @Singleton
-class DeprecatedPluginValidator extends AbstractMavenPluginParametersValidator
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( DeprecatedPluginValidator.class );
+@Named
+class DeprecatedPluginValidator extends AbstractMavenPluginDescriptorSourcedParametersValidator {
 
-    @Override
-    protected Logger getLogger()
-    {
-        return LOGGER;
+    private final MessageBuilderFactory messageBuilderFactory;
+
+    @Inject
+    DeprecatedPluginValidator(
+            PluginValidationManager pluginValidationManager, MessageBuilderFactory messageBuilderFactory) {
+        super(pluginValidationManager);
+        this.messageBuilderFactory = messageBuilderFactory;
     }
 
     @Override
-    protected String getParameterLogReason( Parameter parameter )
-    {
+    protected String getParameterLogReason(Parameter parameter) {
         return "is deprecated: " + parameter.getDeprecated();
     }
 
     @Override
-    public void validate( MojoDescriptor mojoDescriptor,
-                          PlexusConfiguration pomConfiguration,
-                          ExpressionEvaluator expressionEvaluator )
-    {
-        if ( !LOGGER.isWarnEnabled() )
-        {
-            return;
+    protected void doValidate(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator) {
+        if (mojoDescriptor.getDeprecated() != null) {
+            pluginValidationManager.reportPluginMojoValidationIssue(
+                    PluginValidationManager.IssueLocality.INTERNAL,
+                    mavenSession,
+                    mojoDescriptor,
+                    mojoClass,
+                    logDeprecatedMojo(mojoDescriptor));
         }
 
-        if ( mojoDescriptor.getDeprecated() != null )
-        {
-            logDeprecatedMojo( mojoDescriptor );
-        }
-
-        mojoDescriptor.getParameters().stream()
-            .filter( parameter -> parameter.getDeprecated() != null )
-            .filter( Parameter::isEditable )
-            .forEach( parameter -> checkParameter( parameter, pomConfiguration, expressionEvaluator ) );
-    }
-
-    private void checkParameter( Parameter parameter,
-                                 PlexusConfiguration pomConfiguration,
-                                 ExpressionEvaluator expressionEvaluator )
-    {
-        PlexusConfiguration config = pomConfiguration.getChild( parameter.getName(), false );
-
-        if ( isValueSet( config, expressionEvaluator ) )
-        {
-            logParameter( parameter );
+        if (mojoDescriptor.getParameters() != null) {
+            mojoDescriptor.getParameters().stream()
+                    .filter(parameter -> parameter.getDeprecated() != null)
+                    .filter(Parameter::isEditable)
+                    .forEach(parameter -> checkParameter(
+                            mavenSession, mojoDescriptor, mojoClass, parameter, pomConfiguration, expressionEvaluator));
         }
     }
 
-    private void logDeprecatedMojo( MojoDescriptor mojoDescriptor )
-    {
-        String message = MessageUtils.buffer()
-            .warning( "Goal '" )
-            .warning( mojoDescriptor.getGoal() )
-            .warning( "' is deprecated: " )
-            .warning( mojoDescriptor.getDeprecated() )
-            .toString();
+    private void checkParameter(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            Parameter parameter,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator) {
+        PlexusConfiguration config = pomConfiguration.getChild(parameter.getName(), false);
 
-        LOGGER.warn( message );
+        if (isValueSet(config, expressionEvaluator)) {
+            pluginValidationManager.reportPluginMojoValidationIssue(
+                    PluginValidationManager.IssueLocality.INTERNAL,
+                    mavenSession,
+                    mojoDescriptor,
+                    mojoClass,
+                    formatParameter(parameter));
+        }
+    }
+
+    private String logDeprecatedMojo(MojoDescriptor mojoDescriptor) {
+        return messageBuilderFactory
+                .builder()
+                .warning("Goal '")
+                .warning(mojoDescriptor.getGoal())
+                .warning("' is deprecated: ")
+                .warning(mojoDescriptor.getDeprecated())
+                .toString();
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/Maven2DependenciesValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/Maven2DependenciesValidator.java
new file mode 100644
index 0000000..d2f8dd8
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/Maven2DependenciesValidator.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.plugin.PluginValidationManager;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+
+/**
+ * Detects Maven2 plugins.
+ *
+ * @since 3.9.2
+ */
+@Singleton
+@Named
+class Maven2DependenciesValidator extends AbstractMavenPluginDependenciesValidator {
+
+    @Inject
+    Maven2DependenciesValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
+    }
+
+    @Override
+    protected void doValidate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult) {
+        Set<String> maven2Versions = artifactDescriptorResult.getDependencies().stream()
+                .map(Dependency::getArtifact)
+                .filter(d -> "org.apache.maven".equals(d.getGroupId()))
+                .filter(d -> !DefaultPluginValidationManager.EXPECTED_PROVIDED_SCOPE_EXCLUSIONS_GA.contains(
+                        d.getGroupId() + ":" + d.getArtifactId()))
+                .map(Artifact::getVersion)
+                .filter(v -> v.startsWith("2."))
+                .collect(Collectors.toSet());
+
+        if (!maven2Versions.isEmpty()) {
+            pluginValidationManager.reportPluginValidationIssue(
+                    PluginValidationManager.IssueLocality.EXTERNAL,
+                    session,
+                    pluginArtifact,
+                    "Plugin is a Maven 2.x plugin, which will be not supported in Maven 4.x");
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/Maven3CompatDependenciesValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/Maven3CompatDependenciesValidator.java
new file mode 100644
index 0000000..6781224
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/Maven3CompatDependenciesValidator.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.plugin.PluginValidationManager;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+import org.eclipse.aether.util.artifact.JavaScopes;
+
+/**
+ * Detects Maven3 plugins using maven-compat Maven2 compatibility layer.
+ *
+ * @since 3.9.3
+ */
+@Singleton
+@Named
+class Maven3CompatDependenciesValidator extends AbstractMavenPluginDependenciesValidator {
+
+    @Inject
+    Maven3CompatDependenciesValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
+    }
+
+    @Override
+    protected void doValidate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult) {
+        for (org.eclipse.aether.graph.Dependency dependency : artifactDescriptorResult.getDependencies()) {
+            if ("org.apache.maven".equals(dependency.getArtifact().getGroupId())
+                    && "maven-compat".equals(dependency.getArtifact().getArtifactId())
+                    && !JavaScopes.TEST.equals(dependency.getScope())) {
+                pluginValidationManager.reportPluginValidationIssue(
+                        PluginValidationManager.IssueLocality.EXTERNAL,
+                        session,
+                        pluginArtifact,
+                        "Plugin depends on the deprecated Maven 2.x compatibility layer, which will be not supported in Maven 4.x");
+            }
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenMixedDependenciesValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenMixedDependenciesValidator.java
new file mode 100644
index 0000000..2700383
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenMixedDependenciesValidator.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.plugin.PluginValidationManager;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.graph.Dependency;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+
+/**
+ * Detects mixed Maven versions in plugins.
+ *
+ * @since 3.9.2
+ */
+@Singleton
+@Named
+class MavenMixedDependenciesValidator extends AbstractMavenPluginDependenciesValidator {
+
+    @Inject
+    MavenMixedDependenciesValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
+    }
+
+    @Override
+    protected void doValidate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult) {
+        Set<String> mavenVersions = artifactDescriptorResult.getDependencies().stream()
+                .map(Dependency::getArtifact)
+                .filter(d -> "org.apache.maven".equals(d.getGroupId()))
+                .filter(d -> !DefaultPluginValidationManager.EXPECTED_PROVIDED_SCOPE_EXCLUSIONS_GA.contains(
+                        d.getGroupId() + ":" + d.getArtifactId()))
+                .map(Artifact::getVersion)
+                .collect(Collectors.toSet());
+
+        if (mavenVersions.size() > 1) {
+            pluginValidationManager.reportPluginValidationIssue(
+                    PluginValidationManager.IssueLocality.EXTERNAL,
+                    session,
+                    pluginArtifact,
+                    "Plugin mixes multiple Maven versions: " + mavenVersions);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginConfigurationValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginConfigurationValidator.java
index 8252782..9c95574 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginConfigurationValidator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginConfigurationValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,7 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
+import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
@@ -26,14 +26,15 @@
 /**
  * Service responsible for validating plugin configuration.
  *
- * @author Slawomir Jaranowski
  */
-interface MavenPluginConfigurationValidator
-{
+interface MavenPluginConfigurationValidator {
     /**
-     * Check mojo configuration.
+     * Checks mojo configuration issues.
      */
-    void validate( MojoDescriptor mojoDescriptor,
-                   PlexusConfiguration pomConfiguration,
-                   ExpressionEvaluator expressionEvaluator );
+    void validate(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginDependenciesValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginDependenciesValidator.java
new file mode 100644
index 0000000..2ee237d
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginDependenciesValidator.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+
+/**
+ * Service responsible for validating plugin dependencies.
+ *
+ * @since 3.9.3
+ */
+interface MavenPluginDependenciesValidator {
+    /**
+     * Checks mojo dependency issues.
+     */
+    void validate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginJavaPrerequisiteChecker.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginJavaPrerequisiteChecker.java
new file mode 100644
index 0000000..a100c34
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginJavaPrerequisiteChecker.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.plugin.MavenPluginPrerequisitesChecker;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.eclipse.aether.version.InvalidVersionSpecificationException;
+import org.eclipse.aether.version.Version;
+import org.eclipse.aether.version.VersionConstraint;
+import org.eclipse.aether.version.VersionScheme;
+
+@Named
+@Singleton
+public class MavenPluginJavaPrerequisiteChecker implements MavenPluginPrerequisitesChecker {
+
+    private final VersionScheme versionScheme;
+
+    @Inject
+    public MavenPluginJavaPrerequisiteChecker(final VersionScheme versionScheme) {
+        this.versionScheme = versionScheme;
+    }
+
+    @Override
+    public void accept(PluginDescriptor pluginDescriptor) {
+        String requiredJavaVersion = pluginDescriptor.getRequiredJavaVersion();
+        if (requiredJavaVersion != null && !requiredJavaVersion.isEmpty()) {
+            String currentJavaVersion = System.getProperty("java.version");
+            if (!matchesVersion(requiredJavaVersion, currentJavaVersion)) {
+                throw new IllegalStateException("Required Java version " + requiredJavaVersion
+                        + " is not met by current version: " + currentJavaVersion);
+            }
+        }
+    }
+
+    boolean matchesVersion(String requiredVersion, String currentVersion) {
+        VersionConstraint constraint;
+        try {
+            constraint = versionScheme.parseVersionConstraint(requiredVersion);
+        } catch (InvalidVersionSpecificationException e) {
+            throw new IllegalArgumentException("Invalid 'requiredJavaVersion' given in plugin descriptor", e);
+        }
+        Version current;
+        try {
+            current = versionScheme.parseVersion(currentVersion);
+        } catch (InvalidVersionSpecificationException e) {
+            throw new IllegalStateException("Could not parse current Java version", e);
+        }
+        if (constraint.getRange() == null) {
+            return constraint.getVersion().compareTo(current) <= 0;
+        }
+        return constraint.containsVersion(current);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginMavenPrerequisiteChecker.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginMavenPrerequisiteChecker.java
new file mode 100644
index 0000000..55dec64
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginMavenPrerequisiteChecker.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.plugin.MavenPluginPrerequisitesChecker;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.rtinfo.RuntimeInformation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Named
+@Singleton
+public class MavenPluginMavenPrerequisiteChecker implements MavenPluginPrerequisitesChecker {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
+    private final RuntimeInformation runtimeInformation;
+
+    @Inject
+    public MavenPluginMavenPrerequisiteChecker(RuntimeInformation runtimeInformation) {
+        super();
+        this.runtimeInformation = runtimeInformation;
+    }
+
+    @Override
+    public void accept(PluginDescriptor pluginDescriptor) {
+        String requiredMavenVersion = pluginDescriptor.getRequiredMavenVersion();
+
+        boolean isBlankVersion =
+                requiredMavenVersion == null || requiredMavenVersion.trim().isEmpty();
+
+        if (!isBlankVersion) {
+            boolean isRequirementMet = false;
+            try {
+                isRequirementMet = runtimeInformation.isMavenVersion(requiredMavenVersion);
+            } catch (IllegalArgumentException e) {
+                logger.warn(
+                        "Could not verify plugin's Maven prerequisite as an invalid version is given in "
+                                + requiredMavenVersion,
+                        e);
+                return;
+            }
+            if (!isRequirementMet) {
+                throw new IllegalStateException("Required Maven version " + requiredMavenVersion
+                        + " is not met by current version " + runtimeInformation.getMavenVersion());
+            }
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginValidator.java
index 2e36b4b..5333c56 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginValidator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenPluginValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
 import java.util.List;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 
 /**
  * MavenPluginValidator
  */
-interface MavenPluginValidator
-{
+interface MavenPluginValidator {
 
-    void validate( Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List<String> errors );
-
+    void validate(Artifact pluginArtifact, PluginDescriptor pluginDescriptor, List<String> errors);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenScopeDependenciesValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenScopeDependenciesValidator.java
new file mode 100644
index 0000000..844197f
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MavenScopeDependenciesValidator.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.plugin.PluginValidationManager;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+import org.eclipse.aether.util.artifact.JavaScopes;
+
+/**
+ * Detects Maven3 dependencies scope.
+ *
+ * @since 3.9.3
+ */
+@Singleton
+@Named
+class MavenScopeDependenciesValidator extends AbstractMavenPluginDependenciesValidator {
+
+    @Inject
+    MavenScopeDependenciesValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
+    }
+
+    @Override
+    protected void doValidate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult) {
+        Set<String> mavenArtifacts = artifactDescriptorResult.getDependencies().stream()
+                .filter(d -> !JavaScopes.PROVIDED.equals(d.getScope()) && !JavaScopes.TEST.equals(d.getScope()))
+                .map(org.eclipse.aether.graph.Dependency::getArtifact)
+                .filter(a -> "org.apache.maven".equals(a.getGroupId()))
+                .filter(a -> !DefaultPluginValidationManager.EXPECTED_PROVIDED_SCOPE_EXCLUSIONS_GA.contains(
+                        a.getGroupId() + ":" + a.getArtifactId()))
+                .filter(a -> a.getVersion().startsWith("3."))
+                .map(a -> a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getVersion())
+                .collect(Collectors.toSet());
+
+        if (!mavenArtifacts.isEmpty()) {
+            pluginValidationManager.reportPluginValidationIssue(
+                    PluginValidationManager.IssueLocality.EXTERNAL,
+                    session,
+                    pluginArtifact,
+                    "Plugin should declare Maven artifacts in `provided` scope. If the plugin already declares them in `provided` scope, update the maven-plugin-plugin to latest version. Artifacts found with wrong scope: "
+                            + mavenArtifacts);
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/MojoLogWrapper.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/MojoLogWrapper.java
index 060dffd..2ffd05b 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/MojoLogWrapper.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/MojoLogWrapper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
 import org.apache.maven.plugin.logging.Log;
 import org.slf4j.Logger;
@@ -25,122 +24,114 @@
 import static java.util.Objects.requireNonNull;
 
 /**
- * @author jdcasey
  */
-public class MojoLogWrapper
-    implements Log
-{
+public class MojoLogWrapper implements Log {
     private final Logger logger;
 
-    public MojoLogWrapper( Logger logger )
-    {
-        this.logger = requireNonNull( logger );
+    public MojoLogWrapper(Logger logger) {
+        this.logger = requireNonNull(logger);
     }
 
-    public void debug( CharSequence content )
-    {
-        logger.debug( toString( content ) );
-    }
-
-    private String toString( CharSequence content )
-    {
-        if ( content == null )
-        {
-            return "";
+    public void debug(CharSequence content) {
+        if (isDebugEnabled()) {
+            logger.debug(toString(content));
         }
-        else
-        {
+    }
+
+    private String toString(CharSequence content) {
+        if (content == null) {
+            return "";
+        } else {
             return content.toString();
         }
     }
 
     @Override
-    public void debug( CharSequence content, Throwable error )
-    {
-        logger.debug( toString( content ), error );
+    public void debug(CharSequence content, Throwable error) {
+        if (isDebugEnabled()) {
+            logger.debug(toString(content), error);
+        }
     }
 
     @Override
-    public void debug( Throwable error )
-    {
-        logger.debug( "", error );
+    public void debug(Throwable error) {
+        logger.debug("", error);
     }
 
     @Override
-    public void info( CharSequence content )
-    {
-        logger.info( toString( content ) );
+    public void info(CharSequence content) {
+        if (isInfoEnabled()) {
+            logger.info(toString(content));
+        }
     }
 
     @Override
-    public void info( CharSequence content, Throwable error )
-    {
-        logger.info( toString( content ), error );
+    public void info(CharSequence content, Throwable error) {
+        if (isInfoEnabled()) {
+            logger.info(toString(content), error);
+        }
     }
 
     @Override
-    public void info( Throwable error )
-    {
-        logger.info( "", error );
+    public void info(Throwable error) {
+        logger.info("", error);
     }
 
     @Override
-    public void warn( CharSequence content )
-    {
-        logger.warn( toString( content ) );
+    public void warn(CharSequence content) {
+        if (isWarnEnabled()) {
+            logger.warn(toString(content));
+        }
     }
 
     @Override
-    public void warn( CharSequence content, Throwable error )
-    {
-        logger.warn( toString( content ), error );
+    public void warn(CharSequence content, Throwable error) {
+        if (isWarnEnabled()) {
+            logger.warn(toString(content), error);
+        }
     }
 
     @Override
-    public void warn( Throwable error )
-    {
-        logger.warn( "", error );
+    public void warn(Throwable error) {
+        logger.warn("", error);
     }
 
     @Override
-    public void error( CharSequence content )
-    {
-        logger.error( toString( content ) );
+    public void error(CharSequence content) {
+        if (isErrorEnabled()) {
+            logger.error(toString(content));
+        }
     }
 
     @Override
-    public void error( CharSequence content, Throwable error )
-    {
-        logger.error( toString( content ), error );
+    public void error(CharSequence content, Throwable error) {
+        if (isErrorEnabled()) {
+            logger.error(toString(content), error);
+        }
     }
 
     @Override
-    public void error( Throwable error )
-    {
-        logger.error( "", error );
+    public void error(Throwable error) {
+        logger.error("", error);
     }
 
     @Override
-    public boolean isDebugEnabled()
-    {
+    public boolean isDebugEnabled() {
         return logger.isDebugEnabled();
     }
 
     @Override
-    public boolean isInfoEnabled()
-    {
+    public boolean isInfoEnabled() {
         return logger.isInfoEnabled();
     }
 
     @Override
-    public boolean isWarnEnabled()
-    {
+    public boolean isWarnEnabled() {
         return logger.isWarnEnabled();
     }
 
     @Override
-    public boolean isErrorEnabled()
-    {
+    public boolean isErrorEnabled() {
         return logger.isErrorEnabled();
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator.java
new file mode 100644
index 0000000..c0ea4e0
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/PlexusContainerDefaultDependenciesValidator.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.plugin.PluginValidationManager;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.resolution.ArtifactDescriptorResult;
+
+/**
+ * Detects Plexus Container Default in plugins.
+ *
+ * @since 3.9.2
+ */
+@Singleton
+@Named
+class PlexusContainerDefaultDependenciesValidator extends AbstractMavenPluginDependenciesValidator {
+
+    @Inject
+    PlexusContainerDefaultDependenciesValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
+    }
+
+    protected void doValidate(
+            RepositorySystemSession session,
+            Artifact pluginArtifact,
+            ArtifactDescriptorResult artifactDescriptorResult) {
+        boolean pcdPresent = artifactDescriptorResult.getDependencies().stream()
+                .filter(d -> "org.codehaus.plexus".equals(d.getArtifact().getGroupId()))
+                .anyMatch(d -> "plexus-container-default".equals(d.getArtifact().getArtifactId()));
+
+        if (pcdPresent) {
+            pluginValidationManager.reportPluginValidationIssue(
+                    PluginValidationManager.IssueLocality.EXTERNAL,
+                    session,
+                    pluginArtifact,
+                    "Plugin depends on plexus-container-default, which is EOL");
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginConfigurationModule.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginConfigurationModule.java
new file mode 100644
index 0000000..7123cbb
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginConfigurationModule.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import com.google.inject.Binder;
+import com.google.inject.Module;
+import com.google.inject.name.Names;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeImpl;
+import org.apache.maven.internal.xml.XmlPlexusConfiguration;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+
+class PluginConfigurationModule implements Module {
+
+    private final Plugin plugin;
+
+    PluginConfigurationModule(Plugin plugin) {
+        this.plugin = plugin;
+    }
+
+    @Override
+    public void configure(Binder binder) {
+        if (plugin.getKey() != null) {
+            XmlNode configuration = plugin.getConfiguration();
+            if (configuration == null) {
+                configuration = new XmlNodeImpl("configuration");
+            }
+            binder.bind(XmlNode.class)
+                    .annotatedWith(Names.named(plugin.getKey()))
+                    .toInstance(configuration);
+            binder.bind(PlexusConfiguration.class)
+                    .annotatedWith(Names.named(plugin.getKey()))
+                    .toInstance(XmlPlexusConfiguration.toPlexusConfiguration(configuration));
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java
index 4194297..4506ebe 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/PluginDependenciesResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
 import java.util.List;
 
@@ -35,10 +34,8 @@
  * changed or deleted without prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginDependenciesResolver
-{
+public interface PluginDependenciesResolver {
 
     /**
      * Resolves the main artifact of the specified plugin.
@@ -50,8 +47,8 @@
      * @return The resolved plugin artifact, never {@code null}.
      * @throws PluginResolutionException If the plugin artifact could not be resolved.
      */
-    Artifact resolve( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
-        throws PluginResolutionException;
+    Artifact resolve(Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session)
+            throws PluginResolutionException;
 
     /**
      * Resolves the runtime dependencies of the specified plugin.
@@ -64,8 +61,11 @@
      * @return The dependency tree denoting the resolved plugin class path, never {@code null}.
      * @throws PluginResolutionException If any dependency could not be resolved.
      */
-    DependencyNode resolve( Plugin plugin, Artifact pluginArtifact, DependencyFilter dependencyFilter,
-                            List<RemoteRepository> repositories, RepositorySystemSession session )
-        throws PluginResolutionException;
-
+    DependencyNode resolve(
+            Plugin plugin,
+            Artifact pluginArtifact,
+            DependencyFilter dependencyFilter,
+            List<RemoteRepository> repositories,
+            RepositorySystemSession session)
+            throws PluginResolutionException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator.java
index 1541937..2989fb5 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/ReadOnlyPluginParametersValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,63 +16,70 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.plugin.PluginValidationManager;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.Parameter;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Print warnings if read-only parameters of a plugin are used in configuration.
  *
- * @author Slawomir Jaranowski
  */
 @Named
 @Singleton
-public class ReadOnlyPluginParametersValidator extends AbstractMavenPluginParametersValidator
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( ReadOnlyPluginParametersValidator.class );
+class ReadOnlyPluginParametersValidator extends AbstractMavenPluginDescriptorSourcedParametersValidator {
 
-    @Override
-    protected Logger getLogger()
-    {
-        return LOGGER;
+    @Inject
+    ReadOnlyPluginParametersValidator(PluginValidationManager pluginValidationManager) {
+        super(pluginValidationManager);
     }
 
     @Override
-    protected String getParameterLogReason( Parameter parameter )
-    {
+    protected String getParameterLogReason(Parameter parameter) {
         return "is read-only, must not be used in configuration";
     }
 
     @Override
-    public void validate( MojoDescriptor mojoDescriptor, PlexusConfiguration pomConfiguration,
-                          ExpressionEvaluator expressionEvaluator )
-    {
-        if ( !LOGGER.isWarnEnabled() )
-        {
+    protected void doValidate(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator) {
+        if (mojoDescriptor.getParameters() == null) {
             return;
         }
 
         mojoDescriptor.getParameters().stream()
-            .filter( parameter -> !parameter.isEditable() )
-            .forEach( parameter -> checkParameter( parameter, pomConfiguration, expressionEvaluator ) );
+                .filter(parameter -> !parameter.isEditable())
+                .forEach(parameter -> checkParameter(
+                        mavenSession, mojoDescriptor, mojoClass, parameter, pomConfiguration, expressionEvaluator));
     }
 
-    protected void checkParameter( Parameter parameter,
-                                   PlexusConfiguration pomConfiguration,
-                                   ExpressionEvaluator expressionEvaluator )
-    {
-        PlexusConfiguration config = pomConfiguration.getChild( parameter.getName(), false );
+    private void checkParameter(
+            MavenSession mavenSession,
+            MojoDescriptor mojoDescriptor,
+            Class<?> mojoClass,
+            Parameter parameter,
+            PlexusConfiguration pomConfiguration,
+            ExpressionEvaluator expressionEvaluator) {
+        PlexusConfiguration config = pomConfiguration.getChild(parameter.getName(), false);
 
-        if ( isValueSet( config, expressionEvaluator ) )
-        {
-            logParameter( parameter );
+        if (isValueSet(config, expressionEvaluator)) {
+            pluginValidationManager.reportPluginMojoValidationIssue(
+                    PluginValidationManager.IssueLocality.INTERNAL,
+                    mavenSession,
+                    mojoDescriptor,
+                    mojoClass,
+                    formatParameter(parameter));
         }
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java
index c04f448..c87d6a6 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/ValidatingConfigurationListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -31,65 +30,51 @@
  * A configuration listener to help validate the plugin configuration. For instance, check for required but missing
  * parameters.
  *
- * @author Benjamin Bentmann
  */
-class ValidatingConfigurationListener
-    implements ConfigurationListener
-{
+class ValidatingConfigurationListener implements ConfigurationListener {
     private final Object mojo;
 
     private final ConfigurationListener delegate;
 
     private final Map<String, Parameter> missingParameters;
 
-    ValidatingConfigurationListener( Object mojo, MojoDescriptor mojoDescriptor, ConfigurationListener delegate )
-    {
+    ValidatingConfigurationListener(Object mojo, MojoDescriptor mojoDescriptor, ConfigurationListener delegate) {
         this.mojo = mojo;
         this.delegate = delegate;
         this.missingParameters = new HashMap<>();
 
-        if ( mojoDescriptor.getParameters() != null )
-        {
-            for ( Parameter param : mojoDescriptor.getParameters() )
-            {
-                if ( param.isRequired() )
-                {
-                    missingParameters.put( param.getName(), param );
+        if (mojoDescriptor.getParameters() != null) {
+            for (Parameter param : mojoDescriptor.getParameters()) {
+                if (param.isRequired()) {
+                    missingParameters.put(param.getName(), param);
                 }
             }
         }
     }
 
-    public Collection<Parameter> getMissingParameters()
-    {
+    public Collection<Parameter> getMissingParameters() {
         return missingParameters.values();
     }
 
-    public void notifyFieldChangeUsingSetter( String fieldName, Object value, Object target )
-    {
-        delegate.notifyFieldChangeUsingSetter( fieldName, value, target );
+    public void notifyFieldChangeUsingSetter(String fieldName, Object value, Object target) {
+        delegate.notifyFieldChangeUsingSetter(fieldName, value, target);
 
-        if ( mojo == target )
-        {
-            notify( fieldName, value );
+        if (mojo == target) {
+            notify(fieldName, value);
         }
     }
 
-    public void notifyFieldChangeUsingReflection( String fieldName, Object value, Object target )
-    {
-        delegate.notifyFieldChangeUsingReflection( fieldName, value, target );
+    public void notifyFieldChangeUsingReflection(String fieldName, Object value, Object target) {
+        delegate.notifyFieldChangeUsingReflection(fieldName, value, target);
 
-        if ( mojo == target )
-        {
-            notify( fieldName, value );
+        if (mojo == target) {
+            notify(fieldName, value);
         }
     }
 
-    private void notify( String fieldName, Object value )
-    {
-        if ( value != null )
-        {
-            missingParameters.remove( fieldName );
+    private void notify(String fieldName, Object value) {
+        if (value != null) {
+            missingParameters.remove(fieldName);
         }
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java
index 01194c8..9b1e68a 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/DefaultPluginPrefixRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.prefix;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.prefix;
 
 import java.util.Collections;
 import java.util.List;
@@ -32,11 +31,8 @@
  * Collects settings required to resolve a plugin prefix.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public class DefaultPluginPrefixRequest
-    implements PluginPrefixRequest
-{
+public class DefaultPluginPrefixRequest implements PluginPrefixRequest {
 
     private String prefix;
 
@@ -51,9 +47,7 @@
     /**
      * Creates an empty request.
      */
-    public DefaultPluginPrefixRequest()
-    {
-    }
+    public DefaultPluginPrefixRequest() {}
 
     /**
      * Creates a request for the specified plugin prefix and build session. The provided build session will be used to
@@ -63,94 +57,75 @@
      * @param prefix The plugin prefix to resolve, must not be {@code null}.
      * @param session The build session from which to derive further settings, must not be {@code null}.
      */
-    public DefaultPluginPrefixRequest( String prefix, MavenSession session )
-    {
-        setPrefix( prefix );
+    public DefaultPluginPrefixRequest(String prefix, MavenSession session) {
+        setPrefix(prefix);
 
-        setRepositorySession( session.getRepositorySession() );
+        setRepositorySession(session.getRepositorySession());
 
         MavenProject project = session.getCurrentProject();
-        if ( project != null )
-        {
-            setRepositories( project.getRemotePluginRepositories() );
-            setPom( project.getModel() );
+        if (project != null) {
+            setRepositories(project.getRemotePluginRepositories());
+            setPom(project.getModel());
         }
 
-        setPluginGroups( session.getPluginGroups() );
+        setPluginGroups(session.getPluginGroups());
     }
 
-    public String getPrefix()
-    {
+    public String getPrefix() {
         return prefix;
     }
 
-    public DefaultPluginPrefixRequest setPrefix( String prefix )
-    {
+    public DefaultPluginPrefixRequest setPrefix(String prefix) {
         this.prefix = prefix;
 
         return this;
     }
 
-    public List<String> getPluginGroups()
-    {
+    public List<String> getPluginGroups() {
         return pluginGroups;
     }
 
-    public DefaultPluginPrefixRequest setPluginGroups( List<String> pluginGroups )
-    {
-        if ( pluginGroups != null )
-        {
-            this.pluginGroups = Collections.unmodifiableList( pluginGroups );
-        }
-        else
-        {
+    public DefaultPluginPrefixRequest setPluginGroups(List<String> pluginGroups) {
+        if (pluginGroups != null) {
+            this.pluginGroups = Collections.unmodifiableList(pluginGroups);
+        } else {
             this.pluginGroups = Collections.emptyList();
         }
 
         return this;
     }
 
-    public Model getPom()
-    {
+    public Model getPom() {
         return pom;
     }
 
-    public DefaultPluginPrefixRequest setPom( Model pom )
-    {
+    public DefaultPluginPrefixRequest setPom(Model pom) {
         this.pom = pom;
 
         return this;
     }
 
-    public List<RemoteRepository> getRepositories()
-    {
+    public List<RemoteRepository> getRepositories() {
         return repositories;
     }
 
-    public DefaultPluginPrefixRequest setRepositories( List<RemoteRepository> repositories )
-    {
-        if ( repositories != null )
-        {
-            this.repositories = Collections.unmodifiableList( repositories );
-        }
-        else
-        {
+    public DefaultPluginPrefixRequest setRepositories(List<RemoteRepository> repositories) {
+        if (repositories != null) {
+            this.repositories = Collections.unmodifiableList(repositories);
+        } else {
             this.repositories = Collections.emptyList();
         }
 
         return this;
     }
 
-    public RepositorySystemSession getRepositorySession()
-    {
+    public RepositorySystemSession getRepositorySession() {
         return session;
     }
 
-    public DefaultPluginPrefixRequest setRepositorySession( RepositorySystemSession session )
-    {
+    public DefaultPluginPrefixRequest setRepositorySession(RepositorySystemSession session) {
         this.session = session;
 
         return this;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/NoPluginFoundForPrefixException.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/NoPluginFoundForPrefixException.java
index de53d51..6dc620b 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/NoPluginFoundForPrefixException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/NoPluginFoundForPrefixException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.prefix;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.prefix;
 
 import java.util.List;
 
@@ -27,42 +26,42 @@
 /**
  * NoPluginFoundForPrefixException
  */
-public class NoPluginFoundForPrefixException
-    extends Exception
-{
+public class NoPluginFoundForPrefixException extends Exception {
 
-    public NoPluginFoundForPrefixException( String prefix, List<String> pluginGroups, LocalRepository localRepository,
-                                            List<RemoteRepository> remoteRepositories )
-    {
-        super( "No plugin found for prefix '" + prefix + "' in the current project and in the plugin groups "
-            + pluginGroups + " available from the repositories " + format( localRepository, remoteRepositories ) );
+    public NoPluginFoundForPrefixException(
+            String prefix,
+            List<String> pluginGroups,
+            LocalRepository localRepository,
+            List<RemoteRepository> remoteRepositories) {
+        super("No plugin found for prefix '" + prefix + "' in the current project and in the plugin groups "
+                + pluginGroups + " available from the repositories " + format(localRepository, remoteRepositories));
     }
 
-    private static String format( LocalRepository localRepository, List<RemoteRepository> remoteRepositories )
-    {
-        StringBuilder repos = new StringBuilder( "[" );
+    private static String format(LocalRepository localRepository, List<RemoteRepository> remoteRepositories) {
+        StringBuilder repos = new StringBuilder("[");
 
-        if ( localRepository != null )
-        {
-            repos.append( localRepository.getId() ).append( " (" ).append( localRepository.getBasedir() ).append( ")" );
+        if (localRepository != null) {
+            repos.append(localRepository.getId())
+                    .append(" (")
+                    .append(localRepository.getBasedir())
+                    .append(")");
         }
 
-        if ( remoteRepositories != null && !remoteRepositories.isEmpty() )
-        {
-            for ( RemoteRepository repository : remoteRepositories )
-            {
-                repos.append( ", " );
+        if (remoteRepositories != null && !remoteRepositories.isEmpty()) {
+            for (RemoteRepository repository : remoteRepositories) {
+                repos.append(", ");
 
-                if ( repository != null )
-                {
-                    repos.append( repository.getId() ).append( " (" ).append( repository.getUrl() ).append( ")" );
+                if (repository != null) {
+                    repos.append(repository.getId())
+                            .append(" (")
+                            .append(repository.getUrl())
+                            .append(")");
                 }
             }
         }
 
-        repos.append( "]" );
+        repos.append("]");
 
         return repos.toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixRequest.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixRequest.java
index 23df66e..6a7c061 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.prefix;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.prefix;
 
 import java.util.List;
 
@@ -29,10 +28,8 @@
  * Collects settings required to resolve a plugin prefix.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginPrefixRequest
-{
+public interface PluginPrefixRequest {
 
     /**
      * Gets the prefix of the plugin.
@@ -47,7 +44,7 @@
      * @param prefix The prefix of the plugin.
      * @return This request, never {@code null}.
      */
-    PluginPrefixRequest setPrefix( String prefix );
+    PluginPrefixRequest setPrefix(String prefix);
 
     /**
      * Gets the list of group ids to scan for the plugin prefix.
@@ -62,7 +59,7 @@
      * @param pluginGroups The list of group ids to scan for the plugin prefix, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    PluginPrefixRequest setPluginGroups( List<String> pluginGroups );
+    PluginPrefixRequest setPluginGroups(List<String> pluginGroups);
 
     /**
      * Gets the POM whose build plugins are to be scanned for the prefix.
@@ -79,7 +76,7 @@
      *            plugin repositories.
      * @return This request, never {@code null}.
      */
-    PluginPrefixRequest setPom( Model pom );
+    PluginPrefixRequest setPom(Model pom);
 
     /**
      * Gets the remote repositories to use.
@@ -95,7 +92,7 @@
      * @param repositories The remote repositories to use.
      * @return This request, never {@code null}.
      */
-    PluginPrefixRequest setRepositories( List<RemoteRepository> repositories );
+    PluginPrefixRequest setRepositories(List<RemoteRepository> repositories);
 
     /**
      * Gets the session to use for repository access.
@@ -110,6 +107,5 @@
      * @param repositorySession The repository session to use.
      * @return This request, never {@code null}.
      */
-    PluginPrefixRequest setRepositorySession( RepositorySystemSession repositorySession );
-
+    PluginPrefixRequest setRepositorySession(RepositorySystemSession repositorySession);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResolver.java
index 943e683..3f04b54 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.prefix;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.prefix;
 
 /**
  * Resolves a plugin prefix.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginPrefixResolver
-{
+public interface PluginPrefixResolver {
 
     /**
      * Resolves the plugin prefix for the specified request.
@@ -36,7 +33,5 @@
      * @return The result of the prefix resolution, never {@code null}.
      * @throws NoPluginFoundForPrefixException If the plugin prefix could not be resolved.
      */
-    PluginPrefixResult resolve( PluginPrefixRequest request )
-        throws NoPluginFoundForPrefixException;
-
+    PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFoundForPrefixException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResult.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResult.java
index 8fe1a71..6890119 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResult.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/PluginPrefixResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.prefix;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.prefix;
 
 import org.eclipse.aether.repository.ArtifactRepository;
 
@@ -25,10 +24,8 @@
  * Describes the result of a plugin prefix resolution request.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginPrefixResult
-{
+public interface PluginPrefixResult {
 
     /**
      * The resolved group id for the plugin.
@@ -51,5 +48,4 @@
      *         the supplied POM.
      */
     ArtifactRepository getRepository();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java
index ef2cd83..8bcea49 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.prefix.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.prefix.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -25,10 +28,6 @@
 import java.util.List;
 import java.util.Map;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.artifact.repository.metadata.Metadata;
 import org.apache.maven.artifact.repository.metadata.io.MetadataReader;
 import org.apache.maven.model.Build;
@@ -59,107 +58,89 @@
  * Resolves a plugin prefix.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultPluginPrefixResolver
-    implements PluginPrefixResolver
-{
+public class DefaultPluginPrefixResolver implements PluginPrefixResolver {
     private static final String REPOSITORY_CONTEXT = "plugin";
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private final Logger logger = LoggerFactory.getLogger(getClass());
     private final BuildPluginManager pluginManager;
     private final RepositorySystem repositorySystem;
     private final MetadataReader metadataReader;
 
     @Inject
     public DefaultPluginPrefixResolver(
-            BuildPluginManager pluginManager,
-            RepositorySystem repositorySystem,
-            MetadataReader metadataReader )
-    {
+            BuildPluginManager pluginManager, RepositorySystem repositorySystem, MetadataReader metadataReader) {
         this.pluginManager = pluginManager;
         this.repositorySystem = repositorySystem;
         this.metadataReader = metadataReader;
     }
 
-    public PluginPrefixResult resolve( PluginPrefixRequest request )
-        throws NoPluginFoundForPrefixException
-    {
-        logger.debug( "Resolving plugin prefix " + request.getPrefix() + " from " + request.getPluginGroups() );
+    public PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFoundForPrefixException {
+        logger.debug("Resolving plugin prefix {} from {}", request.getPrefix(), request.getPluginGroups());
 
-        PluginPrefixResult result = resolveFromProject( request );
+        PluginPrefixResult result = resolveFromProject(request);
 
-        if ( result == null )
-        {
-            result = resolveFromRepository( request );
+        if (result == null) {
+            result = resolveFromRepository(request);
 
-            if ( result == null )
-            {
-                throw new NoPluginFoundForPrefixException( request.getPrefix(), request.getPluginGroups(),
-                                                           request.getRepositorySession().getLocalRepository(),
-                                                           request.getRepositories() );
+            if (result == null) {
+                throw new NoPluginFoundForPrefixException(
+                        request.getPrefix(),
+                        request.getPluginGroups(),
+                        request.getRepositorySession().getLocalRepository(),
+                        request.getRepositories());
+            } else {
+                logger.debug(
+                        "Resolved plugin prefix {} to {}:{} from repository {}",
+                        request.getPrefix(),
+                        result.getGroupId(),
+                        result.getArtifactId(),
+                        (result.getRepository() != null ? result.getRepository().getId() : "null"));
             }
-            else if ( logger.isDebugEnabled() )
-            {
-                logger.debug( "Resolved plugin prefix " + request.getPrefix() + " to " + result.getGroupId() + ":"
-                    + result.getArtifactId() + " from repository "
-                    + ( result.getRepository() != null ? result.getRepository().getId() : "null" ) );
-            }
-        }
-        else if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "Resolved plugin prefix " + request.getPrefix() + " to " + result.getGroupId() + ":"
-                + result.getArtifactId() + " from POM " + request.getPom() );
+        } else {
+            logger.debug(
+                    "Resolved plugin prefix {} to {}:{} from POM {}",
+                    request.getPrefix(),
+                    result.getGroupId(),
+                    result.getArtifactId(),
+                    request.getPom());
         }
 
         return result;
     }
 
-    private PluginPrefixResult resolveFromProject( PluginPrefixRequest request )
-    {
+    private PluginPrefixResult resolveFromProject(PluginPrefixRequest request) {
         PluginPrefixResult result = null;
 
-        if ( request.getPom() != null && request.getPom().getBuild() != null )
-        {
+        if (request.getPom() != null && request.getPom().getBuild() != null) {
             Build build = request.getPom().getBuild();
 
-            result = resolveFromProject( request, build.getPlugins() );
+            result = resolveFromProject(request, build.getPlugins());
 
-            if ( result == null && build.getPluginManagement() != null )
-            {
-                result = resolveFromProject( request, build.getPluginManagement().getPlugins() );
+            if (result == null && build.getPluginManagement() != null) {
+                result = resolveFromProject(request, build.getPluginManagement().getPlugins());
             }
         }
 
         return result;
     }
 
-    private PluginPrefixResult resolveFromProject( PluginPrefixRequest request, List<Plugin> plugins )
-    {
-        for ( Plugin plugin : plugins )
-        {
-            try
-            {
+    private PluginPrefixResult resolveFromProject(PluginPrefixRequest request, List<Plugin> plugins) {
+        for (Plugin plugin : plugins) {
+            try {
                 PluginDescriptor pluginDescriptor =
-                    pluginManager.loadPlugin( plugin, request.getRepositories(), request.getRepositorySession() );
+                        pluginManager.loadPlugin(plugin, request.getRepositories(), request.getRepositorySession());
 
-                if ( request.getPrefix().equals( pluginDescriptor.getGoalPrefix() ) )
-                {
-                    return new DefaultPluginPrefixResult( plugin );
+                if (request.getPrefix().equals(pluginDescriptor.getGoalPrefix())) {
+                    return new DefaultPluginPrefixResult(plugin);
                 }
-            }
-            catch ( Exception e )
-            {
-                if ( logger.isDebugEnabled() )
-                {
-                    logger.warn( "Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage(),
-                                 e );
-                }
-                else
-                {
-                    logger.warn( "Failed to retrieve plugin descriptor for " + plugin.getId() + ": " + e.getMessage() );
+            } catch (Exception e) {
+                if (logger.isDebugEnabled()) {
+                    logger.warn("Failed to retrieve plugin descriptor for {}: {}", plugin.getId(), e.getMessage(), e);
+                } else {
+                    logger.warn("Failed to retrieve plugin descriptor for {}: {}", plugin.getId(), e.getMessage());
                 }
             }
         }
@@ -167,135 +148,120 @@
         return null;
     }
 
-    private PluginPrefixResult resolveFromRepository( PluginPrefixRequest request )
-    {
-        RequestTrace trace = RequestTrace.newChild( null, request );
+    private PluginPrefixResult resolveFromRepository(PluginPrefixRequest request) {
+        RequestTrace trace = RequestTrace.newChild(null, request);
 
         List<MetadataRequest> requests = new ArrayList<>();
 
-        for ( String pluginGroup : request.getPluginGroups() )
-        {
+        for (String pluginGroup : request.getPluginGroups()) {
             org.eclipse.aether.metadata.Metadata metadata =
-                new DefaultMetadata( pluginGroup, "maven-metadata.xml", DefaultMetadata.Nature.RELEASE_OR_SNAPSHOT );
+                    new DefaultMetadata(pluginGroup, "maven-metadata.xml", DefaultMetadata.Nature.RELEASE_OR_SNAPSHOT);
 
-            requests.add( new MetadataRequest( metadata, null, REPOSITORY_CONTEXT ).setTrace( trace ) );
+            requests.add(new MetadataRequest(metadata, null, REPOSITORY_CONTEXT).setTrace(trace));
 
-            for ( RemoteRepository repository : request.getRepositories() )
-            {
-                requests.add( new MetadataRequest( metadata, repository, REPOSITORY_CONTEXT ).setTrace( trace ) );
+            for (RemoteRepository repository : request.getRepositories()) {
+                requests.add(new MetadataRequest(metadata, repository, REPOSITORY_CONTEXT).setTrace(trace));
             }
         }
 
         // initial try, use locally cached metadata
 
-        List<MetadataResult> results = repositorySystem.resolveMetadata( request.getRepositorySession(), requests );
+        List<MetadataResult> results = repositorySystem.resolveMetadata(request.getRepositorySession(), requests);
         requests.clear();
 
-        PluginPrefixResult result = processResults( request, trace, results, requests );
+        PluginPrefixResult result = processResults(request, trace, results, requests);
 
-        if ( result != null )
-        {
+        if (result != null) {
             return result;
         }
 
         // second try, refetch all (possibly outdated) metadata that wasn't updated in the first attempt
 
-        if ( !request.getRepositorySession().isOffline() && !requests.isEmpty() )
-        {
-            DefaultRepositorySystemSession session =
-                new DefaultRepositorySystemSession( request.getRepositorySession() );
-            session.setUpdatePolicy( RepositoryPolicy.UPDATE_POLICY_ALWAYS );
+        if (!request.getRepositorySession().isOffline() && !requests.isEmpty()) {
+            DefaultRepositorySystemSession session = new DefaultRepositorySystemSession(request.getRepositorySession());
+            session.setUpdatePolicy(RepositoryPolicy.UPDATE_POLICY_ALWAYS);
 
-            results = repositorySystem.resolveMetadata( session, requests );
+            results = repositorySystem.resolveMetadata(session, requests);
 
-            return processResults( request, trace, results, null );
+            return processResults(request, trace, results, null);
         }
 
         return null;
     }
 
-    private PluginPrefixResult processResults( PluginPrefixRequest request, RequestTrace trace,
-                                               List<MetadataResult> results, List<MetadataRequest> requests )
-    {
-        for ( MetadataResult res : results )
-        {
+    private PluginPrefixResult processResults(
+            PluginPrefixRequest request,
+            RequestTrace trace,
+            List<MetadataResult> results,
+            List<MetadataRequest> requests) {
+        for (MetadataResult res : results) {
             org.eclipse.aether.metadata.Metadata metadata = res.getMetadata();
 
-            if ( metadata != null )
-            {
+            if (metadata != null) {
                 ArtifactRepository repository = res.getRequest().getRepository();
-                if ( repository == null )
-                {
+                if (repository == null) {
                     repository = request.getRepositorySession().getLocalRepository();
                 }
 
                 PluginPrefixResult result =
-                    resolveFromRepository( request, trace, metadata.getGroupId(), metadata, repository );
+                        resolveFromRepository(request, trace, metadata.getGroupId(), metadata, repository);
 
-                if ( result != null )
-                {
+                if (result != null) {
                     return result;
                 }
             }
 
-            if ( requests != null && !res.isUpdated() )
-            {
-                requests.add( res.getRequest() );
+            if (requests != null && !res.isUpdated()) {
+                requests.add(res.getRequest());
             }
         }
 
         return null;
     }
 
-    private PluginPrefixResult resolveFromRepository( PluginPrefixRequest request, RequestTrace trace,
-                                                      String pluginGroup,
-                                                      org.eclipse.aether.metadata.Metadata metadata,
-                                                      ArtifactRepository repository )
-    {
-        if ( metadata != null && metadata.getFile() != null && metadata.getFile().isFile() )
-        {
-            try
-            {
-                Map<String, ?> options = Collections.singletonMap( MetadataReader.IS_STRICT, Boolean.FALSE );
+    private PluginPrefixResult resolveFromRepository(
+            PluginPrefixRequest request,
+            RequestTrace trace,
+            String pluginGroup,
+            org.eclipse.aether.metadata.Metadata metadata,
+            ArtifactRepository repository) {
+        if (metadata != null && metadata.getFile() != null && metadata.getFile().isFile()) {
+            try {
+                Map<String, ?> options = Collections.singletonMap(MetadataReader.IS_STRICT, Boolean.FALSE);
 
-                Metadata pluginGroupMetadata = metadataReader.read( metadata.getFile(), options );
+                Metadata pluginGroupMetadata = metadataReader.read(metadata.getFile(), options);
 
                 List<org.apache.maven.artifact.repository.metadata.Plugin> plugins = pluginGroupMetadata.getPlugins();
 
-                if ( plugins != null )
-                {
-                    for ( org.apache.maven.artifact.repository.metadata.Plugin plugin : plugins )
-                    {
-                        if ( request.getPrefix().equals( plugin.getPrefix() ) )
-                        {
-                            return new DefaultPluginPrefixResult( pluginGroup, plugin.getArtifactId(), repository );
+                if (plugins != null) {
+                    for (org.apache.maven.artifact.repository.metadata.Plugin plugin : plugins) {
+                        if (request.getPrefix().equals(plugin.getPrefix())) {
+                            return new DefaultPluginPrefixResult(pluginGroup, plugin.getArtifactId(), repository);
                         }
                     }
                 }
-            }
-            catch ( IOException e )
-            {
-                invalidMetadata( request.getRepositorySession(), trace, metadata, repository, e );
+            } catch (IOException e) {
+                invalidMetadata(request.getRepositorySession(), trace, metadata, repository, e);
             }
         }
 
         return null;
     }
 
-    private void invalidMetadata( RepositorySystemSession session, RequestTrace trace,
-                                  org.eclipse.aether.metadata.Metadata metadata, ArtifactRepository repository,
-                                  Exception exception )
-    {
+    private void invalidMetadata(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            org.eclipse.aether.metadata.Metadata metadata,
+            ArtifactRepository repository,
+            Exception exception) {
         RepositoryListener listener = session.getRepositoryListener();
-        if ( listener != null )
-        {
-            RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID );
-            event.setTrace( trace );
-            event.setMetadata( metadata );
-            event.setException( exception );
-            event.setRepository( repository );
-            listener.metadataInvalid( event.build() );
+        if (listener != null) {
+            RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INVALID);
+            event.setTrace(trace);
+            event.setMetadata(metadata);
+            event.setException(exception);
+            event.setRepository(repository);
+            listener.metadataInvalid(event.build());
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResult.java b/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResult.java
index 2adc6f3..ad6431a 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResult.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/prefix/internal/DefaultPluginPrefixResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.prefix.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.prefix.internal;
 
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.prefix.PluginPrefixResult;
@@ -27,11 +26,8 @@
  * Describes the result of a plugin prefix resolution request.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-class DefaultPluginPrefixResult
-    implements PluginPrefixResult
-{
+class DefaultPluginPrefixResult implements PluginPrefixResult {
 
     private String groupId;
 
@@ -39,52 +35,42 @@
 
     private ArtifactRepository repository;
 
-    DefaultPluginPrefixResult()
-    {
+    DefaultPluginPrefixResult() {
         // does nothing
     }
 
-    DefaultPluginPrefixResult( Plugin plugin )
-    {
+    DefaultPluginPrefixResult(Plugin plugin) {
         groupId = plugin.getGroupId();
         artifactId = plugin.getArtifactId();
     }
 
-    DefaultPluginPrefixResult( String groupId, String artifactId, ArtifactRepository repository )
-    {
+    DefaultPluginPrefixResult(String groupId, String artifactId, ArtifactRepository repository) {
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.repository = repository;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public void setGroupId( String groupId )
-    {
+    public void setGroupId(String groupId) {
         this.groupId = groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public void setArtifactId( String artifactId )
-    {
+    public void setArtifactId(String artifactId) {
         this.artifactId = artifactId;
     }
 
-    public ArtifactRepository getRepository()
-    {
+    public ArtifactRepository getRepository() {
         return repository;
     }
 
-    public void setRepository( ArtifactRepository repository )
-    {
+    public void setRepository(ArtifactRepository repository) {
         this.repository = repository;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java b/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java
index 57f4250..bd88b69 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/DefaultPluginVersionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version;
 
 import java.util.Collections;
 import java.util.List;
@@ -33,11 +32,8 @@
  * Collects settings required to resolve the version for a plugin.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public class DefaultPluginVersionRequest
-    implements PluginVersionRequest
-{
+public class DefaultPluginVersionRequest implements PluginVersionRequest {
 
     private String groupId;
 
@@ -52,9 +48,7 @@
     /**
      * Creates an empty request.
      */
-    public DefaultPluginVersionRequest()
-    {
-    }
+    public DefaultPluginVersionRequest() {}
 
     /**
      * Creates a request for the specified plugin by copying settings from the specified build session. If the session
@@ -63,17 +57,15 @@
      * @param plugin The plugin for which to resolve a version, must not be {@code null}.
      * @param session The Maven session to use, must not be {@code null}.
      */
-    public DefaultPluginVersionRequest( Plugin plugin, MavenSession session )
-    {
-        setGroupId( plugin.getGroupId() );
-        setArtifactId( plugin.getArtifactId() );
+    public DefaultPluginVersionRequest(Plugin plugin, MavenSession session) {
+        setGroupId(plugin.getGroupId());
+        setArtifactId(plugin.getArtifactId());
 
-        setRepositorySession( session.getRepositorySession() );
+        setRepositorySession(session.getRepositorySession());
 
         MavenProject project = session.getCurrentProject();
-        if ( project != null )
-        {
-            setRepositories( project.getRemotePluginRepositories() );
+        if (project != null) {
+            setRepositories(project.getRemotePluginRepositories());
         }
     }
 
@@ -84,82 +76,67 @@
      * @param session The repository session to use, must not be {@code null}.
      * @param repositories The plugin repositories to query, may be {@code null}.
      */
-    public DefaultPluginVersionRequest( Plugin plugin, RepositorySystemSession session,
-                                        List<RemoteRepository> repositories )
-    {
-        setGroupId( plugin.getGroupId() );
-        setArtifactId( plugin.getArtifactId() );
+    public DefaultPluginVersionRequest(
+            Plugin plugin, RepositorySystemSession session, List<RemoteRepository> repositories) {
+        setGroupId(plugin.getGroupId());
+        setArtifactId(plugin.getArtifactId());
 
-        setRepositorySession( session );
+        setRepositorySession(session);
 
-        setRepositories( repositories );
+        setRepositories(repositories);
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public DefaultPluginVersionRequest setGroupId( String groupId )
-    {
+    public DefaultPluginVersionRequest setGroupId(String groupId) {
         this.groupId = groupId;
 
         return this;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public DefaultPluginVersionRequest setArtifactId( String artifactId )
-    {
+    public DefaultPluginVersionRequest setArtifactId(String artifactId) {
         this.artifactId = artifactId;
 
         return this;
     }
 
-    public Model getPom()
-    {
+    public Model getPom() {
         return pom;
     }
 
-    public DefaultPluginVersionRequest setPom( Model pom )
-    {
+    public DefaultPluginVersionRequest setPom(Model pom) {
         this.pom = pom;
 
         return this;
     }
 
-    public List<RemoteRepository> getRepositories()
-    {
+    public List<RemoteRepository> getRepositories() {
         return repositories;
     }
 
-    public DefaultPluginVersionRequest setRepositories( List<RemoteRepository> repositories )
-    {
-        if ( repositories != null )
-        {
-            this.repositories = Collections.unmodifiableList( repositories );
-        }
-        else
-        {
+    public DefaultPluginVersionRequest setRepositories(List<RemoteRepository> repositories) {
+        if (repositories != null) {
+            this.repositories = Collections.unmodifiableList(repositories);
+        } else {
             this.repositories = Collections.emptyList();
         }
 
         return this;
     }
 
-    public RepositorySystemSession getRepositorySession()
-    {
+    public RepositorySystemSession getRepositorySession() {
         return session;
     }
 
-    public DefaultPluginVersionRequest setRepositorySession( RepositorySystemSession session )
-    {
+    public DefaultPluginVersionRequest setRepositorySession(RepositorySystemSession session) {
         this.session = session;
 
         return this;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionNotFoundException.java b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionNotFoundException.java
index b4864fc..8299b8b 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionNotFoundException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,33 +16,28 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version;
 
 /**
  * PluginVersionNotFoundException
  */
-public class PluginVersionNotFoundException
-    extends Exception
-{
+public class PluginVersionNotFoundException extends Exception {
     private final String groupId;
 
     private final String artifactId;
 
-    public PluginVersionNotFoundException( String groupId, String artifactId )
-    {
-        super( "The plugin '" + groupId + ":" + artifactId + "' does not exist or no valid version could be found" );
+    public PluginVersionNotFoundException(String groupId, String artifactId) {
+        super("The plugin '" + groupId + ":" + artifactId + "' does not exist or no valid version could be found");
 
         this.groupId = groupId;
         this.artifactId = artifactId;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionRequest.java b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionRequest.java
index d947b2a..2287f24 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version;
 
 import java.util.List;
 
@@ -29,10 +28,8 @@
  * Collects settings required to resolve the version for a plugin.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginVersionRequest
-{
+public interface PluginVersionRequest {
 
     /**
      * Gets the group id of the plugin.
@@ -47,7 +44,7 @@
      * @param groupId The group id of the plugin.
      * @return This request, never {@code null}.
      */
-    PluginVersionRequest setGroupId( String groupId );
+    PluginVersionRequest setGroupId(String groupId);
 
     /**
      * Gets the artifact id of the plugin.
@@ -62,7 +59,7 @@
      * @param artifactId The artifact id of the plugin.
      * @return This request, never {@code null}.
      */
-    PluginVersionRequest setArtifactId( String artifactId );
+    PluginVersionRequest setArtifactId(String artifactId);
 
     /**
      * Gets the POM whose build plugins are to be scanned for the version.
@@ -79,7 +76,7 @@
      *            plugin repositories.
      * @return This request, never {@code null}.
      */
-    PluginVersionRequest setPom( Model pom );
+    PluginVersionRequest setPom(Model pom);
 
     /**
      * Gets the remote repositories to use.
@@ -95,7 +92,7 @@
      * @param repositories The remote repositories to use.
      * @return This request, never {@code null}.
      */
-    PluginVersionRequest setRepositories( List<RemoteRepository> repositories );
+    PluginVersionRequest setRepositories(List<RemoteRepository> repositories);
 
     /**
      * Gets the session to use for repository access.
@@ -110,6 +107,5 @@
      * @param repositorySession The repository session to use.
      * @return This request, never {@code null}.
      */
-    PluginVersionRequest setRepositorySession( RepositorySystemSession repositorySession );
-
+    PluginVersionRequest setRepositorySession(RepositorySystemSession repositorySession);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolutionException.java b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolutionException.java
index 6bde3f2..c9ad161 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version;
 
 import java.util.List;
 
@@ -27,84 +26,80 @@
 /**
  * PluginVersionResolutionException
  */
-public class PluginVersionResolutionException
-    extends Exception
-{
+public class PluginVersionResolutionException extends Exception {
     private final String groupId;
 
     private final String artifactId;
 
     private final String baseMessage;
 
-    public PluginVersionResolutionException( String groupId, String artifactId, String baseMessage, Throwable cause )
-    {
-        super( "Error resolving version for plugin '" + groupId + ":" + artifactId + "': " + baseMessage, cause );
+    public PluginVersionResolutionException(String groupId, String artifactId, String baseMessage, Throwable cause) {
+        super("Error resolving version for plugin '" + groupId + ":" + artifactId + "': " + baseMessage, cause);
 
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.baseMessage = baseMessage;
     }
 
-    public PluginVersionResolutionException( String groupId, String artifactId, String baseMessage )
-    {
-        super( "Error resolving version for plugin '" + groupId + ":" + artifactId + "': " + baseMessage );
+    public PluginVersionResolutionException(String groupId, String artifactId, String baseMessage) {
+        super("Error resolving version for plugin '" + groupId + ":" + artifactId + "': " + baseMessage);
 
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.baseMessage = baseMessage;
     }
 
-    public PluginVersionResolutionException( String groupId, String artifactId, LocalRepository localRepository,
-                                             List<RemoteRepository> remoteRepositories, String baseMessage )
-    {
-        super( "Error resolving version for plugin '" + groupId + ":" + artifactId + "' from the repositories "
-            + format( localRepository, remoteRepositories ) + ": " + baseMessage );
+    public PluginVersionResolutionException(
+            String groupId,
+            String artifactId,
+            LocalRepository localRepository,
+            List<RemoteRepository> remoteRepositories,
+            String baseMessage) {
+        super("Error resolving version for plugin '" + groupId + ":" + artifactId + "' from the repositories "
+                + format(localRepository, remoteRepositories) + ": " + baseMessage);
 
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.baseMessage = baseMessage;
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public String getBaseMessage()
-    {
+    public String getBaseMessage() {
         return baseMessage;
     }
 
-    private static String format( LocalRepository localRepository, List<RemoteRepository> remoteRepositories )
-    {
-        StringBuilder repos = new StringBuilder( "[" );
+    private static String format(LocalRepository localRepository, List<RemoteRepository> remoteRepositories) {
+        StringBuilder repos = new StringBuilder("[");
 
-        if ( localRepository != null )
-        {
-            repos.append( localRepository.getId() ).append( " (" ).append( localRepository.getBasedir() ).append( ")" );
+        if (localRepository != null) {
+            repos.append(localRepository.getId())
+                    .append(" (")
+                    .append(localRepository.getBasedir())
+                    .append(")");
         }
 
-        if ( remoteRepositories != null && !remoteRepositories.isEmpty() )
-        {
-            for ( RemoteRepository repository : remoteRepositories )
-            {
-                repos.append( ", " );
+        if (remoteRepositories != null && !remoteRepositories.isEmpty()) {
+            for (RemoteRepository repository : remoteRepositories) {
+                repos.append(", ");
 
-                if ( repository != null )
-                {
-                    repos.append( repository.getId() ).append( " (" ).append( repository.getUrl() ).append( ")" );
+                if (repository != null) {
+                    repos.append(repository.getId())
+                            .append(" (")
+                            .append(repository.getUrl())
+                            .append(")");
                 }
             }
         }
 
-        repos.append( "]" );
+        repos.append("]");
 
         return repos.toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolver.java
index 935fdfc..1825bad 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version;
 
 /**
  * Resolves a version for a plugin.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginVersionResolver
-{
+public interface PluginVersionResolver {
 
     /**
      * Resolves the version for the specified request.
@@ -36,7 +33,5 @@
      * @return The result of the version resolution, never {@code null}.
      * @throws PluginVersionResolutionException If the plugin version could not be resolved.
      */
-    PluginVersionResult resolve( PluginVersionRequest request )
-        throws PluginVersionResolutionException;
-
+    PluginVersionResult resolve(PluginVersionRequest request) throws PluginVersionResolutionException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResult.java b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResult.java
index 09a69e9..5a007ed 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/PluginVersionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version;
 
 import org.eclipse.aether.repository.ArtifactRepository;
 
@@ -25,10 +24,8 @@
  * Describes the result of a plugin version resolution request.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public interface PluginVersionResult
-{
+public interface PluginVersionResult {
 
     /**
      * The resolved plugin version.
@@ -43,5 +40,4 @@
      * @return The repository from which the plugin version was resolved, never {@code null}.
      */
     ArtifactRepository getRepository();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
index 294750f..904606a 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -30,10 +33,6 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.artifact.repository.metadata.Metadata;
 import org.apache.maven.artifact.repository.metadata.Versioning;
 import org.apache.maven.artifact.repository.metadata.io.MetadataReader;
@@ -46,7 +45,6 @@
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.apache.maven.plugin.version.PluginVersionResolver;
 import org.apache.maven.plugin.version.PluginVersionResult;
-import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.RepositoryEvent;
 import org.eclipse.aether.RepositoryEvent.EventType;
 import org.eclipse.aether.RepositoryListener;
@@ -69,18 +67,15 @@
  * Resolves a version for a plugin.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultPluginVersionResolver
-    implements PluginVersionResolver
-{
+public class DefaultPluginVersionResolver implements PluginVersionResolver {
     private static final String REPOSITORY_CONTEXT = "plugin";
 
     private static final Object CACHE_KEY = new Object();
 
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+    private final Logger logger = LoggerFactory.getLogger(getClass());
     private final RepositorySystem repositorySystem;
     private final MetadataReader metadataReader;
     private final MavenPluginManager pluginManager;
@@ -91,8 +86,7 @@
             RepositorySystem repositorySystem,
             MetadataReader metadataReader,
             MavenPluginManager pluginManager,
-            VersionScheme versionScheme )
-    {
+            VersionScheme versionScheme) {
         this.repositorySystem = repositorySystem;
         this.metadataReader = metadataReader;
         this.pluginManager = pluginManager;
@@ -100,311 +94,271 @@
     }
 
     @Override
-    public PluginVersionResult resolve( PluginVersionRequest request )
-        throws PluginVersionResolutionException
-    {
-        PluginVersionResult result = resolveFromProject( request );
+    public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVersionResolutionException {
+        PluginVersionResult result = resolveFromProject(request);
 
-        if ( result == null )
-        {
-            ConcurrentMap<Key, PluginVersionResult> cache = getCache( request.getRepositorySession().getData() );
-            Key key = getKey( request );
-            result = cache.get( key );
+        if (result == null) {
+            ConcurrentMap<Key, PluginVersionResult> cache = getCache(request);
+            Key key = getKey(request);
+            result = cache.get(key);
 
-            if ( result == null )
-            {
-                result = resolveFromRepository( request );
+            if (result == null) {
+                result = resolveFromRepository(request);
 
-                if ( logger.isDebugEnabled() )
-                {
-                    logger.debug( "Resolved plugin version for " + request.getGroupId() + ":" + request.getArtifactId()
-                        + " to " + result.getVersion() + " from repository " + result.getRepository() );
-                }
+                logger.debug(
+                        "Resolved plugin version for {}:{} to {} from repository {}",
+                        request.getGroupId(),
+                        request.getArtifactId(),
+                        result.getVersion(),
+                        result.getRepository());
 
-                cache.putIfAbsent( key, result );
+                cache.putIfAbsent(key, result);
+            } else {
+                logger.debug(
+                        "Reusing cached resolved plugin version for {}:{} to {} from POM {}",
+                        request.getGroupId(),
+                        request.getArtifactId(),
+                        result.getVersion(),
+                        request.getPom());
             }
-            else if ( logger.isDebugEnabled() )
-            {
-                logger.debug( "Reusing cached resolved plugin version for " + request.getGroupId() + ":"
-                        + request.getArtifactId() + " to " + result.getVersion() + " from POM " + request.getPom() );
-            }
-        }
-        else if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "Resolved plugin version for " + request.getGroupId() + ":" + request.getArtifactId() + " to "
-                + result.getVersion() + " from POM " + request.getPom() );
+        } else {
+            logger.debug(
+                    "Reusing cached resolved plugin version for {}:{} to {} from POM {}",
+                    request.getGroupId(),
+                    request.getArtifactId(),
+                    result.getVersion(),
+                    request.getPom());
         }
 
         return result;
     }
 
-    private PluginVersionResult resolveFromRepository( PluginVersionRequest request )
-        throws PluginVersionResolutionException
-    {
-        RequestTrace trace = RequestTrace.newChild( null, request );
+    private PluginVersionResult resolveFromRepository(PluginVersionRequest request)
+            throws PluginVersionResolutionException {
+        RequestTrace trace = RequestTrace.newChild(null, request);
 
         DefaultPluginVersionResult result = new DefaultPluginVersionResult();
 
-        org.eclipse.aether.metadata.Metadata metadata =
-            new DefaultMetadata( request.getGroupId(), request.getArtifactId(), "maven-metadata.xml",
-                                 DefaultMetadata.Nature.RELEASE_OR_SNAPSHOT );
+        org.eclipse.aether.metadata.Metadata metadata = new DefaultMetadata(
+                request.getGroupId(),
+                request.getArtifactId(),
+                "maven-metadata.xml",
+                DefaultMetadata.Nature.RELEASE_OR_SNAPSHOT);
 
         List<MetadataRequest> requests = new ArrayList<>();
 
-        requests.add( new MetadataRequest( metadata, null, REPOSITORY_CONTEXT ).setTrace( trace ) );
+        requests.add(new MetadataRequest(metadata, null, REPOSITORY_CONTEXT).setTrace(trace));
 
-        for ( RemoteRepository repository : request.getRepositories() )
-        {
-            requests.add( new MetadataRequest( metadata, repository, REPOSITORY_CONTEXT ).setTrace( trace ) );
+        for (RemoteRepository repository : request.getRepositories()) {
+            requests.add(new MetadataRequest(metadata, repository, REPOSITORY_CONTEXT).setTrace(trace));
         }
 
-        List<MetadataResult> results = repositorySystem.resolveMetadata( request.getRepositorySession(), requests );
+        List<MetadataResult> results = repositorySystem.resolveMetadata(request.getRepositorySession(), requests);
 
         Versions versions = new Versions();
 
-        for ( MetadataResult res : results )
-        {
+        for (MetadataResult res : results) {
             ArtifactRepository repository = res.getRequest().getRepository();
-            if ( repository == null )
-            {
+            if (repository == null) {
                 repository = request.getRepositorySession().getLocalRepository();
             }
 
-            mergeMetadata( request.getRepositorySession(), trace, versions, res.getMetadata(), repository );
+            mergeMetadata(request.getRepositorySession(), trace, versions, res.getMetadata(), repository);
         }
 
-        selectVersion( result, request, versions );
+        selectVersion(result, request, versions);
 
         return result;
     }
 
-    private void selectVersion( DefaultPluginVersionResult result, PluginVersionRequest request, Versions versions )
-        throws PluginVersionResolutionException
-    {
+    private void selectVersion(DefaultPluginVersionResult result, PluginVersionRequest request, Versions versions)
+            throws PluginVersionResolutionException {
         String version = null;
         ArtifactRepository repo = null;
 
-        if ( StringUtils.isNotEmpty( versions.releaseVersion ) )
-        {
+        if (versions.releaseVersion != null && !versions.releaseVersion.isEmpty()) {
             version = versions.releaseVersion;
             repo = versions.releaseRepository;
-        }
-        else if ( StringUtils.isNotEmpty( versions.latestVersion ) )
-        {
+        } else if (versions.latestVersion != null && !versions.latestVersion.isEmpty()) {
             version = versions.latestVersion;
             repo = versions.latestRepository;
         }
-        if ( version != null && !isCompatible( request, version ) )
-        {
-            versions.versions.remove( version );
+        if (version != null && !isCompatible(request, version)) {
+            versions.versions.remove(version);
             version = null;
         }
 
-        if ( version == null )
-        {
-            TreeSet<Version> releases = new TreeSet<>( Collections.reverseOrder() );
-            TreeSet<Version> snapshots = new TreeSet<>( Collections.reverseOrder() );
+        if (version == null) {
+            TreeSet<Version> releases = new TreeSet<>(Collections.reverseOrder());
+            TreeSet<Version> snapshots = new TreeSet<>(Collections.reverseOrder());
 
-            for ( String ver : versions.versions.keySet() )
-            {
-                try
-                {
-                    Version v = versionScheme.parseVersion( ver );
+            for (String ver : versions.versions.keySet()) {
+                try {
+                    Version v = versionScheme.parseVersion(ver);
 
-                    if ( ver.endsWith( "-SNAPSHOT" ) )
-                    {
-                        snapshots.add( v );
+                    if (ver.endsWith("-SNAPSHOT")) {
+                        snapshots.add(v);
+                    } else {
+                        releases.add(v);
                     }
-                    else
-                    {
-                        releases.add( v );
-                    }
-                }
-                catch ( InvalidVersionSpecificationException e )
-                {
+                } catch (InvalidVersionSpecificationException e) {
                     // ignore
                 }
             }
 
-            for ( Version v : releases )
-            {
+            for (Version v : releases) {
                 String ver = v.toString();
-                if ( isCompatible( request, ver ) )
-                {
+                if (isCompatible(request, ver)) {
                     version = ver;
-                    repo = versions.versions.get( version );
+                    repo = versions.versions.get(version);
                     break;
                 }
             }
 
-            if ( version == null )
-            {
-                for ( Version v : snapshots )
-                {
+            if (version == null) {
+                for (Version v : snapshots) {
                     String ver = v.toString();
-                    if ( isCompatible( request, ver ) )
-                    {
+                    if (isCompatible(request, ver)) {
                         version = ver;
-                        repo = versions.versions.get( version );
+                        repo = versions.versions.get(version);
                         break;
                     }
                 }
             }
         }
 
-        if ( version != null )
-        {
-            result.setVersion( version );
-            result.setRepository( repo );
-        }
-        else
-        {
-            throw new PluginVersionResolutionException( request.getGroupId(), request.getArtifactId(),
-                                                        request.getRepositorySession().getLocalRepository(),
-                                                        request.getRepositories(),
-                                                        "Plugin not found in any plugin repository" );
+        if (version != null) {
+            result.setVersion(version);
+            result.setRepository(repo);
+        } else {
+            throw new PluginVersionResolutionException(
+                    request.getGroupId(),
+                    request.getArtifactId(),
+                    request.getRepositorySession().getLocalRepository(),
+                    request.getRepositories(),
+                    "Plugin not found in any plugin repository");
         }
     }
 
-    private boolean isCompatible( PluginVersionRequest request, String version )
-    {
+    private boolean isCompatible(PluginVersionRequest request, String version) {
         Plugin plugin = new Plugin();
-        plugin.setGroupId( request.getGroupId() );
-        plugin.setArtifactId( request.getArtifactId() );
-        plugin.setVersion( version );
+        plugin.setGroupId(request.getGroupId());
+        plugin.setArtifactId(request.getArtifactId());
+        plugin.setVersion(version);
 
         PluginDescriptor pluginDescriptor;
 
-        try
-        {
-            pluginDescriptor =
-                pluginManager.getPluginDescriptor( plugin, request.getRepositories(), request.getRepositorySession() );
-        }
-        catch ( PluginResolutionException e )
-        {
-            logger.debug( "Ignoring unresolvable plugin version " + version, e );
+        try {
+            pluginDescriptor = pluginManager.getPluginDescriptor(
+                    plugin, request.getRepositories(), request.getRepositorySession());
+        } catch (PluginResolutionException e) {
+            logger.debug("Ignoring unresolvable plugin version {}", version, e);
             return false;
-        }
-        catch ( Exception e )
-        {
+        } catch (Exception e) {
             // ignore for now and delay failure to higher level processing
             return true;
         }
 
-        try
-        {
-            pluginManager.checkRequiredMavenVersion( pluginDescriptor );
-        }
-        catch ( Exception e )
-        {
-            logger.debug( "Ignoring incompatible plugin version " + version + ": " + e.getMessage() );
+        try {
+            pluginManager.checkPrerequisites(pluginDescriptor);
+        } catch (Exception e) {
+            logger.warn("Ignoring incompatible plugin version {}", version, e);
             return false;
         }
 
         return true;
     }
 
-    private void mergeMetadata( RepositorySystemSession session, RequestTrace trace, Versions versions,
-                                org.eclipse.aether.metadata.Metadata metadata, ArtifactRepository repository )
-    {
-        if ( metadata != null && metadata.getFile() != null && metadata.getFile().isFile() )
-        {
-            try
-            {
-                Map<String, ?> options = Collections.singletonMap( MetadataReader.IS_STRICT, Boolean.FALSE );
+    private void mergeMetadata(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            Versions versions,
+            org.eclipse.aether.metadata.Metadata metadata,
+            ArtifactRepository repository) {
+        if (metadata != null && metadata.getFile() != null && metadata.getFile().isFile()) {
+            try {
+                Map<String, ?> options = Collections.singletonMap(MetadataReader.IS_STRICT, Boolean.FALSE);
 
-                Metadata repoMetadata = metadataReader.read( metadata.getFile(), options );
+                Metadata repoMetadata = metadataReader.read(metadata.getFile(), options);
 
-                mergeMetadata( versions, repoMetadata, repository );
-            }
-            catch ( IOException e )
-            {
-                invalidMetadata( session, trace, metadata, repository, e );
+                mergeMetadata(versions, repoMetadata, repository);
+            } catch (IOException e) {
+                invalidMetadata(session, trace, metadata, repository, e);
             }
         }
     }
 
-    private void invalidMetadata( RepositorySystemSession session, RequestTrace trace,
-                                  org.eclipse.aether.metadata.Metadata metadata, ArtifactRepository repository,
-                                  Exception exception )
-    {
+    private void invalidMetadata(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            org.eclipse.aether.metadata.Metadata metadata,
+            ArtifactRepository repository,
+            Exception exception) {
         RepositoryListener listener = session.getRepositoryListener();
-        if ( listener != null )
-        {
-            RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID );
-            event.setTrace( trace );
-            event.setMetadata( metadata );
-            event.setException( exception );
-            event.setRepository( repository );
-            listener.metadataInvalid( event.build() );
+        if (listener != null) {
+            RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INVALID);
+            event.setTrace(trace);
+            event.setMetadata(metadata);
+            event.setException(exception);
+            event.setRepository(repository);
+            listener.metadataInvalid(event.build());
         }
     }
 
-    private void mergeMetadata( Versions versions, Metadata source, ArtifactRepository repository )
-    {
+    private void mergeMetadata(Versions versions, Metadata source, ArtifactRepository repository) {
         Versioning versioning = source.getVersioning();
-        if ( versioning != null )
-        {
-            String timestamp = StringUtils.clean( versioning.getLastUpdated() );
+        if (versioning != null) {
+            String timestamp = versioning.getLastUpdated() == null
+                    ? ""
+                    : versioning.getLastUpdated().trim();
 
-            if ( StringUtils.isNotEmpty( versioning.getRelease() )
-                && timestamp.compareTo( versions.releaseTimestamp ) > 0 )
-            {
+            if (versioning.getRelease() != null
+                    && !versioning.getRelease().isEmpty()
+                    && timestamp.compareTo(versions.releaseTimestamp) > 0) {
                 versions.releaseVersion = versioning.getRelease();
                 versions.releaseTimestamp = timestamp;
                 versions.releaseRepository = repository;
             }
 
-            if ( StringUtils.isNotEmpty( versioning.getLatest() )
-                && timestamp.compareTo( versions.latestTimestamp ) > 0 )
-            {
+            if (versioning.getLatest() != null
+                    && !versioning.getLatest().isEmpty()
+                    && timestamp.compareTo(versions.latestTimestamp) > 0) {
                 versions.latestVersion = versioning.getLatest();
                 versions.latestTimestamp = timestamp;
                 versions.latestRepository = repository;
             }
 
-            for ( String version : versioning.getVersions() )
-            {
-                if ( !versions.versions.containsKey( version ) )
-                {
-                    versions.versions.put( version, repository );
+            for (String version : versioning.getVersions()) {
+                if (!versions.versions.containsKey(version)) {
+                    versions.versions.put(version, repository);
                 }
             }
         }
     }
 
-    private PluginVersionResult resolveFromProject( PluginVersionRequest request )
-    {
+    private PluginVersionResult resolveFromProject(PluginVersionRequest request) {
         PluginVersionResult result = null;
 
-        if ( request.getPom() != null && request.getPom().getBuild() != null )
-        {
+        if (request.getPom() != null && request.getPom().getBuild() != null) {
             Build build = request.getPom().getBuild();
 
-            result = resolveFromProject( request, build.getPlugins() );
+            result = resolveFromProject(request, build.getPlugins());
 
-            if ( result == null && build.getPluginManagement() != null )
-            {
-                result = resolveFromProject( request, build.getPluginManagement().getPlugins() );
+            if (result == null && build.getPluginManagement() != null) {
+                result = resolveFromProject(request, build.getPluginManagement().getPlugins());
             }
         }
 
         return result;
     }
 
-    private PluginVersionResult resolveFromProject( PluginVersionRequest request, List<Plugin> plugins )
-    {
-        for ( Plugin plugin : plugins )
-        {
-            if ( request.getGroupId().equals( plugin.getGroupId() )
-                && request.getArtifactId().equals( plugin.getArtifactId() ) )
-            {
-                if ( plugin.getVersion() != null )
-                {
-                    return new DefaultPluginVersionResult( plugin.getVersion() );
-                }
-                else
-                {
+    private PluginVersionResult resolveFromProject(PluginVersionRequest request, List<Plugin> plugins) {
+        for (Plugin plugin : plugins) {
+            if (request.getGroupId().equals(plugin.getGroupId())
+                    && request.getArtifactId().equals(plugin.getArtifactId())) {
+                if (plugin.getVersion() != null) {
+                    return new DefaultPluginVersionResult(plugin.getVersion());
+                } else {
                     return null;
                 }
             }
@@ -412,69 +366,51 @@
         return null;
     }
 
-    @SuppressWarnings( "unchecked" )
-    private ConcurrentMap<Key, PluginVersionResult> getCache( SessionData data )
-    {
-        ConcurrentMap<Key, PluginVersionResult> cache =
-                ( ConcurrentMap<Key, PluginVersionResult> ) data.get( CACHE_KEY );
-        while ( cache == null )
-        {
-            cache = new ConcurrentHashMap<>( 256 );
-            if ( data.set( CACHE_KEY, null, cache ) )
-            {
-                break;
-            }
-            cache = ( ConcurrentMap<Key, PluginVersionResult> ) data.get( CACHE_KEY );
-        }
-        return cache;
+    @SuppressWarnings("unchecked")
+    private ConcurrentMap<Key, PluginVersionResult> getCache(PluginVersionRequest request) {
+        SessionData data = request.getRepositorySession().getData();
+        return (ConcurrentMap<Key, PluginVersionResult>)
+                data.computeIfAbsent(CACHE_KEY, () -> new ConcurrentHashMap<>(256));
     }
 
-    private static Key getKey( PluginVersionRequest request )
-    {
-        return new Key( request.getGroupId(), request.getArtifactId(), request.getRepositories() );
+    private static Key getKey(PluginVersionRequest request) {
+        return new Key(request.getGroupId(), request.getArtifactId(), request.getRepositories());
     }
 
-    static class Key
-    {
+    static class Key {
         final String groupId;
         final String artifactId;
         final List<RemoteRepository> repositories;
         final int hash;
 
-        Key( String groupId, String artifactId, List<RemoteRepository> repositories )
-        {
+        Key(String groupId, String artifactId, List<RemoteRepository> repositories) {
             this.groupId = groupId;
             this.artifactId = artifactId;
             this.repositories = repositories;
-            this.hash = Objects.hash( groupId, artifactId, repositories );
+            this.hash = Objects.hash(groupId, artifactId, repositories);
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( this == o )
-            {
+        public boolean equals(Object o) {
+            if (this == o) {
                 return true;
             }
-            if ( o == null || getClass() != o.getClass() )
-            {
+            if (o == null || getClass() != o.getClass()) {
                 return false;
             }
-            Key key = ( Key ) o;
-            return groupId.equals( key.groupId )
-                    && artifactId.equals( key.artifactId )
-                    && repositories.equals( key.repositories );
+            Key key = (Key) o;
+            return groupId.equals(key.groupId)
+                    && artifactId.equals(key.artifactId)
+                    && repositories.equals(key.repositories);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hash;
         }
     }
 
-    static class Versions
-    {
+    static class Versions {
 
         String releaseVersion = "";
 
@@ -489,7 +425,5 @@
         ArtifactRepository latestRepository;
 
         Map<String, ArtifactRepository> versions = new LinkedHashMap<>();
-
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResult.java b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResult.java
index 020d6e7..f8bf0b1 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/version/internal/DefaultPluginVersionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.version.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.version.internal;
 
 import org.apache.maven.plugin.version.PluginVersionResult;
 import org.eclipse.aether.repository.ArtifactRepository;
@@ -26,44 +25,34 @@
  * Describes the result of a plugin version resolution request.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-class DefaultPluginVersionResult
-    implements PluginVersionResult
-{
+class DefaultPluginVersionResult implements PluginVersionResult {
 
     private String version;
 
     private ArtifactRepository repository;
 
-    DefaultPluginVersionResult()
-    {
+    DefaultPluginVersionResult() {
         // does nothing
     }
 
-    DefaultPluginVersionResult( String version )
-    {
+    DefaultPluginVersionResult(String version) {
         this.version = version;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
-    public void setVersion( String version )
-    {
+    public void setVersion(String version) {
         this.version = version;
     }
 
-    public ArtifactRepository getRepository()
-    {
+    public ArtifactRepository getRepository() {
         return repository;
     }
 
-    public void setRepository( ArtifactRepository repository )
-    {
+    public void setRepository(ArtifactRepository repository) {
         this.repository = repository;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/CycleDetectedException.java b/maven-core/src/main/java/org/apache/maven/project/CycleDetectedException.java
new file mode 100644
index 0000000..3340342
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/project/CycleDetectedException.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project;
+
+import java.util.List;
+
+public class CycleDetectedException extends Exception {
+    private final List<String> cycle;
+
+    public CycleDetectedException(String message, List<String> cycle) {
+        super(message);
+        this.cycle = cycle;
+    }
+
+    public List<String> getCycle() {
+        return cycle;
+    }
+
+    @Override
+    public String getMessage() {
+        return super.getMessage() + " " + String.join(" --> ", cycle);
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionRequest.java b/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionRequest.java
index cf5b0d7..40aca60 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.graph.DependencyFilter;
 
 /**
- * @author Benjamin Bentmann
  */
-public class DefaultDependencyResolutionRequest
-    implements DependencyResolutionRequest
-{
+public class DefaultDependencyResolutionRequest implements DependencyResolutionRequest {
 
     private MavenProject project;
 
@@ -35,48 +31,39 @@
 
     private RepositorySystemSession session;
 
-    public DefaultDependencyResolutionRequest()
-    {
+    public DefaultDependencyResolutionRequest() {
         // enables default constructor
     }
 
-    public DefaultDependencyResolutionRequest( MavenProject project, RepositorySystemSession session )
-    {
-        setMavenProject( project );
-        setRepositorySession( session );
+    public DefaultDependencyResolutionRequest(MavenProject project, RepositorySystemSession session) {
+        setMavenProject(project);
+        setRepositorySession(session);
     }
 
-    public DependencyFilter getResolutionFilter()
-    {
+    public DependencyFilter getResolutionFilter() {
         return filter;
     }
 
-    public MavenProject getMavenProject()
-    {
+    public MavenProject getMavenProject() {
         return project;
     }
 
-    public RepositorySystemSession getRepositorySession()
-    {
+    public RepositorySystemSession getRepositorySession() {
         return session;
     }
 
-    public DependencyResolutionRequest setResolutionFilter( DependencyFilter filter )
-    {
+    public DependencyResolutionRequest setResolutionFilter(DependencyFilter filter) {
         this.filter = filter;
         return this;
     }
 
-    public DependencyResolutionRequest setMavenProject( MavenProject project )
-    {
+    public DependencyResolutionRequest setMavenProject(MavenProject project) {
         this.project = project;
         return this;
     }
 
-    public DependencyResolutionRequest setRepositorySession( RepositorySystemSession repositorySession )
-    {
+    public DependencyResolutionRequest setRepositorySession(RepositorySystemSession repositorySession) {
         this.session = repositorySession;
         return this;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java b/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java
index 8e5a6ba..30d72e1 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultDependencyResolutionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -29,11 +28,8 @@
 import org.eclipse.aether.graph.DependencyNode;
 
 /**
- * @author Benjamin Bentmann
  */
-class DefaultDependencyResolutionResult
-    implements DependencyResolutionResult
-{
+class DefaultDependencyResolutionResult implements DependencyResolutionResult {
 
     private DependencyNode root;
 
@@ -47,68 +43,51 @@
 
     private Map<Dependency, List<Exception>> resolutionErrors = new IdentityHashMap<>();
 
-    public DependencyNode getDependencyGraph()
-    {
+    public DependencyNode getDependencyGraph() {
         return root;
     }
 
-    public void setDependencyGraph( DependencyNode root )
-    {
+    public void setDependencyGraph(DependencyNode root) {
         this.root = root;
     }
 
-    public List<Dependency> getDependencies()
-    {
+    public List<Dependency> getDependencies() {
         return dependencies;
     }
 
-    public List<Dependency> getResolvedDependencies()
-    {
+    public List<Dependency> getResolvedDependencies() {
         return resolvedDependencies;
     }
 
-    public void addResolvedDependency( Dependency dependency )
-    {
-        dependencies.add( dependency );
-        resolvedDependencies.add( dependency );
+    public void addResolvedDependency(Dependency dependency) {
+        dependencies.add(dependency);
+        resolvedDependencies.add(dependency);
     }
 
-    public List<Dependency> getUnresolvedDependencies()
-    {
+    public List<Dependency> getUnresolvedDependencies() {
         return unresolvedDependencies;
     }
 
-    public List<Exception> getCollectionErrors()
-    {
+    public List<Exception> getCollectionErrors() {
         return collectionErrors;
     }
 
-    public void setCollectionErrors( List<Exception> exceptions )
-    {
-        if ( exceptions != null )
-        {
+    public void setCollectionErrors(List<Exception> exceptions) {
+        if (exceptions != null) {
             this.collectionErrors = exceptions;
-        }
-        else
-        {
+        } else {
             this.collectionErrors = new ArrayList<>();
         }
     }
 
-    public List<Exception> getResolutionErrors( Dependency dependency )
-    {
-        List<Exception> errors = resolutionErrors.get( dependency );
-        return ( errors != null )
-                   ? Collections.unmodifiableList( errors )
-                   : Collections.emptyList();
-
+    public List<Exception> getResolutionErrors(Dependency dependency) {
+        List<Exception> errors = resolutionErrors.get(dependency);
+        return (errors != null) ? Collections.unmodifiableList(errors) : Collections.emptyList();
     }
 
-    public void setResolutionErrors( Dependency dependency, List<Exception> errors )
-    {
-        dependencies.add( dependency );
-        unresolvedDependencies.add( dependency );
-        resolutionErrors.put( dependency, errors );
+    public void setResolutionErrors(Dependency dependency, List<Exception> errors) {
+        dependencies.add(dependency);
+        unresolvedDependencies.add(dependency);
+        resolutionErrors.put(dependency, errors);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultMavenProjectHelper.java b/maven-core/src/main/java/org/apache/maven/project/DefaultMavenProjectHelper.java
index e2c3b5c..b5ee23b 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultMavenProjectHelper.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultMavenProjectHelper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.util.List;
+package org.apache.maven.project;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+import java.util.List;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.handler.ArtifactHandler;
 import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
@@ -36,68 +35,58 @@
 /**
  * DefaultMavenProjectHelper
  */
-@SuppressWarnings( "deprecation" )
+@SuppressWarnings("deprecation")
 @Named
 @Singleton
-public class DefaultMavenProjectHelper
-    extends AbstractLogEnabled
-    implements MavenProjectHelper
-{
+public class DefaultMavenProjectHelper extends AbstractLogEnabled implements MavenProjectHelper {
     private final ArtifactHandlerManager artifactHandlerManager;
 
     @Inject
-    public DefaultMavenProjectHelper( ArtifactHandlerManager artifactHandlerManager )
-    {
+    public DefaultMavenProjectHelper(ArtifactHandlerManager artifactHandlerManager) {
         this.artifactHandlerManager = artifactHandlerManager;
     }
 
-    public void attachArtifact( MavenProject project, String artifactType, String artifactClassifier,
-                                File artifactFile )
-    {
+    public void attachArtifact(
+            MavenProject project, String artifactType, String artifactClassifier, File artifactFile) {
         ArtifactHandler handler = null;
 
-        if ( artifactType != null )
-        {
-            handler = artifactHandlerManager.getArtifactHandler( artifactType );
+        if (artifactType != null) {
+            handler = artifactHandlerManager.getArtifactHandler(artifactType);
         }
 
-        if ( handler == null )
-        {
-            handler = artifactHandlerManager.getArtifactHandler( "jar" );
+        if (handler == null) {
+            handler = artifactHandlerManager.getArtifactHandler("jar");
         }
 
-        Artifact artifact = new AttachedArtifact( project.getArtifact(), artifactType, artifactClassifier, handler );
+        Artifact artifact = new AttachedArtifact(project.getArtifact(), artifactType, artifactClassifier, handler);
 
-        artifact.setFile( artifactFile );
-        artifact.setResolved( true );
+        artifact.setFile(artifactFile);
+        artifact.setResolved(true);
 
-        attachArtifact( project, artifact );
+        attachArtifact(project, artifact);
     }
 
-    public void attachArtifact( MavenProject project, String artifactType, File artifactFile )
-    {
-        ArtifactHandler handler = artifactHandlerManager.getArtifactHandler( artifactType );
+    public void attachArtifact(MavenProject project, String artifactType, File artifactFile) {
+        ArtifactHandler handler = artifactHandlerManager.getArtifactHandler(artifactType);
 
-        Artifact artifact = new AttachedArtifact( project.getArtifact(), artifactType, handler );
+        Artifact artifact = new AttachedArtifact(project.getArtifact(), artifactType, handler);
 
-        artifact.setFile( artifactFile );
-        artifact.setResolved( true );
+        artifact.setFile(artifactFile);
+        artifact.setResolved(true);
 
-        attachArtifact( project, artifact );
+        attachArtifact(project, artifact);
     }
 
-    public void attachArtifact( MavenProject project, File artifactFile, String artifactClassifier )
-    {
+    public void attachArtifact(MavenProject project, File artifactFile, String artifactClassifier) {
         Artifact projectArtifact = project.getArtifact();
 
-        Artifact artifact =
-            new AttachedArtifact( projectArtifact, projectArtifact.getType(), artifactClassifier,
-                                  projectArtifact.getArtifactHandler() );
+        Artifact artifact = new AttachedArtifact(
+                projectArtifact, projectArtifact.getType(), artifactClassifier, projectArtifact.getArtifactHandler());
 
-        artifact.setFile( artifactFile );
-        artifact.setResolved( true );
+        artifact.setFile(artifactFile);
+        artifact.setResolved(true);
 
-        attachArtifact( project, artifact );
+        attachArtifact(project, artifact);
     }
 
     /**
@@ -107,31 +96,27 @@
      * @param project project reference.
      * @param artifact artifact to add or replace.
      */
-    public void attachArtifact( MavenProject project, Artifact artifact )
-    {
-        project.addAttachedArtifact( artifact );
+    public void attachArtifact(MavenProject project, Artifact artifact) {
+        project.addAttachedArtifact(artifact);
     }
 
-    public void addResource( MavenProject project, String resourceDirectory, List<String> includes,
-                             List<String> excludes )
-    {
+    public void addResource(
+            MavenProject project, String resourceDirectory, List<String> includes, List<String> excludes) {
         Resource resource = new Resource();
-        resource.setDirectory( resourceDirectory );
-        resource.setIncludes( includes );
-        resource.setExcludes( excludes );
+        resource.setDirectory(resourceDirectory);
+        resource.setIncludes(includes);
+        resource.setExcludes(excludes);
 
-        project.addResource( resource );
+        project.addResource(resource);
     }
 
-    public void addTestResource( MavenProject project, String resourceDirectory, List<String> includes,
-                                 List<String> excludes )
-    {
+    public void addTestResource(
+            MavenProject project, String resourceDirectory, List<String> includes, List<String> excludes) {
         Resource resource = new Resource();
-        resource.setDirectory( resourceDirectory );
-        resource.setIncludes( includes );
-        resource.setExcludes( excludes );
+        resource.setDirectory(resourceDirectory);
+        resource.setIncludes(includes);
+        resource.setExcludes(excludes);
 
-        project.addTestResource( resource );
+        project.addTestResource(resource);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java b/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java
index ca60794..2b2f2ff 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultModelBuildingListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.List;
 import java.util.Objects;
@@ -36,13 +35,10 @@
 /**
  * Processes events from the model builder while building the effective model for a {@link MavenProject} instance.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultModelBuildingListener
-    extends AbstractModelBuildingListener
-{
+public class DefaultModelBuildingListener extends AbstractModelBuildingListener {
 
-    private MavenProject project;
+    private final MavenProject project;
 
     private ProjectBuildingHelper projectBuildingHelper;
 
@@ -52,14 +48,15 @@
 
     private List<ArtifactRepository> pluginRepositories;
 
-    public DefaultModelBuildingListener( MavenProject project, ProjectBuildingHelper projectBuildingHelper,
-                                         ProjectBuildingRequest projectBuildingRequest )
-    {
-        this.project = Objects.requireNonNull( project, "project cannot be null" );
+    public DefaultModelBuildingListener(
+            MavenProject project,
+            ProjectBuildingHelper projectBuildingHelper,
+            ProjectBuildingRequest projectBuildingRequest) {
+        this.project = Objects.requireNonNull(project, "project cannot be null");
         this.projectBuildingHelper =
-            Objects.requireNonNull( projectBuildingHelper, "projectBuildingHelper cannot be null" );
+                Objects.requireNonNull(projectBuildingHelper, "projectBuildingHelper cannot be null");
         this.projectBuildingRequest =
-            Objects.requireNonNull( projectBuildingRequest, "projectBuildingRequest cannot be null" );
+                Objects.requireNonNull(projectBuildingRequest, "projectBuildingRequest cannot be null");
         this.remoteRepositories = projectBuildingRequest.getRemoteRepositories();
         this.pluginRepositories = projectBuildingRequest.getPluginArtifactRepositories();
     }
@@ -69,64 +66,52 @@
      *
      * @return The project, never {@code null}.
      */
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
     @Override
-    public void buildExtensionsAssembled( ModelBuildingEvent event )
-    {
+    public void buildExtensionsAssembled(ModelBuildingEvent event) {
         Model model = event.getModel();
 
-        try
-        {
-            pluginRepositories =
-                projectBuildingHelper.createArtifactRepositories( model.getPluginRepositories(), pluginRepositories,
-                                                                  projectBuildingRequest );
+        try {
+            pluginRepositories = projectBuildingHelper.createArtifactRepositories(
+                    model.getPluginRepositories(), pluginRepositories, projectBuildingRequest);
+        } catch (Exception e) {
+            event.getProblems()
+                    .add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                            .setMessage("Invalid plugin repository: " + e.getMessage())
+                            .setException(e));
         }
-        catch ( Exception e )
-        {
-            event.getProblems().add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "Invalid plugin repository: " + e.getMessage() )
-                    .setException( e ) );
-        }
-        project.setPluginArtifactRepositories( pluginRepositories );
+        project.setPluginArtifactRepositories(pluginRepositories);
 
-        if ( event.getRequest().isProcessPlugins() )
-        {
-            try
-            {
+        if (event.getRequest().isProcessPlugins()) {
+            try {
                 ProjectRealmCache.CacheRecord record =
-                    projectBuildingHelper.createProjectRealm( project, model, projectBuildingRequest );
+                        projectBuildingHelper.createProjectRealm(project, model, projectBuildingRequest);
 
-                project.setClassRealm( record.getRealm() );
-                project.setExtensionDependencyFilter( record.getExtensionArtifactFilter() );
-            }
-            catch ( PluginResolutionException | PluginManagerException | PluginVersionResolutionException e )
-            {
-                event.getProblems().add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( "Unresolvable build extension: " + e.getMessage() )
-                        .setException( e ) );
+                project.setClassRealm(record.getRealm());
+                project.setExtensionDependencyFilter(record.getExtensionArtifactFilter());
+            } catch (PluginResolutionException | PluginManagerException | PluginVersionResolutionException e) {
+                event.getProblems()
+                        .add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                                .setMessage("Unresolvable build extension: " + e.getMessage())
+                                .setException(e));
             }
 
-            projectBuildingHelper.selectProjectRealm( project );
+            projectBuildingHelper.selectProjectRealm(project);
         }
 
         // build the regular repos after extensions are loaded to allow for custom layouts
-        try
-        {
-            remoteRepositories =
-                projectBuildingHelper.createArtifactRepositories( model.getRepositories(), remoteRepositories,
-                                                                  projectBuildingRequest );
+        try {
+            remoteRepositories = projectBuildingHelper.createArtifactRepositories(
+                    model.getRepositories(), remoteRepositories, projectBuildingRequest);
+        } catch (Exception e) {
+            event.getProblems()
+                    .add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                            .setMessage("Invalid artifact repository: " + e.getMessage())
+                            .setException(e));
         }
-        catch ( Exception e )
-        {
-            event.getProblems().add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "Invalid artifact repository: " + e.getMessage() )
-                    .setException( e ) );
-        }
-        project.setRemoteArtifactRepositories( remoteRepositories );
+        project.setRemoteArtifactRepositories(remoteRepositories);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
index f364d4c..be9e14c 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,34 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.io.IOException;
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
+package org.apache.maven.project;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinTask;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.apache.maven.ProjectCycleException;
 import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.feature.Features;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.InvalidArtifactRTException;
 import org.apache.maven.artifact.InvalidRepositoryException;
 import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.LegacyLocalRepositoryManager;
 import org.apache.maven.bridge.MavenRepositorySystem;
-import org.apache.maven.feature.Features;
+import org.apache.maven.internal.impl.InternalSession;
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.DependencyManagement;
@@ -56,7 +50,7 @@
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.ReportPlugin;
 import org.apache.maven.model.building.ArtifactModelSource;
-import org.apache.maven.model.building.TransformerContextBuilder;
+import org.apache.maven.model.building.DefaultModelBuilder;
 import org.apache.maven.model.building.DefaultModelBuildingRequest;
 import org.apache.maven.model.building.DefaultModelProblem;
 import org.apache.maven.model.building.FileModelSource;
@@ -69,11 +63,12 @@
 import org.apache.maven.model.building.ModelSource;
 import org.apache.maven.model.building.StringModelSource;
 import org.apache.maven.model.building.TransformerContext;
+import org.apache.maven.model.building.TransformerContextBuilder;
 import org.apache.maven.model.resolution.ModelResolver;
+import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.repository.internal.ArtifactDescriptorUtils;
 import org.apache.maven.repository.internal.ModelCacheFactory;
-import org.codehaus.plexus.util.Os;
-import org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.utils.Os;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.RequestTrace;
@@ -91,10 +86,11 @@
  */
 @Named
 @Singleton
-public class DefaultProjectBuilder
-    implements ProjectBuilder
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class DefaultProjectBuilder implements ProjectBuilder {
+    public static final String BUILDER_PARALLELISM = "maven.projectBuilder.parallelism";
+    public static final int DEFAULT_BUILDER_PARALLELISM = 4;
+
+    private final Logger logger = LoggerFactory.getLogger(getClass());
     private final ModelBuilder modelBuilder;
     private final ModelProcessor modelProcessor;
     private final ProjectBuildingHelper projectBuildingHelper;
@@ -104,6 +100,9 @@
     private final ProjectDependenciesResolver dependencyResolver;
     private final ModelCacheFactory modelCacheFactory;
 
+    private final RootLocator rootLocator;
+
+    @SuppressWarnings("checkstyle:ParameterNumber")
     @Inject
     public DefaultProjectBuilder(
             ModelBuilder modelBuilder,
@@ -113,8 +112,8 @@
             RepositorySystem repoSystem,
             RemoteRepositoryManager repositoryManager,
             ProjectDependenciesResolver dependencyResolver,
-            ModelCacheFactory modelCacheFactory )
-    {
+            ModelCacheFactory modelCacheFactory,
+            RootLocator rootLocator) {
         this.modelBuilder = modelBuilder;
         this.modelProcessor = modelProcessor;
         this.projectBuildingHelper = projectBuildingHelper;
@@ -123,463 +122,50 @@
         this.repositoryManager = repositoryManager;
         this.dependencyResolver = dependencyResolver;
         this.modelCacheFactory = modelCacheFactory;
+        this.rootLocator = rootLocator;
     }
-// ----------------------------------------------------------------------
+    // ----------------------------------------------------------------------
     // MavenProjectBuilder Implementation
     // ----------------------------------------------------------------------
 
     @Override
-    public ProjectBuildingResult build( File pomFile, ProjectBuildingRequest request )
-        throws ProjectBuildingException
-    {
-        return build( pomFile, new FileModelSource( pomFile ),
-                new InternalConfig( request, null, null ) );
+    public ProjectBuildingResult build(File pomFile, ProjectBuildingRequest request) throws ProjectBuildingException {
+        try (BuildSession bs = new BuildSession(request, false)) {
+            return bs.build(pomFile, new FileModelSource(pomFile));
+        }
     }
 
     @Override
-    public ProjectBuildingResult build( ModelSource modelSource, ProjectBuildingRequest request )
-        throws ProjectBuildingException
-    {
-        return build( null, modelSource,
-                 new InternalConfig( request, null, null ) );
-    }
-
-    private ProjectBuildingResult build( File pomFile, ModelSource modelSource, InternalConfig config )
-        throws ProjectBuildingException
-    {
-        ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
-
-        try
-        {
-            ProjectBuildingRequest projectBuildingRequest = config.request;
-
-            MavenProject project = projectBuildingRequest.getProject();
-
-            List<ModelProblem> modelProblems = null;
-            Throwable error = null;
-
-            if ( project == null )
-            {
-                ModelBuildingRequest request = getModelBuildingRequest( config );
-
-                project = new MavenProject();
-                project.setFile( pomFile );
-
-                DefaultModelBuildingListener listener =
-                    new DefaultModelBuildingListener( project, projectBuildingHelper, projectBuildingRequest );
-                request.setModelBuildingListener( listener );
-
-                request.setPomFile( pomFile );
-                request.setModelSource( modelSource );
-                request.setLocationTracking( true );
-
-                ModelBuildingResult result;
-                try
-                {
-                    result = modelBuilder.build( request );
-                }
-                catch ( ModelBuildingException e )
-                {
-                    result = e.getResult();
-                    if ( result == null || result.getEffectiveModel() == null )
-                    {
-                        throw new ProjectBuildingException( e.getModelId(), e.getMessage(), pomFile, e );
-                    }
-                    // validation error, continue project building and delay failing to help IDEs
-                    error = e;
-                }
-
-                modelProblems = result.getProblems();
-
-                initProject( project, Collections.emptyMap(), true,
-                             result, new HashMap<>(), projectBuildingRequest );
-            }
-            else if ( projectBuildingRequest.isResolveDependencies() )
-            {
-                projectBuildingHelper.selectProjectRealm( project );
-            }
-
-            DependencyResolutionResult resolutionResult = null;
-
-            if ( projectBuildingRequest.isResolveDependencies() )
-            {
-                resolutionResult = resolveDependencies( project, config.session );
-            }
-
-            ProjectBuildingResult result = new DefaultProjectBuildingResult( project, modelProblems, resolutionResult );
-
-            if ( error != null )
-            {
-                ProjectBuildingException e = new ProjectBuildingException( Arrays.asList( result ) );
-                e.initCause( error );
-                throw e;
-            }
-
-            return result;
+    public ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request)
+            throws ProjectBuildingException {
+        try (BuildSession bs = new BuildSession(request, false)) {
+            return bs.build(null, modelSource);
         }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( oldContextClassLoader );
-        }
-    }
-
-    private DependencyResolutionResult resolveDependencies( MavenProject project, RepositorySystemSession session )
-    {
-        DependencyResolutionResult resolutionResult;
-
-        try
-        {
-            DefaultDependencyResolutionRequest resolution = new DefaultDependencyResolutionRequest( project, session );
-            resolutionResult = dependencyResolver.resolve( resolution );
-        }
-        catch ( DependencyResolutionException e )
-        {
-            resolutionResult = e.getResult();
-        }
-
-        Set<Artifact> artifacts = new LinkedHashSet<>();
-        if ( resolutionResult.getDependencyGraph() != null )
-        {
-            RepositoryUtils.toArtifacts( artifacts, resolutionResult.getDependencyGraph().getChildren(),
-                                         Collections.singletonList( project.getArtifact().getId() ), null );
-
-            // Maven 2.x quirk: an artifact always points at the local repo, regardless whether resolved or not
-            LocalRepositoryManager lrm = session.getLocalRepositoryManager();
-            for ( Artifact artifact : artifacts )
-            {
-                if ( !artifact.isResolved() )
-                {
-                    String path = lrm.getPathForLocalArtifact( RepositoryUtils.toArtifact( artifact ) );
-                    artifact.setFile( new File( lrm.getRepository().getBasedir(), path ) );
-                }
-            }
-        }
-        project.setResolvedArtifacts( artifacts );
-        project.setArtifacts( artifacts );
-
-        return resolutionResult;
-    }
-
-    private List<String> getProfileIds( List<Profile> profiles )
-    {
-        return profiles.stream().map( Profile::getId ).collect( Collectors.toList() );
-    }
-
-    private ModelBuildingRequest getModelBuildingRequest( InternalConfig config )
-    {
-        ProjectBuildingRequest configuration = config.request;
-
-        ModelBuildingRequest request = new DefaultModelBuildingRequest();
-
-        RequestTrace trace = RequestTrace.newChild( null, configuration ).newChild( request );
-
-        ModelResolver resolver =
-            new ProjectModelResolver( config.session, trace, repoSystem, repositoryManager, config.repositories,
-                                      configuration.getRepositoryMerging(), config.modelPool );
-
-        request.setValidationLevel( configuration.getValidationLevel() );
-        request.setProcessPlugins( configuration.isProcessPlugins() );
-        request.setProfiles( configuration.getProfiles() );
-        request.setActiveProfileIds( configuration.getActiveProfileIds() );
-        request.setInactiveProfileIds( configuration.getInactiveProfileIds() );
-        request.setSystemProperties( configuration.getSystemProperties() );
-        request.setUserProperties( configuration.getUserProperties() );
-        request.setBuildStartTime( configuration.getBuildStartTime() );
-        request.setModelResolver( resolver );
-        // this is a hint that we want to build 1 file, so don't cache. See MNG-7063
-        if ( config.modelPool != null )
-        {
-            request.setModelCache( modelCacheFactory.createCache( config.session ) );
-        }
-        request.setTransformerContextBuilder( config.transformerContextBuilder );
-
-        return request;
     }
 
     @Override
-    public ProjectBuildingResult build( Artifact artifact, ProjectBuildingRequest request )
-        throws ProjectBuildingException
-    {
-        return build( artifact, false, request );
+    public ProjectBuildingResult build(Artifact artifact, ProjectBuildingRequest request)
+            throws ProjectBuildingException {
+        return build(artifact, false, request);
     }
 
     @Override
-    public ProjectBuildingResult build( Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request )
-        throws ProjectBuildingException
-    {
-        org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact( artifact );
-        pomArtifact = ArtifactDescriptorUtils.toPomArtifact( pomArtifact );
-
-        InternalConfig config =
-            new InternalConfig( request, null, null );
-
-        boolean localProject;
-
-        try
-        {
-            ArtifactRequest pomRequest = new ArtifactRequest();
-            pomRequest.setArtifact( pomArtifact );
-            pomRequest.setRepositories( config.repositories );
-            ArtifactResult pomResult = repoSystem.resolveArtifact( config.session, pomRequest );
-
-            pomArtifact = pomResult.getArtifact();
-            localProject = pomResult.getRepository() instanceof WorkspaceRepository;
+    public ProjectBuildingResult build(Artifact artifact, boolean allowStubModel, ProjectBuildingRequest request)
+            throws ProjectBuildingException {
+        try (BuildSession bs = new BuildSession(request, false)) {
+            return bs.build(artifact, allowStubModel);
         }
-        catch ( org.eclipse.aether.resolution.ArtifactResolutionException e )
-        {
-            if ( e.getResults().get( 0 ).isMissing() && allowStubModel )
-            {
-                return build( null, createStubModelSource( artifact ), config );
-            }
-            throw new ProjectBuildingException( artifact.getId(),
-                                                "Error resolving project artifact: " + e.getMessage(), e );
-        }
-
-        File pomFile = pomArtifact.getFile();
-
-        if ( "pom".equals( artifact.getType() ) )
-        {
-            artifact.selectVersion( pomArtifact.getVersion() );
-            artifact.setFile( pomFile );
-            artifact.setResolved( true );
-        }
-
-        if ( localProject )
-        {
-            return build( pomFile, new FileModelSource( pomFile ), config );
-        }
-        else
-        {
-            return build( null, new ArtifactModelSource( pomFile, artifact.getGroupId(), artifact.getArtifactId(),
-                                                         artifact.getVersion() ),
-                          config );
-        }
-    }
-
-    private ModelSource createStubModelSource( Artifact artifact )
-    {
-        StringBuilder buffer = new StringBuilder( 1024 );
-
-        buffer.append( "<?xml version='1.0'?>" );
-        buffer.append( "<project>" );
-        buffer.append( "<modelVersion>4.0.0</modelVersion>" );
-        buffer.append( "<groupId>" ).append( artifact.getGroupId() ).append( "</groupId>" );
-        buffer.append( "<artifactId>" ).append( artifact.getArtifactId() ).append( "</artifactId>" );
-        buffer.append( "<version>" ).append( artifact.getBaseVersion() ).append( "</version>" );
-        buffer.append( "<packaging>" ).append( artifact.getType() ).append( "</packaging>" );
-        buffer.append( "</project>" );
-
-        return new StringModelSource( buffer, artifact.getId() );
     }
 
     @Override
-    public List<ProjectBuildingResult> build( List<File> pomFiles, boolean recursive, ProjectBuildingRequest request )
-        throws ProjectBuildingException
-    {
-        List<ProjectBuildingResult> results = new ArrayList<>();
-
-        List<InterimResult> interimResults = new ArrayList<>();
-
-        ReactorModelPool.Builder poolBuilder = new ReactorModelPool.Builder();
-        final ReactorModelPool modelPool = poolBuilder.build();
-
-        InternalConfig config =
-            new InternalConfig( request, modelPool, modelBuilder.newTransformerContextBuilder() );
-
-        Map<File, MavenProject> projectIndex = new HashMap<>( 256 );
-
-        // phase 1: get file Models from the reactor.
-        boolean noErrors =
-            build( results, interimResults, projectIndex, pomFiles, new LinkedHashSet<>(), true, recursive,
-                   config, poolBuilder );
-
-        ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
-
-        try
-        {
-            // Phase 2: get effective models from the reactor
-            noErrors =
-                build( results, new ArrayList<>(), projectIndex, interimResults, request,
-                        new HashMap<>(), config.session ) && noErrors;
+    public List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive, ProjectBuildingRequest request)
+            throws ProjectBuildingException {
+        try (BuildSession bs = new BuildSession(request, true)) {
+            return bs.build(pomFiles, recursive);
         }
-        finally
-        {
-            Thread.currentThread().setContextClassLoader( oldContextClassLoader );
-        }
-
-        if ( Features.buildConsumer( request.getUserProperties() ).isActive() )
-        {
-            request.getRepositorySession().getData().set( TransformerContext.KEY,
-                                                          config.transformerContextBuilder.build() );
-        }
-
-        if ( !noErrors )
-        {
-            throw new ProjectBuildingException( results );
-        }
-
-        return results;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean build( List<ProjectBuildingResult> results, List<InterimResult> interimResults,
-                           Map<File, MavenProject> projectIndex, List<File> pomFiles, Set<File> aggregatorFiles,
-                           boolean root, boolean recursive, InternalConfig config,
-                           ReactorModelPool.Builder poolBuilder )
-    {
-        boolean noErrors = true;
-
-        for ( File pomFile : pomFiles )
-        {
-            aggregatorFiles.add( pomFile );
-
-            if ( !build( results, interimResults, projectIndex, pomFile, aggregatorFiles, root, recursive, config,
-                         poolBuilder ) )
-            {
-                noErrors = false;
-            }
-
-            aggregatorFiles.remove( pomFile );
-        }
-
-        return noErrors;
-    }
-
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean build( List<ProjectBuildingResult> results, List<InterimResult> interimResults,
-                           Map<File, MavenProject> projectIndex, File pomFile, Set<File> aggregatorFiles,
-                           boolean isRoot, boolean recursive, InternalConfig config,
-                           ReactorModelPool.Builder poolBuilder )
-    {
-        boolean noErrors = true;
-
-        MavenProject project = new MavenProject();
-        project.setFile( pomFile );
-
-        ModelBuildingRequest request = getModelBuildingRequest( config )
-                        .setPomFile( pomFile )
-                        .setTwoPhaseBuilding( true )
-                        .setLocationTracking( true );
-
-        DefaultModelBuildingListener listener =
-            new DefaultModelBuildingListener( project, projectBuildingHelper, config.request );
-        request.setModelBuildingListener( listener );
-
-        ModelBuildingResult result;
-        try
-        {
-            result = modelBuilder.build( request );
-        }
-        catch ( ModelBuildingException e )
-        {
-            result = e.getResult();
-            if ( result == null || result.getFileModel() == null )
-            {
-                 results.add( new DefaultProjectBuildingResult( e.getModelId(), pomFile, e.getProblems() ) );
-
-                 return false;
-            }
-            // validation error, continue project building and delay failing to help IDEs
-            // result.getProblems().addAll(e.getProblems()) ?
-            noErrors = false;
-        }
-
-        Model model = result.getFileModel().clone();
-
-        poolBuilder.put( model.getPomFile().toPath(),  model );
-
-        InterimResult interimResult = new InterimResult( pomFile, request, result, listener, isRoot );
-        interimResults.add( interimResult );
-
-        if ( recursive )
-        {
-            File basedir = pomFile.getParentFile();
-            List<File> moduleFiles = new ArrayList<>();
-            for ( String module : model.getModules() )
-            {
-                if ( StringUtils.isEmpty( module ) )
-                {
-                    continue;
-                }
-
-                module = module.replace( '\\', File.separatorChar ).replace( '/', File.separatorChar );
-
-                File moduleFile = new File( basedir, module );
-
-                if ( moduleFile.isDirectory() )
-                {
-                    moduleFile = modelProcessor.locatePom( moduleFile );
-                }
-
-                if ( !moduleFile.isFile() )
-                {
-                    ModelProblem problem =
-                        new DefaultModelProblem( "Child module " + moduleFile + " of " + pomFile
-                            + " does not exist", ModelProblem.Severity.ERROR, ModelProblem.Version.BASE, model, -1,
-                                                 -1, null );
-                    result.getProblems().add( problem );
-
-                    noErrors = false;
-
-                    continue;
-                }
-
-                if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
-                {
-                    // we don't canonicalize on unix to avoid interfering with symlinks
-                    try
-                    {
-                        moduleFile = moduleFile.getCanonicalFile();
-                    }
-                    catch ( IOException e )
-                    {
-                        moduleFile = moduleFile.getAbsoluteFile();
-                    }
-                }
-                else
-                {
-                    moduleFile = new File( moduleFile.toURI().normalize() );
-                }
-
-                if ( aggregatorFiles.contains( moduleFile ) )
-                {
-                    StringBuilder buffer = new StringBuilder( 256 );
-                    for ( File aggregatorFile : aggregatorFiles )
-                    {
-                        buffer.append( aggregatorFile ).append( " -> " );
-                    }
-                    buffer.append( moduleFile );
-
-                    ModelProblem problem =
-                        new DefaultModelProblem( "Child module " + moduleFile + " of " + pomFile
-                            + " forms aggregation cycle " + buffer, ModelProblem.Severity.ERROR,
-                                                 ModelProblem.Version.BASE, model, -1, -1, null );
-                    result.getProblems().add( problem );
-
-                    noErrors = false;
-
-                    continue;
-                }
-
-                moduleFiles.add( moduleFile );
-            }
-
-            interimResult.modules = new ArrayList<>();
-
-            if ( !build( results, interimResult.modules, projectIndex, moduleFiles, aggregatorFiles, false,
-                         recursive, config, poolBuilder ) )
-            {
-                noErrors = false;
-            }
-        }
-
-        projectIndex.put( pomFile, project );
-
-        return noErrors;
-    }
-
-    static class InterimResult
-    {
+    static class InterimResult {
 
         File pomFile;
 
@@ -587,459 +173,807 @@
 
         ModelBuildingResult result;
 
-        DefaultModelBuildingListener listener;
+        MavenProject project;
 
         boolean root;
 
         List<InterimResult> modules = Collections.emptyList();
 
-        InterimResult( File pomFile, ModelBuildingRequest request, ModelBuildingResult result,
-                       DefaultModelBuildingListener listener, boolean root )
-        {
+        ProjectBuildingResult projectBuildingResult;
+
+        InterimResult(
+                File pomFile,
+                ModelBuildingRequest request,
+                ModelBuildingResult result,
+                MavenProject project,
+                boolean root) {
             this.pomFile = pomFile;
             this.request = request;
             this.result = result;
-            this.listener = listener;
+            this.project = project;
             this.root = root;
         }
 
+        InterimResult(ModelBuildingRequest request, ProjectBuildingResult projectBuildingResult) {
+            this.request = request;
+            this.projectBuildingResult = projectBuildingResult;
+            this.pomFile = projectBuildingResult.getPomFile();
+            this.project = projectBuildingResult.getProject();
+        }
     }
 
-    private boolean build( List<ProjectBuildingResult> results, List<MavenProject> projects,
-                           Map<File, MavenProject> projectIndex, List<InterimResult> interimResults,
-                           ProjectBuildingRequest request, Map<File, Boolean> profilesXmls,
-                           RepositorySystemSession session )
-    {
-        boolean noErrors = true;
+    class BuildSession implements AutoCloseable {
+        private final ProjectBuildingRequest request;
+        private final RepositorySystemSession session;
+        private final List<RemoteRepository> repositories;
+        private final ReactorModelPool modelPool;
+        private final TransformerContextBuilder transformerContextBuilder;
+        private final ForkJoinPool forkJoinPool;
 
-        for ( InterimResult interimResult : interimResults )
-        {
-            MavenProject project = interimResult.listener.getProject();
-            try
-            {
-                ModelBuildingResult result = modelBuilder.build( interimResult.request, interimResult.result );
+        BuildSession(ProjectBuildingRequest request, boolean localProjects) {
+            this.request = request;
+            this.session =
+                    RepositoryUtils.overlay(request.getLocalRepository(), request.getRepositorySession(), repoSystem);
+            this.repositories = RepositoryUtils.toRepos(request.getRemoteRepositories());
+            this.forkJoinPool = new ForkJoinPool(getParallelism(request));
+            if (localProjects) {
+                this.modelPool = new ReactorModelPool();
+                this.transformerContextBuilder = modelBuilder.newTransformerContextBuilder();
+            } else {
+                this.modelPool = null;
+                this.transformerContextBuilder = null;
+            }
+        }
+
+        @Override
+        public void close() {
+            this.forkJoinPool.shutdownNow();
+        }
+
+        private int getParallelism(ProjectBuildingRequest request) {
+            int parallelism = DEFAULT_BUILDER_PARALLELISM;
+            try {
+                String str = request.getUserProperties().getProperty(BUILDER_PARALLELISM);
+                if (str == null) {
+                    str = request.getSystemProperties().getProperty(BUILDER_PARALLELISM);
+                }
+                if (str != null) {
+                    parallelism = Integer.parseInt(str);
+                }
+            } catch (Exception e) {
+                // ignore
+            }
+            return Math.max(1, Math.min(parallelism, Runtime.getRuntime().availableProcessors()));
+        }
+
+        ProjectBuildingResult build(File pomFile, ModelSource modelSource) throws ProjectBuildingException {
+            ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
+
+            try {
+                MavenProject project = request.getProject();
+
+                List<ModelProblem> modelProblems = null;
+                Throwable error = null;
+
+                if (project == null) {
+                    ModelBuildingRequest request = getModelBuildingRequest();
+
+                    project = new MavenProject();
+                    project.setFile(pomFile);
+
+                    DefaultModelBuildingListener listener =
+                            new DefaultModelBuildingListener(project, projectBuildingHelper, this.request);
+                    request.setModelBuildingListener(listener);
+
+                    request.setPomFile(pomFile);
+                    request.setModelSource(modelSource);
+                    request.setLocationTracking(true);
+
+                    if (pomFile != null) {
+                        project.setRootDirectory(
+                                rootLocator.findRoot(pomFile.getParentFile().toPath()));
+                    }
+
+                    ModelBuildingResult result;
+                    try {
+                        result = modelBuilder.build(request);
+                    } catch (ModelBuildingException e) {
+                        result = e.getResult();
+                        if (result == null || result.getEffectiveModel() == null) {
+                            throw new ProjectBuildingException(e.getModelId(), e.getMessage(), pomFile, e);
+                        }
+                        // validation error, continue project building and delay failing to help IDEs
+                        error = e;
+                    }
+
+                    modelProblems = result.getProblems();
+
+                    initProject(project, Collections.emptyMap(), result);
+                } else if (request.isResolveDependencies()) {
+                    projectBuildingHelper.selectProjectRealm(project);
+                }
+
+                DependencyResolutionResult resolutionResult = null;
+
+                if (request.isResolveDependencies()) {
+                    resolutionResult = resolveDependencies(project);
+                }
+
+                ProjectBuildingResult result =
+                        new DefaultProjectBuildingResult(project, modelProblems, resolutionResult);
+
+                if (error != null) {
+                    ProjectBuildingException e = new ProjectBuildingException(Arrays.asList(result));
+                    e.initCause(error);
+                    throw e;
+                }
+
+                return result;
+            } finally {
+                Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+            }
+        }
+
+        ProjectBuildingResult build(Artifact artifact, boolean allowStubModel) throws ProjectBuildingException {
+            org.eclipse.aether.artifact.Artifact pomArtifact = RepositoryUtils.toArtifact(artifact);
+            pomArtifact = ArtifactDescriptorUtils.toPomArtifact(pomArtifact);
+
+            boolean localProject;
+
+            try {
+                ArtifactRequest pomRequest = new ArtifactRequest();
+                pomRequest.setArtifact(pomArtifact);
+                pomRequest.setRepositories(repositories);
+                ArtifactResult pomResult = repoSystem.resolveArtifact(session, pomRequest);
+
+                pomArtifact = pomResult.getArtifact();
+                localProject = pomResult.getRepository() instanceof WorkspaceRepository;
+            } catch (org.eclipse.aether.resolution.ArtifactResolutionException e) {
+                if (e.getResults().get(0).isMissing() && allowStubModel) {
+                    return build(null, createStubModelSource(artifact));
+                }
+                throw new ProjectBuildingException(
+                        artifact.getId(), "Error resolving project artifact: " + e.getMessage(), e);
+            }
+
+            File pomFile = pomArtifact.getFile();
+
+            if ("pom".equals(artifact.getType())) {
+                artifact.selectVersion(pomArtifact.getVersion());
+                artifact.setFile(pomFile);
+                artifact.setResolved(true);
+            }
+
+            if (localProject) {
+                return build(pomFile, new FileModelSource(pomFile));
+            } else {
+                return build(
+                        null,
+                        new ArtifactModelSource(
+                                pomFile, artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion()));
+            }
+        }
+
+        List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive) throws ProjectBuildingException {
+            ForkJoinTask<List<ProjectBuildingResult>> task = forkJoinPool.submit(() -> doBuild(pomFiles, recursive));
+
+            // ForkJoinTask.getException rewraps the exception in a weird way
+            // which cause an additional layer of exception, so try to unwrap it
+            task.quietlyJoin();
+            if (task.isCompletedAbnormally()) {
+                Throwable e = task.getException();
+                Throwable c = e.getCause();
+                uncheckedThrow(c != null && c.getClass() == e.getClass() ? c : e);
+            }
+
+            List<ProjectBuildingResult> results = task.getRawResult();
+            if (results.stream()
+                    .flatMap(r -> r.getProblems().stream())
+                    .anyMatch(p -> p.getSeverity() != ModelProblem.Severity.WARNING)) {
+                ModelProblem cycle = results.stream()
+                        .flatMap(r -> r.getProblems().stream())
+                        .filter(p -> p.getException() instanceof CycleDetectedException)
+                        .findAny()
+                        .orElse(null);
+                if (cycle != null) {
+                    throw new RuntimeException(new ProjectCycleException(
+                            "The projects in the reactor contain a cyclic reference: " + cycle.getMessage(),
+                            (CycleDetectedException) cycle.getException()));
+                }
+                throw new ProjectBuildingException(results);
+            }
+
+            return results;
+        }
+
+        List<ProjectBuildingResult> doBuild(List<File> pomFiles, boolean recursive) {
+            Map<File, MavenProject> projectIndex = new ConcurrentHashMap<>(256);
+
+            // phase 1: get file Models from the reactor.
+            List<InterimResult> interimResults = build(projectIndex, pomFiles, new LinkedHashSet<>(), true, recursive);
+
+            ClassLoader oldContextClassLoader = Thread.currentThread().getContextClassLoader();
+
+            try {
+                // Phase 2: get effective models from the reactor
+                List<ProjectBuildingResult> results = build(projectIndex, interimResults);
+
+                if (Features.buildConsumer(request.getUserProperties())) {
+                    request.getRepositorySession()
+                            .getData()
+                            .set(TransformerContext.KEY, transformerContextBuilder.build());
+                }
+
+                return results;
+            } finally {
+                Thread.currentThread().setContextClassLoader(oldContextClassLoader);
+            }
+        }
+
+        @SuppressWarnings("checkstyle:parameternumber")
+        private List<InterimResult> build(
+                Map<File, MavenProject> projectIndex,
+                List<File> pomFiles,
+                Set<File> aggregatorFiles,
+                boolean root,
+                boolean recursive) {
+            List<ForkJoinTask<InterimResult>> tasks = pomFiles.stream()
+                    .map(pomFile -> ForkJoinTask.adapt(
+                            () -> build(projectIndex, pomFile, concat(aggregatorFiles, pomFile), root, recursive)))
+                    .collect(Collectors.toList());
+
+            return ForkJoinTask.invokeAll(tasks).stream()
+                    .map(ForkJoinTask::getRawResult)
+                    .collect(Collectors.toList());
+        }
+
+        private <T> Set<T> concat(Set<T> set, T elem) {
+            Set<T> newSet = new HashSet<>(set);
+            newSet.add(elem);
+            return newSet;
+        }
+
+        @SuppressWarnings("checkstyle:parameternumber")
+        private InterimResult build(
+                Map<File, MavenProject> projectIndex,
+                File pomFile,
+                Set<File> aggregatorFiles,
+                boolean isRoot,
+                boolean recursive) {
+            MavenProject project = new MavenProject();
+            project.setFile(pomFile);
+
+            project.setRootDirectory(
+                    rootLocator.findRoot(pomFile.getParentFile().toPath()));
+
+            ModelBuildingRequest modelBuildingRequest = getModelBuildingRequest()
+                    .setPomFile(pomFile)
+                    .setTwoPhaseBuilding(true)
+                    .setLocationTracking(true);
+
+            DefaultModelBuildingListener listener =
+                    new DefaultModelBuildingListener(project, projectBuildingHelper, request);
+            modelBuildingRequest.setModelBuildingListener(listener);
+
+            ModelBuildingResult result;
+            try {
+                result = modelBuilder.build(modelBuildingRequest);
+            } catch (ModelBuildingException e) {
+                result = e.getResult();
+                if (result == null || result.getFileModel() == null) {
+                    return new InterimResult(
+                            modelBuildingRequest,
+                            new DefaultProjectBuildingResult(e.getModelId(), pomFile, e.getProblems()));
+                }
+                // validation error, continue project building and delay failing to help IDEs
+                // result.getProblems().addAll(e.getProblems()) ?
+            }
+
+            Model model = modelBuildingRequest.getFileModel();
+
+            modelPool.put(model.getPomFile().toPath(), model);
+
+            InterimResult interimResult = new InterimResult(pomFile, modelBuildingRequest, result, project, isRoot);
+
+            if (recursive) {
+                File basedir = pomFile.getParentFile();
+                List<File> moduleFiles = new ArrayList<>();
+                for (String module : model.getModules()) {
+                    if (module == null || module.isEmpty()) {
+                        continue;
+                    }
+
+                    module = module.replace('\\', File.separatorChar).replace('/', File.separatorChar);
+
+                    File moduleFile = modelProcessor.locateExistingPom(new File(basedir, module));
+
+                    if (moduleFile == null) {
+                        ModelProblem problem = new DefaultModelProblem(
+                                "Child module " + moduleFile + " of " + pomFile + " does not exist",
+                                ModelProblem.Severity.ERROR,
+                                ModelProblem.Version.BASE,
+                                model,
+                                -1,
+                                -1,
+                                null);
+                        result.getProblems().add(problem);
+
+                        continue;
+                    }
+
+                    if (Os.IS_WINDOWS) {
+                        // we don't canonicalize on unix to avoid interfering with symlinks
+                        try {
+                            moduleFile = moduleFile.getCanonicalFile();
+                        } catch (IOException e) {
+                            moduleFile = moduleFile.getAbsoluteFile();
+                        }
+                    } else {
+                        moduleFile = new File(moduleFile.toURI().normalize());
+                    }
+
+                    if (aggregatorFiles.contains(moduleFile)) {
+                        StringBuilder buffer = new StringBuilder(256);
+                        for (File aggregatorFile : aggregatorFiles) {
+                            buffer.append(aggregatorFile).append(" -> ");
+                        }
+                        buffer.append(moduleFile);
+
+                        ModelProblem problem = new DefaultModelProblem(
+                                "Child module " + moduleFile + " of " + pomFile + " forms aggregation cycle " + buffer,
+                                ModelProblem.Severity.ERROR,
+                                ModelProblem.Version.BASE,
+                                model,
+                                -1,
+                                -1,
+                                null);
+                        result.getProblems().add(problem);
+
+                        continue;
+                    }
+
+                    moduleFiles.add(moduleFile);
+                }
+
+                if (!moduleFiles.isEmpty()) {
+                    interimResult.modules = build(projectIndex, moduleFiles, aggregatorFiles, false, recursive);
+                }
+            }
+
+            projectIndex.put(pomFile, project);
+
+            return interimResult;
+        }
+
+        private List<ProjectBuildingResult> build(
+                Map<File, MavenProject> projectIndex, List<InterimResult> interimResults) {
+            // The transformation may need to access dependencies raw models,
+            // which may cause some re-entrance in the build() method and can
+            // actually cause deadlocks.  In order to workaround the problem,
+            // we do a first pass by reading all rawModels in order.
+            if (modelBuilder instanceof DefaultModelBuilder) {
+                List<ProjectBuildingResult> results = new ArrayList<>();
+                DefaultModelBuilder dmb = (DefaultModelBuilder) modelBuilder;
+                boolean failure = false;
+                for (InterimResult r : interimResults) {
+                    DefaultProjectBuildingResult res;
+                    try {
+                        Model model = dmb.buildRawModel(r.request);
+                        res = new DefaultProjectBuildingResult(model.getId(), model.getPomFile(), null);
+                    } catch (ModelBuildingException e) {
+                        failure = true;
+                        res = new DefaultProjectBuildingResult(e.getModelId(), r.request.getPomFile(), e.getProblems());
+                    }
+                    results.add(res);
+                }
+                if (failure) {
+                    return results;
+                }
+            }
+
+            return interimResults.parallelStream()
+                    .map(interimResult -> doBuild(projectIndex, interimResult))
+                    .flatMap(List::stream)
+                    .collect(Collectors.toList());
+        }
+
+        private List<ProjectBuildingResult> doBuild(Map<File, MavenProject> projectIndex, InterimResult interimResult) {
+            if (interimResult.projectBuildingResult != null) {
+                return Collections.singletonList(interimResult.projectBuildingResult);
+            }
+            MavenProject project = interimResult.project;
+            try {
+                ModelBuildingResult result = modelBuilder.build(interimResult.request, interimResult.result);
 
                 // 2nd pass of initialization: resolve and build parent if necessary
-                try
-                {
-                    initProject( project, projectIndex, true, result, profilesXmls, request );
-                }
-                catch ( InvalidArtifactRTException iarte )
-                {
-                    result.getProblems().add( new DefaultModelProblem( null, ModelProblem.Severity.ERROR, null,
-                            result.getEffectiveModel(), -1, -1, iarte ) );
+                try {
+                    initProject(project, projectIndex, result);
+                } catch (InvalidArtifactRTException iarte) {
+                    result.getProblems()
+                            .add(new DefaultModelProblem(
+                                    null,
+                                    ModelProblem.Severity.ERROR,
+                                    null,
+                                    result.getEffectiveModel(),
+                                    -1,
+                                    -1,
+                                    iarte));
                 }
 
-                List<MavenProject> modules = new ArrayList<>();
-                noErrors =
-                    build( results, modules, projectIndex, interimResult.modules, request, profilesXmls, session )
-                    && noErrors;
+                List<ProjectBuildingResult> results = build(projectIndex, interimResult.modules);
 
-                projects.addAll( modules );
-                projects.add( project );
-
-                project.setExecutionRoot( interimResult.root );
-                project.setCollectedProjects( modules );
+                project.setExecutionRoot(interimResult.root);
+                project.setCollectedProjects(
+                        results.stream().map(ProjectBuildingResult::getProject).collect(Collectors.toList()));
                 DependencyResolutionResult resolutionResult = null;
-                if ( request.isResolveDependencies() )
-                {
-                    resolutionResult = resolveDependencies( project, session );
+                if (request.isResolveDependencies()) {
+                    resolutionResult = resolveDependencies(project);
                 }
 
-                results.add( new DefaultProjectBuildingResult( project, result.getProblems(), resolutionResult ) );
-            }
-            catch ( ModelBuildingException e )
-            {
-                DefaultProjectBuildingResult result = null;
-                if ( project == null || interimResult.result.getEffectiveModel() == null )
-                {
-                    result = new DefaultProjectBuildingResult( e.getModelId(), interimResult.pomFile, e.getProblems() );
-                }
-                else
-                {
-                    project.setModel( interimResult.result.getEffectiveModel() );
+                results.add(new DefaultProjectBuildingResult(project, result.getProblems(), resolutionResult));
 
-                    result = new DefaultProjectBuildingResult( project, e.getProblems(), null );
+                return results;
+            } catch (ModelBuildingException e) {
+                DefaultProjectBuildingResult result;
+                if (project == null || interimResult.result.getEffectiveModel() == null) {
+                    result = new DefaultProjectBuildingResult(e.getModelId(), interimResult.pomFile, e.getProblems());
+                } else {
+                    project.setModel(interimResult.result.getEffectiveModel());
+                    result = new DefaultProjectBuildingResult(project, e.getProblems(), null);
                 }
-                results.add( result );
-
-                noErrors = false;
+                return Collections.singletonList(result);
             }
         }
 
-        return noErrors;
-    }
+        @SuppressWarnings("checkstyle:methodlength")
+        private void initProject(MavenProject project, Map<File, MavenProject> projects, ModelBuildingResult result) {
+            project.setModel(result.getEffectiveModel());
+            project.setOriginalModel(result.getFileModel());
 
-    @SuppressWarnings( "checkstyle:methodlength" )
-    private void initProject( MavenProject project, Map<File, MavenProject> projects,
-                              boolean buildParentIfNotExisting, ModelBuildingResult result,
-                              Map<File, Boolean> profilesXmls, ProjectBuildingRequest projectBuildingRequest )
-    {
-        Model model = result.getEffectiveModel();
+            initParent(project, projects, result);
 
-        project.setModel( model );
-        project.setOriginalModel( result.getFileModel() );
+            Artifact projectArtifact = repositorySystem.createArtifact(
+                    project.getGroupId(), project.getArtifactId(), project.getVersion(), null, project.getPackaging());
+            project.setArtifact(projectArtifact);
 
-        initParent( project, projects, buildParentIfNotExisting, result, projectBuildingRequest );
-
-        Artifact projectArtifact =
-            repositorySystem.createArtifact( project.getGroupId(), project.getArtifactId(), project.getVersion(), null,
-                                             project.getPackaging() );
-        project.setArtifact( projectArtifact );
-
-        if ( project.getFile() != null && buildParentIfNotExisting ) // only set those on 2nd phase, ignore on 1st pass
-        {
-            Build build = project.getBuild();
-            project.addScriptSourceRoot( build.getScriptSourceDirectory() );
-            project.addCompileSourceRoot( build.getSourceDirectory() );
-            project.addTestCompileSourceRoot( build.getTestSourceDirectory() );
-        }
-
-        List<Profile> activeProfiles = new ArrayList<>();
-        activeProfiles.addAll( result.getActivePomProfiles( result.getModelIds().get( 0 ) ) );
-        activeProfiles.addAll( result.getActiveExternalProfiles() );
-        project.setActiveProfiles( activeProfiles );
-
-        project.setInjectedProfileIds( "external", getProfileIds( result.getActiveExternalProfiles() ) );
-        for ( String modelId : result.getModelIds() )
-        {
-            project.setInjectedProfileIds( modelId, getProfileIds( result.getActivePomProfiles( modelId ) ) );
-        }
-
-        //
-        // All the parts that were taken out of MavenProject for Maven 4.0.0
-        //
-
-        project.setProjectBuildingRequest( projectBuildingRequest );
-
-        // pluginArtifacts
-        Set<Artifact> pluginArtifacts = new HashSet<>();
-        for ( Plugin plugin : project.getBuildPlugins() )
-        {
-            Artifact artifact = repositorySystem.createPluginArtifact( plugin );
-
-            if ( artifact != null )
-            {
-                pluginArtifacts.add( artifact );
+            // only set those on 2nd phase, ignore on 1st pass
+            if (project.getFile() != null) {
+                Build build = project.getBuild();
+                project.addScriptSourceRoot(build.getScriptSourceDirectory());
+                project.addCompileSourceRoot(build.getSourceDirectory());
+                project.addTestCompileSourceRoot(build.getTestSourceDirectory());
             }
-        }
-        project.setPluginArtifacts( pluginArtifacts );
 
-        // reportArtifacts
-        Set<Artifact> reportArtifacts = new HashSet<>();
-        for ( ReportPlugin report : project.getReportPlugins() )
-        {
-            Plugin pp = new Plugin();
-            pp.setGroupId( report.getGroupId() );
-            pp.setArtifactId( report.getArtifactId() );
-            pp.setVersion( report.getVersion() );
+            List<Profile> activeProfiles = new ArrayList<>();
+            activeProfiles.addAll(
+                    result.getActivePomProfiles(result.getModelIds().get(0)));
+            activeProfiles.addAll(result.getActiveExternalProfiles());
+            project.setActiveProfiles(activeProfiles);
 
-            Artifact artifact = repositorySystem.createPluginArtifact( pp );
-
-            if ( artifact != null )
-            {
-                reportArtifacts.add( artifact );
+            project.setInjectedProfileIds("external", getProfileIds(result.getActiveExternalProfiles()));
+            for (String modelId : result.getModelIds()) {
+                project.setInjectedProfileIds(modelId, getProfileIds(result.getActivePomProfiles(modelId)));
             }
-        }
-        project.setReportArtifacts( reportArtifacts );
 
-        // extensionArtifacts
-        Set<Artifact> extensionArtifacts = new HashSet<>();
-        List<Extension> extensions = project.getBuildExtensions();
-        if ( extensions != null )
-        {
-            for ( Extension ext : extensions )
-            {
-                String version;
-                if ( StringUtils.isEmpty( ext.getVersion() ) )
-                {
-                    version = "RELEASE";
-                }
-                else
-                {
-                    version = ext.getVersion();
-                }
+            //
+            // All the parts that were taken out of MavenProject for Maven 4.0.0
+            //
 
-                Artifact artifact =
-                    repositorySystem.createArtifact( ext.getGroupId(), ext.getArtifactId(), version, null, "jar" );
+            project.setProjectBuildingRequest(request);
 
-                if ( artifact != null )
-                {
-                    extensionArtifacts.add( artifact );
+            // pluginArtifacts
+            Set<Artifact> pluginArtifacts = new HashSet<>();
+            for (Plugin plugin : project.getBuildPlugins()) {
+                Artifact artifact = repositorySystem.createPluginArtifact(plugin);
+
+                if (artifact != null) {
+                    pluginArtifacts.add(artifact);
                 }
             }
-        }
-        project.setExtensionArtifacts( extensionArtifacts );
+            project.setPluginArtifacts(pluginArtifacts);
 
-        // managedVersionMap
-        Map<String, Artifact> map = null;
-        if ( repositorySystem != null )
-        {
+            // reportArtifacts
+            Set<Artifact> reportArtifacts = new HashSet<>();
+            for (ReportPlugin report : project.getReportPlugins()) {
+                Plugin pp = new Plugin();
+                pp.setGroupId(report.getGroupId());
+                pp.setArtifactId(report.getArtifactId());
+                pp.setVersion(report.getVersion());
+
+                Artifact artifact = repositorySystem.createPluginArtifact(pp);
+
+                if (artifact != null) {
+                    reportArtifacts.add(artifact);
+                }
+            }
+            project.setReportArtifacts(reportArtifacts);
+
+            // extensionArtifacts
+            Set<Artifact> extensionArtifacts = new HashSet<>();
+            List<Extension> extensions = project.getBuildExtensions();
+            if (extensions != null) {
+                for (Extension ext : extensions) {
+                    String version;
+                    if (ext.getVersion() == null || ext.getVersion().isEmpty()) {
+                        version = "RELEASE";
+                    } else {
+                        version = ext.getVersion();
+                    }
+
+                    Artifact artifact = repositorySystem.createArtifact(
+                            ext.getGroupId(), ext.getArtifactId(), version, null, "jar");
+
+                    if (artifact != null) {
+                        extensionArtifacts.add(artifact);
+                    }
+                }
+            }
+            project.setExtensionArtifacts(extensionArtifacts);
+
+            // managedVersionMap
+            Map<String, Artifact> map = Collections.emptyMap();
             final DependencyManagement dependencyManagement = project.getDependencyManagement();
-            if ( ( dependencyManagement != null ) && ( ( dependencyManagement.getDependencies() ) != null )
-                && ( dependencyManagement.getDependencies().size() > 0 ) )
-            {
-                map = new AbstractMap<String, Artifact>()
-                {
-                    HashMap<String, Artifact> delegate;
-
-                    @Override
-                    public Set<Entry<String, Artifact>> entrySet()
-                    {
-                        return Collections.unmodifiableSet( compute().entrySet() );
+            if (dependencyManagement != null
+                    && dependencyManagement.getDependencies() != null
+                    && !dependencyManagement.getDependencies().isEmpty()) {
+                map = new LazyMap<>(() -> {
+                    Map<String, Artifact> tmp = new HashMap<>();
+                    for (Dependency d : dependencyManagement.getDependencies()) {
+                        Artifact artifact = repositorySystem.createDependencyArtifact(d);
+                        if (artifact != null) {
+                            tmp.put(d.getManagementKey(), artifact);
+                        }
                     }
+                    return Collections.unmodifiableMap(tmp);
+                });
+            }
+            project.setManagedVersionMap(map);
 
-                    @Override
-                    public Set<String> keySet()
-                    {
-                        return Collections.unmodifiableSet( compute().keySet() );
+            // release artifact repository
+            if (project.getDistributionManagement() != null
+                    && project.getDistributionManagement().getRepository() != null) {
+                try {
+                    DeploymentRepository r = project.getDistributionManagement().getRepository();
+                    if (r.getId() != null
+                            && !r.getId().isEmpty()
+                            && r.getUrl() != null
+                            && !r.getUrl().isEmpty()) {
+                        ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(r);
+                        repositorySystem.injectProxy(request.getRepositorySession(), Arrays.asList(repo));
+                        repositorySystem.injectAuthentication(request.getRepositorySession(), Arrays.asList(repo));
+                        project.setReleaseArtifactRepository(repo);
                     }
+                } catch (InvalidRepositoryException e) {
+                    throw new IllegalStateException(
+                            "Failed to create release distribution repository for " + project.getId(), e);
+                }
+            }
 
-                    @Override
-                    public Collection<Artifact> values()
-                    {
-                        return Collections.unmodifiableCollection( compute().values() );
+            // snapshot artifact repository
+            if (project.getDistributionManagement() != null
+                    && project.getDistributionManagement().getSnapshotRepository() != null) {
+                try {
+                    DeploymentRepository r = project.getDistributionManagement().getSnapshotRepository();
+                    if (r.getId() != null
+                            && !r.getId().isEmpty()
+                            && r.getUrl() != null
+                            && !r.getUrl().isEmpty()) {
+                        ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository(r);
+                        repositorySystem.injectProxy(request.getRepositorySession(), Arrays.asList(repo));
+                        repositorySystem.injectAuthentication(request.getRepositorySession(), Arrays.asList(repo));
+                        project.setSnapshotArtifactRepository(repo);
                     }
+                } catch (InvalidRepositoryException e) {
+                    throw new IllegalStateException(
+                            "Failed to create snapshot distribution repository for " + project.getId(), e);
+                }
+            }
+        }
 
-                    @Override
-                    public boolean containsValue( Object value )
-                    {
-                        return compute().containsValue( value );
-                    }
+        private void initParent(MavenProject project, Map<File, MavenProject> projects, ModelBuildingResult result) {
+            Model parentModel = result.getModelIds().size() > 1
+                            && !result.getModelIds().get(1).isEmpty()
+                    ? result.getRawModel(result.getModelIds().get(1))
+                    : null;
 
-                    @Override
-                    public boolean containsKey( Object key )
-                    {
-                        return compute().containsKey( key );
-                    }
+            if (parentModel != null) {
+                final String parentGroupId = inheritedGroupId(result, 1);
+                final String parentVersion = inheritedVersion(result, 1);
 
-                    @Override
-                    public Artifact get( Object key )
-                    {
-                        return compute().get( key );
-                    }
+                project.setParentArtifact(repositorySystem.createProjectArtifact(
+                        parentGroupId, parentModel.getArtifactId(), parentVersion));
 
-                    HashMap<String, Artifact> compute()
-                    {
-                        if ( delegate == null )
-                        {
-                            delegate = new HashMap<>();
-                            for ( Dependency d : dependencyManagement.getDependencies() )
-                            {
-                                Artifact artifact = repositorySystem.createDependencyArtifact( d );
-
-                                if ( artifact != null )
-                                {
-                                    delegate.put( d.getManagementKey(), artifact );
-                                }
+                // org.apache.maven.its.mng4834:parent:0.1
+                String parentModelId = result.getModelIds().get(1);
+                File parentPomFile = result.getRawModel(parentModelId).getPomFile();
+                MavenProject parent = parentPomFile != null ? projects.get(parentPomFile) : null;
+                if (parent == null) {
+                    //
+                    // At this point the DefaultModelBuildingListener has fired and it populates the
+                    // remote repositories with those found in the pom.xml, along with the existing externally
+                    // defined repositories.
+                    //
+                    request.setRemoteRepositories(project.getRemoteArtifactRepositories());
+                    if (parentPomFile != null) {
+                        project.setParentFile(parentPomFile);
+                        try {
+                            parent = build(parentPomFile, new FileModelSource(parentPomFile))
+                                    .getProject();
+                        } catch (ProjectBuildingException e) {
+                            // MNG-4488 where let invalid parents slide on by
+                            if (logger.isDebugEnabled()) {
+                                // Message below is checked for in the MNG-2199 core IT.
+                                logger.warn("Failed to build parent project for " + project.getId(), e);
+                            } else {
+                                // Message below is checked for in the MNG-2199 core IT.
+                                logger.warn("Failed to build parent project for " + project.getId());
                             }
                         }
-
-                        return delegate;
+                    } else {
+                        Artifact parentArtifact = project.getParentArtifact();
+                        try {
+                            parent = build(parentArtifact, false).getProject();
+                        } catch (ProjectBuildingException e) {
+                            // MNG-4488 where let invalid parents slide on by
+                            if (logger.isDebugEnabled()) {
+                                // Message below is checked for in the MNG-2199 core IT.
+                                logger.warn("Failed to build parent project for " + project.getId(), e);
+                            } else {
+                                // Message below is checked for in the MNG-2199 core IT.
+                                logger.warn("Failed to build parent project for " + project.getId());
+                            }
+                        }
                     }
-                };
-            }
-            else
-            {
-                map = Collections.emptyMap();
-            }
-        }
-        project.setManagedVersionMap( map );
-
-        // release artifact repository
-        if ( project.getDistributionManagement() != null
-                        && project.getDistributionManagement().getRepository() != null )
-        {
-            try
-            {
-                DeploymentRepository r = project.getDistributionManagement().getRepository();
-                if ( !StringUtils.isEmpty( r.getId() ) && !StringUtils.isEmpty( r.getUrl() ) )
-                {
-                    ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository( r );
-                    repositorySystem.injectProxy( projectBuildingRequest.getRepositorySession(),
-                                                  Arrays.asList( repo ) );
-                    repositorySystem.injectAuthentication( projectBuildingRequest.getRepositorySession(),
-                                                           Arrays.asList( repo ) );
-                    project.setReleaseArtifactRepository( repo );
                 }
-            }
-            catch ( InvalidRepositoryException e )
-            {
-                throw new IllegalStateException( "Failed to create release distribution repository for "
-                    + project.getId(), e );
+                project.setParent(parent);
+                if (project.getParentFile() == null && parent != null) {
+                    project.setParentFile(parent.getFile());
+                }
             }
         }
 
-        // snapshot artifact repository
-        if ( project.getDistributionManagement() != null
-            && project.getDistributionManagement().getSnapshotRepository() != null )
-        {
-            try
-            {
-                DeploymentRepository r = project.getDistributionManagement().getSnapshotRepository();
-                if ( !StringUtils.isEmpty( r.getId() ) && !StringUtils.isEmpty( r.getUrl() ) )
-                {
-                    ArtifactRepository repo = MavenRepositorySystem.buildArtifactRepository( r );
-                    repositorySystem.injectProxy( projectBuildingRequest.getRepositorySession(),
-                                                  Arrays.asList( repo ) );
-                    repositorySystem.injectAuthentication( projectBuildingRequest.getRepositorySession(),
-                                                           Arrays.asList( repo ) );
-                    project.setSnapshotArtifactRepository( repo );
+        private ModelBuildingRequest getModelBuildingRequest() {
+            ModelBuildingRequest modelBuildingRequest = new DefaultModelBuildingRequest();
+
+            RequestTrace trace = RequestTrace.newChild(null, request).newChild(modelBuildingRequest);
+
+            ModelResolver resolver = new ProjectModelResolver(
+                    session,
+                    trace,
+                    repoSystem,
+                    repositoryManager,
+                    repositories,
+                    request.getRepositoryMerging(),
+                    modelPool);
+
+            modelBuildingRequest.setValidationLevel(request.getValidationLevel());
+            modelBuildingRequest.setProcessPlugins(request.isProcessPlugins());
+            modelBuildingRequest.setProfiles(request.getProfiles());
+            modelBuildingRequest.setActiveProfileIds(request.getActiveProfileIds());
+            modelBuildingRequest.setInactiveProfileIds(request.getInactiveProfileIds());
+            modelBuildingRequest.setSystemProperties(request.getSystemProperties());
+            modelBuildingRequest.setUserProperties(request.getUserProperties());
+            modelBuildingRequest.setBuildStartTime(request.getBuildStartTime());
+            modelBuildingRequest.setModelResolver(resolver);
+            // this is a hint that we want to build 1 file, so don't cache. See MNG-7063
+            if (modelPool != null) {
+                modelBuildingRequest.setModelCache(modelCacheFactory.createCache(session));
+            }
+            modelBuildingRequest.setTransformerContextBuilder(transformerContextBuilder);
+            InternalSession session = (InternalSession) this.session.getData().get(InternalSession.class);
+            if (session != null) {
+                try {
+                    modelBuildingRequest.setRootDirectory(session.getRootDirectory());
+                } catch (IllegalStateException e) {
+                    // can happen if root directory cannot be found, just ignore
                 }
             }
-            catch ( InvalidRepositoryException e )
-            {
-                throw new IllegalStateException( "Failed to create snapshot distribution repository for "
-                    + project.getId(), e );
+
+            return modelBuildingRequest;
+        }
+
+        private DependencyResolutionResult resolveDependencies(MavenProject project) {
+            DependencyResolutionResult resolutionResult;
+
+            try {
+                DefaultDependencyResolutionRequest resolution =
+                        new DefaultDependencyResolutionRequest(project, session);
+                resolutionResult = dependencyResolver.resolve(resolution);
+            } catch (DependencyResolutionException e) {
+                resolutionResult = e.getResult();
             }
+
+            Set<Artifact> artifacts = new LinkedHashSet<>();
+            if (resolutionResult.getDependencyGraph() != null) {
+                RepositoryUtils.toArtifacts(
+                        artifacts,
+                        resolutionResult.getDependencyGraph().getChildren(),
+                        Collections.singletonList(project.getArtifact().getId()),
+                        null);
+
+                // Maven 2.x quirk: an artifact always points at the local repo, regardless whether resolved or not
+                LocalRepositoryManager lrm = session.getLocalRepositoryManager();
+                for (Artifact artifact : artifacts) {
+                    if (!artifact.isResolved()) {
+                        String path = lrm.getPathForLocalArtifact(RepositoryUtils.toArtifact(artifact));
+                        artifact.setFile(new File(lrm.getRepository().getBasedir(), path));
+                    }
+                }
+            }
+            project.setResolvedArtifacts(artifacts);
+            project.setArtifacts(artifacts);
+
+            return resolutionResult;
         }
     }
 
-    private void initParent( MavenProject project, Map<File, MavenProject> projects, boolean buildParentIfNotExisting,
-                             ModelBuildingResult result, ProjectBuildingRequest projectBuildingRequest )
-    {
-        Model parentModel = result.getModelIds().size() > 1 && !result.getModelIds().get( 1 ).isEmpty()
-                                ? result.getRawModel( result.getModelIds().get( 1 ) )
-                                : null;
-
-        if ( parentModel != null )
-        {
-            final String parentGroupId = inheritedGroupId( result, 1 );
-            final String parentVersion = inheritedVersion( result, 1 );
-
-            project.setParentArtifact( repositorySystem.createProjectArtifact( parentGroupId,
-                                                                               parentModel.getArtifactId(),
-                                                                               parentVersion ) );
-
-            // org.apache.maven.its.mng4834:parent:0.1
-            String parentModelId = result.getModelIds().get( 1 );
-            File parentPomFile = result.getRawModel( parentModelId ).getPomFile();
-            MavenProject parent = projects.get( parentPomFile );
-            if ( parent == null && buildParentIfNotExisting )
-            {
-                //
-                // At this point the DefaultModelBuildingListener has fired and it populates the
-                // remote repositories with those found in the pom.xml, along with the existing externally
-                // defined repositories.
-                //
-                projectBuildingRequest.setRemoteRepositories( project.getRemoteArtifactRepositories() );
-                if ( parentPomFile != null )
-                {
-                    project.setParentFile( parentPomFile );
-                    try
-                    {
-                        parent = build( parentPomFile, projectBuildingRequest ).getProject();
-                    }
-                    catch ( ProjectBuildingException e )
-                    {
-                        // MNG-4488 where let invalid parents slide on by
-                        if ( logger.isDebugEnabled() )
-                        {
-                            // Message below is checked for in the MNG-2199 core IT.
-                            logger.warn( "Failed to build parent project for " + project.getId(), e );
-                        }
-                        else
-                        {
-                            // Message below is checked for in the MNG-2199 core IT.
-                            logger.warn( "Failed to build parent project for " + project.getId() );
-                        }
-                    }
-                }
-                else
-                {
-                    Artifact parentArtifact = project.getParentArtifact();
-                    try
-                    {
-                        parent = build( parentArtifact, projectBuildingRequest ).getProject();
-                    }
-                    catch ( ProjectBuildingException e )
-                    {
-                        // MNG-4488 where let invalid parents slide on by
-                        if ( logger.isDebugEnabled() )
-                        {
-                            // Message below is checked for in the MNG-2199 core IT.
-                            logger.warn( "Failed to build parent project for " + project.getId(), e );
-                        }
-                        else
-                        {
-                            // Message below is checked for in the MNG-2199 core IT.
-                            logger.warn( "Failed to build parent project for " + project.getId() );
-                        }
-                    }
-                }
-            }
-            project.setParent( parent );
-            if ( project.getParentFile() == null && parent != null )
-            {
-                project.setParentFile( parent.getFile() );
-            }
-        }
+    private List<String> getProfileIds(List<org.apache.maven.model.Profile> profiles) {
+        return profiles.stream().map(org.apache.maven.model.Profile::getId).collect(Collectors.toList());
     }
 
-    private static String inheritedGroupId( final ModelBuildingResult result, final int modelIndex )
-    {
+    private static ModelSource createStubModelSource(Artifact artifact) {
+        StringBuilder buffer = new StringBuilder(1024);
+
+        buffer.append("<?xml version='1.0'?>");
+        buffer.append("<project>");
+        buffer.append("<modelVersion>4.0.0</modelVersion>");
+        buffer.append("<groupId>").append(artifact.getGroupId()).append("</groupId>");
+        buffer.append("<artifactId>").append(artifact.getArtifactId()).append("</artifactId>");
+        buffer.append("<version>").append(artifact.getBaseVersion()).append("</version>");
+        buffer.append("<packaging>").append(artifact.getType()).append("</packaging>");
+        buffer.append("</project>");
+
+        return new StringModelSource(buffer, artifact.getId());
+    }
+
+    private static String inheritedGroupId(final ModelBuildingResult result, final int modelIndex) {
         String groupId = null;
-        final String modelId = result.getModelIds().get( modelIndex );
+        final String modelId = result.getModelIds().get(modelIndex);
 
-        if ( !modelId.isEmpty() )
-        {
-            final Model model = result.getRawModel( modelId );
-            groupId = model.getGroupId() != null
-                          ? model.getGroupId()
-                          : inheritedGroupId( result, modelIndex + 1 );
-
+        if (!modelId.isEmpty()) {
+            final Model model = result.getRawModel(modelId);
+            groupId = model.getGroupId() != null ? model.getGroupId() : inheritedGroupId(result, modelIndex + 1);
         }
 
         return groupId;
     }
 
-    private static String inheritedVersion( final ModelBuildingResult result, final int modelIndex )
-    {
+    private static String inheritedVersion(final ModelBuildingResult result, final int modelIndex) {
         String version = null;
-        final String modelId = result.getModelIds().get( modelIndex );
+        final String modelId = result.getModelIds().get(modelIndex);
 
-        if ( !modelId.isEmpty() )
-        {
-            final Model model = result.getRawModel( modelId );
-            version = model.getVersion() != null
-                          ? model.getVersion()
-                          : inheritedVersion( result, modelIndex + 1 );
-
+        if (!modelId.isEmpty()) {
+            version = result.getRawModel(modelId).getVersion();
+            if (version == null) {
+                version = inheritedVersion(result, modelIndex + 1);
+            }
         }
 
         return version;
     }
 
-    /**
-     * InternalConfig
-     */
-    class InternalConfig
-    {
-
-        private final ProjectBuildingRequest request;
-
-        private final RepositorySystemSession session;
-
-        private final List<RemoteRepository> repositories;
-
-        private final ReactorModelPool modelPool;
-
-        private final TransformerContextBuilder transformerContextBuilder;
-
-        InternalConfig( ProjectBuildingRequest request, ReactorModelPool modelPool,
-                        TransformerContextBuilder transformerContextBuilder )
-        {
-            this.request = request;
-            this.modelPool = modelPool;
-            this.transformerContextBuilder = transformerContextBuilder;
-
-            session =
-                LegacyLocalRepositoryManager.overlay( request.getLocalRepository(), request.getRepositorySession(),
-                                                      repoSystem );
-            repositories = RepositoryUtils.toRepos( request.getRemoteRepositories() );
-
-        }
-
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
+        throw (T) t; // rely on vacuous cast
     }
 
+    static class LazyMap<K, V> extends AbstractMap<K, V> {
+        private final Supplier<Map<K, V>> supplier;
+        private volatile Map<K, V> delegate;
+
+        LazyMap(Supplier<Map<K, V>> supplier) {
+            this.supplier = supplier;
+        }
+
+        @Override
+        public Set<Entry<K, V>> entrySet() {
+            if (delegate == null) {
+                synchronized (this) {
+                    if (delegate == null) {
+                        delegate = supplier.get();
+                    }
+                }
+            }
+            return delegate.entrySet();
+        }
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingHelper.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingHelper.java
index 690dcd1..aac66e6 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingHelper.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingHelper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -29,14 +32,12 @@
 import java.util.Map;
 import java.util.Set;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.InvalidRepositoryException;
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.classrealm.ClassRealmManager;
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Extension;
@@ -48,9 +49,9 @@
 import org.apache.maven.plugin.PluginManagerException;
 import org.apache.maven.plugin.PluginResolutionException;
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
-import org.apache.maven.repository.RepositorySystem;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.eclipse.aether.graph.DependencyFilter;
 import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
 import org.slf4j.Logger;
@@ -61,18 +62,15 @@
  * technical reasons, it is not part of the public API. In particular, this class can be changed or deleted without
  * prior notice.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultProjectBuildingHelper
-    implements ProjectBuildingHelper
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class DefaultProjectBuildingHelper implements ProjectBuildingHelper {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
     private final PlexusContainer container; // TODO not used? Then remove
     private final ClassRealmManager classRealmManager;
     private final ProjectRealmCache projectRealmCache;
-    private final RepositorySystem repositorySystem;
+    private final MavenRepositorySystem repositorySystem;
     private final MavenPluginManager pluginManager;
 
     @Inject
@@ -80,9 +78,8 @@
             PlexusContainer container,
             ClassRealmManager classRealmManager,
             ProjectRealmCache projectRealmCache,
-            RepositorySystem repositorySystem,
-            MavenPluginManager pluginManager )
-    {
+            MavenRepositorySystem repositorySystem,
+            MavenPluginManager pluginManager) {
         this.container = container;
         this.classRealmManager = classRealmManager;
         this.projectRealmCache = projectRealmCache;
@@ -90,34 +87,30 @@
         this.pluginManager = pluginManager;
     }
 
-    public List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
-                                                                List<ArtifactRepository> externalRepositories,
-                                                                ProjectBuildingRequest request )
-        throws InvalidRepositoryException
-    {
+    public List<ArtifactRepository> createArtifactRepositories(
+            List<Repository> pomRepositories,
+            List<ArtifactRepository> externalRepositories,
+            ProjectBuildingRequest request)
+            throws InvalidRepositoryException {
         List<ArtifactRepository> internalRepositories = new ArrayList<>();
 
-        for ( Repository repository : pomRepositories )
-        {
-            internalRepositories.add( repositorySystem.buildArtifactRepository( repository ) );
+        for (Repository repository : pomRepositories) {
+            internalRepositories.add(MavenRepositorySystem.buildArtifactRepository(repository));
         }
 
-        repositorySystem.injectMirror( request.getRepositorySession(), internalRepositories );
+        repositorySystem.injectMirror(request.getRepositorySession(), internalRepositories);
 
-        repositorySystem.injectProxy( request.getRepositorySession(), internalRepositories );
+        repositorySystem.injectProxy(request.getRepositorySession(), internalRepositories);
 
-        repositorySystem.injectAuthentication( request.getRepositorySession(), internalRepositories );
+        repositorySystem.injectAuthentication(request.getRepositorySession(), internalRepositories);
 
         List<ArtifactRepository> dominantRepositories;
         List<ArtifactRepository> recessiveRepositories;
 
-        if ( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals( request.getRepositoryMerging() ) )
-        {
+        if (ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals(request.getRepositoryMerging())) {
             dominantRepositories = externalRepositories;
             recessiveRepositories = internalRepositories;
-        }
-        else
-        {
+        } else {
             dominantRepositories = internalRepositories;
             recessiveRepositories = externalRepositories;
         }
@@ -125,69 +118,61 @@
         List<ArtifactRepository> artifactRepositories = new ArrayList<>();
         Collection<String> repoIds = new HashSet<>();
 
-        if ( dominantRepositories != null )
-        {
-            for ( ArtifactRepository repository : dominantRepositories )
-            {
-                repoIds.add( repository.getId() );
-                artifactRepositories.add( repository );
+        if (dominantRepositories != null) {
+            for (ArtifactRepository repository : dominantRepositories) {
+                repoIds.add(repository.getId());
+                artifactRepositories.add(repository);
             }
         }
 
-        if ( recessiveRepositories != null )
-        {
-            for ( ArtifactRepository repository : recessiveRepositories )
-            {
-                if ( repoIds.add( repository.getId() ) )
-                {
-                    artifactRepositories.add( repository );
+        if (recessiveRepositories != null) {
+            for (ArtifactRepository repository : recessiveRepositories) {
+                if (repoIds.add(repository.getId())) {
+                    artifactRepositories.add(repository);
                 }
             }
         }
 
-        artifactRepositories = repositorySystem.getEffectiveRepositories( artifactRepositories );
+        artifactRepositories = repositorySystem.getEffectiveRepositories(artifactRepositories);
 
         return artifactRepositories;
     }
 
-    public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProject project, Model model,
-                                                                          ProjectBuildingRequest request )
-        throws PluginResolutionException, PluginVersionResolutionException, PluginManagerException
-    {
+    public synchronized ProjectRealmCache.CacheRecord createProjectRealm(
+            MavenProject project, Model model, ProjectBuildingRequest request)
+            throws PluginResolutionException, PluginVersionResolutionException, PluginManagerException {
         ClassRealm projectRealm;
 
         List<Plugin> extensionPlugins = new ArrayList<>();
 
         Build build = model.getBuild();
 
-        if ( build != null )
-        {
-            for ( Extension extension : build.getExtensions() )
-            {
+        if (build != null) {
+            for (Extension extension : build.getExtensions()) {
                 Plugin plugin = new Plugin();
-                plugin.setGroupId( extension.getGroupId() );
-                plugin.setArtifactId( extension.getArtifactId() );
-                plugin.setVersion( extension.getVersion() );
-                extensionPlugins.add( plugin );
+                plugin.setGroupId(extension.getGroupId());
+                plugin.setArtifactId(extension.getArtifactId());
+                plugin.setVersion(extension.getVersion());
+                XmlNode configuration = extension.getDelegate().getConfiguration();
+                if (configuration != null) {
+                    plugin.setConfiguration(new Xpp3Dom(configuration));
+                }
+                extensionPlugins.add(plugin);
             }
 
-            for ( Plugin plugin : build.getPlugins() )
-            {
-                if ( plugin.isExtensions() )
-                {
-                    extensionPlugins.add( plugin );
+            for (Plugin plugin : build.getPlugins()) {
+                if (plugin.isExtensions()) {
+                    extensionPlugins.add(plugin);
                 }
             }
         }
 
-        if ( extensionPlugins.isEmpty() )
-        {
-            if ( logger.isDebugEnabled() )
-            {
-                logger.debug( "Extension realms for project " + model.getId() + ": (none)" );
+        if (extensionPlugins.isEmpty()) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("Extension realms for project " + model.getId() + ": (none)");
             }
 
-            return new ProjectRealmCache.CacheRecord( null, null );
+            return new ProjectRealmCache.CacheRecord(null, null);
         }
 
         List<ClassRealm> extensionRealms = new ArrayList<>();
@@ -198,104 +183,92 @@
 
         List<Artifact> publicArtifacts = new ArrayList<>();
 
-        for ( Plugin plugin : extensionPlugins )
-        {
+        for (Plugin plugin : extensionPlugins) {
             ExtensionRealmCache.CacheRecord recordRealm =
-                pluginManager.setupExtensionsRealm( project, plugin, request.getRepositorySession() );
+                    pluginManager.setupExtensionsRealm(project, plugin, request.getRepositorySession());
 
             final ClassRealm extensionRealm = recordRealm.getRealm();
             final ExtensionDescriptor extensionDescriptor = recordRealm.getDescriptor();
             final List<Artifact> artifacts = recordRealm.getArtifacts();
 
-            extensionRealms.add( extensionRealm );
-            if ( extensionDescriptor != null )
-            {
-                exportedPackages.put( extensionRealm, extensionDescriptor.getExportedPackages() );
-                exportedArtifacts.put( extensionRealm, extensionDescriptor.getExportedArtifacts() );
+            extensionRealms.add(extensionRealm);
+            if (extensionDescriptor != null) {
+                exportedPackages.put(extensionRealm, extensionDescriptor.getExportedPackages());
+                exportedArtifacts.put(extensionRealm, extensionDescriptor.getExportedArtifacts());
             }
 
-            if ( !plugin.isExtensions() && artifacts.size() == 1 && artifacts.get( 0 ).getFile() != null )
-            {
+            if (!plugin.isExtensions()
+                    && artifacts.size() == 1
+                    && artifacts.get(0).getFile() != null) {
                 /*
                  * This is purely for backward-compat with 2.x where <extensions> consisting of a single artifact where
                  * loaded into the core and hence available to plugins, in contrast to bigger extensions that were
                  * loaded into a dedicated realm which is invisible to plugins (MNG-2749).
                  */
-                publicArtifacts.addAll( artifacts );
+                publicArtifacts.addAll(artifacts);
             }
         }
 
-        if ( logger.isDebugEnabled() )
-        {
-            logger.debug( "Extension realms for project " + model.getId() + ": " + extensionRealms );
+        if (logger.isDebugEnabled()) {
+            logger.debug("Extension realms for project " + model.getId() + ": " + extensionRealms);
         }
 
-        ProjectRealmCache.Key projectRealmKey = projectRealmCache.createKey( extensionRealms );
+        ProjectRealmCache.Key projectRealmKey = projectRealmCache.createKey(extensionRealms);
 
-        ProjectRealmCache.CacheRecord record = projectRealmCache.get( projectRealmKey );
+        ProjectRealmCache.CacheRecord record = projectRealmCache.get(projectRealmKey);
 
-        if ( record == null )
-        {
-            projectRealm = classRealmManager.createProjectRealm( model, toAetherArtifacts( publicArtifacts ) );
+        if (record == null) {
+            projectRealm = classRealmManager.createProjectRealm(model, toAetherArtifacts(publicArtifacts));
 
             Set<String> exclusions = new LinkedHashSet<>();
 
-            for ( ClassRealm extensionRealm : extensionRealms )
-            {
-                List<String> excludes = exportedArtifacts.get( extensionRealm );
+            for (ClassRealm extensionRealm : extensionRealms) {
+                List<String> excludes = exportedArtifacts.get(extensionRealm);
 
-                if ( excludes != null )
-                {
-                    exclusions.addAll( excludes );
+                if (excludes != null) {
+                    exclusions.addAll(excludes);
                 }
 
-                List<String> exports = exportedPackages.get( extensionRealm );
+                List<String> exports = exportedPackages.get(extensionRealm);
 
-                if ( exports == null || exports.isEmpty() )
-                {
+                if (exports == null || exports.isEmpty()) {
                     /*
                      * Most existing extensions don't define exported packages, i.e. no classes are to be exposed to
                      * plugins, yet the components provided by the extension (e.g. artifact handlers) must be
                      * accessible, i.e. we still must import the extension realm into the project realm.
                      */
-                    exports = Arrays.asList( extensionRealm.getId() );
+                    exports = Arrays.asList(extensionRealm.getId());
                 }
 
-                for ( String export : exports )
-                {
-                    projectRealm.importFrom( extensionRealm, export );
+                for (String export : exports) {
+                    projectRealm.importFrom(extensionRealm, export);
                 }
             }
 
             DependencyFilter extensionArtifactFilter = null;
-            if ( !exclusions.isEmpty() )
-            {
-                extensionArtifactFilter = new ExclusionsDependencyFilter( exclusions );
+            if (!exclusions.isEmpty()) {
+                extensionArtifactFilter = new ExclusionsDependencyFilter(exclusions);
             }
 
-            record = projectRealmCache.put( projectRealmKey, projectRealm, extensionArtifactFilter );
+            record = projectRealmCache.put(projectRealmKey, projectRealm, extensionArtifactFilter);
         }
 
-        projectRealmCache.register( project, projectRealmKey, record );
+        projectRealmCache.register(project, projectRealmKey, record);
 
         return record;
     }
 
-    public void selectProjectRealm( MavenProject project )
-    {
+    public void selectProjectRealm(MavenProject project) {
         ClassLoader projectRealm = project.getClassRealm();
 
-        if ( projectRealm == null )
-        {
+        if (projectRealm == null) {
             projectRealm = classRealmManager.getCoreRealm();
         }
 
-        Thread.currentThread().setContextClassLoader( projectRealm );
+        Thread.currentThread().setContextClassLoader(projectRealm);
     }
 
-    private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts( final List<Artifact> pluginArtifacts )
-    {
-        return new ArrayList<>( RepositoryUtils.toArtifacts( pluginArtifacts ) );
+    private List<org.eclipse.aether.artifact.Artifact> toAetherArtifacts(final List<Artifact> pluginArtifacts) {
+        return new ArrayList<>(RepositoryUtils.toArtifacts(pluginArtifacts));
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java
index 39ccf96..8f18435 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.ArrayList;
 import java.util.Date;
@@ -34,9 +33,7 @@
 /**
  * DefaultProjectBuildingRequest
  */
-public class DefaultProjectBuildingRequest
-    implements ProjectBuildingRequest
-{
+public class DefaultProjectBuildingRequest implements ProjectBuildingRequest {
 
     private RepositorySystemSession repositorySession;
 
@@ -71,8 +68,7 @@
 
     private RepositoryMerging repositoryMerging = RepositoryMerging.POM_DOMINANT;
 
-    public DefaultProjectBuildingRequest()
-    {
+    public DefaultProjectBuildingRequest() {
         processPlugins = true;
         profiles = new ArrayList<>();
         activeProfileIds = new ArrayList<>();
@@ -83,144 +79,115 @@
         pluginArtifactRepositories = new ArrayList<>();
     }
 
-    public DefaultProjectBuildingRequest( ProjectBuildingRequest request )
-    {
+    public DefaultProjectBuildingRequest(ProjectBuildingRequest request) {
         this();
-        setProcessPlugins( request.isProcessPlugins() );
-        setProfiles( request.getProfiles() );
-        setActiveProfileIds( request.getActiveProfileIds() );
-        setInactiveProfileIds( request.getInactiveProfileIds() );
-        setSystemProperties( request.getSystemProperties() );
-        setUserProperties( request.getUserProperties() );
-        setRemoteRepositories( request.getRemoteRepositories() );
-        setPluginArtifactRepositories( request.getPluginArtifactRepositories() );
-        setRepositorySession( request.getRepositorySession() );
-        setLocalRepository( request.getLocalRepository() );
-        setBuildStartTime( request.getBuildStartTime() );
-        setProject( request.getProject() );
-        setResolveDependencies( request.isResolveDependencies() );
-        setValidationLevel( request.getValidationLevel() );
-        setResolveVersionRanges( request.isResolveVersionRanges() );
-        setRepositoryMerging( request.getRepositoryMerging() );
+        setProcessPlugins(request.isProcessPlugins());
+        setProfiles(request.getProfiles());
+        setActiveProfileIds(request.getActiveProfileIds());
+        setInactiveProfileIds(request.getInactiveProfileIds());
+        setSystemProperties(request.getSystemProperties());
+        setUserProperties(request.getUserProperties());
+        setRemoteRepositories(request.getRemoteRepositories());
+        setPluginArtifactRepositories(request.getPluginArtifactRepositories());
+        setRepositorySession(request.getRepositorySession());
+        setLocalRepository(request.getLocalRepository());
+        setBuildStartTime(request.getBuildStartTime());
+        setProject(request.getProject());
+        setResolveDependencies(request.isResolveDependencies());
+        setValidationLevel(request.getValidationLevel());
+        setResolveVersionRanges(request.isResolveVersionRanges());
+        setRepositoryMerging(request.getRepositoryMerging());
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public void setProject( MavenProject mavenProject )
-    {
+    public void setProject(MavenProject mavenProject) {
         this.project = mavenProject;
     }
 
-    public ProjectBuildingRequest setLocalRepository( ArtifactRepository localRepository )
-    {
+    public ProjectBuildingRequest setLocalRepository(ArtifactRepository localRepository) {
         this.localRepository = localRepository;
         return this;
     }
 
-    public ArtifactRepository getLocalRepository()
-    {
+    public ArtifactRepository getLocalRepository() {
         return localRepository;
     }
 
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
+    public List<ArtifactRepository> getRemoteRepositories() {
         return remoteRepositories;
     }
 
-    public ProjectBuildingRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
-    {
-        if ( remoteRepositories != null )
-        {
-            this.remoteRepositories = new ArrayList<>( remoteRepositories );
-        }
-        else
-        {
+    public ProjectBuildingRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories) {
+        if (remoteRepositories != null) {
+            this.remoteRepositories = new ArrayList<>(remoteRepositories);
+        } else {
             this.remoteRepositories.clear();
         }
 
         return this;
     }
 
-    public List<ArtifactRepository> getPluginArtifactRepositories()
-    {
+    public List<ArtifactRepository> getPluginArtifactRepositories() {
         return pluginArtifactRepositories;
     }
 
-    public ProjectBuildingRequest setPluginArtifactRepositories( List<ArtifactRepository> pluginArtifactRepositories )
-    {
-        if ( pluginArtifactRepositories != null )
-        {
-            this.pluginArtifactRepositories = new ArrayList<>( pluginArtifactRepositories );
-        }
-        else
-        {
+    public ProjectBuildingRequest setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories) {
+        if (pluginArtifactRepositories != null) {
+            this.pluginArtifactRepositories = new ArrayList<>(pluginArtifactRepositories);
+        } else {
             this.pluginArtifactRepositories.clear();
         }
 
         return this;
     }
 
-    public Properties getSystemProperties()
-    {
+    public Properties getSystemProperties() {
         return systemProperties;
     }
 
-    public ProjectBuildingRequest setSystemProperties( Properties systemProperties )
-    {
-        if ( systemProperties != null )
-        {
-            this.systemProperties = SystemProperties.copyProperties( systemProperties );
-        }
-        else
-        {
+    public ProjectBuildingRequest setSystemProperties(Properties systemProperties) {
+        if (systemProperties != null) {
+            this.systemProperties = SystemProperties.copyProperties(systemProperties);
+        } else {
             this.systemProperties.clear();
         }
 
         return this;
     }
 
-    public Properties getUserProperties()
-    {
+    public Properties getUserProperties() {
         return userProperties;
     }
 
-    public ProjectBuildingRequest setUserProperties( Properties userProperties )
-    {
-        if ( userProperties != null )
-        {
+    public ProjectBuildingRequest setUserProperties(Properties userProperties) {
+        if (userProperties != null) {
             this.userProperties = new Properties();
-            this.userProperties.putAll( userProperties );
-        }
-        else
-        {
+            this.userProperties.putAll(userProperties);
+        } else {
             this.userProperties.clear();
         }
 
         return this;
     }
 
-    public boolean isProcessPlugins()
-    {
+    public boolean isProcessPlugins() {
         return processPlugins;
     }
 
-    public ProjectBuildingRequest setProcessPlugins( boolean processPlugins )
-    {
+    public ProjectBuildingRequest setProcessPlugins(boolean processPlugins) {
         this.processPlugins = processPlugins;
         return this;
     }
 
-    public ProjectBuildingRequest setResolveDependencies( boolean resolveDependencies )
-    {
+    public ProjectBuildingRequest setResolveDependencies(boolean resolveDependencies) {
         this.resolveDependencies = resolveDependencies;
         return this;
     }
 
-    public boolean isResolveDependencies()
-    {
+    public boolean isResolveDependencies() {
         return resolveDependencies;
     }
 
@@ -230,8 +197,7 @@
      * Commit 6cf9320942c34bc68205425ab696b1712ace9ba4 updated the way 'MavenProject' objects are initialized.
      */
     @Deprecated
-    public ProjectBuildingRequest setResolveVersionRanges( boolean value )
-    {
+    public ProjectBuildingRequest setResolveVersionRanges(boolean value) {
         this.resolveVersionRanges = value;
         return this;
     }
@@ -242,108 +208,82 @@
      * Commit 6cf9320942c34bc68205425ab696b1712ace9ba4 updated the way 'MavenProject' objects are initialized.
      */
     @Deprecated
-    public boolean isResolveVersionRanges()
-    {
+    public boolean isResolveVersionRanges() {
         return this.resolveVersionRanges;
     }
 
-    public ProjectBuildingRequest setValidationLevel( int validationLevel )
-    {
+    public ProjectBuildingRequest setValidationLevel(int validationLevel) {
         this.validationLevel = validationLevel;
         return this;
     }
 
-    public int getValidationLevel()
-    {
+    public int getValidationLevel() {
         return validationLevel;
     }
 
-    public List<String> getActiveProfileIds()
-    {
+    public List<String> getActiveProfileIds() {
         return activeProfileIds;
     }
 
-    public void setActiveProfileIds( List<String> activeProfileIds )
-    {
-        if ( activeProfileIds != null )
-        {
-            this.activeProfileIds = new ArrayList<>( activeProfileIds );
-        }
-        else
-        {
+    public void setActiveProfileIds(List<String> activeProfileIds) {
+        if (activeProfileIds != null) {
+            this.activeProfileIds = new ArrayList<>(activeProfileIds);
+        } else {
             this.activeProfileIds.clear();
         }
     }
 
-    public List<String> getInactiveProfileIds()
-    {
+    public List<String> getInactiveProfileIds() {
         return inactiveProfileIds;
     }
 
-    public void setInactiveProfileIds( List<String> inactiveProfileIds )
-    {
-        if ( inactiveProfileIds != null )
-        {
-            this.inactiveProfileIds = new ArrayList<>( inactiveProfileIds );
-        }
-        else
-        {
+    public void setInactiveProfileIds(List<String> inactiveProfileIds) {
+        if (inactiveProfileIds != null) {
+            this.inactiveProfileIds = new ArrayList<>(inactiveProfileIds);
+        } else {
             this.inactiveProfileIds.clear();
         }
     }
 
-    public void setProfiles( List<Profile> profiles )
-    {
-        if ( profiles != null )
-        {
-            this.profiles = new ArrayList<>( profiles );
-        }
-        else
-        {
+    public void setProfiles(List<Profile> profiles) {
+        if (profiles != null) {
+            this.profiles = new ArrayList<>(profiles);
+        } else {
             this.profiles.clear();
         }
     }
 
-    public void addProfile( Profile profile )
-    {
-        profiles.add( profile );
+    public void addProfile(Profile profile) {
+        profiles.add(profile);
     }
 
-    public List<Profile> getProfiles()
-    {
+    public List<Profile> getProfiles() {
         return profiles;
     }
 
-    public Date getBuildStartTime()
-    {
+    public Date getBuildStartTime() {
         return buildStartTime;
     }
 
-    public void setBuildStartTime( Date buildStartTime )
-    {
+    public void setBuildStartTime(Date buildStartTime) {
         this.buildStartTime = buildStartTime;
     }
 
-    public RepositorySystemSession getRepositorySession()
-    {
+    public RepositorySystemSession getRepositorySession() {
         return repositorySession;
     }
 
-    public DefaultProjectBuildingRequest setRepositorySession( RepositorySystemSession repositorySession )
-    {
+    public DefaultProjectBuildingRequest setRepositorySession(RepositorySystemSession repositorySession) {
         this.repositorySession = repositorySession;
         return this;
     }
 
-    public DefaultProjectBuildingRequest setRepositoryMerging( RepositoryMerging repositoryMerging )
-    {
-        this.repositoryMerging = Objects.requireNonNull( repositoryMerging, "repositoryMerging cannot be null" );
+    public DefaultProjectBuildingRequest setRepositoryMerging(RepositoryMerging repositoryMerging) {
+        this.repositoryMerging = Objects.requireNonNull(repositoryMerging, "repositoryMerging cannot be null");
         return this;
     }
 
-    public RepositoryMerging getRepositoryMerging()
-    {
+    public RepositoryMerging getRepositoryMerging() {
         return repositoryMerging;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingResult.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingResult.java
index bcc6b4f..65bc41b 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingResult.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
-import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.maven.model.building.ModelProblem;
@@ -28,21 +27,18 @@
 /**
  * Collects the output of the project builder.
  *
- * @author Benjamin Bentmann
  */
-class DefaultProjectBuildingResult
-    implements ProjectBuildingResult
-{
+class DefaultProjectBuildingResult implements ProjectBuildingResult {
 
-    private String projectId;
+    private final String projectId;
 
-    private File pomFile;
+    private final File pomFile;
 
-    private MavenProject project;
+    private final MavenProject project;
 
-    private List<ModelProblem> problems;
+    private final List<ModelProblem> problems;
 
-    private DependencyResolutionResult dependencyResolutionResult;
+    private final DependencyResolutionResult dependencyResolutionResult;
 
     /**
      * Creates a new result with the specified contents.
@@ -51,15 +47,14 @@
      * @param problems The problems that were encountered, may be {@code null}.
      * @param dependencyResolutionResult The result of the resolution for the project dependencies, may be {@code null}.
      */
-    DefaultProjectBuildingResult( MavenProject project, List<ModelProblem> problems,
-                                  DependencyResolutionResult dependencyResolutionResult )
-    {
-        this.projectId =
-            ( project != null ) ? project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion()
-                            : "";
-        this.pomFile = ( project != null ) ? project.getFile() : null;
+    DefaultProjectBuildingResult(
+            MavenProject project, List<ModelProblem> problems, DependencyResolutionResult dependencyResolutionResult) {
+        this.projectId = (project != null)
+                ? project.getGroupId() + ':' + project.getArtifactId() + ':' + project.getVersion()
+                : "";
+        this.pomFile = (project != null) ? project.getFile() : null;
         this.project = project;
-        this.problems = problems;
+        this.problems = problems != null ? problems : Collections.emptyList();
         this.dependencyResolutionResult = dependencyResolutionResult;
     }
 
@@ -70,41 +65,31 @@
      * @param pomFile The POM file from which the project was built, may be {@code null}.
      * @param problems The problems that were encountered, may be {@code null}.
      */
-    DefaultProjectBuildingResult( String projectId, File pomFile, List<ModelProblem> problems )
-    {
-        this.projectId = ( projectId != null ) ? projectId : "";
+    DefaultProjectBuildingResult(String projectId, File pomFile, List<ModelProblem> problems) {
+        this.projectId = (projectId != null) ? projectId : "";
         this.pomFile = pomFile;
-        this.problems = problems;
+        this.project = null;
+        this.problems = problems != null ? problems : Collections.emptyList();
+        this.dependencyResolutionResult = null;
     }
 
-    public String getProjectId()
-    {
+    public String getProjectId() {
         return projectId;
     }
 
-    public File getPomFile()
-    {
+    public File getPomFile() {
         return pomFile;
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public List<ModelProblem> getProblems()
-    {
-        if ( problems == null )
-        {
-            problems = new ArrayList<>();
-        }
-
+    public List<ModelProblem> getProblems() {
         return problems;
     }
 
-    public DependencyResolutionResult getDependencyResolutionResult()
-    {
+    public DependencyResolutionResult getDependencyResolutionResult() {
         return dependencyResolutionResult;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java
index c20b9aa..202fc4b 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectDependenciesResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Collection;
 import java.util.HashMap;
@@ -25,16 +28,11 @@
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.model.Exclusion;
-import org.codehaus.plexus.util.StringUtils;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
@@ -55,30 +53,24 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultProjectDependenciesResolver
-    implements ProjectDependenciesResolver
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class DefaultProjectDependenciesResolver implements ProjectDependenciesResolver {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
     private final RepositorySystem repoSystem;
     private final List<RepositorySessionDecorator> decorators;
 
     @Inject
     public DefaultProjectDependenciesResolver(
-            RepositorySystem repoSystem,
-            List<RepositorySessionDecorator> decorators )
-    {
+            RepositorySystem repoSystem, List<RepositorySessionDecorator> decorators) {
         this.repoSystem = repoSystem;
         this.decorators = decorators;
     }
 
-    public DependencyResolutionResult resolve( DependencyResolutionRequest request )
-        throws DependencyResolutionException
-    {
-        final RequestTrace trace = RequestTrace.newChild( null, request );
+    public DependencyResolutionResult resolve(DependencyResolutionRequest request)
+            throws DependencyResolutionException {
+        final RequestTrace trace = RequestTrace.newChild(null, request);
 
         final DefaultDependencyResolutionResult result = new DefaultDependencyResolutionResult();
 
@@ -87,261 +79,217 @@
         RepositorySystemSession session = request.getRepositorySession();
         ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
 
-        if ( logger.isDebugEnabled()
-            && session.getConfigProperties().get( DependencyManagerUtils.CONFIG_PROP_VERBOSE ) == null )
-        {
-            DefaultRepositorySystemSession verbose = new DefaultRepositorySystemSession( session );
-            verbose.setConfigProperty( DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE );
+        if (logger.isDebugEnabled()
+                && session.getConfigProperties().get(DependencyManagerUtils.CONFIG_PROP_VERBOSE) == null) {
+            DefaultRepositorySystemSession verbose = new DefaultRepositorySystemSession(session);
+            verbose.setConfigProperty(DependencyManagerUtils.CONFIG_PROP_VERBOSE, Boolean.TRUE);
             session = verbose;
         }
 
-        for ( RepositorySessionDecorator decorator : decorators )
-        {
-            RepositorySystemSession decorated = decorator.decorate( project, session );
-            if ( decorated != null )
-            {
+        for (RepositorySessionDecorator decorator : decorators) {
+            RepositorySystemSession decorated = decorator.decorate(project, session);
+            if (decorated != null) {
                 session = decorated;
             }
         }
 
         CollectRequest collect = new CollectRequest();
-        collect.setRootArtifact( RepositoryUtils.toArtifact( project.getArtifact() ) );
-        collect.setRequestContext( "project" );
-        collect.setRepositories( project.getRemoteProjectRepositories() );
+        collect.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
+        collect.setRequestContext("project");
+        collect.setRepositories(project.getRemoteProjectRepositories());
 
-        if ( project.getDependencyArtifacts() == null )
-        {
-            for ( Dependency dependency : project.getDependencies() )
-            {
-                if ( StringUtils.isEmpty( dependency.getGroupId() ) || StringUtils.isEmpty( dependency.getArtifactId() )
-                    || StringUtils.isEmpty( dependency.getVersion() ) )
-                {
+        if (project.getDependencyArtifacts() == null) {
+            for (Dependency dependency : project.getDependencies()) {
+                if (dependency.getGroupId() == null
+                        || dependency.getGroupId().isEmpty()
+                        || dependency.getArtifactId() == null
+                        || dependency.getArtifactId().isEmpty()
+                        || dependency.getVersion() == null
+                        || dependency.getVersion().isEmpty()) {
                     // guard against case where best-effort resolution for invalid models is requested
                     continue;
                 }
-                collect.addDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
+                collect.addDependency(RepositoryUtils.toDependency(dependency, stereotypes));
             }
-        }
-        else
-        {
+        } else {
             Map<String, Dependency> dependencies = new HashMap<>();
-            for ( Dependency dependency : project.getDependencies() )
-            {
+            for (Dependency dependency : project.getDependencies()) {
                 String classifier = dependency.getClassifier();
-                if ( classifier == null )
-                {
-                    ArtifactType type = stereotypes.get( dependency.getType() );
-                    if ( type != null )
-                    {
+                if (classifier == null) {
+                    ArtifactType type = stereotypes.get(dependency.getType());
+                    if (type != null) {
                         classifier = type.getClassifier();
                     }
                 }
-                String key =
-                    ArtifactIdUtils.toVersionlessId( dependency.getGroupId(), dependency.getArtifactId(),
-                                                    dependency.getType(), classifier );
-                dependencies.put( key, dependency );
+                String key = ArtifactIdUtils.toVersionlessId(
+                        dependency.getGroupId(), dependency.getArtifactId(), dependency.getType(), classifier);
+                dependencies.put(key, dependency);
             }
-            for ( Artifact artifact : project.getDependencyArtifacts() )
-            {
+            for (Artifact artifact : project.getDependencyArtifacts()) {
                 String key = artifact.getDependencyConflictId();
-                Dependency dependency = dependencies.get( key );
+                Dependency dependency = dependencies.get(key);
                 Collection<Exclusion> exclusions = dependency != null ? dependency.getExclusions() : null;
-                org.eclipse.aether.graph.Dependency dep = RepositoryUtils.toDependency( artifact, exclusions );
-                if ( !JavaScopes.SYSTEM.equals( dep.getScope() ) && dep.getArtifact().getFile() != null )
-                {
+                org.eclipse.aether.graph.Dependency dep = RepositoryUtils.toDependency(artifact, exclusions);
+                if (!JavaScopes.SYSTEM.equals(dep.getScope())
+                        && dep.getArtifact().getFile() != null) {
                     // enable re-resolution
                     org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
-                    art = art.setFile( null ).setVersion( art.getBaseVersion() );
-                    dep = dep.setArtifact( art );
+                    art = art.setFile(null).setVersion(art.getBaseVersion());
+                    dep = dep.setArtifact(art);
                 }
-                collect.addDependency( dep );
+                collect.addDependency(dep);
             }
         }
 
         DependencyManagement depMgmt = project.getDependencyManagement();
-        if ( depMgmt != null )
-        {
-            for ( Dependency dependency : depMgmt.getDependencies() )
-            {
-                collect.addManagedDependency( RepositoryUtils.toDependency( dependency, stereotypes ) );
+        if (depMgmt != null) {
+            for (Dependency dependency : depMgmt.getDependencies()) {
+                collect.addManagedDependency(RepositoryUtils.toDependency(dependency, stereotypes));
             }
         }
 
-        DependencyRequest depRequest = new DependencyRequest( collect, filter );
-        depRequest.setTrace( trace );
+        DependencyRequest depRequest = new DependencyRequest(collect, filter);
+        depRequest.setTrace(trace);
 
         DependencyNode node;
-        try
-        {
-            collect.setTrace( RequestTrace.newChild( trace, depRequest ) );
-            node = repoSystem.collectDependencies( session, collect ).getRoot();
-            result.setDependencyGraph( node );
-        }
-        catch ( DependencyCollectionException e )
-        {
-            result.setDependencyGraph( e.getResult().getRoot() );
-            result.setCollectionErrors( e.getResult().getExceptions() );
+        try {
+            collect.setTrace(RequestTrace.newChild(trace, depRequest));
+            node = repoSystem.collectDependencies(session, collect).getRoot();
+            result.setDependencyGraph(node);
+        } catch (DependencyCollectionException e) {
+            result.setDependencyGraph(e.getResult().getRoot());
+            result.setCollectionErrors(e.getResult().getExceptions());
 
-            throw new DependencyResolutionException( result, "Could not resolve dependencies for project "
-                + project.getId() + ": " + e.getMessage(), e );
+            throw new DependencyResolutionException(
+                    result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e);
         }
 
-        depRequest.setRoot( node );
+        depRequest.setRoot(node);
 
-        if ( logger.isWarnEnabled() )
-        {
-            for ( DependencyNode child : node.getChildren() )
-            {
-                if ( !child.getRelocations().isEmpty() )
-                {
-                    org.eclipse.aether.artifact.Artifact relocated = child.getDependency().getArtifact();
+        if (logger.isWarnEnabled()) {
+            for (DependencyNode child : node.getChildren()) {
+                if (!child.getRelocations().isEmpty()) {
+                    org.eclipse.aether.artifact.Artifact relocated =
+                            child.getDependency().getArtifact();
                     String message = relocated instanceof org.apache.maven.repository.internal.RelocatedArtifact
-                            ? ( ( org.apache.maven.repository.internal.RelocatedArtifact ) relocated ).getMessage()
+                            ? ((org.apache.maven.repository.internal.RelocatedArtifact) relocated).getMessage()
                             : null;
-                    logger.warn( "The artifact " + child.getRelocations().get( 0 ) + " has been relocated to "
-                        + relocated + ( message != null ? ": " + message : "" ) );
+                    logger.warn("The artifact " + child.getRelocations().get(0) + " has been relocated to " + relocated
+                            + (message != null ? ": " + message : ""));
                 }
             }
         }
 
-        if ( logger.isDebugEnabled() )
-        {
-            node.accept( new GraphLogger( project ) );
+        if (logger.isDebugEnabled()) {
+            node.accept(new GraphLogger(project));
         }
 
-        try
-        {
-            process( result, repoSystem.resolveDependencies( session, depRequest ).getArtifactResults() );
-        }
-        catch ( org.eclipse.aether.resolution.DependencyResolutionException e )
-        {
-            process( result, e.getResult().getArtifactResults() );
+        try {
+            process(result, repoSystem.resolveDependencies(session, depRequest).getArtifactResults());
+        } catch (org.eclipse.aether.resolution.DependencyResolutionException e) {
+            process(result, e.getResult().getArtifactResults());
 
-            throw new DependencyResolutionException( result, "Could not resolve dependencies for project "
-                + project.getId() + ": " + e.getMessage(), e );
+            throw new DependencyResolutionException(
+                    result, "Could not resolve dependencies for project " + project.getId() + ": " + e.getMessage(), e);
         }
 
         return result;
     }
 
-    private void process( DefaultDependencyResolutionResult result, Collection<ArtifactResult> results )
-    {
-        for ( ArtifactResult ar : results )
-        {
+    private void process(DefaultDependencyResolutionResult result, Collection<ArtifactResult> results) {
+        for (ArtifactResult ar : results) {
             DependencyNode node = ar.getRequest().getDependencyNode();
-            if ( ar.isResolved() )
-            {
-                result.addResolvedDependency( node.getDependency() );
-            }
-            else
-            {
-                result.setResolutionErrors( node.getDependency(), ar.getExceptions() );
+            if (ar.isResolved()) {
+                result.addResolvedDependency(node.getDependency());
+            } else {
+                result.setResolutionErrors(node.getDependency(), ar.getExceptions());
             }
         }
     }
 
     // Keep this class in sync with org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver.GraphLogger
-    class GraphLogger
-        implements DependencyVisitor
-    {
+    class GraphLogger implements DependencyVisitor {
 
         private final MavenProject project;
 
         private String indent = "";
 
-        GraphLogger( MavenProject project )
-        {
+        GraphLogger(MavenProject project) {
             this.project = project;
         }
 
-        public boolean visitEnter( DependencyNode node )
-        {
-            StringBuilder buffer = new StringBuilder( 128 );
-            buffer.append( indent );
+        public boolean visitEnter(DependencyNode node) {
+            StringBuilder buffer = new StringBuilder(128);
+            buffer.append(indent);
             org.eclipse.aether.graph.Dependency dep = node.getDependency();
-            if ( dep != null )
-            {
+            if (dep != null) {
                 org.eclipse.aether.artifact.Artifact art = dep.getArtifact();
 
-                buffer.append( art );
-                if ( StringUtils.isNotEmpty( dep.getScope() ) )
-                {
-                    buffer.append( ':' ).append( dep.getScope() );
+                buffer.append(art);
+                if (dep.getScope() != null && !dep.getScope().isEmpty()) {
+                    buffer.append(':').append(dep.getScope());
                 }
 
-                if ( dep.isOptional() )
-                {
-                    buffer.append( " (optional)" );
+                if (dep.isOptional()) {
+                    buffer.append(" (optional)");
                 }
 
                 // TODO We currently cannot tell which <dependencyManagement> section contained the management
                 //      information. When the resolver provides this information, these log messages should be updated
                 //      to contain it.
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_SCOPE ) == DependencyNode.MANAGED_SCOPE )
-                {
-                    final String premanagedScope = DependencyManagerUtils.getPremanagedScope( node );
-                    buffer.append( " (scope managed from " );
-                    buffer.append( Objects.toString( premanagedScope, "default" ) );
-                    buffer.append( ')' );
+                if ((node.getManagedBits() & DependencyNode.MANAGED_SCOPE) == DependencyNode.MANAGED_SCOPE) {
+                    final String premanagedScope = DependencyManagerUtils.getPremanagedScope(node);
+                    buffer.append(" (scope managed from ");
+                    buffer.append(Objects.toString(premanagedScope, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_VERSION ) == DependencyNode.MANAGED_VERSION )
-                {
-                    final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion( node );
-                    buffer.append( " (version managed from " );
-                    buffer.append( Objects.toString( premanagedVersion, "default" ) );
-                    buffer.append( ')' );
+                if ((node.getManagedBits() & DependencyNode.MANAGED_VERSION) == DependencyNode.MANAGED_VERSION) {
+                    final String premanagedVersion = DependencyManagerUtils.getPremanagedVersion(node);
+                    buffer.append(" (version managed from ");
+                    buffer.append(Objects.toString(premanagedVersion, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL ) == DependencyNode.MANAGED_OPTIONAL )
-                {
-                    final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional( node );
-                    buffer.append( " (optionality managed from " );
-                    buffer.append( Objects.toString( premanagedOptional, "default" ) );
-                    buffer.append( ')' );
+                if ((node.getManagedBits() & DependencyNode.MANAGED_OPTIONAL) == DependencyNode.MANAGED_OPTIONAL) {
+                    final Boolean premanagedOptional = DependencyManagerUtils.getPremanagedOptional(node);
+                    buffer.append(" (optionality managed from ");
+                    buffer.append(Objects.toString(premanagedOptional, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS )
-                         == DependencyNode.MANAGED_EXCLUSIONS )
-                {
+                if ((node.getManagedBits() & DependencyNode.MANAGED_EXCLUSIONS) == DependencyNode.MANAGED_EXCLUSIONS) {
                     final Collection<org.eclipse.aether.graph.Exclusion> premanagedExclusions =
-                        DependencyManagerUtils.getPremanagedExclusions( node );
+                            DependencyManagerUtils.getPremanagedExclusions(node);
 
-                    buffer.append( " (exclusions managed from " );
-                    buffer.append( Objects.toString( premanagedExclusions, "default" ) );
-                    buffer.append( ')' );
+                    buffer.append(" (exclusions managed from ");
+                    buffer.append(Objects.toString(premanagedExclusions, "default"));
+                    buffer.append(')');
                 }
 
-                if ( ( node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES )
-                         == DependencyNode.MANAGED_PROPERTIES )
-                {
+                if ((node.getManagedBits() & DependencyNode.MANAGED_PROPERTIES) == DependencyNode.MANAGED_PROPERTIES) {
                     final Map<String, String> premanagedProperties =
-                        DependencyManagerUtils.getPremanagedProperties( node );
+                            DependencyManagerUtils.getPremanagedProperties(node);
 
-                    buffer.append( " (properties managed from " );
-                    buffer.append( Objects.toString( premanagedProperties, "default" ) );
-                    buffer.append( ')' );
+                    buffer.append(" (properties managed from ");
+                    buffer.append(Objects.toString(premanagedProperties, "default"));
+                    buffer.append(')');
                 }
-            }
-            else
-            {
-                buffer.append( project.getGroupId() );
-                buffer.append( ':' ).append( project.getArtifactId() );
-                buffer.append( ':' ).append( project.getPackaging() );
-                buffer.append( ':' ).append( project.getVersion() );
+            } else {
+                buffer.append(project.getGroupId());
+                buffer.append(':').append(project.getArtifactId());
+                buffer.append(':').append(project.getPackaging());
+                buffer.append(':').append(project.getVersion());
             }
 
-            logger.debug( buffer.toString() );
+            logger.debug(buffer.toString());
             indent += "   ";
             return true;
         }
 
-        public boolean visitLeave( DependencyNode node )
-        {
-            indent = indent.substring( 0, indent.length() - 3 );
+        public boolean visitLeave(DependencyNode node) {
+            indent = indent.substring(0, indent.length() - 3);
             return true;
         }
-
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java
index d67e5a6..eff2288 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DefaultProjectRealmCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.Collections;
 import java.util.List;
@@ -25,9 +27,6 @@
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
@@ -38,56 +37,45 @@
  */
 @Named
 @Singleton
-public class DefaultProjectRealmCache
-    implements ProjectRealmCache, Disposable
-{
+public class DefaultProjectRealmCache implements ProjectRealmCache, Disposable {
     /**
      * CacheKey
      */
-    protected static class CacheKey
-        implements Key
-    {
+    protected static class CacheKey implements Key {
 
         private final List<? extends ClassRealm> extensionRealms;
 
         private final int hashCode;
 
-        public CacheKey( List<? extends ClassRealm> extensionRealms )
-        {
-            this.extensionRealms = ( extensionRealms != null )
-                                       ? Collections.unmodifiableList( extensionRealms )
-                                       : Collections.emptyList();
+        public CacheKey(List<? extends ClassRealm> extensionRealms) {
+            this.extensionRealms =
+                    (extensionRealms != null) ? Collections.unmodifiableList(extensionRealms) : Collections.emptyList();
 
             this.hashCode = this.extensionRealms.hashCode();
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( o == this )
-            {
+        public boolean equals(Object o) {
+            if (o == this) {
                 return true;
             }
 
-            if ( !( o instanceof CacheKey ) )
-            {
+            if (!(o instanceof CacheKey)) {
                 return false;
             }
 
             CacheKey other = (CacheKey) o;
 
-            return extensionRealms.equals( other.extensionRealms );
+            return extensionRealms.equals(other.extensionRealms);
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return extensionRealms.toString();
         }
     }
@@ -95,58 +83,46 @@
     protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
 
     @Override
-    public Key createKey( List<? extends ClassRealm> extensionRealms )
-    {
-        return new CacheKey( extensionRealms );
+    public Key createKey(List<? extends ClassRealm> extensionRealms) {
+        return new CacheKey(extensionRealms);
     }
 
-    public CacheRecord get( Key key )
-    {
-        return cache.get( key );
+    public CacheRecord get(Key key) {
+        return cache.get(key);
     }
 
-    public CacheRecord put( Key key, ClassRealm projectRealm, DependencyFilter extensionArtifactFilter )
-    {
-        Objects.requireNonNull( projectRealm, "projectRealm cannot be null" );
+    public CacheRecord put(Key key, ClassRealm projectRealm, DependencyFilter extensionArtifactFilter) {
+        Objects.requireNonNull(projectRealm, "projectRealm cannot be null");
 
-        if ( cache.containsKey( key ) )
-        {
-            throw new IllegalStateException( "Duplicate project realm for extensions " + key );
+        if (cache.containsKey(key)) {
+            throw new IllegalStateException("Duplicate project realm for extensions " + key);
         }
 
-        CacheRecord record = new CacheRecord( projectRealm, extensionArtifactFilter );
+        CacheRecord record = new CacheRecord(projectRealm, extensionArtifactFilter);
 
-        cache.put( key, record );
+        cache.put(key, record);
 
         return record;
     }
 
-    public void flush()
-    {
-        for ( CacheRecord record : cache.values() )
-        {
+    public void flush() {
+        for (CacheRecord record : cache.values()) {
             ClassRealm realm = record.getRealm();
-            try
-            {
-                realm.getWorld().disposeRealm( realm.getId() );
-            }
-            catch ( NoSuchRealmException e )
-            {
+            try {
+                realm.getWorld().disposeRealm(realm.getId());
+            } catch (NoSuchRealmException e) {
                 // ignore
             }
         }
         cache.clear();
     }
 
-    public void register( MavenProject project, Key key, CacheRecord record )
-    {
+    public void register(MavenProject project, Key key, CacheRecord record) {
         // default cache does not track record usage
     }
 
     @Override
-    public void dispose()
-    {
+    public void dispose() {
         flush();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java
index ecd0151..794986b 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,25 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 /**
- * @author Benjamin Bentmann
  */
-public class DependencyResolutionException
-    extends Exception
-{
+public class DependencyResolutionException extends Exception {
 
     private final transient DependencyResolutionResult result;
 
-    public DependencyResolutionException( DependencyResolutionResult result, String message, Throwable cause )
-    {
-        super( message, cause );
+    public DependencyResolutionException(DependencyResolutionResult result, String message, Throwable cause) {
+        super(message, cause);
         this.result = result;
     }
 
-    public DependencyResolutionResult getResult()
-    {
+    public DependencyResolutionResult getResult() {
         return result;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionRequest.java b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionRequest.java
index c120a13..6388adf 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.graph.DependencyFilter;
@@ -25,10 +24,8 @@
 /**
  * A request to resolve the dependencies of a project.
  *
- * @author Benjamin Bentmann
  */
-public interface DependencyResolutionRequest
-{
+public interface DependencyResolutionRequest {
 
     /**
      * Gets the project to resolve dependencies for.
@@ -43,7 +40,7 @@
      * @param project The project to resolve dependencies for, may be {@code null}.
      * @return This request for chaining, never {@code null}.
      */
-    DependencyResolutionRequest setMavenProject( MavenProject project );
+    DependencyResolutionRequest setMavenProject(MavenProject project);
 
     /**
      * Gets the filter used to exclude some dependencies from resolution.
@@ -61,7 +58,7 @@
      *            dependencies.
      * @return This request for chaining, never {@code null}.
      */
-    DependencyResolutionRequest setResolutionFilter( DependencyFilter filter );
+    DependencyResolutionRequest setResolutionFilter(DependencyFilter filter);
 
     /**
      * Gets the session to use for repository access.
@@ -76,6 +73,5 @@
      * @param repositorySession The repository session to use.
      * @return This request for chaining, never {@code null}.
      */
-    DependencyResolutionRequest setRepositorySession( RepositorySystemSession repositorySession );
-
+    DependencyResolutionRequest setRepositorySession(RepositorySystemSession repositorySession);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionResult.java b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionResult.java
index 6ad55fa..ce02b39 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionResult.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DependencyResolutionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.List;
 
@@ -27,10 +26,8 @@
 /**
  * The result of a project dependency resolution.
  *
- * @author Benjamin Bentmann
  */
-public interface DependencyResolutionResult
-{
+public interface DependencyResolutionResult {
 
     /**
      * Gets the dependency graph of the project.
@@ -75,6 +72,5 @@
      * @param dependency The dependency for which to retrieve the errors, must not be {@code null}.
      * @return The resolution errors for the specified dependency, never {@code null}.
      */
-    List<Exception> getResolutionErrors( Dependency dependency );
-
+    List<Exception> getResolutionErrors(Dependency dependency);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DuplicateArtifactAttachmentException.java b/maven-core/src/main/java/org/apache/maven/project/DuplicateArtifactAttachmentException.java
index d263c28..e963a32 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DuplicateArtifactAttachmentException.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DuplicateArtifactAttachmentException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import org.apache.maven.artifact.Artifact;
 
@@ -25,14 +24,10 @@
  * This exception is thrown if an application attempts to attach
  * two of the same artifacts to a single project.
  *
- * @author pgier
- * @author jdcasey
  * TODO Make this a checked exception, and modify the API of MavenProjectHelper.
  * Currently, this modification would create compatibility problems for existing plugins.
  */
-public class DuplicateArtifactAttachmentException
-    extends RuntimeException
-{
+public class DuplicateArtifactAttachmentException extends RuntimeException {
 
     private static final String DEFAULT_MESSAGE = "Duplicate artifact attachment detected.";
 
@@ -40,25 +35,21 @@
 
     private final MavenProject project;
 
-    public DuplicateArtifactAttachmentException( MavenProject project, Artifact artifact )
-    {
-        super( constructMessage( project, artifact ) );
+    public DuplicateArtifactAttachmentException(MavenProject project, Artifact artifact) {
+        super(constructMessage(project, artifact));
         this.project = project;
         this.artifact = artifact;
     }
 
-    private static String constructMessage( MavenProject project, Artifact artifact )
-    {
+    private static String constructMessage(MavenProject project, Artifact artifact) {
         return DEFAULT_MESSAGE + " (project: " + project.getId() + "; illegal attachment: " + artifact.getId() + ")";
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public Artifact getArtifact()
-    {
+    public Artifact getArtifact() {
         return artifact;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/DuplicateProjectException.java b/maven-core/src/main/java/org/apache/maven/project/DuplicateProjectException.java
index f73c46b..6b32191 100644
--- a/maven-core/src/main/java/org/apache/maven/project/DuplicateProjectException.java
+++ b/maven-core/src/main/java/org/apache/maven/project/DuplicateProjectException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 
 /**
  * Exception that occurs when the project list contains duplicate projects instead of ignoring one.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class DuplicateProjectException
-    extends Exception
-{
+public class DuplicateProjectException extends Exception {
     private final String projectId;
 
     private final File existingProjectFile;
@@ -38,43 +34,39 @@
     /**
      * @deprecated use {@link #DuplicateProjectException(String, File, File, String)}
      */
-    public DuplicateProjectException( String message )
-    {
-        this( null, null, null, message );
+    @Deprecated
+    public DuplicateProjectException(String message) {
+        this(null, null, null, message);
     }
 
     /**
      * @deprecated use {@link #DuplicateProjectException(String, File, File, String)}
      */
-    public DuplicateProjectException( String message, Exception e )
-    {
-        super( message, e );
+    @Deprecated
+    public DuplicateProjectException(String message, Exception e) {
+        super(message, e);
         this.projectId = null;
         this.existingProjectFile = null;
         this.conflictingProjectFile = null;
     }
 
-    public DuplicateProjectException( String projectId, File existingProjectFile, File conflictingProjectFile,
-                                      String message )
-    {
-        super( message );
+    public DuplicateProjectException(
+            String projectId, File existingProjectFile, File conflictingProjectFile, String message) {
+        super(message);
         this.projectId = projectId;
         this.existingProjectFile = existingProjectFile;
         this.conflictingProjectFile = conflictingProjectFile;
     }
 
-    public String getProjectId()
-    {
+    public String getProjectId() {
         return projectId;
     }
 
-    public File getExistingProjectFile()
-    {
+    public File getExistingProjectFile() {
         return existingProjectFile;
     }
 
-    public File getConflictingProjectFile()
-    {
+    public File getConflictingProjectFile() {
         return conflictingProjectFile;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptor.java b/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptor.java
index 9602c00..525ccdc 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptor.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,62 +26,46 @@
  * public for technical reasons, it is not part of the public API. In particular, this class can be changed or deleted
  * without prior notice.
  *
- * @author Benjamin Bentmann
  */
-public class ExtensionDescriptor
-{
+public class ExtensionDescriptor {
 
     private List<String> exportedPackages;
 
     private List<String> exportedArtifacts;
 
-    ExtensionDescriptor()
-    {
+    ExtensionDescriptor() {
         // hide constructor
     }
 
-    public List<String> getExportedPackages()
-    {
-        if ( exportedPackages == null )
-        {
+    public List<String> getExportedPackages() {
+        if (exportedPackages == null) {
             exportedPackages = new ArrayList<>();
         }
 
         return exportedPackages;
     }
 
-    public void setExportedPackages( List<String> exportedPackages )
-    {
-        if ( exportedPackages == null )
-        {
+    public void setExportedPackages(List<String> exportedPackages) {
+        if (exportedPackages == null) {
             this.exportedPackages = null;
-        }
-        else
-        {
-            this.exportedPackages = new ArrayList<>( exportedPackages );
+        } else {
+            this.exportedPackages = new ArrayList<>(exportedPackages);
         }
     }
 
-    public List<String> getExportedArtifacts()
-    {
-        if ( exportedArtifacts == null )
-        {
+    public List<String> getExportedArtifacts() {
+        if (exportedArtifacts == null) {
             exportedArtifacts = new ArrayList<>();
         }
 
         return exportedArtifacts;
     }
 
-    public void setExportedArtifacts( List<String> exportedArtifacts )
-    {
-        if ( exportedArtifacts == null )
-        {
+    public void setExportedArtifacts(List<String> exportedArtifacts) {
+        if (exportedArtifacts == null) {
             this.exportedArtifacts = null;
-        }
-        else
-        {
-            this.exportedArtifacts = new ArrayList<>( exportedArtifacts );
+        } else {
+            this.exportedArtifacts = new ArrayList<>(exportedArtifacts);
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java b/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java
index 6880e7a..e4d2ef5 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ExtensionDescriptorBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,35 +16,34 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
 
-import java.io.BufferedInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.jar.JarFile;
 import java.util.zip.ZipEntry;
 
+import com.ctc.wstx.stax.WstxInputFactory;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+
 /**
  * Creates an extension descriptor from some XML stream.
  *
- * @author Benjamin Bentmann
  */
-public class ExtensionDescriptorBuilder
-{
+public class ExtensionDescriptorBuilder {
 
     /**
      * @since 3.3.0
      */
-    public String getExtensionDescriptorLocation()
-    {
+    public String getExtensionDescriptorLocation() {
         return "META-INF/maven/extension.xml";
     }
 
@@ -57,35 +54,25 @@
      * @return The extracted descriptor or {@code null} if no descriptor was found.
      * @throws IOException If the descriptor is present but could not be parsed.
      */
-    public ExtensionDescriptor build( File extensionJar )
-        throws IOException
-    {
+    public ExtensionDescriptor build(File extensionJar) throws IOException {
         ExtensionDescriptor extensionDescriptor = null;
 
-        if ( extensionJar.isFile() )
-        {
-            try ( JarFile pluginJar = new JarFile( extensionJar, false ) )
-            {
-                ZipEntry pluginDescriptorEntry = pluginJar.getEntry( getExtensionDescriptorLocation() );
+        if (extensionJar.isFile()) {
+            try (JarFile pluginJar = new JarFile(extensionJar, false)) {
+                ZipEntry pluginDescriptorEntry = pluginJar.getEntry(getExtensionDescriptorLocation());
 
-                if ( pluginDescriptorEntry != null )
-                {
-                    try ( InputStream is = pluginJar.getInputStream( pluginDescriptorEntry ) )
-                    {
-                        extensionDescriptor = build( is );
+                if (pluginDescriptorEntry != null) {
+                    try (InputStream is = pluginJar.getInputStream(pluginDescriptorEntry)) {
+                        extensionDescriptor = build(is);
                     }
                 }
             }
-        }
-        else
-        {
-            File pluginXml = new File( extensionJar, getExtensionDescriptorLocation() );
+        } else {
+            File pluginXml = new File(extensionJar, getExtensionDescriptorLocation());
 
-            if ( pluginXml.canRead() )
-            {
-                try ( InputStream is = new BufferedInputStream( new FileInputStream( pluginXml ) ) )
-                {
-                    extensionDescriptor = build( is );
+            if (pluginXml.canRead()) {
+                try (InputStream is = Files.newInputStream(pluginXml.toPath())) {
+                    extensionDescriptor = build(is);
                 }
             }
         }
@@ -96,50 +83,40 @@
     /**
      * @since 3.3.0
      */
-    public ExtensionDescriptor build( InputStream is )
-        throws IOException
-    {
+    public ExtensionDescriptor build(InputStream is) throws IOException {
         ExtensionDescriptor extensionDescriptor = new ExtensionDescriptor();
 
-        Xpp3Dom dom;
-        try
-        {
-            dom = Xpp3DomBuilder.build( ReaderFactory.newXmlReader( is ) );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new IOException( e.getMessage(), e );
+        XmlNode dom;
+        try {
+            XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(is);
+            dom = XmlNodeBuilder.build(reader);
+        } catch (XMLStreamException e) {
+            throw new IOException(e.getMessage(), e);
         }
 
-        if ( !"extension".equals( dom.getName() ) )
-        {
-            throw new IOException( "Unexpected root element \"" + dom.getName() + "\", expected \"extension\"" );
+        if (!"extension".equals(dom.getName())) {
+            throw new IOException("Unexpected root element \"" + dom.getName() + "\", expected \"extension\"");
         }
 
-        extensionDescriptor.setExportedPackages( parseStrings( dom.getChild( "exportedPackages" ) ) );
+        extensionDescriptor.setExportedPackages(parseStrings(dom.getChild("exportedPackages")));
 
-        extensionDescriptor.setExportedArtifacts( parseStrings( dom.getChild( "exportedArtifacts" ) ) );
+        extensionDescriptor.setExportedArtifacts(parseStrings(dom.getChild("exportedArtifacts")));
 
         return extensionDescriptor;
     }
 
-    private List<String> parseStrings( Xpp3Dom dom )
-    {
+    private List<String> parseStrings(XmlNode dom) {
         List<String> strings = null;
 
-        if ( dom != null )
-        {
+        if (dom != null) {
             strings = new ArrayList<>();
 
-            for ( Xpp3Dom child : dom.getChildren() )
-            {
+            for (XmlNode child : dom.getChildren()) {
                 String string = child.getValue();
-                if ( string != null )
-                {
+                if (string != null) {
                     string = string.trim();
-                    if ( string.length() > 0 )
-                    {
-                        strings.add( string );
+                    if (string.length() > 0) {
+                        strings.add(string);
                     }
                 }
             }
@@ -147,5 +124,4 @@
 
         return strings;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/Graph.java b/maven-core/src/main/java/org/apache/maven/project/Graph.java
new file mode 100644
index 0000000..a0c75cb
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/project/Graph.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project;
+
+import java.util.*;
+
+class Graph {
+    private enum DfsState {
+        VISITING,
+        VISITED
+    }
+
+    final Map<String, Vertex> vertices = new LinkedHashMap<>();
+
+    public Vertex getVertex(String id) {
+        return vertices.get(id);
+    }
+
+    public Collection<Vertex> getVertices() {
+        return vertices.values();
+    }
+
+    Vertex addVertex(String label) {
+        return vertices.computeIfAbsent(label, Vertex::new);
+    }
+
+    void addEdge(Vertex from, Vertex to) throws CycleDetectedException {
+        from.children.add(to);
+        to.parents.add(from);
+        List<String> cycle = findCycle(to);
+        if (cycle != null) {
+            // remove edge which introduced cycle
+            removeEdge(from, to);
+            throw new CycleDetectedException(
+                    "Edge between '" + from.label + "' and '" + to.label + "' introduces to cycle in the graph", cycle);
+        }
+    }
+
+    void removeEdge(Vertex from, Vertex to) {
+        from.children.remove(to);
+        to.parents.remove(from);
+    }
+
+    List<String> visitAll() {
+        return visitAll(vertices.values(), new HashMap<>(), new ArrayList<>());
+    }
+
+    List<String> findCycle(Vertex vertex) {
+        return visitCycle(Collections.singleton(vertex), new HashMap<>(), new LinkedList<>());
+    }
+
+    private static List<String> visitAll(
+            Collection<Vertex> children, Map<Vertex, DfsState> stateMap, List<String> list) {
+        for (Vertex v : children) {
+            DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
+            if (state == null) {
+                visitAll(v.children, stateMap, list);
+                stateMap.put(v, DfsState.VISITED);
+                list.add(v.label);
+            }
+        }
+        return list;
+    }
+
+    private static List<String> visitCycle(
+            Collection<Vertex> children, Map<Vertex, DfsState> stateMap, LinkedList<String> cycle) {
+        for (Vertex v : children) {
+            DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
+            if (state == null) {
+                cycle.addLast(v.label);
+                List<String> ret = visitCycle(v.children, stateMap, cycle);
+                if (ret != null) {
+                    return ret;
+                }
+                cycle.removeLast();
+                stateMap.put(v, DfsState.VISITED);
+            } else if (state == DfsState.VISITING) {
+                // we are already visiting this vertex, this mean we have a cycle
+                int pos = cycle.lastIndexOf(v.label);
+                List<String> ret = cycle.subList(pos, cycle.size());
+                ret.add(v.label);
+                return ret;
+            }
+        }
+        return null;
+    }
+
+    static class Vertex {
+        final String label;
+        final List<Vertex> children = new ArrayList<>();
+        final List<Vertex> parents = new ArrayList<>();
+
+        Vertex(String label) {
+            this.label = label;
+        }
+
+        String getLabel() {
+            return label;
+        }
+
+        List<Vertex> getChildren() {
+            return children;
+        }
+
+        List<Vertex> getParents() {
+            return parents;
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/project/InvalidProjectVersionException.java b/maven-core/src/main/java/org/apache/maven/project/InvalidProjectVersionException.java
index 8080f6e..07613e7 100644
--- a/maven-core/src/main/java/org/apache/maven/project/InvalidProjectVersionException.java
+++ b/maven-core/src/main/java/org/apache/maven/project/InvalidProjectVersionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 
@@ -26,37 +25,37 @@
 /**
  * InvalidProjectVersionException
  */
-public class InvalidProjectVersionException
-    extends ProjectBuildingException
-{
+public class InvalidProjectVersionException extends ProjectBuildingException {
 
     private final String locationInPom;
 
     private final String offendingVersion;
 
-    public InvalidProjectVersionException( String projectId, String locationInPom, String offendingVersion,
-                                           File pomFile, InvalidVersionSpecificationException cause )
-    {
-        super( projectId, formatMessage( projectId, locationInPom, offendingVersion, cause ), pomFile, cause );
+    public InvalidProjectVersionException(
+            String projectId,
+            String locationInPom,
+            String offendingVersion,
+            File pomFile,
+            InvalidVersionSpecificationException cause) {
+        super(projectId, formatMessage(projectId, locationInPom, offendingVersion, cause), pomFile, cause);
         this.locationInPom = locationInPom;
         this.offendingVersion = offendingVersion;
     }
 
-    private static String formatMessage( String projectId, String locationInPom, String offendingVersion,
-                                         InvalidVersionSpecificationException cause )
-    {
+    private static String formatMessage(
+            String projectId,
+            String locationInPom,
+            String offendingVersion,
+            InvalidVersionSpecificationException cause) {
         return "Invalid version: " + offendingVersion + " found for: " + locationInPom + " in project: " + projectId
-            + ". Reason: " + cause.getMessage();
+                + ". Reason: " + cause.getMessage();
     }
 
-    public String getOffendingVersion()
-    {
+    public String getOffendingVersion() {
         return offendingVersion;
     }
 
-    public String getLocationInPom()
-    {
+    public String getLocationInPom() {
         return locationInPom;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
index 4501d79..0e165e0 100644
--- a/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
+++ b/maven-core/src/main/java/org/apache/maven/project/MavenProject.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,10 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.Writer;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -29,18 +29,18 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 import java.util.Set;
-import java.util.Objects;
 
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
-// remove once createArtifacts() is removed
 import org.apache.maven.artifact.factory.ArtifactFactory;
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
+import org.apache.maven.lifecycle.internal.DefaultProjectArtifactFactory;
 import org.apache.maven.model.Build;
 import org.apache.maven.model.CiManagement;
 import org.apache.maven.model.Contributor;
@@ -66,8 +66,8 @@
 import org.apache.maven.model.Resource;
 import org.apache.maven.model.Scm;
 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
+import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.project.artifact.InvalidDependencyVersionException;
-import org.apache.maven.project.artifact.MavenMetadataSource;
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.eclipse.aether.graph.DependencyFilter;
@@ -89,11 +89,9 @@
  * directories but I hope to take care of this during the Maven 4.0 release (jvz).
  * </p>
  */
-public class MavenProject
-    implements Cloneable
-{
+public class MavenProject implements Cloneable {
 
-    private static final Logger LOGGER = LoggerFactory.getLogger( MavenProject.class );
+    private static final Logger LOGGER = LoggerFactory.getLogger(MavenProject.class);
 
     public static final String EMPTY_PROJECT_GROUP_ID = "unknown";
 
@@ -109,6 +107,8 @@
 
     private File basedir;
 
+    private Path rootDirectory;
+
     private Set<Artifact> resolvedArtifacts;
 
     private ArtifactFilter artifactFilter;
@@ -180,36 +180,35 @@
 
     private DependencyFilter extensionDependencyFilter;
 
-    private final Set<String> lifecyclePhases = Collections.synchronizedSet( new LinkedHashSet<>() );
+    private final Set<String> lifecyclePhases = Collections.synchronizedSet(new LinkedHashSet<>());
 
-    public MavenProject()
-    {
+    public MavenProject() {
         Model model = new Model();
 
-        model.setGroupId( EMPTY_PROJECT_GROUP_ID );
-        model.setArtifactId( EMPTY_PROJECT_ARTIFACT_ID );
-        model.setVersion( EMPTY_PROJECT_VERSION );
+        model.setGroupId(EMPTY_PROJECT_GROUP_ID);
+        model.setArtifactId(EMPTY_PROJECT_ARTIFACT_ID);
+        model.setVersion(EMPTY_PROJECT_VERSION);
 
-        setModel( model );
+        setModel(model);
     }
 
-    public MavenProject( Model model )
-    {
-        setModel( model );
+    public MavenProject(org.apache.maven.api.model.Model model) {
+        this(new Model(model));
     }
 
-    public MavenProject( MavenProject project )
-    {
-        deepCopy( project );
+    public MavenProject(Model model) {
+        setModel(model);
     }
 
-    public File getParentFile()
-    {
+    public MavenProject(MavenProject project) {
+        deepCopy(project);
+    }
+
+    public File getParentFile() {
         return parentFile;
     }
 
-    public void setParentFile( File parentFile )
-    {
+    public void setParentFile(File parentFile) {
         this.parentFile = parentFile;
     }
 
@@ -217,19 +216,16 @@
     // Accessors
     // ----------------------------------------------------------------------
 
-    public Artifact getArtifact()
-    {
+    public Artifact getArtifact() {
         return artifact;
     }
 
-    public void setArtifact( Artifact artifact )
-    {
+    public void setArtifact(Artifact artifact) {
         this.artifact = artifact;
     }
 
     // TODO I would like to get rid of this. jvz.
-    public Model getModel()
-    {
+    public Model getModel() {
         return model;
     }
 
@@ -238,28 +234,23 @@
      *
      * @return the parent, or null if no parent is declared or there was an error building it
      */
-    public MavenProject getParent()
-    {
+    public MavenProject getParent() {
         return parent;
     }
 
-    public void setParent( MavenProject parent )
-    {
+    public void setParent(MavenProject parent) {
         this.parent = parent;
     }
 
-    public boolean hasParent()
-    {
+    public boolean hasParent() {
         return getParent() != null;
     }
 
-    public File getFile()
-    {
+    public File getFile() {
         return file;
     }
 
-    public void setFile( File file )
-    {
+    public void setFile(File file) {
         this.file = file;
         this.basedir = file != null ? file.getParentFile() : null;
     }
@@ -269,28 +260,23 @@
      *
      * @since 3.2.4
      */
-    public void setPomFile( File file )
-    {
+    public void setPomFile(File file) {
         this.file = file;
     }
 
-    public File getBasedir()
-    {
+    public File getBasedir() {
         return basedir;
     }
 
-    public void setDependencies( List<Dependency> dependencies )
-    {
-        getModel().setDependencies( dependencies );
+    public void setDependencies(List<Dependency> dependencies) {
+        getModel().setDependencies(dependencies);
     }
 
-    public List<Dependency> getDependencies()
-    {
+    public List<Dependency> getDependencies() {
         return getModel().getDependencies();
     }
 
-    public DependencyManagement getDependencyManagement()
-    {
+    public DependencyManagement getDependencyManagement() {
         return getModel().getDependencyManagement();
     }
 
@@ -298,75 +284,57 @@
     // Test and compile source roots.
     // ----------------------------------------------------------------------
 
-    private void addPath( List<String> paths, String path )
-    {
-        if ( path != null )
-        {
+    private void addPath(List<String> paths, String path) {
+        if (path != null) {
             path = path.trim();
-            if ( path.length() > 0 )
-            {
-                File file = new File( path );
-                if ( file.isAbsolute() )
-                {
+            if (path.length() > 0) {
+                File file = new File(path);
+                if (file.isAbsolute()) {
                     path = file.getAbsolutePath();
-                }
-                else if ( ".".equals( path ) )
-                {
+                } else if (".".equals(path)) {
                     path = getBasedir().getAbsolutePath();
-                }
-                else
-                {
-                    path = new File( getBasedir(), path ).getAbsolutePath();
+                } else {
+                    path = new File(getBasedir(), path).getAbsolutePath();
                 }
 
-                if ( !paths.contains( path ) )
-                {
-                    paths.add( path );
+                if (!paths.contains(path)) {
+                    paths.add(path);
                 }
             }
         }
     }
 
-    public void addCompileSourceRoot( String path )
-    {
-        addPath( getCompileSourceRoots(), path );
+    public void addCompileSourceRoot(String path) {
+        addPath(getCompileSourceRoots(), path);
     }
 
-    public void addTestCompileSourceRoot( String path )
-    {
-        addPath( getTestCompileSourceRoots(), path );
+    public void addTestCompileSourceRoot(String path) {
+        addPath(getTestCompileSourceRoots(), path);
     }
 
-    public List<String> getCompileSourceRoots()
-    {
+    public List<String> getCompileSourceRoots() {
         return compileSourceRoots;
     }
 
-    public List<String> getTestCompileSourceRoots()
-    {
+    public List<String> getTestCompileSourceRoots() {
         return testCompileSourceRoots;
     }
 
-    public List<String> getCompileClasspathElements()
-        throws DependencyResolutionRequiredException
-    {
-        List<String> list = new ArrayList<>( getArtifacts().size() + 1 );
+    public List<String> getCompileClasspathElements() throws DependencyResolutionRequiredException {
+        List<String> list = new ArrayList<>(getArtifacts().size() + 1);
 
         String d = getBuild().getOutputDirectory();
-        if ( d != null )
-        {
-            list.add( d );
+        if (d != null) {
+            list.add(d);
         }
 
-        for ( Artifact a : getArtifacts() )
-        {
-            if ( a.getArtifactHandler().isAddedToClasspath() )
-            {
+        for (Artifact a : getArtifacts()) {
+            if (a.getArtifactHandler().isAddedToClasspath()) {
                 // TODO let the scope handler deal with this
-                if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
-                    || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
-                {
-                    addArtifactPath( a, list );
+                if (Artifact.SCOPE_COMPILE.equals(a.getScope())
+                        || Artifact.SCOPE_PROVIDED.equals(a.getScope())
+                        || Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
+                    addArtifactPath(a, list);
                 }
             }
         }
@@ -376,52 +344,41 @@
 
     // TODO this checking for file == null happens because the resolver has been confused about the root
     // artifact or not. things like the stupid dummy artifact coming from surefire.
-    public List<String> getTestClasspathElements()
-        throws DependencyResolutionRequiredException
-    {
-        List<String> list = new ArrayList<>( getArtifacts().size() + 2 );
+    public List<String> getTestClasspathElements() throws DependencyResolutionRequiredException {
+        List<String> list = new ArrayList<>(getArtifacts().size() + 2);
 
         String d = getBuild().getTestOutputDirectory();
-        if ( d != null )
-        {
-            list.add( d );
+        if (d != null) {
+            list.add(d);
         }
 
         d = getBuild().getOutputDirectory();
-        if ( d != null )
-        {
-            list.add( d );
+        if (d != null) {
+            list.add(d);
         }
 
-        for ( Artifact a : getArtifacts() )
-        {
-            if ( a.getArtifactHandler().isAddedToClasspath() )
-            {
-                addArtifactPath( a, list );
+        for (Artifact a : getArtifacts()) {
+            if (a.getArtifactHandler().isAddedToClasspath()) {
+                addArtifactPath(a, list);
             }
         }
 
         return list;
     }
 
-    public List<String> getRuntimeClasspathElements()
-        throws DependencyResolutionRequiredException
-    {
-        List<String> list = new ArrayList<>( getArtifacts().size() + 1 );
+    public List<String> getRuntimeClasspathElements() throws DependencyResolutionRequiredException {
+        List<String> list = new ArrayList<>(getArtifacts().size() + 1);
 
         String d = getBuild().getOutputDirectory();
-        if ( d != null )
-        {
-            list.add( d );
+        if (d != null) {
+            list.add(d);
         }
 
-        for ( Artifact a : getArtifacts() )
-        {
-            if ( a.getArtifactHandler().isAddedToClasspath()
-            // TODO let the scope handler deal with this
-                && ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_RUNTIME.equals( a.getScope() ) ) )
-            {
-                addArtifactPath( a, list );
+        for (Artifact a : getArtifacts()) {
+            if (a.getArtifactHandler().isAddedToClasspath()
+                    // TODO let the scope handler deal with this
+                    && (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope()))) {
+                addArtifactPath(a, list);
             }
         }
         return list;
@@ -431,270 +388,216 @@
     // Delegate to the model
     // ----------------------------------------------------------------------
 
-    public void setModelVersion( String pomVersion )
-    {
-        getModel().setModelVersion( pomVersion );
+    public void setModelVersion(String pomVersion) {
+        getModel().setModelVersion(pomVersion);
     }
 
-    public String getModelVersion()
-    {
+    public String getModelVersion() {
         return getModel().getModelVersion();
     }
 
-    public String getId()
-    {
+    public String getId() {
         return getModel().getId();
     }
 
-    public void setGroupId( String groupId )
-    {
-        getModel().setGroupId( groupId );
+    public void setGroupId(String groupId) {
+        getModel().setGroupId(groupId);
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         String groupId = getModel().getGroupId();
 
-        if ( ( groupId == null ) && ( getModel().getParent() != null ) )
-        {
+        if ((groupId == null) && (getModel().getParent() != null)) {
             groupId = getModel().getParent().getGroupId();
         }
 
         return groupId;
     }
 
-    public void setArtifactId( String artifactId )
-    {
-        getModel().setArtifactId( artifactId );
+    public void setArtifactId(String artifactId) {
+        getModel().setArtifactId(artifactId);
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return getModel().getArtifactId();
     }
 
-    public void setName( String name )
-    {
-        getModel().setName( name );
+    public void setName(String name) {
+        getModel().setName(name);
     }
 
-    public String getName()
-    {
+    public String getName() {
         // TODO this should not be allowed to be null.
-        if ( getModel().getName() != null )
-        {
+        if (getModel().getName() != null) {
             return getModel().getName();
-        }
-        else
-        {
+        } else {
             return getArtifactId();
         }
     }
 
-    public void setVersion( String version )
-    {
-        getModel().setVersion( version );
+    public void setVersion(String version) {
+        getModel().setVersion(version);
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         String version = getModel().getVersion();
 
-        if ( ( version == null ) && ( getModel().getParent() != null ) )
-        {
+        if ((version == null) && (getModel().getParent() != null)) {
             version = getModel().getParent().getVersion();
         }
 
         return version;
     }
 
-    public String getPackaging()
-    {
+    public String getPackaging() {
         return getModel().getPackaging();
     }
 
-    public void setPackaging( String packaging )
-    {
-        getModel().setPackaging( packaging );
+    public void setPackaging(String packaging) {
+        getModel().setPackaging(packaging);
     }
 
-    public void setInceptionYear( String inceptionYear )
-    {
-        getModel().setInceptionYear( inceptionYear );
+    public void setInceptionYear(String inceptionYear) {
+        getModel().setInceptionYear(inceptionYear);
     }
 
-    public String getInceptionYear()
-    {
+    public String getInceptionYear() {
         return getModel().getInceptionYear();
     }
 
-    public void setUrl( String url )
-    {
-        getModel().setUrl( url );
+    public void setUrl(String url) {
+        getModel().setUrl(url);
     }
 
-    public String getUrl()
-    {
+    public String getUrl() {
         return getModel().getUrl();
     }
 
-    public Prerequisites getPrerequisites()
-    {
+    public Prerequisites getPrerequisites() {
         return getModel().getPrerequisites();
     }
 
-    public void setIssueManagement( IssueManagement issueManagement )
-    {
-        getModel().setIssueManagement( issueManagement );
+    public void setIssueManagement(IssueManagement issueManagement) {
+        getModel().setIssueManagement(issueManagement);
     }
 
-    public CiManagement getCiManagement()
-    {
+    public CiManagement getCiManagement() {
         return getModel().getCiManagement();
     }
 
-    public void setCiManagement( CiManagement ciManagement )
-    {
-        getModel().setCiManagement( ciManagement );
+    public void setCiManagement(CiManagement ciManagement) {
+        getModel().setCiManagement(ciManagement);
     }
 
-    public IssueManagement getIssueManagement()
-    {
+    public IssueManagement getIssueManagement() {
         return getModel().getIssueManagement();
     }
 
-    public void setDistributionManagement( DistributionManagement distributionManagement )
-    {
-        getModel().setDistributionManagement( distributionManagement );
+    public void setDistributionManagement(DistributionManagement distributionManagement) {
+        getModel().setDistributionManagement(distributionManagement);
     }
 
-    public DistributionManagement getDistributionManagement()
-    {
+    public DistributionManagement getDistributionManagement() {
         return getModel().getDistributionManagement();
     }
 
-    public void setDescription( String description )
-    {
-        getModel().setDescription( description );
+    public void setDescription(String description) {
+        getModel().setDescription(description);
     }
 
-    public String getDescription()
-    {
+    public String getDescription() {
         return getModel().getDescription();
     }
 
-    public void setOrganization( Organization organization )
-    {
-        getModel().setOrganization( organization );
+    public void setOrganization(Organization organization) {
+        getModel().setOrganization(organization);
     }
 
-    public Organization getOrganization()
-    {
+    public Organization getOrganization() {
         return getModel().getOrganization();
     }
 
-    public void setScm( Scm scm )
-    {
-        getModel().setScm( scm );
+    public void setScm(Scm scm) {
+        getModel().setScm(scm);
     }
 
-    public Scm getScm()
-    {
+    public Scm getScm() {
         return getModel().getScm();
     }
 
-    public void setMailingLists( List<MailingList> mailingLists )
-    {
-        getModel().setMailingLists( mailingLists );
+    public void setMailingLists(List<MailingList> mailingLists) {
+        getModel().setMailingLists(mailingLists);
     }
 
-    public List<MailingList> getMailingLists()
-    {
+    public List<MailingList> getMailingLists() {
         return getModel().getMailingLists();
     }
 
-    public void addMailingList( MailingList mailingList )
-    {
-        getModel().addMailingList( mailingList );
+    public void addMailingList(MailingList mailingList) {
+        getModel().addMailingList(mailingList);
     }
 
-    public void setDevelopers( List<Developer> developers )
-    {
-        getModel().setDevelopers( developers );
+    public void setDevelopers(List<Developer> developers) {
+        getModel().setDevelopers(developers);
     }
 
-    public List<Developer> getDevelopers()
-    {
+    public List<Developer> getDevelopers() {
         return getModel().getDevelopers();
     }
 
-    public void addDeveloper( Developer developer )
-    {
-        getModel().addDeveloper( developer );
+    public void addDeveloper(Developer developer) {
+        getModel().addDeveloper(developer);
     }
 
-    public void setContributors( List<Contributor> contributors )
-    {
-        getModel().setContributors( contributors );
+    public void setContributors(List<Contributor> contributors) {
+        getModel().setContributors(contributors);
     }
 
-    public List<Contributor> getContributors()
-    {
+    public List<Contributor> getContributors() {
         return getModel().getContributors();
     }
 
-    public void addContributor( Contributor contributor )
-    {
-        getModel().addContributor( contributor );
+    public void addContributor(Contributor contributor) {
+        getModel().addContributor(contributor);
     }
 
-    public void setBuild( Build build )
-    {
-        getModel().setBuild( build );
+    public void setBuild(Build build) {
+        getModel().setBuild(build);
     }
 
-    public Build getBuild()
-    {
+    public Build getBuild() {
         return getModelBuild();
     }
 
-    public List<Resource> getResources()
-    {
+    public List<Resource> getResources() {
         return getBuild().getResources();
     }
 
-    public List<Resource> getTestResources()
-    {
+    public List<Resource> getTestResources() {
         return getBuild().getTestResources();
     }
 
-    public void addResource( Resource resource )
-    {
-        getBuild().addResource( resource );
+    public void addResource(Resource resource) {
+        getBuild().addResource(resource);
     }
 
-    public void addTestResource( Resource testResource )
-    {
-        getBuild().addTestResource( testResource );
+    public void addTestResource(Resource testResource) {
+        getBuild().addTestResource(testResource);
     }
 
-    public void setLicenses( List<License> licenses )
-    {
-        getModel().setLicenses( licenses );
+    public void setLicenses(List<License> licenses) {
+        getModel().setLicenses(licenses);
     }
 
-    public List<License> getLicenses()
-    {
+    public List<License> getLicenses() {
         return getModel().getLicenses();
     }
 
-    public void addLicense( License license )
-    {
-        getModel().addLicense( license );
+    public void addLicense(License license) {
+        getModel().addLicense(license);
     }
 
-    public void setArtifacts( Set<Artifact> artifacts )
-    {
+    public void setArtifacts(Set<Artifact> artifacts) {
         this.artifacts = artifacts;
 
         // flush the calculated artifactMap
@@ -709,22 +612,15 @@
      * @return {@link Set} &lt; {@link Artifact} &gt;
      * @see #getDependencyArtifacts() to get only direct dependencies
      */
-    public Set<Artifact> getArtifacts()
-    {
-        if ( artifacts == null )
-        {
-            if ( artifactFilter == null || resolvedArtifacts == null )
-            {
+    public Set<Artifact> getArtifacts() {
+        if (artifacts == null) {
+            if (artifactFilter == null || resolvedArtifacts == null) {
                 artifacts = new LinkedHashSet<>();
-            }
-            else
-            {
-                artifacts = new LinkedHashSet<>( resolvedArtifacts.size() * 2 );
-                for ( Artifact artifact : resolvedArtifacts )
-                {
-                    if ( artifactFilter.include( artifact ) )
-                    {
-                        artifacts.add( artifact );
+            } else {
+                artifacts = new LinkedHashSet<>(resolvedArtifacts.size() * 2);
+                for (Artifact artifact : resolvedArtifacts) {
+                    if (artifactFilter.include(artifact)) {
+                        artifacts.add(artifact);
                     }
                 }
             }
@@ -732,49 +628,40 @@
         return artifacts;
     }
 
-    public Map<String, Artifact> getArtifactMap()
-    {
-        if ( artifactMap == null )
-        {
-            artifactMap = ArtifactUtils.artifactMapByVersionlessId( getArtifacts() );
+    public Map<String, Artifact> getArtifactMap() {
+        if (artifactMap == null) {
+            artifactMap = ArtifactUtils.artifactMapByVersionlessId(getArtifacts());
         }
         return artifactMap;
     }
 
-    public void setPluginArtifacts( Set<Artifact> pluginArtifacts )
-    {
+    public void setPluginArtifacts(Set<Artifact> pluginArtifacts) {
         this.pluginArtifacts = pluginArtifacts;
 
         this.pluginArtifactMap = null;
     }
 
-    public Set<Artifact> getPluginArtifacts()
-    {
+    public Set<Artifact> getPluginArtifacts() {
         return pluginArtifacts;
     }
 
-    public Map<String, Artifact> getPluginArtifactMap()
-    {
-        if ( pluginArtifactMap == null )
-        {
-            pluginArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getPluginArtifacts() );
+    public Map<String, Artifact> getPluginArtifactMap() {
+        if (pluginArtifactMap == null) {
+            pluginArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getPluginArtifacts());
         }
 
         return pluginArtifactMap;
     }
 
-    public void setParentArtifact( Artifact parentArtifact )
-    {
+    public void setParentArtifact(Artifact parentArtifact) {
         this.parentArtifact = parentArtifact;
     }
 
-    public Artifact getParentArtifact()
-    {
+    public Artifact getParentArtifact() {
         return parentArtifact;
     }
 
-    public List<Repository> getRepositories()
-    {
+    public List<Repository> getRepositories() {
         return getModel().getRepositories();
     }
 
@@ -782,124 +669,101 @@
     // Plugins
     // ----------------------------------------------------------------------
 
-    public List<Plugin> getBuildPlugins()
-    {
-        if ( getModel().getBuild() == null )
-        {
+    public List<Plugin> getBuildPlugins() {
+        if (getModel().getBuild() == null) {
             return Collections.emptyList();
         }
-        return Collections.unmodifiableList( getModel().getBuild().getPlugins() );
+        return Collections.unmodifiableList(getModel().getBuild().getPlugins());
     }
 
-    public List<String> getModules()
-    {
+    public List<String> getModules() {
         return getModel().getModules();
     }
 
-    public PluginManagement getPluginManagement()
-    {
+    public PluginManagement getPluginManagement() {
         PluginManagement pluginMgmt = null;
 
         Build build = getModel().getBuild();
-        if ( build != null )
-        {
+        if (build != null) {
             pluginMgmt = build.getPluginManagement();
         }
 
         return pluginMgmt;
     }
 
-    private Build getModelBuild()
-    {
+    private Build getModelBuild() {
         Build build = getModel().getBuild();
 
-        if ( build == null )
-        {
+        if (build == null) {
             build = new Build();
 
-            getModel().setBuild( build );
+            getModel().setBuild(build);
         }
 
         return build;
     }
 
-    public void setRemoteArtifactRepositories( List<ArtifactRepository> remoteArtifactRepositories )
-    {
+    public void setRemoteArtifactRepositories(List<ArtifactRepository> remoteArtifactRepositories) {
         this.remoteArtifactRepositories = remoteArtifactRepositories;
-        this.remoteProjectRepositories = RepositoryUtils.toRepos( getRemoteArtifactRepositories() );
+        this.remoteProjectRepositories = RepositoryUtils.toRepos(getRemoteArtifactRepositories());
     }
 
-    public List<ArtifactRepository> getRemoteArtifactRepositories()
-    {
-        if ( remoteArtifactRepositories == null )
-        {
+    public List<ArtifactRepository> getRemoteArtifactRepositories() {
+        if (remoteArtifactRepositories == null) {
             remoteArtifactRepositories = new ArrayList<>();
         }
 
         return remoteArtifactRepositories;
     }
 
-    public void setPluginArtifactRepositories( List<ArtifactRepository> pluginArtifactRepositories )
-    {
+    public void setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories) {
         this.pluginArtifactRepositories = pluginArtifactRepositories;
-        this.remotePluginRepositories = RepositoryUtils.toRepos( getPluginArtifactRepositories() );
+        this.remotePluginRepositories = RepositoryUtils.toRepos(getPluginArtifactRepositories());
     }
 
     /**
      * @return a list of ArtifactRepository objects constructed from the Repository objects returned by
      *         getPluginRepositories.
      */
-    public List<ArtifactRepository> getPluginArtifactRepositories()
-    {
-        if ( pluginArtifactRepositories == null )
-        {
+    public List<ArtifactRepository> getPluginArtifactRepositories() {
+        if (pluginArtifactRepositories == null) {
             pluginArtifactRepositories = new ArrayList<>();
         }
 
         return pluginArtifactRepositories;
     }
 
-    public ArtifactRepository getDistributionManagementArtifactRepository()
-    {
-        return getArtifact().isSnapshot() && ( getSnapshotArtifactRepository() != null )
-                        ? getSnapshotArtifactRepository()
-                        : getReleaseArtifactRepository();
+    public ArtifactRepository getDistributionManagementArtifactRepository() {
+        return getArtifact().isSnapshot() && (getSnapshotArtifactRepository() != null)
+                ? getSnapshotArtifactRepository()
+                : getReleaseArtifactRepository();
     }
 
-    public List<Repository> getPluginRepositories()
-    {
+    public List<Repository> getPluginRepositories() {
         return getModel().getPluginRepositories();
     }
 
-    public List<RemoteRepository> getRemoteProjectRepositories()
-    {
+    public List<RemoteRepository> getRemoteProjectRepositories() {
         return remoteProjectRepositories;
     }
 
-    public List<RemoteRepository> getRemotePluginRepositories()
-    {
+    public List<RemoteRepository> getRemotePluginRepositories() {
         return remotePluginRepositories;
     }
 
-    public void setActiveProfiles( List<Profile> activeProfiles )
-    {
+    public void setActiveProfiles(List<Profile> activeProfiles) {
         this.activeProfiles = activeProfiles;
     }
 
-    public List<Profile> getActiveProfiles()
-    {
+    public List<Profile> getActiveProfiles() {
         return activeProfiles;
     }
 
-    public void setInjectedProfileIds( String source, List<String> injectedProfileIds )
-    {
-        if ( injectedProfileIds != null )
-        {
-            this.injectedProfileIds.put( source, new ArrayList<>( injectedProfileIds ) );
-        }
-        else
-        {
-            this.injectedProfileIds.remove( source );
+    public void setInjectedProfileIds(String source, List<String> injectedProfileIds) {
+        if (injectedProfileIds != null) {
+            this.injectedProfileIds.put(source, new ArrayList<>(injectedProfileIds));
+        } else {
+            this.injectedProfileIds.remove(source);
         }
     }
 
@@ -913,8 +777,7 @@
      * @return The identifiers of all injected profiles, indexed by the source from which the profiles originated, never
      *         {@code null}.
      */
-    public Map<String, List<String>> getInjectedProfileIds()
-    {
+    public Map<String, List<String>> getInjectedProfileIds() {
         return this.injectedProfileIds;
     }
 
@@ -929,51 +792,45 @@
      * @deprecated Please use {@link MavenProjectHelper}
      * @throws DuplicateArtifactAttachmentException will never happen but leave it for backward compatibility
      */
-    public void addAttachedArtifact( Artifact artifact )
-        throws DuplicateArtifactAttachmentException
-    {
+    public void addAttachedArtifact(Artifact artifact) throws DuplicateArtifactAttachmentException {
         // if already there we remove it and add again
-        int index = attachedArtifacts.indexOf( artifact );
-        if ( index >= 0 )
-        {
-            LOGGER.warn( "artifact '{}' already attached, replacing previous instance", artifact );
-            attachedArtifacts.set( index, artifact );
-        }
-        else
-        {
-            attachedArtifacts.add( artifact );
+        int index = attachedArtifacts.indexOf(artifact);
+        if (index >= 0) {
+            LOGGER.warn("artifact '{}' already attached, replacing previous instance", artifact);
+            attachedArtifacts.set(index, artifact);
+        } else {
+            attachedArtifacts.add(artifact);
         }
     }
 
-    public List<Artifact> getAttachedArtifacts()
-    {
-        if ( attachedArtifacts == null )
-        {
+    /**
+     * Returns a read-only list of the attached artifacts to this project.
+     *
+     * @return the attached artifacts of this project
+     */
+    public List<Artifact> getAttachedArtifacts() {
+        if (attachedArtifacts == null) {
             attachedArtifacts = new ArrayList<>();
         }
-        return Collections.unmodifiableList( attachedArtifacts );
+        return Collections.unmodifiableList(attachedArtifacts);
     }
 
-    public Xpp3Dom getGoalConfiguration( String pluginGroupId, String pluginArtifactId, String executionId,
-                                         String goalId )
-    {
+    public Xpp3Dom getGoalConfiguration(
+            String pluginGroupId, String pluginArtifactId, String executionId, String goalId) {
         Xpp3Dom dom = null;
 
-        if ( getBuildPlugins() != null )
-        {
-            for ( Plugin plugin : getBuildPlugins() )
-            {
-                if ( pluginGroupId.equals( plugin.getGroupId() ) && pluginArtifactId.equals( plugin.getArtifactId() ) )
-                {
+        if (getBuildPlugins() != null) {
+            for (Plugin plugin : getBuildPlugins()) {
+                if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
                     dom = (Xpp3Dom) plugin.getConfiguration();
 
-                    if ( executionId != null )
-                    {
-                        PluginExecution execution = plugin.getExecutionsAsMap().get( executionId );
-                        if ( execution != null )
-                        {
-                            // NOTE: The PluginConfigurationExpander already merged the plugin-level config in
-                            dom = (Xpp3Dom) execution.getConfiguration();
+                    if (executionId != null) {
+                        for (PluginExecution execution : plugin.getExecutions()) {
+                            if (executionId.equals(execution.getId())) {
+                                // NOTE: The PluginConfigurationExpander already merged the plugin-level config in
+                                dom = (Xpp3Dom) execution.getConfiguration();
+                                break;
+                            }
                         }
                     }
                     break;
@@ -981,32 +838,27 @@
             }
         }
 
-        if ( dom != null )
-        {
+        if (dom != null) {
             // make a copy so the original in the POM doesn't get messed with
-            dom = new Xpp3Dom( dom );
+            dom = new Xpp3Dom(dom);
         }
 
         return dom;
     }
 
-    public MavenProject getExecutionProject()
-    {
-        return ( executionProject == null ? this : executionProject );
+    public MavenProject getExecutionProject() {
+        return (executionProject == null ? this : executionProject);
     }
 
-    public void setExecutionProject( MavenProject executionProject )
-    {
+    public void setExecutionProject(MavenProject executionProject) {
         this.executionProject = executionProject;
     }
 
-    public List<MavenProject> getCollectedProjects()
-    {
+    public List<MavenProject> getCollectedProjects() {
         return collectedProjects;
     }
 
-    public void setCollectedProjects( List<MavenProject> collectedProjects )
-    {
+    public void setCollectedProjects(List<MavenProject> collectedProjects) {
         this.collectedProjects = collectedProjects;
     }
 
@@ -1017,147 +869,116 @@
      * @see #getArtifacts() to get all transitive dependencies
      */
     @Deprecated
-    public Set<Artifact> getDependencyArtifacts()
-    {
+    public Set<Artifact> getDependencyArtifacts() {
         return dependencyArtifacts;
     }
 
     @Deprecated
-    public void setDependencyArtifacts( Set<Artifact> dependencyArtifacts )
-    {
+    public void setDependencyArtifacts(Set<Artifact> dependencyArtifacts) {
         this.dependencyArtifacts = dependencyArtifacts;
     }
 
-    public void setReleaseArtifactRepository( ArtifactRepository releaseArtifactRepository )
-    {
+    public void setReleaseArtifactRepository(ArtifactRepository releaseArtifactRepository) {
         this.releaseArtifactRepository = releaseArtifactRepository;
     }
 
-    public void setSnapshotArtifactRepository( ArtifactRepository snapshotArtifactRepository )
-    {
+    public void setSnapshotArtifactRepository(ArtifactRepository snapshotArtifactRepository) {
         this.snapshotArtifactRepository = snapshotArtifactRepository;
     }
 
-    public void setOriginalModel( Model originalModel )
-    {
+    public void setOriginalModel(Model originalModel) {
         this.originalModel = originalModel;
     }
 
-    public Model getOriginalModel()
-    {
+    public Model getOriginalModel() {
         return originalModel;
     }
 
-    public void setManagedVersionMap( Map<String, Artifact> map )
-    {
+    public void setManagedVersionMap(Map<String, Artifact> map) {
         managedVersionMap = map;
     }
 
-    public Map<String, Artifact> getManagedVersionMap()
-    {
+    public Map<String, Artifact> getManagedVersionMap() {
         return managedVersionMap;
     }
 
     @Override
-    public boolean equals( Object other )
-    {
-        if ( other == this )
-        {
+    public boolean equals(Object other) {
+        if (other == this) {
             return true;
-        }
-        else if ( !( other instanceof MavenProject ) )
-        {
+        } else if (!(other instanceof MavenProject)) {
             return false;
         }
 
         MavenProject that = (MavenProject) other;
 
-        return Objects.equals( getArtifactId(), that.getArtifactId() )
-            && Objects.equals( getGroupId(), that.getGroupId() )
-            && Objects.equals( getVersion(), that.getVersion() );
+        return Objects.equals(getArtifactId(), that.getArtifactId())
+                && Objects.equals(getGroupId(), that.getGroupId())
+                && Objects.equals(getVersion(), that.getVersion());
     }
 
     @Override
-    public int hashCode()
-    {
-        int hash = 17;
-        hash = 31 * hash + getGroupId().hashCode();
-        hash = 31 * hash + getArtifactId().hashCode();
-        hash = 31 * hash + getVersion().hashCode();
-        return hash;
+    public int hashCode() {
+        return Objects.hash(getGroupId(), getArtifactId(), getVersion());
     }
 
-    public List<Extension> getBuildExtensions()
-    {
+    public List<Extension> getBuildExtensions() {
         Build build = getBuild();
-        if ( ( build == null ) || ( build.getExtensions() == null ) )
-        {
+        if ((build == null) || (build.getExtensions() == null)) {
             return Collections.emptyList();
-        }
-        else
-        {
-            return Collections.unmodifiableList( build.getExtensions() );
+        } else {
+            return Collections.unmodifiableList(build.getExtensions());
         }
     }
 
-    public void addProjectReference( MavenProject project )
-    {
-        projectReferences.put( getProjectReferenceId( project.getGroupId(), project.getArtifactId(),
-                                                      project.getVersion() ), project );
+    public void addProjectReference(MavenProject project) {
+        projectReferences.put(
+                getProjectReferenceId(project.getGroupId(), project.getArtifactId(), project.getVersion()), project);
     }
 
-    public Properties getProperties()
-    {
+    public Properties getProperties() {
         return getModel().getProperties();
     }
 
-    public List<String> getFilters()
-    {
+    public List<String> getFilters() {
         return getBuild().getFilters();
     }
 
-    public Map<String, MavenProject> getProjectReferences()
-    {
+    public Map<String, MavenProject> getProjectReferences() {
         return projectReferences;
     }
 
-    public boolean isExecutionRoot()
-    {
+    public boolean isExecutionRoot() {
         return executionRoot;
     }
 
-    public void setExecutionRoot( boolean executionRoot )
-    {
+    public void setExecutionRoot(boolean executionRoot) {
         this.executionRoot = executionRoot;
     }
 
-    public String getDefaultGoal()
-    {
+    public String getDefaultGoal() {
         return getBuild() != null ? getBuild().getDefaultGoal() : null;
     }
 
-    public Plugin getPlugin( String pluginKey )
-    {
-        return getBuild().getPluginsAsMap().get( pluginKey );
+    public Plugin getPlugin(String pluginKey) {
+        return getBuild().getPluginsAsMap().get(pluginKey);
     }
 
     /**
      * Default toString
      */
     @Override
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 128 );
-        sb.append( "MavenProject: " );
-        sb.append( getGroupId() );
-        sb.append( ':' );
-        sb.append( getArtifactId() );
-        sb.append( ':' );
-        sb.append( getVersion() );
-        if ( getFile() != null )
-        {
-            sb.append( " @ " );
-            sb.append( getFile().getPath() );
+    public String toString() {
+        StringBuilder sb = new StringBuilder(128);
+        sb.append("MavenProject: ");
+        sb.append(getGroupId());
+        sb.append(':');
+        sb.append(getArtifactId());
+        sb.append(':');
+        sb.append(getVersion());
+        if (getFile() != null) {
+            sb.append(" @ ");
+            sb.append(getFile().getPath());
         }
 
         return sb.toString();
@@ -1167,55 +988,44 @@
      * @since 2.0.9
      */
     @Override
-    public MavenProject clone()
-    {
+    public MavenProject clone() {
         MavenProject clone;
-        try
-        {
+        try {
             clone = (MavenProject) super.clone();
-        }
-        catch ( CloneNotSupportedException e )
-        {
-            throw new UnsupportedOperationException( e );
+        } catch (CloneNotSupportedException e) {
+            throw new UnsupportedOperationException(e);
         }
 
-        clone.deepCopy( this );
+        clone.deepCopy(this);
 
         return clone;
     }
 
-    public void setModel( Model model )
-    {
+    public void setModel(Model model) {
         this.model = model;
     }
 
-    protected void setAttachedArtifacts( List<Artifact> attachedArtifacts )
-    {
+    protected void setAttachedArtifacts(List<Artifact> attachedArtifacts) {
         this.attachedArtifacts = attachedArtifacts;
     }
 
-    protected void setCompileSourceRoots( List<String> compileSourceRoots )
-    {
+    protected void setCompileSourceRoots(List<String> compileSourceRoots) {
         this.compileSourceRoots = compileSourceRoots;
     }
 
-    protected void setTestCompileSourceRoots( List<String> testCompileSourceRoots )
-    {
+    protected void setTestCompileSourceRoots(List<String> testCompileSourceRoots) {
         this.testCompileSourceRoots = testCompileSourceRoots;
     }
 
-    protected ArtifactRepository getReleaseArtifactRepository()
-    {
+    protected ArtifactRepository getReleaseArtifactRepository() {
         return releaseArtifactRepository;
     }
 
-    protected ArtifactRepository getSnapshotArtifactRepository()
-    {
+    protected ArtifactRepository getSnapshotArtifactRepository() {
         return snapshotArtifactRepository;
     }
 
-    private void deepCopy( MavenProject project )
-    {
+    private void deepCopy(MavenProject project) {
         // disown the parent
 
         // copy fields
@@ -1224,113 +1034,93 @@
 
         // don't need a deep copy, they don't get modified or added/removed to/from - but make them unmodifiable to be
         // sure!
-        if ( project.getDependencyArtifacts() != null )
-        {
-            setDependencyArtifacts( Collections.unmodifiableSet( project.getDependencyArtifacts() ) );
+        if (project.getDependencyArtifacts() != null) {
+            setDependencyArtifacts(Collections.unmodifiableSet(project.getDependencyArtifacts()));
         }
 
-        if ( project.getArtifacts() != null )
-        {
-            setArtifacts( Collections.unmodifiableSet( project.getArtifacts() ) );
+        if (project.getArtifacts() != null) {
+            setArtifacts(Collections.unmodifiableSet(project.getArtifacts()));
         }
 
-        if ( project.getParentFile() != null )
-        {
-            parentFile = new File( project.getParentFile().getAbsolutePath() );
+        if (project.getParentFile() != null) {
+            parentFile = new File(project.getParentFile().getAbsolutePath());
         }
 
-        if ( project.getPluginArtifacts() != null )
-        {
-            setPluginArtifacts( Collections.unmodifiableSet( project.getPluginArtifacts() ) );
+        if (project.getPluginArtifacts() != null) {
+            setPluginArtifacts(Collections.unmodifiableSet(project.getPluginArtifacts()));
         }
 
-        if ( project.getReportArtifacts() != null )
-        {
-            setReportArtifacts( Collections.unmodifiableSet( project.getReportArtifacts() ) );
+        if (project.getReportArtifacts() != null) {
+            setReportArtifacts(Collections.unmodifiableSet(project.getReportArtifacts()));
         }
 
-        if ( project.getExtensionArtifacts() != null )
-        {
-            setExtensionArtifacts( Collections.unmodifiableSet( project.getExtensionArtifacts() ) );
+        if (project.getExtensionArtifacts() != null) {
+            setExtensionArtifacts(Collections.unmodifiableSet(project.getExtensionArtifacts()));
         }
 
-        setParentArtifact( ( project.getParentArtifact() ) );
+        setParentArtifact((project.getParentArtifact()));
 
-        if ( project.getRemoteArtifactRepositories() != null )
-        {
-            setRemoteArtifactRepositories( Collections.unmodifiableList( project.getRemoteArtifactRepositories() ) );
+        if (project.getRemoteArtifactRepositories() != null) {
+            setRemoteArtifactRepositories(Collections.unmodifiableList(project.getRemoteArtifactRepositories()));
         }
 
-        if ( project.getPluginArtifactRepositories() != null )
-        {
-            setPluginArtifactRepositories( Collections.unmodifiableList( project.getPluginArtifactRepositories() ) );
+        if (project.getPluginArtifactRepositories() != null) {
+            setPluginArtifactRepositories(Collections.unmodifiableList(project.getPluginArtifactRepositories()));
         }
 
-        if ( project.getActiveProfiles() != null )
-        {
-            setActiveProfiles( ( Collections.unmodifiableList( project.getActiveProfiles() ) ) );
+        if (project.getActiveProfiles() != null) {
+            setActiveProfiles((Collections.unmodifiableList(project.getActiveProfiles())));
         }
 
-        if ( project.getAttachedArtifacts() != null )
-        {
+        if (project.getAttachedArtifacts() != null) {
             // clone properties modifiable by plugins in a forked lifecycle
-            setAttachedArtifacts( new ArrayList<>( project.getAttachedArtifacts() ) );
+            setAttachedArtifacts(new ArrayList<>(project.getAttachedArtifacts()));
         }
 
-        if ( project.getCompileSourceRoots() != null )
-        {
+        if (project.getCompileSourceRoots() != null) {
             // clone source roots
-            setCompileSourceRoots( ( new ArrayList<>( project.getCompileSourceRoots() ) ) );
+            setCompileSourceRoots((new ArrayList<>(project.getCompileSourceRoots())));
         }
 
-        if ( project.getTestCompileSourceRoots() != null )
-        {
-            setTestCompileSourceRoots( ( new ArrayList<>( project.getTestCompileSourceRoots() ) ) );
+        if (project.getTestCompileSourceRoots() != null) {
+            setTestCompileSourceRoots((new ArrayList<>(project.getTestCompileSourceRoots())));
         }
 
-        if ( project.getScriptSourceRoots() != null )
-        {
-            setScriptSourceRoots( ( new ArrayList<>( project.getScriptSourceRoots() ) ) );
+        if (project.getScriptSourceRoots() != null) {
+            setScriptSourceRoots((new ArrayList<>(project.getScriptSourceRoots())));
         }
 
-        if ( project.getModel() != null )
-        {
-            setModel( project.getModel().clone() );
+        if (project.getModel() != null) {
+            setModel(project.getModel().clone());
         }
 
-        if ( project.getOriginalModel() != null )
-        {
-            setOriginalModel( project.getOriginalModel() );
+        if (project.getOriginalModel() != null) {
+            setOriginalModel(project.getOriginalModel());
         }
 
-        setExecutionRoot( project.isExecutionRoot() );
+        setExecutionRoot(project.isExecutionRoot());
 
-        if ( project.getArtifact() != null )
-        {
-            setArtifact( ArtifactUtils.copyArtifact( project.getArtifact() ) );
+        if (project.getArtifact() != null) {
+            setArtifact(ArtifactUtils.copyArtifact(project.getArtifact()));
         }
 
-        if ( project.getManagedVersionMap() != null )
-        {
-            setManagedVersionMap( project.getManagedVersionMap() );
+        if (project.getManagedVersionMap() != null) {
+            setManagedVersionMap(project.getManagedVersionMap());
         }
 
-        lifecyclePhases.addAll( project.lifecyclePhases );
+        lifecyclePhases.addAll(project.lifecyclePhases);
     }
 
-    private void addArtifactPath( Artifact artifact, List<String> classpath )
-    {
+    private void addArtifactPath(Artifact artifact, List<String> classpath) {
         File file = artifact.getFile();
-        if ( file != null )
-        {
-            classpath.add( file.getPath() );
+        if (file != null) {
+            classpath.add(file.getPath());
         }
     }
 
-    private static String getProjectReferenceId( String groupId, String artifactId, String version )
-    {
-        StringBuilder buffer = new StringBuilder( 128 );
-        buffer.append( groupId ).append( ':' ).append( artifactId ).append( ':' ).append( version );
+    private static String getProjectReferenceId(String groupId, String artifactId, String version) {
+        StringBuilder buffer = new StringBuilder(128);
+        buffer.append(groupId).append(':').append(artifactId).append(':').append(version);
         return buffer.toString();
     }
 
@@ -1339,32 +1129,25 @@
      * <code>null</code>, the context value is removed from this project. Context values are intended to allow core
      * extensions to associate derived state with project instances.
      */
-    public void setContextValue( String key, Object value )
-    {
-        if ( context == null )
-        {
+    public void setContextValue(String key, Object value) {
+        if (context == null) {
             context = new HashMap<>();
         }
-        if ( value != null )
-        {
-            context.put( key, value );
-        }
-        else
-        {
-            context.remove( key );
+        if (value != null) {
+            context.put(key, value);
+        } else {
+            context.remove(key);
         }
     }
 
     /**
      * Returns context value of this project associated with the given key or null if this project has no such value.
      */
-    public Object getContextValue( String key )
-    {
-        if ( context == null )
-        {
+    public Object getContextValue(String key) {
+        if (context == null) {
             return null;
         }
-        return context.get( key );
+        return context.get(key);
     }
 
     /**
@@ -1374,8 +1157,7 @@
      *
      * @param classRealm The class realm hosting the build extensions of this project, may be {@code null}.
      */
-    public void setClassRealm( ClassRealm classRealm )
-    {
+    public void setClassRealm(ClassRealm classRealm) {
         this.classRealm = classRealm;
     }
 
@@ -1387,8 +1169,7 @@
      *
      * @return The project's class realm or {@code null}.
      */
-    public ClassRealm getClassRealm()
-    {
+    public ClassRealm getClassRealm() {
         return classRealm;
     }
 
@@ -1399,8 +1180,7 @@
      *
      * @param extensionDependencyFilter The dependency filter to apply to plugins, may be {@code null}.
      */
-    public void setExtensionDependencyFilter( DependencyFilter extensionDependencyFilter )
-    {
+    public void setExtensionDependencyFilter(DependencyFilter extensionDependencyFilter) {
         this.extensionDependencyFilter = extensionDependencyFilter;
     }
 
@@ -1412,8 +1192,7 @@
      *
      * @return The dependency filter or {@code null}.
      */
-    public DependencyFilter getExtensionDependencyFilter()
-    {
+    public DependencyFilter getExtensionDependencyFilter() {
         return extensionDependencyFilter;
     }
 
@@ -1425,9 +1204,8 @@
      *
      * @param artifacts The set of artifacts, may be {@code null}.
      */
-    public void setResolvedArtifacts( Set<Artifact> artifacts )
-    {
-        this.resolvedArtifacts = ( artifacts != null ) ? artifacts : Collections.<Artifact>emptySet();
+    public void setResolvedArtifacts(Set<Artifact> artifacts) {
+        this.resolvedArtifacts = (artifacts != null) ? artifacts : Collections.<Artifact>emptySet();
         this.artifacts = null;
         this.artifactMap = null;
     }
@@ -1440,8 +1218,7 @@
      *
      * @param artifactFilter The artifact filter, may be {@code null} to exclude all artifacts.
      */
-    public void setArtifactFilter( ArtifactFilter artifactFilter )
-    {
+    public void setArtifactFilter(ArtifactFilter artifactFilter) {
         this.artifactFilter = artifactFilter;
         this.artifacts = null;
         this.artifactMap = null;
@@ -1455,9 +1232,8 @@
      * @param phase The phase to check for, must not be {@code null}.
      * @return {@code true} if the phase has been seen.
      */
-    public boolean hasLifecyclePhase( String phase )
-    {
-        return lifecyclePhases.contains( phase );
+    public boolean hasLifecyclePhase(String phase) {
+        return lifecyclePhases.contains(phase);
     }
 
     /**
@@ -1467,9 +1243,8 @@
      *
      * @param lifecyclePhase The lifecycle phase to add, must not be {@code null}.
      */
-    public void addLifecyclePhase( String lifecyclePhase )
-    {
-        lifecyclePhases.add( lifecyclePhase );
+    public void addLifecyclePhase(String lifecyclePhase) {
+        lifecyclePhases.add(lifecyclePhase);
     }
 
     // ----------------------------------------------------------------------------------------------------------------
@@ -1489,112 +1264,93 @@
     private Map<String, String> moduleAdjustments;
 
     @Deprecated // This appears only to be used in test code
-    public String getModulePathAdjustment( MavenProject moduleProject )
-        throws IOException
-    {
+    public String getModulePathAdjustment(MavenProject moduleProject) throws IOException {
         // FIXME: This is hacky. What if module directory doesn't match artifactid, and parent
         // is coming from the repository??
         String module = moduleProject.getArtifactId();
 
         File moduleFile = moduleProject.getFile();
 
-        if ( moduleFile != null )
-        {
+        if (moduleFile != null) {
             File moduleDir = moduleFile.getCanonicalFile().getParentFile();
 
             module = moduleDir.getName();
         }
 
-        if ( moduleAdjustments == null )
-        {
+        if (moduleAdjustments == null) {
             moduleAdjustments = new HashMap<>();
 
             List<String> modules = getModules();
-            if ( modules != null )
-            {
-                for ( String modulePath : modules )
-                {
+            if (modules != null) {
+                for (String modulePath : modules) {
                     String moduleName = modulePath;
 
-                    if ( moduleName.endsWith( "/" ) || moduleName.endsWith( "\\" ) )
-                    {
-                        moduleName = moduleName.substring( 0, moduleName.length() - 1 );
+                    if (moduleName.endsWith("/") || moduleName.endsWith("\\")) {
+                        moduleName = moduleName.substring(0, moduleName.length() - 1);
                     }
 
-                    int lastSlash = moduleName.lastIndexOf( '/' );
+                    int lastSlash = moduleName.lastIndexOf('/');
 
-                    if ( lastSlash < 0 )
-                    {
-                        lastSlash = moduleName.lastIndexOf( '\\' );
+                    if (lastSlash < 0) {
+                        lastSlash = moduleName.lastIndexOf('\\');
                     }
 
                     String adjustment = null;
 
-                    if ( lastSlash > -1 )
-                    {
-                        moduleName = moduleName.substring( lastSlash + 1 );
-                        adjustment = modulePath.substring( 0, lastSlash );
+                    if (lastSlash > -1) {
+                        moduleName = moduleName.substring(lastSlash + 1);
+                        adjustment = modulePath.substring(0, lastSlash);
                     }
 
-                    moduleAdjustments.put( moduleName, adjustment );
+                    moduleAdjustments.put(moduleName, adjustment);
                 }
             }
         }
 
-        return moduleAdjustments.get( module );
+        return moduleAdjustments.get(module);
     }
 
     @Deprecated
-    public Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, String inheritedScope,
-                                          ArtifactFilter filter )
-        throws InvalidDependencyVersionException
-    {
-        return MavenMetadataSource.createArtifacts( artifactFactory, getDependencies(), inheritedScope, filter, this );
+    public Set<Artifact> createArtifacts(ArtifactFactory artifactFactory, String inheritedScope, ArtifactFilter filter)
+            throws InvalidDependencyVersionException {
+        return DefaultProjectArtifactFactory.createArtifacts(
+                artifactFactory, getModel().getDependencies(), inheritedScope, filter, this);
     }
 
     @Deprecated
-    protected void setScriptSourceRoots( List<String> scriptSourceRoots )
-    {
+    protected void setScriptSourceRoots(List<String> scriptSourceRoots) {
         this.scriptSourceRoots = scriptSourceRoots;
     }
 
     @Deprecated
-    public void addScriptSourceRoot( String path )
-    {
-        if ( path != null )
-        {
+    public void addScriptSourceRoot(String path) {
+        if (path != null) {
             path = path.trim();
-            if ( path.length() != 0 )
-            {
-                if ( !getScriptSourceRoots().contains( path ) )
-                {
-                    getScriptSourceRoots().add( path );
+            if (path.length() != 0) {
+                if (!getScriptSourceRoots().contains(path)) {
+                    getScriptSourceRoots().add(path);
                 }
             }
         }
     }
 
     @Deprecated
-    public List<String> getScriptSourceRoots()
-    {
+    public List<String> getScriptSourceRoots() {
         return scriptSourceRoots;
     }
 
     @Deprecated
-    public List<Artifact> getCompileArtifacts()
-    {
-        List<Artifact> list = new ArrayList<>( getArtifacts().size() );
+    public List<Artifact> getCompileArtifacts() {
+        List<Artifact> list = new ArrayList<>(getArtifacts().size());
 
-        for ( Artifact a : getArtifacts() )
-        {
+        for (Artifact a : getArtifacts()) {
             // TODO classpath check doesn't belong here - that's the other method
-            if ( a.getArtifactHandler().isAddedToClasspath() )
-            {
+            if (a.getArtifactHandler().isAddedToClasspath()) {
                 // TODO let the scope handler deal with this
-                if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
-                    || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
-                {
-                    list.add( a );
+                if (Artifact.SCOPE_COMPILE.equals(a.getScope())
+                        || Artifact.SCOPE_PROVIDED.equals(a.getScope())
+                        || Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
+                    list.add(a);
                 }
             }
         }
@@ -1602,152 +1358,130 @@
     }
 
     @Deprecated
-    public List<Dependency> getCompileDependencies()
-    {
+    public List<Dependency> getCompileDependencies() {
         Set<Artifact> artifacts = getArtifacts();
 
-        if ( ( artifacts == null ) || artifacts.isEmpty() )
-        {
+        if ((artifacts == null) || artifacts.isEmpty()) {
             return Collections.emptyList();
         }
 
-        List<Dependency> list = new ArrayList<>( artifacts.size() );
+        List<Dependency> list = new ArrayList<>(artifacts.size());
 
-        for ( Artifact a : getArtifacts() )
-        {
+        for (Artifact a : getArtifacts()) {
             // TODO let the scope handler deal with this
-            if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_PROVIDED.equals( a.getScope() )
-                     || Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
-            {
+            if (Artifact.SCOPE_COMPILE.equals(a.getScope())
+                    || Artifact.SCOPE_PROVIDED.equals(a.getScope())
+                    || Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
                 Dependency dependency = new Dependency();
 
-                dependency.setArtifactId( a.getArtifactId() );
-                dependency.setGroupId( a.getGroupId() );
-                dependency.setVersion( a.getVersion() );
-                dependency.setScope( a.getScope() );
-                dependency.setType( a.getType() );
-                dependency.setClassifier( a.getClassifier() );
+                dependency.setArtifactId(a.getArtifactId());
+                dependency.setGroupId(a.getGroupId());
+                dependency.setVersion(a.getVersion());
+                dependency.setScope(a.getScope());
+                dependency.setType(a.getType());
+                dependency.setClassifier(a.getClassifier());
 
-                list.add( dependency );
+                list.add(dependency);
             }
         }
-        return Collections.unmodifiableList( list );
+        return Collections.unmodifiableList(list);
     }
 
     @Deprecated
-    public List<Artifact> getTestArtifacts()
-    {
-        List<Artifact> list = new ArrayList<>( getArtifacts().size() );
+    public List<Artifact> getTestArtifacts() {
+        List<Artifact> list = new ArrayList<>(getArtifacts().size());
 
-        for ( Artifact a : getArtifacts() )
-        {
+        for (Artifact a : getArtifacts()) {
             // TODO classpath check doesn't belong here - that's the other method
-            if ( a.getArtifactHandler().isAddedToClasspath() )
-            {
-                list.add( a );
+            if (a.getArtifactHandler().isAddedToClasspath()) {
+                list.add(a);
             }
         }
         return list;
     }
 
     @Deprecated
-    public List<Dependency> getTestDependencies()
-    {
+    public List<Dependency> getTestDependencies() {
         Set<Artifact> artifacts = getArtifacts();
 
-        if ( ( artifacts == null ) || artifacts.isEmpty() )
-        {
+        if ((artifacts == null) || artifacts.isEmpty()) {
             return Collections.emptyList();
         }
 
-        List<Dependency> list = new ArrayList<>( artifacts.size() );
+        List<Dependency> list = new ArrayList<>(artifacts.size());
 
-        for ( Artifact a : getArtifacts() )
-        {
+        for (Artifact a : getArtifacts()) {
             Dependency dependency = new Dependency();
 
-            dependency.setArtifactId( a.getArtifactId() );
-            dependency.setGroupId( a.getGroupId() );
-            dependency.setVersion( a.getVersion() );
-            dependency.setScope( a.getScope() );
-            dependency.setType( a.getType() );
-            dependency.setClassifier( a.getClassifier() );
+            dependency.setArtifactId(a.getArtifactId());
+            dependency.setGroupId(a.getGroupId());
+            dependency.setVersion(a.getVersion());
+            dependency.setScope(a.getScope());
+            dependency.setType(a.getType());
+            dependency.setClassifier(a.getClassifier());
 
-            list.add( dependency );
+            list.add(dependency);
         }
-        return Collections.unmodifiableList( list );
+        return Collections.unmodifiableList(list);
     }
 
     @Deprecated // used by the Maven ITs
-    public List<Dependency> getRuntimeDependencies()
-    {
+    public List<Dependency> getRuntimeDependencies() {
         Set<Artifact> artifacts = getArtifacts();
 
-        if ( ( artifacts == null ) || artifacts.isEmpty() )
-        {
+        if ((artifacts == null) || artifacts.isEmpty()) {
             return Collections.emptyList();
         }
 
-        List<Dependency> list = new ArrayList<>( artifacts.size() );
+        List<Dependency> list = new ArrayList<>(artifacts.size());
 
-        for ( Artifact a : getArtifacts() )
-        {
+        for (Artifact a : getArtifacts()) {
             // TODO let the scope handler deal with this
-            if ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_RUNTIME.equals( a.getScope() ) )
-            {
+            if (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope())) {
                 Dependency dependency = new Dependency();
 
-                dependency.setArtifactId( a.getArtifactId() );
-                dependency.setGroupId( a.getGroupId() );
-                dependency.setVersion( a.getVersion() );
-                dependency.setScope( a.getScope() );
-                dependency.setType( a.getType() );
-                dependency.setClassifier( a.getClassifier() );
+                dependency.setArtifactId(a.getArtifactId());
+                dependency.setGroupId(a.getGroupId());
+                dependency.setVersion(a.getVersion());
+                dependency.setScope(a.getScope());
+                dependency.setType(a.getType());
+                dependency.setClassifier(a.getClassifier());
 
-                list.add( dependency );
+                list.add(dependency);
             }
         }
-        return Collections.unmodifiableList( list );
+        return Collections.unmodifiableList(list);
     }
 
     @Deprecated
-    public List<Artifact> getRuntimeArtifacts()
-    {
-        List<Artifact> list = new ArrayList<>( getArtifacts().size() );
+    public List<Artifact> getRuntimeArtifacts() {
+        List<Artifact> list = new ArrayList<>(getArtifacts().size());
 
-        for ( Artifact a : getArtifacts()  )
-        {
+        for (Artifact a : getArtifacts()) {
             // TODO classpath check doesn't belong here - that's the other method
-            if ( a.getArtifactHandler().isAddedToClasspath()
-            // TODO let the scope handler deal with this
-                && ( Artifact.SCOPE_COMPILE.equals( a.getScope() ) || Artifact.SCOPE_RUNTIME.equals( a.getScope() ) ) )
-            {
-                list.add( a );
+            if (a.getArtifactHandler().isAddedToClasspath()
+                    // TODO let the scope handler deal with this
+                    && (Artifact.SCOPE_COMPILE.equals(a.getScope()) || Artifact.SCOPE_RUNTIME.equals(a.getScope()))) {
+                list.add(a);
             }
         }
         return list;
     }
 
     @Deprecated
-    public List<String> getSystemClasspathElements()
-        throws DependencyResolutionRequiredException
-    {
-        List<String> list = new ArrayList<>( getArtifacts().size() );
+    public List<String> getSystemClasspathElements() throws DependencyResolutionRequiredException {
+        List<String> list = new ArrayList<>(getArtifacts().size());
 
         String d = getBuild().getOutputDirectory();
-        if ( d != null )
-        {
-            list.add( d );
+        if (d != null) {
+            list.add(d);
         }
 
-        for ( Artifact a : getArtifacts() )
-        {
-            if ( a.getArtifactHandler().isAddedToClasspath() )
-            {
+        for (Artifact a : getArtifacts()) {
+            if (a.getArtifactHandler().isAddedToClasspath()) {
                 // TODO let the scope handler deal with this
-                if ( Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
-                {
-                    addArtifactPath( a, list );
+                if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
+                    addArtifactPath(a, list);
                 }
             }
         }
@@ -1755,19 +1489,15 @@
     }
 
     @Deprecated
-    public List<Artifact> getSystemArtifacts()
-    {
-        List<Artifact> list = new ArrayList<>( getArtifacts().size() );
+    public List<Artifact> getSystemArtifacts() {
+        List<Artifact> list = new ArrayList<>(getArtifacts().size());
 
-        for ( Artifact a : getArtifacts() )
-        {
+        for (Artifact a : getArtifacts()) {
             // TODO classpath check doesn't belong here - that's the other method
-            if ( a.getArtifactHandler().isAddedToClasspath() )
-            {
+            if (a.getArtifactHandler().isAddedToClasspath()) {
                 // TODO let the scope handler deal with this
-                if ( Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
-                {
-                    list.add( a );
+                if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
+                    list.add(a);
                 }
             }
         }
@@ -1775,112 +1505,95 @@
     }
 
     @Deprecated
-    public List<Dependency> getSystemDependencies()
-    {
+    public List<Dependency> getSystemDependencies() {
         Set<Artifact> artifacts = getArtifacts();
 
-        if ( ( artifacts == null ) || artifacts.isEmpty() )
-        {
+        if ((artifacts == null) || artifacts.isEmpty()) {
             return Collections.emptyList();
         }
 
-        List<Dependency> list = new ArrayList<>( artifacts.size() );
+        List<Dependency> list = new ArrayList<>(artifacts.size());
 
-        for ( Artifact a : getArtifacts() )
-        {
+        for (Artifact a : getArtifacts()) {
             // TODO let the scope handler deal with this
-            if ( Artifact.SCOPE_SYSTEM.equals( a.getScope() ) )
-            {
+            if (Artifact.SCOPE_SYSTEM.equals(a.getScope())) {
                 Dependency dependency = new Dependency();
 
-                dependency.setArtifactId( a.getArtifactId() );
-                dependency.setGroupId( a.getGroupId() );
-                dependency.setVersion( a.getVersion() );
-                dependency.setScope( a.getScope() );
-                dependency.setType( a.getType() );
-                dependency.setClassifier( a.getClassifier() );
+                dependency.setArtifactId(a.getArtifactId());
+                dependency.setGroupId(a.getGroupId());
+                dependency.setVersion(a.getVersion());
+                dependency.setScope(a.getScope());
+                dependency.setType(a.getType());
+                dependency.setClassifier(a.getClassifier());
 
-                list.add( dependency );
+                list.add(dependency);
             }
         }
-        return Collections.unmodifiableList( list );
+        return Collections.unmodifiableList(list);
     }
 
     @Deprecated
-    public void setReporting( Reporting reporting )
-    {
-        getModel().setReporting( reporting );
+    public void setReporting(Reporting reporting) {
+        getModel().setReporting(reporting);
     }
 
     @Deprecated
-    public Reporting getReporting()
-    {
+    public Reporting getReporting() {
         return getModel().getReporting();
     }
 
     @Deprecated
-    public void setReportArtifacts( Set<Artifact> reportArtifacts )
-    {
+    public void setReportArtifacts(Set<Artifact> reportArtifacts) {
         this.reportArtifacts = reportArtifacts;
 
         reportArtifactMap = null;
     }
 
     @Deprecated
-    public Set<Artifact> getReportArtifacts()
-    {
+    public Set<Artifact> getReportArtifacts() {
         return reportArtifacts;
     }
 
     @Deprecated
-    public Map<String, Artifact> getReportArtifactMap()
-    {
-        if ( reportArtifactMap == null )
-        {
-            reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getReportArtifacts() );
+    public Map<String, Artifact> getReportArtifactMap() {
+        if (reportArtifactMap == null) {
+            reportArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getReportArtifacts());
         }
 
         return reportArtifactMap;
     }
 
     @Deprecated
-    public void setExtensionArtifacts( Set<Artifact> extensionArtifacts )
-    {
+    public void setExtensionArtifacts(Set<Artifact> extensionArtifacts) {
         this.extensionArtifacts = extensionArtifacts;
 
         extensionArtifactMap = null;
     }
 
     @Deprecated
-    public Set<Artifact> getExtensionArtifacts()
-    {
+    public Set<Artifact> getExtensionArtifacts() {
         return extensionArtifacts;
     }
 
     @Deprecated
-    public Map<String, Artifact> getExtensionArtifactMap()
-    {
-        if ( extensionArtifactMap == null )
-        {
-            extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId( getExtensionArtifacts() );
+    public Map<String, Artifact> getExtensionArtifactMap() {
+        if (extensionArtifactMap == null) {
+            extensionArtifactMap = ArtifactUtils.artifactMapByVersionlessId(getExtensionArtifacts());
         }
 
         return extensionArtifactMap;
     }
 
     @Deprecated
-    public List<ReportPlugin> getReportPlugins()
-    {
-        if ( getModel().getReporting() == null )
-        {
+    public List<ReportPlugin> getReportPlugins() {
+        if (getModel().getReporting() == null) {
             return Collections.emptyList();
         }
-        return Collections.unmodifiableList( getModel().getReporting().getPlugins() );
+        return Collections.unmodifiableList(getModel().getReporting().getPlugins());
     }
 
     @Deprecated
-    public Xpp3Dom getReportConfiguration( String pluginGroupId, String pluginArtifactId, String reportSetId )
-    {
+    public Xpp3Dom getReportConfiguration(String pluginGroupId, String pluginArtifactId, String reportSetId) {
         Xpp3Dom dom = null;
 
         // ----------------------------------------------------------------------
@@ -1889,24 +1602,18 @@
         // for now I have to iterate through and see what we have.
         // ----------------------------------------------------------------------
 
-        if ( getReportPlugins() != null )
-        {
-            for ( ReportPlugin plugin : getReportPlugins() )
-            {
-                if ( pluginGroupId.equals( plugin.getGroupId() ) && pluginArtifactId.equals( plugin.getArtifactId() ) )
-                {
+        if (getReportPlugins() != null) {
+            for (ReportPlugin plugin : getReportPlugins()) {
+                if (pluginGroupId.equals(plugin.getGroupId()) && pluginArtifactId.equals(plugin.getArtifactId())) {
                     dom = (Xpp3Dom) plugin.getConfiguration();
 
-                    if ( reportSetId != null )
-                    {
-                        ReportSet reportSet = plugin.getReportSetsAsMap().get( reportSetId );
-                        if ( reportSet != null )
-                        {
+                    if (reportSetId != null) {
+                        ReportSet reportSet = plugin.getReportSetsAsMap().get(reportSetId);
+                        if (reportSet != null) {
                             Xpp3Dom executionConfiguration = (Xpp3Dom) reportSet.getConfiguration();
-                            if ( executionConfiguration != null )
-                            {
-                                Xpp3Dom newDom = new Xpp3Dom( executionConfiguration );
-                                dom = Xpp3Dom.mergeXpp3Dom( newDom, dom );
+                            if (executionConfiguration != null) {
+                                Xpp3Dom newDom = new Xpp3Dom(executionConfiguration);
+                                dom = Xpp3Dom.mergeXpp3Dom(newDom, dom);
                             }
                         }
                     }
@@ -1915,10 +1622,9 @@
             }
         }
 
-        if ( dom != null )
-        {
+        if (dom != null) {
             // make a copy so the original in the POM doesn't get messed with
-            dom = new Xpp3Dom( dom );
+            dom = new Xpp3Dom(dom);
         }
 
         return dom;
@@ -1928,35 +1634,28 @@
      * @deprecated Use MavenProjectHelper.attachArtifact(..) instead.
      */
     @Deprecated
-    public void attachArtifact( String type, String classifier, File file )
-    {
+    public void attachArtifact(String type, String classifier, File file) {}
+
+    /**
+     * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
+     */
+    @Deprecated
+    public void writeModel(Writer writer) throws IOException {
+        MavenXpp3Writer pomWriter = new MavenXpp3Writer();
+        pomWriter.write(writer, getModel());
     }
 
     /**
      * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
      */
     @Deprecated
-    public void writeModel( Writer writer )
-        throws IOException
-    {
+    public void writeOriginalModel(Writer writer) throws IOException {
         MavenXpp3Writer pomWriter = new MavenXpp3Writer();
-        pomWriter.write( writer, getModel() );
-    }
-
-    /**
-     * @deprecated Use {@link org.apache.maven.model.io.ModelWriter}.
-     */
-    @Deprecated
-    public void writeOriginalModel( Writer writer )
-        throws IOException
-    {
-        MavenXpp3Writer pomWriter = new MavenXpp3Writer();
-        pomWriter.write( writer, getOriginalModel() );
+        pomWriter.write(writer, getOriginalModel());
     }
 
     @Deprecated
-    public Artifact replaceWithActiveArtifact( Artifact pluginArtifact )
-    {
+    public Artifact replaceWithActiveArtifact(Artifact pluginArtifact) {
         return pluginArtifact;
     }
 
@@ -1968,8 +1667,7 @@
      * @since 2.1
      */
     @Deprecated
-    public ProjectBuildingRequest getProjectBuildingRequest()
-    {
+    public ProjectBuildingRequest getProjectBuildingRequest() {
         return projectBuilderConfiguration;
     }
 
@@ -1982,8 +1680,23 @@
      */
     // used by maven-dependency-tree
     @Deprecated
-    public void setProjectBuildingRequest( ProjectBuildingRequest projectBuildingRequest )
-    {
+    public void setProjectBuildingRequest(ProjectBuildingRequest projectBuildingRequest) {
         this.projectBuilderConfiguration = projectBuildingRequest;
     }
+
+    /**
+     * @since 4.0.0
+     * @return the rootDirectory for this project
+     * @throws IllegalStateException if the rootDirectory cannot be found
+     */
+    public Path getRootDirectory() {
+        if (rootDirectory == null) {
+            throw new IllegalStateException(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
+        }
+        return rootDirectory;
+    }
+
+    public void setRootDirectory(Path rootDirectory) {
+        this.rootDirectory = rootDirectory;
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/MavenProjectHelper.java b/maven-core/src/main/java/org/apache/maven/project/MavenProjectHelper.java
index ec5c390..4e75473 100644
--- a/maven-core/src/main/java/org/apache/maven/project/MavenProjectHelper.java
+++ b/maven-core/src/main/java/org/apache/maven/project/MavenProjectHelper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.util.List;
@@ -25,8 +24,7 @@
 /**
  * Convenience interface for plugins to add or replace artifacts and resources on projects.
  */
-public interface MavenProjectHelper
-{
+public interface MavenProjectHelper {
     String ROLE = MavenProjectHelper.class.getName();
 
     /**
@@ -35,7 +33,7 @@
      * @param artifactFile artifact file.
      * @param artifactClassifier artifact classifier.
      */
-    void attachArtifact( MavenProject project, File artifactFile, String artifactClassifier );
+    void attachArtifact(MavenProject project, File artifactFile, String artifactClassifier);
 
     /**
      * * See {@link #attachArtifact(MavenProject, String, String, java.io.File)}, but with classifier set to null.
@@ -43,7 +41,7 @@
      * @param artifactType artifact type.
      * @param artifactFile artifact file.
      */
-    void attachArtifact( MavenProject project, String artifactType, File artifactFile );
+    void attachArtifact(MavenProject project, String artifactType, File artifactFile);
 
     /**
      * Add or replace an artifact to the current project.
@@ -52,7 +50,7 @@
      * @param artifactClassifier the classifier or null.
      * @param artifactFile the file for the artifact.
      */
-    void attachArtifact( MavenProject project, String artifactType, String artifactClassifier, File artifactFile );
+    void attachArtifact(MavenProject project, String artifactType, String artifactClassifier, File artifactFile);
 
     /**
      * Add a resource directory to the project.
@@ -61,7 +59,7 @@
      * @param includes include patterns.
      * @param excludes exclude patterns.
      */
-    void addResource( MavenProject project, String resourceDirectory, List<String> includes, List<String> excludes );
+    void addResource(MavenProject project, String resourceDirectory, List<String> includes, List<String> excludes);
 
     /**
      * Add a test resource directory to the project.
@@ -70,7 +68,5 @@
      * @param includes include patterns.
      * @param excludes exclude patterns.
      */
-    void addTestResource( MavenProject project, String resourceDirectory, List<String> includes,
-                          List<String> excludes );
-
+    void addTestResource(MavenProject project, String resourceDirectory, List<String> includes, List<String> excludes);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java b/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java
index a2db80e..8c71c48 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.util.List;
@@ -28,8 +27,7 @@
 /**
  * Builds in-memory descriptions of projects.
  */
-public interface ProjectBuilder
-{
+public interface ProjectBuilder {
 
     /**
      * Builds a project descriptor from the specified POM file.
@@ -39,8 +37,7 @@
      * @return The result of the project building, never {@code null}.
      * @throws ProjectBuildingException If the project descriptor could not be successfully built.
      */
-    ProjectBuildingResult build( File projectFile, ProjectBuildingRequest request )
-        throws ProjectBuildingException;
+    ProjectBuildingResult build(File projectFile, ProjectBuildingRequest request) throws ProjectBuildingException;
 
     /**
      * Builds a project descriptor for the specified artifact.
@@ -50,8 +47,8 @@
      * @return The result of the project building, never {@code null}.
      * @throws ProjectBuildingException If the project descriptor could not be successfully built.
      */
-    ProjectBuildingResult build( Artifact projectArtifact, ProjectBuildingRequest request )
-        throws ProjectBuildingException;
+    ProjectBuildingResult build(Artifact projectArtifact, ProjectBuildingRequest request)
+            throws ProjectBuildingException;
 
     /**
      * Builds a project descriptor for the specified artifact.
@@ -64,8 +61,8 @@
      * @return The result of the project building, never {@code null}.
      * @throws ProjectBuildingException If the project descriptor could not be successfully built.
      */
-    ProjectBuildingResult build( Artifact projectArtifact, boolean allowStubModel, ProjectBuildingRequest request )
-        throws ProjectBuildingException;
+    ProjectBuildingResult build(Artifact projectArtifact, boolean allowStubModel, ProjectBuildingRequest request)
+            throws ProjectBuildingException;
 
     /**
      * Builds a project descriptor for the specified model source.
@@ -77,8 +74,8 @@
      *
      * @see org.apache.maven.model.building.ModelSource2
      */
-    ProjectBuildingResult build( ModelSource modelSource, ProjectBuildingRequest request )
-        throws ProjectBuildingException;
+    ProjectBuildingResult build(ModelSource modelSource, ProjectBuildingRequest request)
+            throws ProjectBuildingException;
 
     /**
      * Builds the projects for the specified POM files and optionally their children.
@@ -92,7 +89,6 @@
      * @throws ProjectBuildingException If an error was encountered during building of any project.
      *             {@link ProjectBuildingException#getResults()} provides access to the details of the problems.
      */
-    List<ProjectBuildingResult> build( List<File> pomFiles, boolean recursive, ProjectBuildingRequest request )
-        throws ProjectBuildingException;
-
+    List<ProjectBuildingResult> build(List<File> pomFiles, boolean recursive, ProjectBuildingRequest request)
+            throws ProjectBuildingException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingException.java b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingException.java
index 148d215..d8b3ca5 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingException.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,25 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.util.List;
 
 /**
- * @author Jason van Zyl
  */
-public class ProjectBuildingException
-    extends Exception
-{
+public class ProjectBuildingException extends Exception {
     private final String projectId;
 
     private File pomFile;
 
     private List<ProjectBuildingResult> results;
 
-    public ProjectBuildingException( String projectId, String message, Throwable cause )
-    {
-        super( createMessage( message, projectId, null ), cause );
+    public ProjectBuildingException(String projectId, String message, Throwable cause) {
+        super(createMessage(message, projectId, null), cause);
         this.projectId = projectId;
     }
 
@@ -45,9 +40,8 @@
      * @param message
      * @param pomFile   pom file location
      */
-    public ProjectBuildingException( String projectId, String message, File pomFile )
-    {
-        super( createMessage( message, projectId, pomFile ) );
+    public ProjectBuildingException(String projectId, String message, File pomFile) {
+        super(createMessage(message, projectId, pomFile));
         this.projectId = projectId;
         this.pomFile = pomFile;
     }
@@ -58,60 +52,49 @@
      * @param pomFile   pom file location
      * @param cause
      */
-    protected ProjectBuildingException( String projectId, String message, File pomFile, Throwable cause )
-    {
-        super( createMessage( message, projectId, pomFile ), cause );
+    protected ProjectBuildingException(String projectId, String message, File pomFile, Throwable cause) {
+        super(createMessage(message, projectId, pomFile), cause);
         this.projectId = projectId;
         this.pomFile = pomFile;
     }
 
-    public ProjectBuildingException( List<ProjectBuildingResult> results )
-    {
-        super( "Some problems were encountered while processing the POMs" );
+    public ProjectBuildingException(List<ProjectBuildingResult> results) {
+        super("Some problems were encountered while processing the POMs");
         this.projectId = "";
         this.results = results;
     }
 
-    public File getPomFile()
-    {
+    public File getPomFile() {
         return pomFile;
     }
 
     /**
      * @deprecated use {@link #getPomFile()}
      */
-    public String getPomLocation()
-    {
-        if ( getPomFile() != null )
-        {
+    @Deprecated
+    public String getPomLocation() {
+        if (getPomFile() != null) {
             return getPomFile().getAbsolutePath();
-        }
-        else
-        {
+        } else {
             return "null";
         }
     }
 
-    public String getProjectId()
-    {
+    public String getProjectId() {
         return projectId;
     }
 
-    public List<ProjectBuildingResult> getResults()
-    {
+    public List<ProjectBuildingResult> getResults() {
         return results;
     }
 
-    private static String createMessage( String message, String projectId, File pomFile )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-        buffer.append( message );
-        buffer.append( " for project " ).append( projectId );
-        if ( pomFile != null )
-        {
-            buffer.append( " at " ).append( pomFile.getAbsolutePath() );
+    private static String createMessage(String message, String projectId, File pomFile) {
+        StringBuilder buffer = new StringBuilder(256);
+        buffer.append(message);
+        buffer.append(" for project ").append(projectId);
+        if (pomFile != null) {
+            buffer.append(" at ").append(pomFile.getAbsolutePath());
         }
         return buffer.toString();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingHelper.java b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingHelper.java
index 45fff6e..e9caaca 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingHelper.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingHelper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.List;
 
@@ -34,10 +33,8 @@
  * technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
  * prior notice.
  *
- * @author Benjamin Bentmann
  */
-public interface ProjectBuildingHelper
-{
+public interface ProjectBuildingHelper {
 
     /**
      * Creates the effective artifact repositories from the specified POM repositories.
@@ -50,10 +47,11 @@
      * @return The effective artifact repositories, never {@code null}.
      * @throws InvalidRepositoryException
      */
-    List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
-                                                         List<ArtifactRepository> externalRepositories,
-                                                         ProjectBuildingRequest request )
-        throws InvalidRepositoryException;
+    List<ArtifactRepository> createArtifactRepositories(
+            List<Repository> pomRepositories,
+            List<ArtifactRepository> externalRepositories,
+            ProjectBuildingRequest request)
+            throws InvalidRepositoryException;
 
     /**
      * Creates the project realm that hosts the build extensions of the specified model.
@@ -65,9 +63,8 @@
      * @return The record with the project realm and extension artifact filter, never {@code null}.
      * @throws PluginResolutionException If any build extension could not be resolved.
      */
-    ProjectRealmCache.CacheRecord createProjectRealm( MavenProject project, Model model,
-                                                      ProjectBuildingRequest request )
-        throws PluginResolutionException, PluginVersionResolutionException, PluginManagerException;
+    ProjectRealmCache.CacheRecord createProjectRealm(MavenProject project, Model model, ProjectBuildingRequest request)
+            throws PluginResolutionException, PluginVersionResolutionException, PluginManagerException;
 
     /**
      * Updates the context class loader such that the container will search the project realm when the model builder
@@ -76,6 +73,5 @@
      *
      * @param project The project whose class realm should be selected, must not be {@code null}.
      */
-    void selectProjectRealm( MavenProject project );
-
+    void selectProjectRealm(MavenProject project);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingRequest.java b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingRequest.java
index 80523ae..7d3cae8 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingRequest.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.Date;
 import java.util.List;
@@ -30,18 +29,17 @@
 /**
  * ProjectBuildingRequest
  */
-public interface ProjectBuildingRequest
-{
+public interface ProjectBuildingRequest {
 
-    ProjectBuildingRequest setLocalRepository( ArtifactRepository localRepository );
+    ProjectBuildingRequest setLocalRepository(ArtifactRepository localRepository);
 
     ArtifactRepository getLocalRepository();
 
-    ProjectBuildingRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories );
+    ProjectBuildingRequest setRemoteRepositories(List<ArtifactRepository> remoteRepositories);
 
     List<ArtifactRepository> getRemoteRepositories();
 
-    ProjectBuildingRequest setPluginArtifactRepositories( List<ArtifactRepository> pluginArtifactRepositories );
+    ProjectBuildingRequest setPluginArtifactRepositories(List<ArtifactRepository> pluginArtifactRepositories);
 
     List<ArtifactRepository> getPluginArtifactRepositories();
 
@@ -52,7 +50,7 @@
      * @param systemProperties The system properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ProjectBuildingRequest setSystemProperties( Properties systemProperties );
+    ProjectBuildingRequest setSystemProperties(Properties systemProperties);
 
     /**
      * Gets the system properties to use for interpolation and profile activation. The system properties are collected
@@ -70,7 +68,7 @@
      * @param userProperties The user properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ProjectBuildingRequest setUserProperties( Properties userProperties );
+    ProjectBuildingRequest setUserProperties(Properties userProperties);
 
     /**
      * Gets the user properties to use for interpolation and profile activation. The user properties have been
@@ -81,15 +79,15 @@
      */
     Properties getUserProperties();
 
-    void setProject( MavenProject mavenProject );
+    void setProject(MavenProject mavenProject);
 
     MavenProject getProject();
 
-    ProjectBuildingRequest setProcessPlugins( boolean processPlugins );
+    ProjectBuildingRequest setProcessPlugins(boolean processPlugins);
 
     boolean isProcessPlugins();
 
-    ProjectBuildingRequest setResolveDependencies( boolean resolveDependencies );
+    ProjectBuildingRequest setResolveDependencies(boolean resolveDependencies);
 
     boolean isResolveDependencies();
 
@@ -100,7 +98,7 @@
      *            {@link org.apache.maven.model.building.ModelBuildingRequest#VALIDATION_LEVEL_STRICT}.
      * @return This configuration, never {@code null}.
      */
-    ProjectBuildingRequest setValidationLevel( int validationLevel );
+    ProjectBuildingRequest setValidationLevel(int validationLevel);
 
     /**
      * Gets the level of validation to perform on processed models.
@@ -115,11 +113,11 @@
      * Set any active profiles that the {@link ProjectBuilder} should consider while constructing
      * a {@link MavenProject}.
      */
-    void setActiveProfileIds( List<String> activeProfileIds );
+    void setActiveProfileIds(List<String> activeProfileIds);
 
     List<String> getActiveProfileIds();
 
-    void setInactiveProfileIds( List<String> inactiveProfileIds );
+    void setInactiveProfileIds(List<String> inactiveProfileIds);
 
     List<String> getInactiveProfileIds();
 
@@ -129,9 +127,9 @@
      *
      * @param profile
      */
-    void addProfile( Profile profile );
+    void addProfile(Profile profile);
 
-    void setProfiles( List<Profile> profiles );
+    void setProfiles(List<Profile> profiles);
 
     List<Profile> getProfiles();
 
@@ -147,11 +145,11 @@
      *
      * @param buildStartTime The start time of the build, may be {@code null}.
      */
-    void setBuildStartTime( Date buildStartTime );
+    void setBuildStartTime(Date buildStartTime);
 
     RepositorySystemSession getRepositorySession();
 
-    ProjectBuildingRequest setRepositorySession( RepositorySystemSession repositorySession );
+    ProjectBuildingRequest setRepositorySession(RepositorySystemSession repositorySession);
 
     /**
      * Sets the merge mode used to combine repositories declared in the POM with the repositories specified in this
@@ -161,7 +159,7 @@
      * @return This request for chaining, never {@code null}.
      * @see #setRemoteRepositories(List)
      */
-    ProjectBuildingRequest setRepositoryMerging( RepositoryMerging mode );
+    ProjectBuildingRequest setRepositoryMerging(RepositoryMerging mode);
 
     /**
      * Gets the merge mode used to combine repositories declared in the POM with the repositories specified in this
@@ -185,13 +183,12 @@
      * Commit 6cf9320942c34bc68205425ab696b1712ace9ba4 updated the way 'MavenProject' objects are initialized.
      */
     @Deprecated
-    ProjectBuildingRequest setResolveVersionRanges( boolean value );
+    ProjectBuildingRequest setResolveVersionRanges(boolean value);
 
     /**
      * The possible merge modes for combining remote repositories.
      */
-    enum RepositoryMerging
-    {
+    enum RepositoryMerging {
 
         /**
          * The repositories declared in the POM have precedence over the repositories specified in the request.
@@ -203,5 +200,4 @@
          */
         REQUEST_DOMINANT,
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingResult.java b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingResult.java
index 9a43154..897b055 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingResult.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.util.List;
@@ -27,10 +26,8 @@
 /**
  * Collects the output of the project builder.
  *
- * @author Benjamin Bentmann
  */
-public interface ProjectBuildingResult
-{
+public interface ProjectBuildingResult {
 
     /**
      * Gets the identifier of the project that could not be built. The general format of the identifier is {@code
@@ -70,5 +67,4 @@
      *         not requested.
      */
     DependencyResolutionResult getDependencyResolutionResult();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectDependenciesResolver.java b/maven-core/src/main/java/org/apache/maven/project/ProjectDependenciesResolver.java
index 539055c..d5794be 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectDependenciesResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectDependenciesResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 /**
  * Resolves the transitive dependencies of a project.
  *
- * @author Benjamin Bentmann
  */
-public interface ProjectDependenciesResolver
-{
+public interface ProjectDependenciesResolver {
 
     /**
      * Resolves the transitive dependencies of a project.
@@ -34,7 +31,5 @@
      * @return The resolution result, never {@code null}.
      * @throws DependencyResolutionException If any project dependency could not be resolved.
      */
-    DependencyResolutionResult resolve( DependencyResolutionRequest request )
-        throws DependencyResolutionException;
-
+    DependencyResolutionResult resolve(DependencyResolutionRequest request) throws DependencyResolutionException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java b/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java
index 9caa3e6..0ae5bba 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectModelResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -25,11 +24,12 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.maven.model.Dependency;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Parent;
+import org.apache.maven.api.model.Repository;
 import org.apache.maven.model.Model;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.Repository;
 import org.apache.maven.model.building.ArtifactModelSource;
 import org.apache.maven.model.building.FileModelSource;
 import org.apache.maven.model.building.ModelSource;
@@ -50,16 +50,12 @@
 import org.eclipse.aether.resolution.VersionRangeResolutionException;
 import org.eclipse.aether.resolution.VersionRangeResult;
 
-
 /**
  * A model resolver to assist building of projects. This resolver gives priority to those repositories that have been
  * declared in the POM.
  *
- * @author Benjamin Bentmann
  */
-public class ProjectModelResolver
-    implements ModelResolver
-{
+public class ProjectModelResolver implements ModelResolver {
 
     private final RepositorySystemSession session;
 
@@ -83,216 +79,227 @@
 
     private final ProjectBuildingRequest.RepositoryMerging repositoryMerging;
 
-    public ProjectModelResolver( RepositorySystemSession session, RequestTrace trace, RepositorySystem resolver,
-                                 RemoteRepositoryManager remoteRepositoryManager, List<RemoteRepository> repositories,
-                                 ProjectBuildingRequest.RepositoryMerging repositoryMerging,
-                                 ReactorModelPool modelPool )
-    {
+    public ProjectModelResolver(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            RepositorySystem resolver,
+            RemoteRepositoryManager remoteRepositoryManager,
+            List<RemoteRepository> repositories,
+            ProjectBuildingRequest.RepositoryMerging repositoryMerging,
+            ReactorModelPool modelPool) {
         this.session = session;
         this.trace = trace;
         this.resolver = resolver;
         this.remoteRepositoryManager = remoteRepositoryManager;
         this.pomRepositories = new ArrayList<>();
-        this.externalRepositories = Collections.unmodifiableList( new ArrayList<>( repositories ) );
+        this.externalRepositories = Collections.unmodifiableList(new ArrayList<>(repositories));
         this.repositories = new ArrayList<>();
-        this.repositories.addAll( externalRepositories );
+        this.repositories.addAll(externalRepositories);
         this.repositoryMerging = repositoryMerging;
         this.repositoryIds = new HashSet<>();
         this.modelPool = modelPool;
     }
 
-    private ProjectModelResolver( ProjectModelResolver original )
-    {
+    private ProjectModelResolver(ProjectModelResolver original) {
         this.session = original.session;
         this.trace = original.trace;
         this.resolver = original.resolver;
         this.remoteRepositoryManager = original.remoteRepositoryManager;
-        this.pomRepositories = new ArrayList<>( original.pomRepositories );
+        this.pomRepositories = new ArrayList<>(original.pomRepositories);
         this.externalRepositories = original.externalRepositories;
-        this.repositories = new ArrayList<>( original.repositories );
+        this.repositories = new ArrayList<>(original.repositories);
         this.repositoryMerging = original.repositoryMerging;
-        this.repositoryIds = new HashSet<>( original.repositoryIds );
+        this.repositoryIds = new HashSet<>(original.repositoryIds);
         this.modelPool = original.modelPool;
     }
 
-    public void addRepository( Repository repository )
-        throws InvalidRepositoryException
-    {
-         addRepository( repository, false );
+    public void addRepository(Repository repository) throws InvalidRepositoryException {
+        addRepository(repository, false);
     }
 
     @Override
-    public void addRepository( final Repository repository, boolean replace )
-        throws InvalidRepositoryException
-    {
-        if ( !repositoryIds.add( repository.getId() ) )
-        {
-            if ( !replace )
-            {
+    public void addRepository(final Repository repository, boolean replace) throws InvalidRepositoryException {
+        if (!repositoryIds.add(repository.getId())) {
+            if (!replace) {
                 return;
             }
 
             // Remove any previous repository with this Id
-            removeMatchingRepository( repositories, repository.getId() );
-            removeMatchingRepository( pomRepositories, repository.getId() );
+            removeMatchingRepository(repositories, repository.getId());
+            removeMatchingRepository(pomRepositories, repository.getId());
         }
 
-        List<RemoteRepository> newRepositories =
-            Collections.singletonList( ArtifactDescriptorUtils.toRemoteRepository( repository ) );
+        List<RemoteRepository> newRepositories = Collections.singletonList(
+                ArtifactDescriptorUtils.toRemoteRepository(new org.apache.maven.model.Repository(repository)));
 
-        if ( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals( repositoryMerging ) )
-        {
-            repositories = remoteRepositoryManager.aggregateRepositories( session, repositories, newRepositories,
-                                                                          true );
-        }
-        else
-        {
+        if (ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT.equals(repositoryMerging)) {
+            repositories = remoteRepositoryManager.aggregateRepositories(session, repositories, newRepositories, true);
+        } else {
             pomRepositories =
-                remoteRepositoryManager.aggregateRepositories( session, pomRepositories, newRepositories, true );
-            repositories =
-                remoteRepositoryManager.aggregateRepositories( session, pomRepositories, externalRepositories, false );
+                    remoteRepositoryManager.aggregateRepositories(session, pomRepositories, newRepositories, true);
+            repositories = remoteRepositoryManager.aggregateRepositories(
+                    session, pomRepositories, externalRepositories, false);
         }
     }
 
-    private static void removeMatchingRepository( Iterable<RemoteRepository> repositories, final String id )
-    {
-        Iterator<RemoteRepository> iterator = repositories.iterator( );
-        while ( iterator.hasNext() )
-        {
+    private static void removeMatchingRepository(Iterable<RemoteRepository> repositories, final String id) {
+        Iterator<RemoteRepository> iterator = repositories.iterator();
+        while (iterator.hasNext()) {
             RemoteRepository next = iterator.next();
-            if ( next.getId().equals( id ) )
-            {
+            if (next.getId().equals(id)) {
                 iterator.remove();
             }
         }
     }
 
-    public ModelResolver newCopy()
-    {
-        return new ProjectModelResolver( this );
+    public ModelResolver newCopy() {
+        return new ProjectModelResolver(this);
     }
 
-    public ModelSource resolveModel( String groupId, String artifactId, String version )
-        throws UnresolvableModelException
-    {
-        Artifact pomArtifact = new DefaultArtifact( groupId, artifactId, "", "pom", version );
+    public ModelSource resolveModel(String groupId, String artifactId, String version)
+            throws UnresolvableModelException {
+        Artifact pomArtifact = new DefaultArtifact(groupId, artifactId, "", "pom", version);
 
-        try
-        {
-            ArtifactRequest request = new ArtifactRequest( pomArtifact, repositories, context );
-            request.setTrace( trace );
-            pomArtifact = resolver.resolveArtifact( session, request ).getArtifact();
-        }
-        catch ( ArtifactResolutionException e )
-        {
-            throw new UnresolvableModelException( e.getMessage(), groupId, artifactId, version, e );
+        try {
+            ArtifactRequest request = new ArtifactRequest(pomArtifact, repositories, context);
+            request.setTrace(trace);
+            pomArtifact = resolver.resolveArtifact(session, request).getArtifact();
+        } catch (ArtifactResolutionException e) {
+            throw new UnresolvableModelException(e.getMessage(), groupId, artifactId, version, e);
         }
 
-        return new ArtifactModelSource( pomArtifact.getFile(), groupId, artifactId, version );
+        return new ArtifactModelSource(pomArtifact.getFile(), groupId, artifactId, version);
     }
 
     @Override
-    public ModelSource resolveModel( final Parent parent )
-        throws UnresolvableModelException
-    {
-        try
-        {
-            final Artifact artifact = new DefaultArtifact( parent.getGroupId(), parent.getArtifactId(), "", "pom",
-                                                           parent.getVersion() );
+    public ModelSource resolveModel(final Parent parent, AtomicReference<Parent> modified)
+            throws UnresolvableModelException {
+        try {
+            final Artifact artifact =
+                    new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());
 
-            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest( artifact, repositories, context );
-            versionRangeRequest.setTrace( trace );
+            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, repositories, context);
+            versionRangeRequest.setTrace(trace);
 
-            final VersionRangeResult versionRangeResult = resolver.resolveVersionRange( session, versionRangeRequest );
+            final VersionRangeResult versionRangeResult = resolver.resolveVersionRange(session, versionRangeRequest);
 
-            if ( versionRangeResult.getHighestVersion() == null )
-            {
+            if (versionRangeResult.getHighestVersion() == null) {
                 throw new UnresolvableModelException(
-                    String.format( "No versions matched the requested parent version range '%s'",
-                                   parent.getVersion() ),
-                    parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-
+                        String.format(
+                                "No versions matched the requested parent version range '%s'", parent.getVersion()),
+                        parent.getGroupId(),
+                        parent.getArtifactId(),
+                        parent.getVersion());
             }
 
-            if ( versionRangeResult.getVersionConstraint() != null
-                     && versionRangeResult.getVersionConstraint().getRange() != null
-                     && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null )
-            {
+            if (versionRangeResult.getVersionConstraint() != null
+                    && versionRangeResult.getVersionConstraint().getRange() != null
+                    && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
                 // Message below is checked for in the MNG-2199 core IT.
                 throw new UnresolvableModelException(
-                    String.format( "The requested parent version range '%s' does not specify an upper bound",
-                                   parent.getVersion() ),
-                    parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-
+                        String.format(
+                                "The requested parent version range '%s' does not specify an upper bound",
+                                parent.getVersion()),
+                        parent.getGroupId(),
+                        parent.getArtifactId(),
+                        parent.getVersion());
             }
 
-            parent.setVersion( versionRangeResult.getHighestVersion().toString() );
+            String newVersion = versionRangeResult.getHighestVersion().toString();
+            if (!parent.getVersion().equals(newVersion)) {
+                modified.set(parent.withVersion(newVersion));
+            }
 
-            return resolveModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-        }
-        catch ( final VersionRangeResolutionException e )
-        {
-            throw new UnresolvableModelException( e.getMessage(), parent.getGroupId(), parent.getArtifactId(),
-                                                  parent.getVersion(), e );
-
+            return resolveModel(parent.getGroupId(), parent.getArtifactId(), newVersion);
+        } catch (final VersionRangeResolutionException e) {
+            throw new UnresolvableModelException(
+                    e.getMessage(), parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), e);
         }
     }
 
     @Override
-    public ModelSource resolveModel( final Dependency dependency )
-        throws UnresolvableModelException
-    {
-        try
-        {
-            final Artifact artifact = new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), "",
-                                                           "pom", dependency.getVersion() );
+    public ModelSource resolveModel(final Dependency dependency, AtomicReference<Dependency> modified)
+            throws UnresolvableModelException {
+        try {
+            final Artifact artifact = new DefaultArtifact(
+                    dependency.getGroupId(), dependency.getArtifactId(), "", "pom", dependency.getVersion());
 
-            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest( artifact, repositories, context );
-            versionRangeRequest.setTrace( trace );
+            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, repositories, context);
+            versionRangeRequest.setTrace(trace);
 
-            final VersionRangeResult versionRangeResult = resolver.resolveVersionRange( session, versionRangeRequest );
+            final VersionRangeResult versionRangeResult = resolver.resolveVersionRange(session, versionRangeRequest);
 
-            if ( versionRangeResult.getHighestVersion() == null )
-            {
+            if (versionRangeResult.getHighestVersion() == null) {
                 throw new UnresolvableModelException(
-                    String.format( "No versions matched the requested dependency version range '%s'",
-                                   dependency.getVersion() ),
-                    dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
-
+                        String.format(
+                                "No versions matched the requested dependency version range '%s'",
+                                dependency.getVersion()),
+                        dependency.getGroupId(),
+                        dependency.getArtifactId(),
+                        dependency.getVersion());
             }
 
-            if ( versionRangeResult.getVersionConstraint() != null
-                     && versionRangeResult.getVersionConstraint().getRange() != null
-                     && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null )
-            {
+            if (versionRangeResult.getVersionConstraint() != null
+                    && versionRangeResult.getVersionConstraint().getRange() != null
+                    && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
                 // Message below is checked for in the MNG-4463 core IT.
                 throw new UnresolvableModelException(
-                    String.format( "The requested dependency version range '%s' does not specify an upper bound",
-                                   dependency.getVersion() ),
-                    dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
-
+                        String.format(
+                                "The requested dependency version range '%s' does not specify an upper bound",
+                                dependency.getVersion()),
+                        dependency.getGroupId(),
+                        dependency.getArtifactId(),
+                        dependency.getVersion());
             }
 
-            dependency.setVersion( versionRangeResult.getHighestVersion().toString() );
+            String newVersion = versionRangeResult.getHighestVersion().toString();
+            if (!dependency.getVersion().equals(newVersion)) {
+                modified.set(dependency.withVersion(newVersion));
+            }
 
-            if ( modelPool != null )
-            {
-                Model model =
-                    modelPool.get( dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
+            if (modelPool != null) {
+                Model model = modelPool.get(dependency.getGroupId(), dependency.getArtifactId(), newVersion);
 
-                if ( model != null )
-                {
-                    return new FileModelSource( model.getPomFile() );
+                if (model != null) {
+                    return new FileModelSource(model.getPomFile());
                 }
             }
 
-            return resolveModel( dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
+            return resolveModel(dependency.getGroupId(), dependency.getArtifactId(), newVersion);
+        } catch (VersionRangeResolutionException e) {
+            throw new UnresolvableModelException(
+                    e.getMessage(), dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), e);
         }
-        catch ( VersionRangeResolutionException e )
-        {
-            throw new UnresolvableModelException( e.getMessage(), dependency.getGroupId(), dependency.getArtifactId(),
-                                                  dependency.getVersion(), e );
+    }
 
+    @Override
+    public ModelSource resolveModel(org.apache.maven.model.Parent parent) throws UnresolvableModelException {
+        AtomicReference<org.apache.maven.api.model.Parent> resolvedParent = new AtomicReference<>();
+        ModelSource result = resolveModel(parent.getDelegate(), resolvedParent);
+        if (resolvedParent.get() != null) {
+            parent.setVersion(resolvedParent.get().getVersion());
         }
+        return result;
+    }
+
+    @Override
+    public ModelSource resolveModel(org.apache.maven.model.Dependency dependency) throws UnresolvableModelException {
+        AtomicReference<org.apache.maven.api.model.Dependency> resolvedDependency = new AtomicReference<>();
+        ModelSource result = resolveModel(dependency.getDelegate(), resolvedDependency);
+        if (resolvedDependency.get() != null) {
+            dependency.setVersion(resolvedDependency.get().getVersion());
+        }
+        return result;
+    }
+
+    @Override
+    public void addRepository(org.apache.maven.model.Repository repository) throws InvalidRepositoryException {
+        addRepository(repository.getDelegate());
+    }
+
+    @Override
+    public void addRepository(org.apache.maven.model.Repository repository, boolean replace)
+            throws InvalidRepositoryException {
+        addRepository(repository.getDelegate(), replace);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectRealmCache.java b/maven-core/src/main/java/org/apache/maven/project/ProjectRealmCache.java
index 28ac0d6..dd07b49 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectRealmCache.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectRealmCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.List;
 
@@ -29,33 +28,26 @@
  * technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
  * prior notice.
  *
- * @author Igor Fedorenko
- * @author Benjamin Bentmann
  */
-public interface ProjectRealmCache
-{
+public interface ProjectRealmCache {
 
     /**
      * A cache key.
      */
-    interface Key
-    {
+    interface Key {
         // marker interface for cache keys
     }
 
     /**
      * CacheRecord
      */
-    class CacheRecord
-    {
+    class CacheRecord {
 
-        public ClassRealm getRealm()
-        {
+        public ClassRealm getRealm() {
             return realm;
         }
 
-        public DependencyFilter getExtensionArtifactFilter()
-        {
+        public DependencyFilter getExtensionArtifactFilter() {
             return extensionArtifactFilter;
         }
 
@@ -63,19 +55,17 @@
 
         private final DependencyFilter extensionArtifactFilter;
 
-        CacheRecord( ClassRealm realm, DependencyFilter extensionArtifactFilter )
-        {
+        CacheRecord(ClassRealm realm, DependencyFilter extensionArtifactFilter) {
             this.realm = realm;
             this.extensionArtifactFilter = extensionArtifactFilter;
         }
-
     }
 
-    Key createKey( List<? extends ClassRealm> extensionRealms );
+    Key createKey(List<? extends ClassRealm> extensionRealms);
 
-    CacheRecord get( Key key );
+    CacheRecord get(Key key);
 
-    CacheRecord put( Key key, ClassRealm projectRealm, DependencyFilter extensionArtifactFilter );
+    CacheRecord put(Key key, ClassRealm projectRealm, DependencyFilter extensionArtifactFilter);
 
     void flush();
 
@@ -87,6 +77,5 @@
      * @param project The project that employs the plugin realm, must not be {@code null}.
      * @param record The cache record being used for the project, must not be {@code null}.
      */
-    void register( MavenProject project, Key key, CacheRecord record );
-
+    void register(MavenProject project, Key key, CacheRecord record);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java b/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java
index 1051638..32be1fe 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ProjectSorter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -26,23 +25,19 @@
 import java.util.Map;
 import java.util.stream.Collectors;
 
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Extension;
+import org.apache.maven.api.model.Parent;
+import org.apache.maven.api.model.Plugin;
 import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Extension;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.Plugin;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
-import org.codehaus.plexus.util.dag.DAG;
-import org.codehaus.plexus.util.dag.TopologicalSorter;
-import org.codehaus.plexus.util.dag.Vertex;
+import org.apache.maven.project.Graph.Vertex;
 
 /**
  * ProjectSorter
  */
-public class ProjectSorter
-{
-    private DAG dag;
+public class ProjectSorter {
+    private Graph graph;
 
     private List<MavenProject> sortedProjects;
 
@@ -71,190 +66,214 @@
     // In this case, both the verify and the report goals are called
     // in a different lifecycle. Though the compiler-plugin has a valid use case, although
     // that seems to work fine. We need to take versions and lifecycle into account.
-    public ProjectSorter( Collection<MavenProject> projects )
-        throws CycleDetectedException, DuplicateProjectException
-    {
-        dag = new DAG();
+    public ProjectSorter(Collection<MavenProject> projects) throws CycleDetectedException, DuplicateProjectException {
+        graph = new Graph();
 
         // groupId:artifactId:version -> project
-        projectMap = new HashMap<>( projects.size() * 2 );
+        projectMap = new HashMap<>(projects.size() * 2);
 
         // groupId:artifactId -> (version -> vertex)
-        Map<String, Map<String, Vertex>> vertexMap = new HashMap<>( projects.size() * 2 );
+        Map<String, Map<String, Vertex>> vertexMap = new HashMap<>(projects.size() * 2);
 
-        for ( MavenProject project : projects )
-        {
-            String projectId = getId( project );
+        for (MavenProject project : projects) {
+            String projectId = getId(project);
 
-            MavenProject conflictingProject = projectMap.put( projectId, project );
+            MavenProject conflictingProject = projectMap.put(projectId, project);
 
-            if ( conflictingProject != null )
-            {
-                throw new DuplicateProjectException( projectId, conflictingProject.getFile(), project.getFile(),
-                                                     "Project '" + projectId + "' is duplicated in the reactor" );
+            if (conflictingProject != null) {
+                throw new DuplicateProjectException(
+                        projectId,
+                        conflictingProject.getFile(),
+                        project.getFile(),
+                        "Project '" + projectId + "' is duplicated in the reactor");
             }
 
-            String projectKey = ArtifactUtils.versionlessKey( project.getGroupId(), project.getArtifactId() );
+            String projectKey = ArtifactUtils.versionlessKey(project.getGroupId(), project.getArtifactId());
 
-            Map<String, Vertex> vertices = vertexMap.computeIfAbsent( projectKey, k -> new HashMap<>( 2, 1 ) );
+            Map<String, Vertex> vertices = vertexMap.computeIfAbsent(projectKey, k -> new HashMap<>(2, 1));
 
-            vertices.put( project.getVersion(), dag.addVertex( projectId ) );
+            vertices.put(project.getVersion(), graph.addVertex(projectId));
         }
 
-        for ( Vertex projectVertex : dag.getVertices() )
-        {
+        for (Vertex projectVertex : graph.getVertices()) {
             String projectId = projectVertex.getLabel();
 
-            MavenProject project = projectMap.get( projectId );
+            MavenProject project = projectMap.get(projectId);
 
-            for ( Dependency dependency : project.getDependencies() )
-            {
-                addEdge( projectMap, vertexMap, project, projectVertex, dependency.getGroupId(),
-                         dependency.getArtifactId(), dependency.getVersion(), false, false );
+            for (Dependency dependency : project.getModel().getDelegate().getDependencies()) {
+                addEdge(
+                        projectMap,
+                        vertexMap,
+                        project,
+                        projectVertex,
+                        dependency.getGroupId(),
+                        dependency.getArtifactId(),
+                        dependency.getVersion(),
+                        false,
+                        false);
             }
 
-            Parent parent = project.getModel().getParent();
+            Parent parent = project.getModel().getDelegate().getParent();
 
-            if ( parent != null )
-            {
+            if (parent != null) {
                 // Parent is added as an edge, but must not cause a cycle - so we remove any other edges it has
                 // in conflict
-                addEdge( projectMap, vertexMap, null, projectVertex, parent.getGroupId(), parent.getArtifactId(),
-                         parent.getVersion(), true, false );
+                addEdge(
+                        projectMap,
+                        vertexMap,
+                        null,
+                        projectVertex,
+                        parent.getGroupId(),
+                        parent.getArtifactId(),
+                        parent.getVersion(),
+                        true,
+                        false);
             }
 
-            for ( Plugin plugin : project.getBuildPlugins() )
-            {
-                addEdge( projectMap, vertexMap, project, projectVertex, plugin.getGroupId(),
-                         plugin.getArtifactId(), plugin.getVersion(), false, true );
+            Build build = project.getModel().getDelegate().getBuild();
+            if (build != null) {
+                for (Plugin plugin : build.getPlugins()) {
+                    addEdge(
+                            projectMap,
+                            vertexMap,
+                            project,
+                            projectVertex,
+                            plugin.getGroupId(),
+                            plugin.getArtifactId(),
+                            plugin.getVersion(),
+                            false,
+                            true);
 
-                for ( Dependency dependency : plugin.getDependencies() )
-                {
-                    addEdge( projectMap, vertexMap, project, projectVertex, dependency.getGroupId(),
-                             dependency.getArtifactId(), dependency.getVersion(), false, true );
+                    for (Dependency dependency : plugin.getDependencies()) {
+                        addEdge(
+                                projectMap,
+                                vertexMap,
+                                project,
+                                projectVertex,
+                                dependency.getGroupId(),
+                                dependency.getArtifactId(),
+                                dependency.getVersion(),
+                                false,
+                                true);
+                    }
                 }
-            }
 
-            for ( Extension extension : project.getBuildExtensions() )
-            {
-                addEdge( projectMap, vertexMap, project, projectVertex, extension.getGroupId(),
-                         extension.getArtifactId(), extension.getVersion(), false, true );
+                for (Extension extension : build.getExtensions()) {
+                    addEdge(
+                            projectMap,
+                            vertexMap,
+                            project,
+                            projectVertex,
+                            extension.getGroupId(),
+                            extension.getArtifactId(),
+                            extension.getVersion(),
+                            false,
+                            true);
+                }
             }
         }
 
-        List<String> sortedProjectLabels = TopologicalSorter.sort( dag );
+        List<String> sortedProjectLabels = graph.visitAll();
 
-        this.sortedProjects = sortedProjectLabels.stream().map( id -> projectMap.get( id ) )
-                .collect( Collectors.collectingAndThen( Collectors.toList(), Collections::unmodifiableList ) );
+        this.sortedProjects = sortedProjectLabels.stream()
+                .map(id -> projectMap.get(id))
+                .collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
     }
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private void addEdge( Map<String, MavenProject> projectMap, Map<String, Map<String, Vertex>> vertexMap,
-                          MavenProject project, Vertex projectVertex, String groupId, String artifactId,
-                          String version, boolean force, boolean safe )
-        throws CycleDetectedException
-    {
-        String projectKey = ArtifactUtils.versionlessKey( groupId, artifactId );
 
-        Map<String, Vertex> vertices = vertexMap.get( projectKey );
+    @SuppressWarnings("checkstyle:parameternumber")
+    private void addEdge(
+            Map<String, MavenProject> projectMap,
+            Map<String, Map<String, Vertex>> vertexMap,
+            MavenProject project,
+            Vertex projectVertex,
+            String groupId,
+            String artifactId,
+            String version,
+            boolean force,
+            boolean safe)
+            throws CycleDetectedException {
+        String projectKey = ArtifactUtils.versionlessKey(groupId, artifactId);
 
-        if ( vertices != null )
-        {
-            if ( isSpecificVersion( version ) )
-            {
-                Vertex vertex = vertices.get( version );
-                if ( vertex != null )
-                {
-                    addEdge( projectVertex, vertex, project, projectMap, force, safe );
+        Map<String, Vertex> vertices = vertexMap.get(projectKey);
+
+        if (vertices != null) {
+            if (isSpecificVersion(version)) {
+                Vertex vertex = vertices.get(version);
+                if (vertex != null) {
+                    addEdge(projectVertex, vertex, project, projectMap, force, safe);
                 }
-            }
-            else
-            {
-                for ( Vertex vertex : vertices.values() )
-                {
-                    addEdge( projectVertex, vertex, project, projectMap, force, safe );
+            } else {
+                for (Vertex vertex : vertices.values()) {
+                    addEdge(projectVertex, vertex, project, projectMap, force, safe);
                 }
             }
         }
     }
 
-    private void addEdge( Vertex fromVertex, Vertex toVertex, MavenProject fromProject,
-                          Map<String, MavenProject> projectMap, boolean force, boolean safe )
-        throws CycleDetectedException
-    {
-        if ( fromVertex.equals( toVertex ) )
-        {
+    private void addEdge(
+            Vertex fromVertex,
+            Vertex toVertex,
+            MavenProject fromProject,
+            Map<String, MavenProject> projectMap,
+            boolean force,
+            boolean safe)
+            throws CycleDetectedException {
+        if (fromVertex.equals(toVertex)) {
             return;
         }
 
-        if ( fromProject != null )
-        {
-            MavenProject toProject = projectMap.get( toVertex.getLabel() );
-            fromProject.addProjectReference( toProject );
+        if (fromProject != null) {
+            MavenProject toProject = projectMap.get(toVertex.getLabel());
+            fromProject.addProjectReference(toProject);
         }
 
-        if ( force && toVertex.getChildren().contains( fromVertex ) )
-        {
-            dag.removeEdge( toVertex, fromVertex );
+        if (force && toVertex.getChildren().contains(fromVertex)) {
+            graph.removeEdge(toVertex, fromVertex);
         }
 
-        try
-        {
-            dag.addEdge( fromVertex, toVertex );
-        }
-        catch ( CycleDetectedException e )
-        {
-            if ( !safe )
-            {
+        try {
+            graph.addEdge(fromVertex, toVertex);
+        } catch (CycleDetectedException e) {
+            if (!safe) {
                 throw e;
             }
         }
     }
 
-    private boolean isSpecificVersion( String version )
-    {
-        return !( StringUtils.isEmpty( version ) || version.startsWith( "[" ) || version.startsWith( "(" ) );
+    private boolean isSpecificVersion(String version) {
+        return !((version == null || version.isEmpty()) || version.startsWith("[") || version.startsWith("("));
     }
 
-    // TODO !![jc; 28-jul-2005] check this; if we're using '-r' and there are aggregator tasks, this will result in weirdness.
-    public MavenProject getTopLevelProject()
-    {
-        return sortedProjects.stream().filter( MavenProject::isExecutionRoot ).findFirst()
-                .orElse( null );
+    // TODO !![jc; 28-jul-2005] check this; if we're using '-r' and there are aggregator tasks, this will result in
+    // weirdness.
+    public MavenProject getTopLevelProject() {
+        return sortedProjects.stream()
+                .filter(MavenProject::isExecutionRoot)
+                .findFirst()
+                .orElse(null);
     }
 
-    public List<MavenProject> getSortedProjects()
-    {
+    public List<MavenProject> getSortedProjects() {
         return sortedProjects;
     }
 
-    public boolean hasMultipleProjects()
-    {
+    public boolean hasMultipleProjects() {
         return sortedProjects.size() > 1;
     }
 
-    public List<String> getDependents( String id )
-    {
-        return dag.getParentLabels( id );
+    public List<String> getDependents(String id) {
+        return graph.getVertex(id).getParents().stream().map(Vertex::getLabel).collect(Collectors.toList());
     }
 
-    public List<String> getDependencies( String id )
-    {
-        return dag.getChildLabels( id );
+    public List<String> getDependencies(String id) {
+        return graph.getVertex(id).getChildren().stream().map(Vertex::getLabel).collect(Collectors.toList());
     }
 
-    public static String getId( MavenProject project )
-    {
-        return ArtifactUtils.key( project.getGroupId(), project.getArtifactId(), project.getVersion() );
+    public static String getId(MavenProject project) {
+        return ArtifactUtils.key(project.getGroupId(), project.getArtifactId(), project.getVersion());
     }
 
-    public DAG getDAG()
-    {
-        return dag;
-    }
-
-    public Map<String, MavenProject> getProjectMap()
-    {
+    public Map<String, MavenProject> getProjectMap() {
         return projectMap;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java b/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java
index de8af7e..1a17572 100644
--- a/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java
+++ b/maven-core/src/main/java/org/apache/maven/project/ReactorModelPool.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.maven.model.Model;
 
@@ -34,14 +32,11 @@
  * Holds all Models that are known to the reactor. This allows the project builder to resolve imported Models from the
  * reactor when building another project's effective model.
  *
- * @author Benjamin Bentmann
- * @author Robert Scholte
  */
-class ReactorModelPool
-{
-    private final Map<GAKey, Set<Model>> modelsByGa = new HashMap<>();
+class ReactorModelPool {
+    private final Map<GAKey, Set<Model>> modelsByGa = new ConcurrentHashMap<>();
 
-    private final Map<Path, Model> modelsByPath = new HashMap<>();
+    private final Map<Path, Model> modelsByPath = new ConcurrentHashMap<>();
 
     /**
      * Get the model by its GAV or (since 4.0.0) by its GA if there is only one.
@@ -52,78 +47,40 @@
      * @return the matching model or {@code null}
      * @throws IllegalStateException if version was null and multiple modules share the same groupId + artifactId
      */
-    public Model get( String groupId, String artifactId, String version )
-    {
-        return modelsByGa.getOrDefault( new GAKey( groupId, artifactId ), Collections.emptySet() ).stream()
-                        .filter( m -> version == null || version.equals( getVersion( m ) ) )
-                        .reduce( ( a, b ) ->
-                        {
-                            throw new IllegalStateException( "Multiple modules with key "
-                                + a.getGroupId() + ':' + a.getArtifactId() );
-                        } ).orElse( null );
+    public Model get(String groupId, String artifactId, String version) {
+        return modelsByGa.getOrDefault(new GAKey(groupId, artifactId), Collections.emptySet()).stream()
+                .filter(m -> version == null || version.equals(getVersion(m)))
+                .reduce((a, b) -> {
+                    throw new IllegalStateException(
+                            "Multiple modules with key " + a.getGroupId() + ':' + a.getArtifactId());
+                })
+                .orElse(null);
     }
 
-    /**
-     * Find model by path, useful when location the parent by relativePath
-     *
-     * @param path
-     * @return the matching model or {@code null}
-     * @since 4.0.0
-     */
-    public Model get( Path path )
-    {
-        final Path pomFile;
-        if ( Files.isDirectory( path ) )
-        {
-            pomFile = path.resolve( "pom.xml" );
-        }
-        else
-        {
-            pomFile = path;
-        }
-        return modelsByPath.get( pomFile );
-    }
-
-    private String getVersion( Model model )
-    {
+    private String getVersion(Model model) {
         String version = model.getVersion();
-        if ( version == null && model.getParent() != null )
-        {
+        if (version == null && model.getParent() != null) {
             version = model.getParent().getVersion();
         }
         return version;
     }
 
-    static class Builder
-    {
-        private ReactorModelPool pool = new ReactorModelPool();
-
-        Builder put( Path pomFile, Model model )
-        {
-            pool.modelsByPath.put( pomFile, model );
-            pool.modelsByGa.computeIfAbsent( new GAKey( getGroupId( model ), model.getArtifactId() ),
-                                             k -> new HashSet<Model>() ).add( model );
-            return this;
-        }
-
-        ReactorModelPool build()
-        {
-            return pool;
-        }
-
-        private static String getGroupId( Model model )
-        {
-            String groupId = model.getGroupId();
-            if ( groupId == null && model.getParent() != null )
-            {
-                groupId = model.getParent().getGroupId();
-            }
-            return groupId;
-        }
+    void put(Path pomFile, Model model) {
+        modelsByPath.put(pomFile, model);
+        modelsByGa
+                .computeIfAbsent(new GAKey(getGroupId(model), model.getArtifactId()), k -> new HashSet<>())
+                .add(model);
     }
 
-    private static final class GAKey
-    {
+    private static String getGroupId(Model model) {
+        String groupId = model.getGroupId();
+        if (groupId == null && model.getParent() != null) {
+            groupId = model.getParent().getGroupId();
+        }
+        return groupId;
+    }
+
+    private static final class GAKey {
 
         private final String groupId;
 
@@ -131,40 +88,33 @@
 
         private final int hashCode;
 
-        GAKey( String groupId, String artifactId )
-        {
-            this.groupId = ( groupId != null ) ? groupId : "";
-            this.artifactId = ( artifactId != null ) ? artifactId : "";
+        GAKey(String groupId, String artifactId) {
+            this.groupId = (groupId != null) ? groupId : "";
+            this.artifactId = (artifactId != null) ? artifactId : "";
 
-            hashCode = Objects.hash( this.groupId, this.artifactId );
+            hashCode = Objects.hash(this.groupId, this.artifactId);
         }
 
         @Override
-        public boolean equals( Object obj )
-        {
-            if ( this == obj )
-            {
+        public boolean equals(Object obj) {
+            if (this == obj) {
                 return true;
             }
-
+            if (!(obj instanceof GAKey)) {
+                return false;
+            }
             GAKey that = (GAKey) obj;
-
-            return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId );
+            return artifactId.equals(that.artifactId) && groupId.equals(that.groupId);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public String toString()
-        {
-            StringBuilder buffer = new StringBuilder( 128 );
-            buffer.append( groupId ).append( ':' ).append( artifactId );
-            return buffer.toString();
+        public String toString() {
+            return groupId + ':' + artifactId;
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/RepositorySessionDecorator.java b/maven-core/src/main/java/org/apache/maven/project/RepositorySessionDecorator.java
index d739c75..e8c1daf 100644
--- a/maven-core/src/main/java/org/apache/maven/project/RepositorySessionDecorator.java
+++ b/maven-core/src/main/java/org/apache/maven/project/RepositorySessionDecorator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import org.eclipse.aether.RepositorySystemSession;
 
@@ -27,10 +26,9 @@
  * <strong>Note:</strong> This interface is part of work in progress and can be changed or removed without notice.
  * @since 3.2.4
  */
-public interface RepositorySessionDecorator
-{
+public interface RepositorySessionDecorator {
     /**
      * Returns possibly {@code null} Aether repository system session to be used to resolve project dependencies.
      */
-    RepositorySystemSession decorate( MavenProject project, RepositorySystemSession session );
+    RepositorySystemSession decorate(MavenProject project, RepositorySystemSession session);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ActiveProjectArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ActiveProjectArtifact.java
deleted file mode 100644
index 5a96efd..0000000
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/ActiveProjectArtifact.java
+++ /dev/null
@@ -1,401 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.handler.ArtifactHandler;
-import org.apache.maven.artifact.metadata.ArtifactMetadata;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-import org.apache.maven.artifact.versioning.ArtifactVersion;
-import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
-import org.apache.maven.artifact.versioning.VersionRange;
-import org.apache.maven.project.MavenProject;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.List;
-
-/**
- * Wraps an active project instance to be able to receive updates from its artifact without affecting the original
- * attributes of this artifact.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- * TODO I think this exposes a design flaw in that the immutable and mutable parts of an artifact are in one class and
- * should be split. ie scope, file, etc depend on the context of use, whereas everything else is immutable.
- */
-@Deprecated
-public class ActiveProjectArtifact
-    implements Artifact
-{
-    private final Artifact artifact;
-
-    private final MavenProject project;
-
-    public ActiveProjectArtifact( MavenProject project, Artifact artifact )
-    {
-        this.artifact = artifact;
-        this.project = project;
-
-        artifact.setFile( project.getArtifact().getFile() );
-        artifact.setResolved( true );
-    }
-
-    /** {@inheritDoc} */
-    public File getFile()
-    {
-        // we need to get the latest file for the project, not the artifact that was created at one point in time
-        return project.getArtifact().getFile();
-    }
-
-    /** {@inheritDoc} */
-    public String getGroupId()
-    {
-        return artifact.getGroupId();
-    }
-
-    /** {@inheritDoc} */
-    public String getArtifactId()
-    {
-        return artifact.getArtifactId();
-    }
-
-    /** {@inheritDoc} */
-    public String getVersion()
-    {
-        return artifact.getVersion();
-    }
-
-    /** {@inheritDoc} */
-    public void setVersion( String version )
-    {
-        artifact.setVersion( version );
-    }
-
-    /** {@inheritDoc} */
-    public String getScope()
-    {
-        return artifact.getScope();
-    }
-
-    /** {@inheritDoc} */
-    public String getType()
-    {
-        return artifact.getType();
-    }
-
-    /** {@inheritDoc} */
-    public String getClassifier()
-    {
-        return artifact.getClassifier();
-    }
-
-    /** {@inheritDoc} */
-    public boolean hasClassifier()
-    {
-        return artifact.hasClassifier();
-    }
-
-    /** {@inheritDoc} */
-    public void setFile( File destination )
-    {
-        artifact.setFile( destination );
-        project.getArtifact().setFile( destination );
-    }
-
-    /** {@inheritDoc} */
-    public String getBaseVersion()
-    {
-        return artifact.getBaseVersion();
-    }
-
-    /** {@inheritDoc} */
-    public void setBaseVersion( String baseVersion )
-    {
-        artifact.setBaseVersion( baseVersion );
-    }
-
-    /** {@inheritDoc} */
-    public String getId()
-    {
-        return artifact.getId();
-    }
-
-    /** {@inheritDoc} */
-    public String getDependencyConflictId()
-    {
-        return artifact.getDependencyConflictId();
-    }
-
-    /** {@inheritDoc} */
-    public void addMetadata( ArtifactMetadata metadata )
-    {
-        artifact.addMetadata( metadata );
-    }
-
-    /** {@inheritDoc} */
-    public Collection<ArtifactMetadata> getMetadataList()
-    {
-        return artifact.getMetadataList();
-    }
-
-    /** {@inheritDoc} */
-    public void setRepository( ArtifactRepository remoteRepository )
-    {
-        artifact.setRepository( remoteRepository );
-    }
-
-    /** {@inheritDoc} */
-    public ArtifactRepository getRepository()
-    {
-        return artifact.getRepository();
-    }
-
-    /** {@inheritDoc} */
-    public void updateVersion( String version, ArtifactRepository localRepository )
-    {
-        artifact.updateVersion( version, localRepository );
-    }
-
-    /** {@inheritDoc} */
-    public String getDownloadUrl()
-    {
-        return artifact.getDownloadUrl();
-    }
-
-    /** {@inheritDoc} */
-    public void setDownloadUrl( String downloadUrl )
-    {
-        artifact.setDownloadUrl( downloadUrl );
-    }
-
-    /** {@inheritDoc} */
-    public ArtifactFilter getDependencyFilter()
-    {
-        return artifact.getDependencyFilter();
-    }
-
-    /** {@inheritDoc} */
-    public void setDependencyFilter( ArtifactFilter artifactFilter )
-    {
-        artifact.setDependencyFilter( artifactFilter );
-    }
-
-    /** {@inheritDoc} */
-    public ArtifactHandler getArtifactHandler()
-    {
-        return artifact.getArtifactHandler();
-    }
-
-    /** {@inheritDoc} */
-    public List<String> getDependencyTrail()
-    {
-        return artifact.getDependencyTrail();
-    }
-
-    /** {@inheritDoc} */
-    public void setDependencyTrail( List<String> dependencyTrail )
-    {
-        artifact.setDependencyTrail( dependencyTrail );
-    }
-
-    /** {@inheritDoc} */
-    public void setScope( String scope )
-    {
-        artifact.setScope( scope );
-    }
-
-    /** {@inheritDoc} */
-    public VersionRange getVersionRange()
-    {
-        return artifact.getVersionRange();
-    }
-
-    /** {@inheritDoc} */
-    public void setVersionRange( VersionRange newRange )
-    {
-        artifact.setVersionRange( newRange );
-    }
-
-    /** {@inheritDoc} */
-    public void selectVersion( String version )
-    {
-        artifact.selectVersion( version );
-    }
-
-    /** {@inheritDoc} */
-    public void setGroupId( String groupId )
-    {
-        artifact.setGroupId( groupId );
-    }
-
-    /** {@inheritDoc} */
-    public void setArtifactId( String artifactId )
-    {
-        artifact.setArtifactId( artifactId );
-    }
-
-    /** {@inheritDoc} */
-    public boolean isSnapshot()
-    {
-        return artifact.isSnapshot();
-    }
-
-    /** {@inheritDoc} */
-    public int compareTo( Artifact a )
-    {
-        return artifact.compareTo( a );
-    }
-
-    /** {@inheritDoc} */
-    public void setResolved( boolean resolved )
-    {
-        artifact.setResolved( resolved );
-    }
-
-    /** {@inheritDoc} */
-    public boolean isResolved()
-    {
-        return artifact.isResolved();
-    }
-
-    /** {@inheritDoc} */
-    public void setResolvedVersion( String version )
-    {
-        artifact.setResolvedVersion( version );
-    }
-
-    /** {@inheritDoc} */
-    public void setArtifactHandler( ArtifactHandler handler )
-    {
-        artifact.setArtifactHandler( handler );
-    }
-
-    /** {@inheritDoc} */
-    public String toString()
-    {
-        return "active project artifact[artifact: " + artifact + ", project: " + project + "]";
-    }
-
-    /** {@inheritDoc} */
-    public boolean isRelease()
-    {
-        return artifact.isRelease();
-    }
-
-    /** {@inheritDoc} */
-    public void setRelease( boolean release )
-    {
-        artifact.setRelease( release );
-    }
-
-    /** {@inheritDoc} */
-    public List<ArtifactVersion> getAvailableVersions()
-    {
-        return artifact.getAvailableVersions();
-    }
-
-    /** {@inheritDoc} */
-    public void setAvailableVersions( List<ArtifactVersion> versions )
-    {
-        artifact.setAvailableVersions( versions );
-    }
-
-    /** {@inheritDoc} */
-    public boolean isOptional()
-    {
-        return artifact.isOptional();
-    }
-
-    /** {@inheritDoc} */
-    public ArtifactVersion getSelectedVersion()
-        throws OverConstrainedVersionException
-    {
-        return artifact.getSelectedVersion();
-    }
-
-    /** {@inheritDoc} */
-    public boolean isSelectedVersionKnown()
-        throws OverConstrainedVersionException
-    {
-        return artifact.isSelectedVersionKnown();
-    }
-
-    /** {@inheritDoc} */
-    public void setOptional( boolean optional )
-    {
-        artifact.setOptional( optional );
-    }
-
-    /** {@inheritDoc} */
-    public int hashCode()
-    {
-        int result = 17;
-
-        result = 37 * result + getGroupId().hashCode();
-        result = 37 * result + getArtifactId().hashCode();
-        result = 37 * result + getType().hashCode();
-        if ( getVersion() != null )
-        {
-            result = 37 * result + getVersion().hashCode();
-        }
-        result = 37 * result + ( getClassifier() != null ? getClassifier().hashCode() : 0 );
-
-        return result;
-    }
-
-    /** {@inheritDoc} */
-    public boolean equals( Object o )
-    {
-        if ( o == this )
-        {
-            return true;
-        }
-
-        if ( !( o instanceof Artifact ) )
-        {
-            return false;
-        }
-
-        Artifact a = (Artifact) o;
-
-        if ( !a.getGroupId().equals( getGroupId() ) )
-        {
-            return false;
-        }
-        else if ( !a.getArtifactId().equals( getArtifactId() ) )
-        {
-            return false;
-        }
-        else if ( !a.getVersion().equals( getVersion() ) )
-        {
-            return false;
-        }
-        else if ( !a.getType().equals( getType() ) )
-        {
-            return false;
-        }
-        else
-        {
-            return a.getClassifier() == null ? getClassifier() == null : a.getClassifier().equals( getClassifier() );
-        }
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ArtifactWithDependencies.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ArtifactWithDependencies.java
index a83cae6..01806ca 100644
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/ArtifactWithDependencies.java
+++ b/maven-core/src/main/java/org/apache/maven/project/artifact/ArtifactWithDependencies.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
 
 import java.util.List;
 
@@ -26,11 +25,9 @@
 /**
  * ArtifactWithDependencies
  */
-public interface ArtifactWithDependencies
-{
+public interface ArtifactWithDependencies {
 
     List<Dependency> getDependencies();
 
     List<Dependency> getManagedDependencies();
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/AttachedArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/AttachedArtifact.java
index fd2b956..aa6a36c 100644
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/AttachedArtifact.java
+++ b/maven-core/src/main/java/org/apache/maven/project/artifact/AttachedArtifact.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.DefaultArtifact;
@@ -28,158 +31,137 @@
 import org.apache.maven.artifact.versioning.ArtifactVersion;
 import org.apache.maven.artifact.versioning.VersionRange;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
 /**
  *<strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
  * of the public API. In particular, this class can be changed or deleted without prior notice. Use
  * {@link org.apache.maven.project.MavenProjectHelper#attachArtifact} instead.
  */
 @Deprecated
-public class AttachedArtifact
-    extends DefaultArtifact
-{
+public class AttachedArtifact extends DefaultArtifact {
 
     private final Artifact parent;
 
-    public AttachedArtifact( Artifact parent, String type, String classifier, ArtifactHandler artifactHandler )
-    {
-        super( parent.getGroupId(), parent.getArtifactId(), parent.getVersionRange(), parent.getScope(), type,
-               classifier, artifactHandler, parent.isOptional() );
+    public AttachedArtifact(Artifact parent, String type, String classifier, ArtifactHandler artifactHandler) {
+        super(
+                parent.getGroupId(),
+                parent.getArtifactId(),
+                parent.getVersionRange(),
+                parent.getScope(),
+                type,
+                classifier,
+                artifactHandler,
+                parent.isOptional());
 
-        setDependencyTrail( Collections.singletonList( parent.getId() ) );
+        setDependencyTrail(Collections.singletonList(parent.getId()));
 
         this.parent = parent;
 
-        if ( getId().equals( parent.getId() ) )
-        {
-            throw new InvalidArtifactRTException( parent.getGroupId(), parent.getArtifactId(), parent.getVersion(),
-                                                  parent.getType(), "An attached artifact must have a different ID"
-                                                      + " than its corresponding main artifact." );
+        if (getId().equals(parent.getId())) {
+            throw new InvalidArtifactRTException(
+                    parent.getGroupId(),
+                    parent.getArtifactId(),
+                    parent.getVersion(),
+                    parent.getType(),
+                    "An attached artifact must have a different ID" + " than its corresponding main artifact.");
         }
     }
 
-    public AttachedArtifact( Artifact parent, String type, ArtifactHandler artifactHandler )
-    {
-        this( parent, type, null, artifactHandler );
+    public AttachedArtifact(Artifact parent, String type, ArtifactHandler artifactHandler) {
+        this(parent, type, null, artifactHandler);
     }
 
-    public void setArtifactId( String artifactId )
-    {
-        throw new UnsupportedOperationException( "Cannot change the artifactId for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setArtifactId(String artifactId) {
+        throw new UnsupportedOperationException(
+                "Cannot change the artifactId for an attached artifact." + " It is derived from the main artifact.");
     }
 
-    public List<ArtifactVersion> getAvailableVersions()
-    {
+    public List<ArtifactVersion> getAvailableVersions() {
         return parent.getAvailableVersions();
     }
 
-    public void setAvailableVersions( List<ArtifactVersion> availableVersions )
-    {
-        throw new UnsupportedOperationException( "Cannot change the version information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setAvailableVersions(List<ArtifactVersion> availableVersions) {
+        throw new UnsupportedOperationException("Cannot change the version information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public String getBaseVersion()
-    {
+    public String getBaseVersion() {
         return parent.getBaseVersion();
     }
 
-    public void setBaseVersion( String baseVersion )
-    {
-        throw new UnsupportedOperationException( "Cannot change the version information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setBaseVersion(String baseVersion) {
+        throw new UnsupportedOperationException("Cannot change the version information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public String getDownloadUrl()
-    {
+    public String getDownloadUrl() {
         return parent.getDownloadUrl();
     }
 
-    public void setDownloadUrl( String downloadUrl )
-    {
-        throw new UnsupportedOperationException( "Cannot change the download information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setDownloadUrl(String downloadUrl) {
+        throw new UnsupportedOperationException("Cannot change the download information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public void setGroupId( String groupId )
-    {
-        throw new UnsupportedOperationException( "Cannot change the groupId for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setGroupId(String groupId) {
+        throw new UnsupportedOperationException(
+                "Cannot change the groupId for an attached artifact." + " It is derived from the main artifact.");
     }
 
-    public ArtifactRepository getRepository()
-    {
+    public ArtifactRepository getRepository() {
         return parent.getRepository();
     }
 
-    public void setRepository( ArtifactRepository repository )
-    {
-        throw new UnsupportedOperationException( "Cannot change the repository information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setRepository(ArtifactRepository repository) {
+        throw new UnsupportedOperationException("Cannot change the repository information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public String getScope()
-    {
+    public String getScope() {
         return parent.getScope();
     }
 
-    public void setScope( String scope )
-    {
-        throw new UnsupportedOperationException( "Cannot change the scoping information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setScope(String scope) {
+        throw new UnsupportedOperationException("Cannot change the scoping information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return parent.getVersion();
     }
 
-    public void setVersion( String version )
-    {
-        throw new UnsupportedOperationException( "Cannot change the version information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setVersion(String version) {
+        throw new UnsupportedOperationException("Cannot change the version information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public VersionRange getVersionRange()
-    {
+    public VersionRange getVersionRange() {
         return parent.getVersionRange();
     }
 
-    public void setVersionRange( VersionRange range )
-    {
-        throw new UnsupportedOperationException( "Cannot change the version information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setVersionRange(VersionRange range) {
+        throw new UnsupportedOperationException("Cannot change the version information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public boolean isRelease()
-    {
+    public boolean isRelease() {
         return parent.isRelease();
     }
 
-    public void setRelease( boolean release )
-    {
-        throw new UnsupportedOperationException( "Cannot change the version information for an attached artifact."
-            + " It is derived from the main artifact." );
+    public void setRelease(boolean release) {
+        throw new UnsupportedOperationException("Cannot change the version information for an attached artifact."
+                + " It is derived from the main artifact.");
     }
 
-    public boolean isSnapshot()
-    {
+    public boolean isSnapshot() {
         return parent.isSnapshot();
     }
 
-    public void addMetadata( ArtifactMetadata metadata )
-    {
+    public void addMetadata(ArtifactMetadata metadata) {
         // ignore. The parent artifact will handle metadata.
         // we must fail silently here to avoid problems with the artifact transformers.
     }
 
-    public Collection<ArtifactMetadata> getMetadataList()
-    {
+    public Collection<ArtifactMetadata> getMetadataList() {
         return Collections.emptyList();
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultMavenMetadataCache.java b/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultMavenMetadataCache.java
deleted file mode 100644
index 5768709..0000000
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultMavenMetadataCache.java
+++ /dev/null
@@ -1,356 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.artifact.metadata.ResolutionGroup;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-
-/**
- * DefaultMavenMetadataCache
- */
-@Named
-@Singleton
-public class DefaultMavenMetadataCache
-    implements MavenMetadataCache
-{
-
-    protected final Map<CacheKey, CacheRecord> cache = new ConcurrentHashMap<>();
-
-    /**
-     * CacheKey
-     */
-    public static class CacheKey
-    {
-        private final Artifact artifact;
-        private final long pomHash;
-        private final boolean resolveManagedVersions;
-        private final List<ArtifactRepository> repositories = new ArrayList<>();
-        private final int hashCode;
-
-        public CacheKey( Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
-                         List<ArtifactRepository> remoteRepositories )
-        {
-            File file = artifact.getFile();
-            this.artifact = ArtifactUtils.copyArtifact( artifact );
-            if ( "pom".equals( artifact.getType() ) && file != null )
-            {
-                pomHash = file.getPath().hashCode() + file.lastModified();
-            }
-            else
-            {
-                pomHash = 0;
-            }
-            this.resolveManagedVersions = resolveManagedVersions;
-            this.repositories.add( localRepository );
-            this.repositories.addAll( remoteRepositories );
-
-            int hash = 17;
-            hash = hash * 31 + artifactHashCode( artifact );
-            hash = hash * 31 + ( resolveManagedVersions ? 1 : 2 );
-            hash = hash * 31 + repositoriesHashCode( repositories );
-            this.hashCode = hash;
-        }
-
-        @Override
-        public int hashCode()
-        {
-            return hashCode;
-        }
-
-        @Override
-        public boolean equals( Object o )
-        {
-            if ( o == this )
-            {
-                return true;
-            }
-
-            if ( !( o instanceof CacheKey ) )
-            {
-                return false;
-            }
-
-            CacheKey other = (CacheKey) o;
-
-            return pomHash == other.pomHash && artifactEquals( artifact, other.artifact )
-                && resolveManagedVersions == other.resolveManagedVersions
-                && repositoriesEquals( repositories, other.repositories );
-        }
-    }
-
-    private static int artifactHashCode( Artifact a )
-    {
-        int result = 17;
-        result = 31 * result + a.getGroupId().hashCode();
-        result = 31 * result + a.getArtifactId().hashCode();
-        result = 31 * result + a.getType().hashCode();
-        if ( a.getVersion() != null )
-        {
-            result = 31 * result + a.getVersion().hashCode();
-        }
-        result = 31 * result + ( a.getClassifier() != null ? a.getClassifier().hashCode() : 0 );
-        result = 31 * result + ( a.getScope() != null ? a.getScope().hashCode() : 0 );
-        result = 31 * result + ( a.getDependencyFilter() != null ? a.getDependencyFilter().hashCode() : 0 );
-        result = 31 * result + ( a.isOptional() ? 1 : 0 );
-        return result;
-    }
-
-    private static boolean artifactEquals( Artifact a1, Artifact a2 )
-    {
-        if ( a1 == a2 )
-        {
-            return true;
-        }
-
-        return Objects.equals( a1.getGroupId(), a2.getGroupId() )
-            && Objects.equals( a1.getArtifactId(), a2.getArtifactId() )
-            && Objects.equals( a1.getType(), a2.getType() )
-            && Objects.equals( a1.getVersion(), a2.getVersion() )
-            && Objects.equals( a1.getClassifier(), a2.getClassifier() )
-            && Objects.equals( a1.getScope(), a2.getScope() )
-            && Objects.equals( a1.getDependencyFilter(), a2.getDependencyFilter() )
-            && a1.isOptional() == a2.isOptional();
-    }
-
-    private static int repositoryHashCode( ArtifactRepository repository )
-    {
-        int result = 17;
-        result = 31 * result + ( repository.getId() != null ? repository.getId().hashCode() : 0 );
-        return result;
-    }
-
-    private static int repositoriesHashCode( List<ArtifactRepository> repositories )
-    {
-        int result = 17;
-        for ( ArtifactRepository repository : repositories )
-        {
-            result = 31 * result + repositoryHashCode( repository );
-        }
-        return result;
-    }
-
-    private static boolean repositoryEquals( ArtifactRepository r1, ArtifactRepository r2 )
-    {
-        if ( r1 == r2 )
-        {
-            return true;
-        }
-
-        return Objects.equals( r1.getId(), r2.getId() )
-            && Objects.equals( r1.getUrl(), r2.getUrl() )
-            && repositoryPolicyEquals( r1.getReleases(), r2.getReleases() )
-            && repositoryPolicyEquals( r1.getSnapshots(), r2.getSnapshots() );
-    }
-
-    private static boolean repositoryPolicyEquals( ArtifactRepositoryPolicy p1, ArtifactRepositoryPolicy p2 )
-    {
-        if ( p1 == p2 )
-        {
-            return true;
-        }
-
-        return p1.isEnabled() == p2.isEnabled() && Objects.equals( p1.getUpdatePolicy(), p2.getUpdatePolicy() );
-    }
-
-    private static boolean repositoriesEquals( List<ArtifactRepository> r1, List<ArtifactRepository> r2 )
-    {
-        if ( r1.size() != r2.size() )
-        {
-            return false;
-        }
-
-        for ( Iterator<ArtifactRepository> it1 = r1.iterator(), it2 = r2.iterator(); it1.hasNext(); )
-        {
-            if ( !repositoryEquals( it1.next(), it2.next() ) )
-            {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    /**
-     * CacheRecord
-     */
-    public class CacheRecord
-    {
-        private Artifact pomArtifact;
-        private Artifact relocatedArtifact;
-        private List<Artifact> artifacts;
-        private Map<String, Artifact> managedVersions;
-        private List<ArtifactRepository> remoteRepositories;
-
-        private long length;
-        private long timestamp;
-
-        CacheRecord( Artifact pomArtifact, Artifact relocatedArtifact, Set<Artifact> artifacts,
-                     Map<String, Artifact> managedVersions, List<ArtifactRepository> remoteRepositories )
-        {
-            this.pomArtifact = ArtifactUtils.copyArtifact( pomArtifact );
-            this.relocatedArtifact = ArtifactUtils.copyArtifactSafe( relocatedArtifact );
-            this.artifacts = ArtifactUtils.copyArtifacts( artifacts, new ArrayList<>() );
-            this.remoteRepositories = new ArrayList<>( remoteRepositories );
-
-            this.managedVersions = managedVersions;
-            if ( managedVersions != null )
-            {
-                this.managedVersions =
-                    ArtifactUtils.copyArtifacts( managedVersions, new LinkedHashMap<>() );
-            }
-
-            File pomFile = pomArtifact.getFile();
-            if ( pomFile != null && pomFile.canRead() )
-            {
-                this.length = pomFile.length();
-                this.timestamp = pomFile.lastModified();
-            }
-            else
-            {
-                this.length = -1;
-                this.timestamp = -1;
-            }
-        }
-
-        public Artifact getArtifact()
-        {
-            return pomArtifact;
-        }
-
-        public Artifact getRelocatedArtifact()
-        {
-            return relocatedArtifact;
-        }
-
-        public List<Artifact> getArtifacts()
-        {
-            return artifacts;
-        }
-
-        public Map<String, Artifact> getManagedVersions()
-        {
-            return managedVersions;
-        }
-
-        public List<ArtifactRepository> getRemoteRepositories()
-        {
-            return remoteRepositories;
-        }
-
-        public boolean isStale()
-        {
-            File pomFile = pomArtifact.getFile();
-            if ( pomFile != null )
-            {
-                if ( pomFile.canRead() )
-                {
-                    return length != pomFile.length() || timestamp != pomFile.lastModified();
-                }
-                else
-                {
-                    // if the POM didn't exist, retry if any repo is configured to always update
-                    boolean snapshot = pomArtifact.isSnapshot();
-                    for ( ArtifactRepository repository : remoteRepositories )
-                    {
-                        ArtifactRepositoryPolicy policy =
-                            snapshot ? repository.getSnapshots() : repository.getReleases();
-                        if ( ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS.equals( policy.getUpdatePolicy() ) )
-                        {
-                            return true;
-                        }
-                    }
-                }
-            }
-
-            return length != -1 || timestamp != -1;
-        }
-    }
-
-
-    public ResolutionGroup get( Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
-                                List<ArtifactRepository> remoteRepositories )
-    {
-        CacheKey cacheKey = newCacheKey( artifact, resolveManagedVersions, localRepository, remoteRepositories );
-
-        CacheRecord cacheRecord = cache.get( cacheKey );
-
-        if ( cacheRecord != null && !cacheRecord.isStale() )
-        {
-            Artifact pomArtifact = ArtifactUtils.copyArtifact( cacheRecord.getArtifact() );
-            Artifact relocatedArtifact = ArtifactUtils.copyArtifactSafe( cacheRecord.getRelocatedArtifact() );
-            Set<Artifact> artifacts =
-                ArtifactUtils.copyArtifacts( cacheRecord.getArtifacts(), new LinkedHashSet<>() );
-            Map<String, Artifact> managedVersions = cacheRecord.getManagedVersions();
-            if ( managedVersions != null )
-            {
-                managedVersions = ArtifactUtils.copyArtifacts( managedVersions, new LinkedHashMap<>() );
-            }
-            return new ResolutionGroup( pomArtifact, relocatedArtifact, artifacts, managedVersions,
-                                        cacheRecord.getRemoteRepositories() );
-        }
-
-        cache.remove( cacheKey );
-
-        return null;
-    }
-
-    public void put( Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
-                     List<ArtifactRepository> remoteRepositories, ResolutionGroup result )
-    {
-        put( newCacheKey( artifact, resolveManagedVersions, localRepository, remoteRepositories ), result );
-    }
-
-    protected CacheKey newCacheKey( Artifact artifact, boolean resolveManagedVersions,
-                                    ArtifactRepository localRepository, List<ArtifactRepository> remoteRepositories )
-    {
-        return new CacheKey( artifact, resolveManagedVersions, localRepository, remoteRepositories );
-    }
-
-    protected void put( CacheKey cacheKey, ResolutionGroup result )
-    {
-        CacheRecord cacheRecord =
-            new CacheRecord( result.getPomArtifact(), result.getRelocatedArtifact(), result.getArtifacts(),
-                             result.getManagedVersions(), result.getResolutionRepositories() );
-
-        cache.put( cacheKey, cacheRecord );
-    }
-
-    public void flush()
-    {
-        cache.clear();
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultMetadataSource.java b/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultMetadataSource.java
deleted file mode 100644
index 8a8eb6f..0000000
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultMetadataSource.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.factory.ArtifactFactory;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
-import org.apache.maven.plugin.LegacySupport;
-import org.apache.maven.project.ProjectBuilder;
-
-/**
- * This realizes the metadata source via the default hint to provide backward-compat with Maven 2.x whose Plexus version
- * registered component descriptors twice: once keyed by role+roleHint and once keyed by role only. This effectively
- * made the metadata source available with its original role hint ("maven") as well as the default hint.
- *
- * @author Benjamin Bentmann
- */
-@Named
-@Singleton
-public class DefaultMetadataSource
-    extends MavenMetadataSource
-{
-    @Inject
-    public DefaultMetadataSource(
-            RepositoryMetadataManager repositoryMetadataManager, ArtifactFactory repositorySystem,
-            ProjectBuilder projectBuilder, MavenMetadataCache cache, LegacySupport legacySupport )
-    {
-        super( repositoryMetadataManager, repositorySystem, projectBuilder, cache, legacySupport );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCache.java b/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCache.java
index b4ec77d..7cce250 100644
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCache.java
+++ b/maven-core/src/main/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -30,9 +32,6 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.RepositoryUtils;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
@@ -43,21 +42,14 @@
 import org.eclipse.aether.repository.WorkspaceRepository;
 
 /**
- * @author Igor Fedorenko
- * @author Benjamin Bentmann
- * @author Anton Tanasenko
  */
 @Named
 @Singleton
-public class DefaultProjectArtifactsCache
-    implements ProjectArtifactsCache
-{
+public class DefaultProjectArtifactsCache implements ProjectArtifactsCache {
     /**
      * CacheKey
      */
-    protected static class CacheKey
-        implements Key
-    {
+    protected static class CacheKey implements Key {
 
         private final String groupId;
 
@@ -81,118 +73,116 @@
 
         private final int hashCode;
 
-        public CacheKey( MavenProject project, List<RemoteRepository> repositories,
-            Collection<String> scopesToCollect, Collection<String> scopesToResolve, boolean aggregating,
-            RepositorySystemSession session )
-        {
+        public CacheKey(
+                MavenProject project,
+                List<RemoteRepository> repositories,
+                Collection<String> scopesToCollect,
+                Collection<String> scopesToResolve,
+                boolean aggregating,
+                RepositorySystemSession session) {
 
             groupId = project.getGroupId();
             artifactId = project.getArtifactId();
             version = project.getVersion();
 
             Set<String> deps = new LinkedHashSet<>();
-            if ( project.getDependencyArtifacts() != null )
-            {
-              for ( Artifact dep: project.getDependencyArtifacts() )
-              {
-                deps.add( dep.toString() );
-              }
-            }
-            dependencyArtifacts = Collections.unmodifiableSet( deps );
-
-            workspace = RepositoryUtils.getWorkspace( session );
-            this.localRepo = session.getLocalRepository();
-            this.repositories = new ArrayList<>( repositories.size() );
-            for ( RemoteRepository repository : repositories )
-            {
-                if ( repository.isRepositoryManager() )
-                {
-                    this.repositories.addAll( repository.getMirroredRepositories() );
+            if (project.getDependencyArtifacts() != null) {
+                for (Artifact dep : project.getDependencyArtifacts()) {
+                    deps.add(dep.toString());
                 }
-                else
-                {
-                    this.repositories.add( repository );
+            }
+            dependencyArtifacts = Collections.unmodifiableSet(deps);
+
+            workspace = RepositoryUtils.getWorkspace(session);
+            this.localRepo = session.getLocalRepository();
+            this.repositories = new ArrayList<>(repositories.size());
+            for (RemoteRepository repository : repositories) {
+                if (repository.isRepositoryManager()) {
+                    this.repositories.addAll(repository.getMirroredRepositories());
+                } else {
+                    this.repositories.add(repository);
                 }
             }
             collect = scopesToCollect == null
-                ? Collections.emptySet()
-                : Collections.unmodifiableSet( new HashSet<>( scopesToCollect ) );
+                    ? Collections.emptySet()
+                    : Collections.unmodifiableSet(new HashSet<>(scopesToCollect));
             resolve = scopesToResolve == null
-                ? Collections.emptySet()
-                : Collections.unmodifiableSet( new HashSet<>( scopesToResolve ) );
+                    ? Collections.emptySet()
+                    : Collections.unmodifiableSet(new HashSet<>(scopesToResolve));
             this.aggregating = aggregating;
 
             int hash = 17;
-            hash = hash * 31 + Objects.hashCode( groupId );
-            hash = hash * 31 + Objects.hashCode( artifactId );
-            hash = hash * 31 + Objects.hashCode( version );
-            hash = hash * 31 + Objects.hashCode( dependencyArtifacts );
-            hash = hash * 31 + Objects.hashCode( workspace );
-            hash = hash * 31 + Objects.hashCode( localRepo );
-            hash = hash * 31 + RepositoryUtils.repositoriesHashCode( repositories );
-            hash = hash * 31 + Objects.hashCode( collect );
-            hash = hash * 31 + Objects.hashCode( resolve );
-            hash = hash * 31 + Objects.hashCode( aggregating );
+            hash = hash * 31 + Objects.hashCode(groupId);
+            hash = hash * 31 + Objects.hashCode(artifactId);
+            hash = hash * 31 + Objects.hashCode(version);
+            hash = hash * 31 + Objects.hashCode(dependencyArtifacts);
+            hash = hash * 31 + Objects.hashCode(workspace);
+            hash = hash * 31 + Objects.hashCode(localRepo);
+            hash = hash * 31 + RepositoryUtils.repositoriesHashCode(repositories);
+            hash = hash * 31 + Objects.hashCode(collect);
+            hash = hash * 31 + Objects.hashCode(resolve);
+            hash = hash * 31 + Objects.hashCode(aggregating);
             this.hashCode = hash;
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return groupId + ":" + artifactId + ":" + version;
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public boolean equals( Object o )
-        {
-            if ( o == this )
-            {
+        public boolean equals(Object o) {
+            if (o == this) {
                 return true;
             }
 
-            if ( !( o instanceof CacheKey ) )
-            {
+            if (!(o instanceof CacheKey)) {
                 return false;
             }
 
             CacheKey that = (CacheKey) o;
 
-            return Objects.equals( groupId, that.groupId ) && Objects.equals( artifactId, that.artifactId )
-                && Objects.equals( version, that.version )
-                && Objects.equals( dependencyArtifacts, that.dependencyArtifacts )
-                && Objects.equals( workspace, that.workspace )
-                && Objects.equals( localRepo, that.localRepo )
-                && RepositoryUtils.repositoriesEquals( repositories, that.repositories )
-                && Objects.equals( collect, that.collect )
-                && Objects.equals( resolve, that.resolve )
-                && aggregating == that.aggregating;
+            return Objects.equals(groupId, that.groupId)
+                    && Objects.equals(artifactId, that.artifactId)
+                    && Objects.equals(version, that.version)
+                    && Objects.equals(dependencyArtifacts, that.dependencyArtifacts)
+                    && Objects.equals(workspace, that.workspace)
+                    && Objects.equals(localRepo, that.localRepo)
+                    && RepositoryUtils.repositoriesEquals(repositories, that.repositories)
+                    && Objects.equals(collect, that.collect)
+                    && Objects.equals(resolve, that.resolve)
+                    && aggregating == that.aggregating;
         }
     }
 
     protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<>();
 
     @Override
-    public Key createKey( MavenProject project, Collection<String> scopesToCollect,
-        Collection<String> scopesToResolve, boolean aggregating, RepositorySystemSession session )
-    {
-        return new CacheKey( project, project.getRemoteProjectRepositories(), scopesToCollect, scopesToResolve,
-            aggregating, session );
+    public Key createKey(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            boolean aggregating,
+            RepositorySystemSession session) {
+        return new CacheKey(
+                project,
+                project.getRemoteProjectRepositories(),
+                scopesToCollect,
+                scopesToResolve,
+                aggregating,
+                session);
     }
 
     @Override
-    public CacheRecord get( Key key )
-        throws LifecycleExecutionException
-    {
-        CacheRecord cacheRecord = cache.get( key );
+    public CacheRecord get(Key key) throws LifecycleExecutionException {
+        CacheRecord cacheRecord = cache.get(key);
 
-        if ( cacheRecord != null && cacheRecord.getException() != null )
-        {
+        if (cacheRecord != null && cacheRecord.getException() != null) {
             throw cacheRecord.getException();
         }
 
@@ -200,52 +190,44 @@
     }
 
     @Override
-    public CacheRecord put( Key key, Set<Artifact> projectArtifacts )
-    {
-        Objects.requireNonNull( projectArtifacts, "projectArtifacts cannot be null" );
+    public CacheRecord put(Key key, Set<Artifact> projectArtifacts) {
+        Objects.requireNonNull(projectArtifacts, "projectArtifacts cannot be null");
 
-        assertUniqueKey( key );
+        assertUniqueKey(key);
 
-        CacheRecord record =
-            new CacheRecord( Collections.unmodifiableSet( new LinkedHashSet<>( projectArtifacts ) ) );
+        CacheRecord record = new CacheRecord(Collections.unmodifiableSet(new LinkedHashSet<>(projectArtifacts)));
 
-        cache.put( key, record );
+        cache.put(key, record);
 
         return record;
     }
 
-    protected void assertUniqueKey( Key key )
-    {
-        if ( cache.containsKey( key ) )
-        {
-            throw new IllegalStateException( "Duplicate artifact resolution result for project " + key );
+    protected void assertUniqueKey(Key key) {
+        if (cache.containsKey(key)) {
+            throw new IllegalStateException("Duplicate artifact resolution result for project " + key);
         }
     }
 
     @Override
-    public CacheRecord put( Key key, LifecycleExecutionException exception )
-    {
-        Objects.requireNonNull( exception, "exception cannot be null" );
+    public CacheRecord put(Key key, LifecycleExecutionException exception) {
+        Objects.requireNonNull(exception, "exception cannot be null");
 
-        assertUniqueKey( key );
+        assertUniqueKey(key);
 
-        CacheRecord record = new CacheRecord( exception );
+        CacheRecord record = new CacheRecord(exception);
 
-        cache.put( key, record );
+        cache.put(key, record);
 
         return record;
     }
 
     @Override
-    public void flush()
-    {
+    public void flush() {
         cache.clear();
     }
 
     @Override
-    public void register( MavenProject project, Key cacheKey, CacheRecord record )
-    {
+    public void register(MavenProject project, Key cacheKey, CacheRecord record) {
         // default cache does not track record usage
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/InvalidDependencyVersionException.java b/maven-core/src/main/java/org/apache/maven/project/artifact/InvalidDependencyVersionException.java
index 8a1de68..605c7b1 100644
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/InvalidDependencyVersionException.java
+++ b/maven-core/src/main/java/org/apache/maven/project/artifact/InvalidDependencyVersionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
 
 import java.io.File;
 
@@ -29,27 +28,21 @@
 /**
  * Thrown if a dependency has an invalid version.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class InvalidDependencyVersionException
-    extends InvalidProjectVersionException
-{
+public class InvalidDependencyVersionException extends InvalidProjectVersionException {
     private Dependency dependency;
 
-    public InvalidDependencyVersionException( String projectId, Dependency dependency, File pomFile,
-                                              InvalidVersionSpecificationException cause )
-    {
-        super( projectId, formatLocationInPom( dependency ), dependency.getVersion(), pomFile, cause );
+    public InvalidDependencyVersionException(
+            String projectId, Dependency dependency, File pomFile, InvalidVersionSpecificationException cause) {
+        super(projectId, formatLocationInPom(dependency), dependency.getVersion(), pomFile, cause);
         this.dependency = dependency;
     }
 
-    private static String formatLocationInPom( Dependency dependency )
-    {
-        return "Dependency: " + ArtifactUtils.versionlessKey( dependency.getGroupId(), dependency.getArtifactId() );
+    private static String formatLocationInPom(Dependency dependency) {
+        return "Dependency: " + ArtifactUtils.versionlessKey(dependency.getGroupId(), dependency.getArtifactId());
     }
 
-    public Dependency getDependency()
-    {
+    public Dependency getDependency() {
         return dependency;
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataCache.java b/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataCache.java
deleted file mode 100644
index 033e42a..0000000
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataCache.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.metadata.ResolutionGroup;
-
-/**
- * MavenMetadataCache
- */
-public interface MavenMetadataCache
-{
-
-    ResolutionGroup get( Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
-                         List<ArtifactRepository> remoteRepositories );
-
-    void put( Artifact artifact, boolean resolveManagedVersions, ArtifactRepository localRepository,
-              List<ArtifactRepository> remoteRepositories, ResolutionGroup result );
-
-    void flush();
-}
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java b/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java
deleted file mode 100644
index b55110a..0000000
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/MavenMetadataSource.java
+++ /dev/null
@@ -1,769 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.RepositoryUtils;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.factory.ArtifactFactory;
-import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
-import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
-import org.apache.maven.artifact.metadata.ResolutionGroup;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
-import org.apache.maven.artifact.repository.metadata.Metadata;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadata;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadataResolutionException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.artifact.resolver.MultipleArtifactsNotFoundException;
-import org.apache.maven.artifact.resolver.filter.AndArtifactFilter;
-import org.apache.maven.artifact.resolver.filter.ArtifactFilter;
-import org.apache.maven.artifact.resolver.filter.ExclusionArtifactFilter;
-import org.apache.maven.artifact.versioning.ArtifactVersion;
-import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
-import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
-import org.apache.maven.artifact.versioning.VersionRange;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Relocation;
-import org.apache.maven.model.building.ModelBuildingException;
-import org.apache.maven.model.building.ModelBuildingRequest;
-import org.apache.maven.model.building.ModelProblem;
-import org.apache.maven.model.resolution.UnresolvableModelException;
-import org.apache.maven.plugin.LegacySupport;
-import org.apache.maven.project.DefaultProjectBuildingRequest;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.project.ProjectBuilder;
-import org.apache.maven.project.ProjectBuildingException;
-import org.apache.maven.project.ProjectBuildingRequest;
-import org.apache.maven.properties.internal.EnvironmentUtils;
-import org.apache.maven.properties.internal.SystemProperties;
-import org.apache.maven.repository.internal.MavenWorkspaceReader;
-import org.apache.maven.repository.legacy.metadata.DefaultMetadataResolutionRequest;
-import org.apache.maven.repository.legacy.metadata.MetadataResolutionRequest;
-import org.eclipse.aether.RepositorySystemSession;
-import org.eclipse.aether.repository.RepositoryPolicy;
-import org.eclipse.aether.repository.WorkspaceReader;
-import org.eclipse.aether.transfer.ArtifactNotFoundException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * @author Jason van Zyl
- */
-@Named( "maven" )
-@Singleton
-public class MavenMetadataSource
-    implements ArtifactMetadataSource
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
-    private final RepositoryMetadataManager repositoryMetadataManager;
-    private final ArtifactFactory repositorySystem;
-    private final ProjectBuilder projectBuilder;
-    private final MavenMetadataCache cache;
-    private final LegacySupport legacySupport;
-
-    @Inject
-    public MavenMetadataSource(
-            RepositoryMetadataManager repositoryMetadataManager,
-            ArtifactFactory repositorySystem,
-            ProjectBuilder projectBuilder,
-            MavenMetadataCache cache,
-            LegacySupport legacySupport )
-    {
-        this.repositoryMetadataManager = repositoryMetadataManager;
-        this.repositorySystem = repositorySystem;
-        this.projectBuilder = projectBuilder;
-        this.cache = cache;
-        this.legacySupport = legacySupport;
-    }
-
-    private void injectSession( MetadataResolutionRequest request )
-    {
-        RepositorySystemSession session = legacySupport.getRepositorySession();
-
-        if ( session != null )
-        {
-            request.setOffline( session.isOffline() );
-            request.setForceUpdate( RepositoryPolicy.UPDATE_POLICY_ALWAYS.equals( session.getUpdatePolicy() ) );
-        }
-    }
-
-    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                                     List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException
-    {
-        return retrieve( artifact, localRepository, remoteRepositories, false );
-    }
-
-    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                                     List<ArtifactRepository> remoteRepositories, boolean resolveManagedVersions )
-        throws ArtifactMetadataRetrievalException
-    {
-        MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
-        injectSession( request );
-        request.setArtifact( artifact );
-        request.setLocalRepository( localRepository );
-        request.setRemoteRepositories( remoteRepositories );
-        request.setResolveManagedVersions( resolveManagedVersions );
-        return retrieve( request );
-    }
-
-    public ResolutionGroup retrieve( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException
-    {
-        Artifact artifact = request.getArtifact();
-
-        //
-        // If we have a system scoped artifact then we do not want any searching in local or remote repositories
-        // and we want artifact resolution to only return the system scoped artifact itself.
-        //
-        if ( artifact.getScope() != null && artifact.getScope().equals( Artifact.SCOPE_SYSTEM ) )
-        {
-            return new ResolutionGroup( null, null, null );
-        }
-
-        ResolutionGroup cached =
-            cache.get( artifact, request.isResolveManagedVersions(), request.getLocalRepository(),
-                       request.getRemoteRepositories() );
-
-        if ( cached != null
-        // if the POM has no file, we cached a missing artifact, only return the cached data if no update forced
-            && ( !request.isForceUpdate() || hasFile( cached.getPomArtifact() ) ) )
-        {
-            return cached;
-        }
-
-        List<Dependency> dependencies;
-
-        List<Dependency> managedDependencies = null;
-
-        List<ArtifactRepository> pomRepositories = null;
-
-        Artifact pomArtifact;
-
-        Artifact relocatedArtifact = null;
-
-        // TODO hack: don't rebuild model if it was already loaded during reactor resolution
-        final WorkspaceReader workspace = legacySupport.getRepositorySession().getWorkspaceReader();
-        Model model = null;
-        if ( workspace instanceof MavenWorkspaceReader )
-        {
-            model = ( (MavenWorkspaceReader) workspace ).findModel( RepositoryUtils.toArtifact( artifact ) );
-        }
-
-        if ( model != null )
-        {
-            pomArtifact = artifact;
-            dependencies = model.getDependencies();
-            DependencyManagement dependencyManagement = model.getDependencyManagement();
-            managedDependencies = dependencyManagement == null ? null : dependencyManagement.getDependencies();
-            MavenSession session = legacySupport.getSession();
-            pomRepositories = session.getProjects().stream()
-                    .filter( p -> artifact.equals( p.getArtifact() ) )
-                    .map( MavenProject::getRemoteArtifactRepositories )
-                    .findFirst()
-                    .orElseGet( ArrayList::new );
-        }
-        else if ( artifact instanceof ArtifactWithDependencies )
-        {
-            pomArtifact = artifact;
-
-            dependencies = ( (ArtifactWithDependencies) artifact ).getDependencies();
-
-            managedDependencies = ( (ArtifactWithDependencies) artifact ).getManagedDependencies();
-        }
-        else
-        {
-            ProjectRelocation rel = retrieveRelocatedProject( artifact, request );
-
-            if ( rel == null )
-            {
-                return null;
-            }
-
-            pomArtifact = rel.pomArtifact;
-
-            relocatedArtifact = rel.relocatedArtifact;
-
-            if ( rel.project == null )
-            {
-                // When this happens we have a Maven 1.x POM, or some invalid POM.
-                // It should have never found its way into Maven 2.x repository but it did.
-                dependencies = Collections.emptyList();
-            }
-            else
-            {
-                dependencies = rel.project.getDependencies();
-
-                DependencyManagement depMgmt = rel.project.getDependencyManagement();
-                managedDependencies = ( depMgmt != null ) ? depMgmt.getDependencies() : null;
-
-                pomRepositories = rel.project.getRemoteArtifactRepositories();
-            }
-        }
-
-        Set<Artifact> artifacts = Collections.emptySet();
-
-        if ( !artifact.getArtifactHandler().isIncludesDependencies() )
-        {
-            artifacts = new LinkedHashSet<>();
-
-            for ( Dependency dependency : dependencies )
-            {
-                Artifact dependencyArtifact = createDependencyArtifact( dependency, artifact, pomArtifact );
-
-                if ( dependencyArtifact != null )
-                {
-                    artifacts.add( dependencyArtifact );
-                }
-            }
-        }
-
-        Map<String, Artifact> managedVersions = null;
-
-        if ( managedDependencies != null && request.isResolveManagedVersions() )
-        {
-            managedVersions = new HashMap<>();
-
-            for ( Dependency managedDependency : managedDependencies )
-            {
-                Artifact managedArtifact = createDependencyArtifact( managedDependency, null, pomArtifact );
-
-                managedVersions.put( managedDependency.getManagementKey(), managedArtifact );
-            }
-        }
-
-        List<ArtifactRepository> aggregatedRepositories =
-            aggregateRepositories( request.getRemoteRepositories(), pomRepositories );
-
-        ResolutionGroup result =
-            new ResolutionGroup( pomArtifact, relocatedArtifact, artifacts, managedVersions, aggregatedRepositories );
-
-        cache.put( artifact, request.isResolveManagedVersions(), request.getLocalRepository(),
-                   request.getRemoteRepositories(), result );
-
-        return result;
-    }
-
-    private boolean hasFile( Artifact artifact )
-    {
-        return artifact != null && artifact.getFile() != null && artifact.getFile().exists();
-    }
-
-    private List<ArtifactRepository> aggregateRepositories( List<ArtifactRepository> requestRepositories,
-                                                            List<ArtifactRepository> pomRepositories )
-    {
-        List<ArtifactRepository> repositories = requestRepositories;
-
-        if ( pomRepositories != null && !pomRepositories.isEmpty() )
-        {
-            Map<String, ArtifactRepository> repos = new LinkedHashMap<>();
-
-            for ( ArtifactRepository repo : requestRepositories )
-            {
-                if ( !repos.containsKey( repo.getId() ) )
-                {
-                    repos.put( repo.getId(), repo );
-                }
-            }
-
-            for ( ArtifactRepository repo : pomRepositories )
-            {
-                if ( !repos.containsKey( repo.getId() ) )
-                {
-                    repos.put( repo.getId(), repo );
-                }
-            }
-
-            repositories = new ArrayList<>( repos.values() );
-        }
-
-        return repositories;
-    }
-
-    private Artifact createDependencyArtifact( Dependency dependency, Artifact owner, Artifact pom )
-        throws ArtifactMetadataRetrievalException
-    {
-        try
-        {
-            String inheritedScope = ( owner != null ) ? owner.getScope() : null;
-
-            ArtifactFilter inheritedFilter = ( owner != null ) ? owner.getDependencyFilter() : null;
-
-            return createDependencyArtifact( repositorySystem, dependency, inheritedScope, inheritedFilter );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
-            throw new ArtifactMetadataRetrievalException( "Invalid version for dependency "
-                + dependency.getManagementKey() + ": " + e.getMessage(), e, pom );
-        }
-    }
-
-    private static Artifact createDependencyArtifact( ArtifactFactory factory, Dependency dependency,
-                                                      String inheritedScope, ArtifactFilter inheritedFilter )
-        throws InvalidVersionSpecificationException
-    {
-        String effectiveScope = getEffectiveScope( dependency.getScope(), inheritedScope );
-
-        if ( effectiveScope == null )
-        {
-            return null;
-        }
-
-        VersionRange versionRange = VersionRange.createFromVersionSpec( dependency.getVersion() );
-
-        Artifact dependencyArtifact =
-            factory.createDependencyArtifact( dependency.getGroupId(), dependency.getArtifactId(), versionRange,
-                                              dependency.getType(), dependency.getClassifier(), effectiveScope,
-                                              dependency.isOptional() );
-
-        if ( inheritedFilter != null && !inheritedFilter.include( dependencyArtifact ) )
-        {
-            return null;
-        }
-
-        if ( Artifact.SCOPE_SYSTEM.equals( effectiveScope ) )
-        {
-            dependencyArtifact.setFile( new File( dependency.getSystemPath() ) );
-        }
-
-        dependencyArtifact.setDependencyFilter( createDependencyFilter( dependency, inheritedFilter ) );
-
-        return dependencyArtifact;
-    }
-
-    private static String getEffectiveScope( String originalScope, String inheritedScope )
-    {
-        String effectiveScope = Artifact.SCOPE_RUNTIME;
-
-        if ( originalScope == null )
-        {
-            originalScope = Artifact.SCOPE_COMPILE;
-        }
-
-        if ( inheritedScope == null )
-        {
-            // direct dependency retains its scope
-            effectiveScope = originalScope;
-        }
-        else if ( Artifact.SCOPE_TEST.equals( originalScope ) || Artifact.SCOPE_PROVIDED.equals( originalScope ) )
-        {
-            // test and provided are not transitive, so exclude them
-            effectiveScope = null;
-        }
-        else if ( Artifact.SCOPE_SYSTEM.equals( originalScope ) )
-        {
-            // system scope come through unchanged...
-            effectiveScope = Artifact.SCOPE_SYSTEM;
-        }
-        else if ( Artifact.SCOPE_COMPILE.equals( originalScope ) && Artifact.SCOPE_COMPILE.equals( inheritedScope ) )
-        {
-            // added to retain compile scope. Remove if you want compile inherited as runtime
-            effectiveScope = Artifact.SCOPE_COMPILE;
-        }
-        else if ( Artifact.SCOPE_TEST.equals( inheritedScope ) )
-        {
-            effectiveScope = Artifact.SCOPE_TEST;
-        }
-        else if ( Artifact.SCOPE_PROVIDED.equals( inheritedScope ) )
-        {
-            effectiveScope = Artifact.SCOPE_PROVIDED;
-        }
-
-        return effectiveScope;
-    }
-
-    private static ArtifactFilter createDependencyFilter( Dependency dependency, ArtifactFilter inheritedFilter )
-    {
-        ArtifactFilter effectiveFilter = inheritedFilter;
-
-        if ( !dependency.getExclusions().isEmpty() )
-        {
-            effectiveFilter = new ExclusionArtifactFilter( dependency.getExclusions() );
-
-            if ( inheritedFilter != null )
-            {
-                effectiveFilter = new AndArtifactFilter( Arrays.asList( inheritedFilter, effectiveFilter ) );
-            }
-        }
-
-        return effectiveFilter;
-    }
-
-    public List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
-                                                            List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException
-    {
-        MetadataResolutionRequest request = new DefaultMetadataResolutionRequest();
-        injectSession( request );
-        request.setArtifact( artifact );
-        request.setLocalRepository( localRepository );
-        request.setRemoteRepositories( remoteRepositories );
-        return retrieveAvailableVersions( request );
-    }
-
-    public List<ArtifactVersion> retrieveAvailableVersions( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException
-    {
-        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( request.getArtifact() );
-
-        try
-        {
-            repositoryMetadataManager.resolve( metadata, request );
-        }
-        catch ( RepositoryMetadataResolutionException e )
-        {
-            throw new ArtifactMetadataRetrievalException( e.getMessage(), e, request.getArtifact() );
-        }
-
-        List<String> availableVersions = request.getLocalRepository().findVersions( request.getArtifact() );
-
-        return retrieveAvailableVersionsFromMetadata( metadata.getMetadata(), availableVersions );
-    }
-
-    public List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact,
-                                                                                    ArtifactRepository localRepository,
-                                                                              ArtifactRepository deploymentRepository )
-        throws ArtifactMetadataRetrievalException
-    {
-        RepositoryMetadata metadata = new ArtifactRepositoryMetadata( artifact );
-
-        try
-        {
-            repositoryMetadataManager.resolveAlways( metadata, localRepository, deploymentRepository );
-        }
-        catch ( RepositoryMetadataResolutionException e )
-        {
-            throw new ArtifactMetadataRetrievalException( e.getMessage(), e, artifact );
-        }
-
-        List<String> availableVersions = localRepository.findVersions( artifact );
-
-        return retrieveAvailableVersionsFromMetadata( metadata.getMetadata(), availableVersions );
-    }
-
-    private List<ArtifactVersion> retrieveAvailableVersionsFromMetadata( Metadata repoMetadata,
-                                                                         List<String> availableVersions )
-    {
-        Collection<String> versions = new LinkedHashSet<>();
-
-        if ( ( repoMetadata != null ) && ( repoMetadata.getVersioning() != null ) )
-        {
-            versions.addAll( repoMetadata.getVersioning().getVersions() );
-        }
-
-        versions.addAll( availableVersions );
-
-        List<ArtifactVersion> artifactVersions = new ArrayList<>( versions.size() );
-
-        for ( String version : versions )
-        {
-            artifactVersions.add( new DefaultArtifactVersion( version ) );
-        }
-
-        return artifactVersions;
-    }
-
-    // USED BY MAVEN ASSEMBLY PLUGIN
-    @Deprecated
-    public static Set<Artifact> createArtifacts( ArtifactFactory artifactFactory, List<Dependency> dependencies,
-                                                 String inheritedScope, ArtifactFilter dependencyFilter,
-                                                 MavenProject project )
-        throws InvalidDependencyVersionException
-    {
-        Set<Artifact> artifacts = new LinkedHashSet<>();
-
-        for ( Dependency d : dependencies )
-        {
-            Artifact dependencyArtifact;
-            try
-            {
-                dependencyArtifact = createDependencyArtifact( artifactFactory, d, inheritedScope, dependencyFilter );
-            }
-            catch ( InvalidVersionSpecificationException e )
-            {
-                throw new InvalidDependencyVersionException( project.getId(), d, project.getFile(), e );
-            }
-
-            if ( dependencyArtifact != null )
-            {
-                artifacts.add( dependencyArtifact );
-            }
-        }
-
-        return artifacts;
-    }
-
-    @SuppressWarnings( "checkstyle:methodlength" )
-    private ProjectRelocation retrieveRelocatedProject( Artifact artifact, MetadataResolutionRequest repositoryRequest )
-        throws ArtifactMetadataRetrievalException
-    {
-        MavenProject project;
-
-        Artifact pomArtifact;
-        Artifact relocatedArtifact = null;
-        boolean done = false;
-        do
-        {
-            project = null;
-
-            pomArtifact =
-                repositorySystem.createProjectArtifact( artifact.getGroupId(),
-                                                        artifact.getArtifactId(),
-                                                        artifact.getVersion(), artifact.getScope() );
-
-            if ( "pom".equals( artifact.getType() ) )
-            {
-                pomArtifact.setFile( artifact.getFile() );
-            }
-
-            if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
-            {
-                done = true;
-            }
-            else
-            {
-                try
-                {
-                    ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-                    configuration.setLocalRepository( repositoryRequest.getLocalRepository() );
-                    configuration.setRemoteRepositories( repositoryRequest.getRemoteRepositories() );
-                    configuration.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
-                    configuration.setProcessPlugins( false );
-                    configuration.setRepositoryMerging( ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT );
-                    configuration.setSystemProperties( getSystemProperties() );
-                    configuration.setUserProperties( new Properties() );
-                    configuration.setRepositorySession( legacySupport.getRepositorySession() );
-
-                    project = projectBuilder.build( pomArtifact, configuration ).getProject();
-                }
-                catch ( ProjectBuildingException e )
-                {
-                    ModelProblem missingParentPom = hasMissingParentPom( e );
-                    if ( missingParentPom != null )
-                    {
-                        throw new ArtifactMetadataRetrievalException( "Failed to process POM for "
-                            + artifact.getId() + ": " + missingParentPom.getMessage(),
-                                                                      missingParentPom.getException(),
-                                                                      artifact );
-                    }
-
-                    String message;
-
-                    if ( isMissingPom( e ) )
-                    {
-                        message = "Missing POM for " + artifact.getId();
-                    }
-                    else if ( isNonTransferablePom( e ) )
-                    {
-                        throw new ArtifactMetadataRetrievalException( "Failed to retrieve POM for "
-                            + artifact.getId() + ": " + e.getCause().getMessage(), e.getCause(),
-                                                                      artifact );
-                    }
-                    else
-                    {
-                        message =
-                            "Invalid POM for " + artifact.getId()
-                                + ", transitive dependencies (if any) will not be available"
-                                + ", enable verbose output (-X) for more details";
-                    }
-
-                    if ( logger.isDebugEnabled() )
-                    {
-                        message += ": " + e.getMessage();
-                    }
-
-                    logger.warn( message );
-                }
-
-                if ( project != null )
-                {
-                    Relocation relocation = null;
-
-                    DistributionManagement distMgmt = project.getDistributionManagement();
-                    if ( distMgmt != null )
-                    {
-                        relocation = distMgmt.getRelocation();
-
-                        artifact.setDownloadUrl( distMgmt.getDownloadUrl() );
-                        pomArtifact.setDownloadUrl( distMgmt.getDownloadUrl() );
-                    }
-
-                    if ( relocation != null )
-                    {
-                        if ( relocation.getGroupId() != null )
-                        {
-                            artifact.setGroupId( relocation.getGroupId() );
-                            relocatedArtifact = artifact;
-                            project.setGroupId( relocation.getGroupId() );
-                        }
-                        if ( relocation.getArtifactId() != null )
-                        {
-                            artifact.setArtifactId( relocation.getArtifactId() );
-                            relocatedArtifact = artifact;
-                            project.setArtifactId( relocation.getArtifactId() );
-                        }
-                        if ( relocation.getVersion() != null )
-                        {
-                            // note: see MNG-3454. This causes a problem, but fixing it may break more.
-                            artifact.setVersionRange( VersionRange.createFromVersion( relocation.getVersion() ) );
-                            relocatedArtifact = artifact;
-                            project.setVersion( relocation.getVersion() );
-                        }
-
-                        if ( artifact.getDependencyFilter() != null
-                            && !artifact.getDependencyFilter().include( artifact ) )
-                        {
-                            return null;
-                        }
-
-                        // MNG-2861: the artifact data has changed. If the available versions where previously
-                        // retrieved, we need to update it.
-                        // TODO shouldn't the versions be merged across relocations?
-                        List<ArtifactVersion> available = artifact.getAvailableVersions();
-                        if ( available != null && !available.isEmpty() )
-                        {
-                            MetadataResolutionRequest metadataRequest =
-                                new DefaultMetadataResolutionRequest( repositoryRequest );
-                            metadataRequest.setArtifact( artifact );
-                            available = retrieveAvailableVersions( metadataRequest );
-                            artifact.setAvailableVersions( available );
-                        }
-
-                        String message =
-                            "  this artifact has been relocated to " + artifact.getGroupId() + ":"
-                                + artifact.getArtifactId() + ":" + artifact.getVersion() + ".";
-
-                        if ( relocation.getMessage() != null )
-                        {
-                            message += "  " + relocation.getMessage();
-                        }
-
-                        if ( artifact.getDependencyTrail() != null && artifact.getDependencyTrail().size() == 1 )
-                        {
-                            logger.warn( "While downloading " + pomArtifact.getGroupId() + ":"
-                                + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message );
-                        }
-                        else
-                        {
-                            logger.debug( "While downloading " + pomArtifact.getGroupId() + ":"
-                                + pomArtifact.getArtifactId() + ":" + pomArtifact.getVersion() + message );
-                        }
-                    }
-                    else
-                    {
-                        done = true;
-                    }
-                }
-                else
-                {
-                    done = true;
-                }
-            }
-        }
-        while ( !done );
-
-        ProjectRelocation rel = new ProjectRelocation();
-        rel.project = project;
-        rel.pomArtifact = pomArtifact;
-        rel.relocatedArtifact = relocatedArtifact;
-
-        return rel;
-    }
-
-    private ModelProblem hasMissingParentPom( ProjectBuildingException e )
-    {
-        if ( e.getCause() instanceof ModelBuildingException )
-        {
-            ModelBuildingException mbe = (ModelBuildingException) e.getCause();
-            for ( ModelProblem problem : mbe.getProblems() )
-            {
-                if ( problem.getException() instanceof UnresolvableModelException )
-                {
-                    return problem;
-                }
-            }
-
-        }
-        return null;
-    }
-
-    private boolean isMissingPom( Exception e )
-    {
-        if ( e.getCause() instanceof MultipleArtifactsNotFoundException )
-        {
-            return true;
-        }
-        return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
-            && e.getCause().getCause() instanceof ArtifactNotFoundException;
-    }
-
-    private boolean isNonTransferablePom( Exception e )
-    {
-        if ( e.getCause() instanceof ArtifactResolutionException )
-        {
-            return true;
-        }
-        return e.getCause() instanceof org.eclipse.aether.resolution.ArtifactResolutionException
-            && !( e.getCause().getCause() instanceof ArtifactNotFoundException );
-    }
-
-    private Properties getSystemProperties()
-    {
-        Properties props = new Properties();
-
-        EnvironmentUtils.addEnvVars( props );
-
-        SystemProperties.addSystemProperties( props );
-
-        return props;
-    }
-
-    private static final class ProjectRelocation
-    {
-        private MavenProject project;
-
-        private Artifact pomArtifact;
-
-        private Artifact relocatedArtifact;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java
index c6bf9b8..d5bb916 100644
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java
+++ b/maven-core/src/main/java/org/apache/maven/project/artifact/PluginArtifact.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
 
 import java.util.Collections;
 import java.util.List;
@@ -31,67 +30,58 @@
 /**
  * PluginArtifact
  */
-public class PluginArtifact
-    extends DefaultArtifact
-    implements ArtifactWithDependencies
-{
+public class PluginArtifact extends DefaultArtifact implements ArtifactWithDependencies {
     private Plugin plugin;
 
-    public PluginArtifact( Plugin plugin, Artifact pluginArtifact )
-    {
-        super( plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion(), null, "maven-plugin", null,
-               new PluginArtifactHandler() );
+    public PluginArtifact(Plugin plugin, Artifact pluginArtifact) {
+        super(
+                plugin.getGroupId(),
+                plugin.getArtifactId(),
+                plugin.getVersion(),
+                null,
+                "maven-plugin",
+                null,
+                new PluginArtifactHandler());
         this.plugin = plugin;
-        setFile( pluginArtifact.getFile() );
-        setResolved( true );
+        setFile(pluginArtifact.getFile());
+        setResolved(true);
     }
 
-    public List<Dependency> getDependencies()
-    {
+    public List<Dependency> getDependencies() {
         return plugin.getDependencies();
     }
 
-    public List<Dependency> getManagedDependencies()
-    {
+    public List<Dependency> getManagedDependencies() {
         return Collections.emptyList();
     }
 
     // TODO: this is duplicate of MavenPluginArtifactHandlerProvider provided one
-    static class PluginArtifactHandler
-        implements ArtifactHandler
-    {
-        public String getClassifier()
-        {
+    static class PluginArtifactHandler implements ArtifactHandler {
+        public String getClassifier() {
             return null;
         }
 
-        public String getDirectory()
-        {
+        public String getDirectory() {
             return null;
         }
 
-        public String getExtension()
-        {
+        public String getExtension() {
             return "jar";
         }
 
-        public String getLanguage()
-        {
+        public String getLanguage() {
             return "none";
         }
 
-        public String getPackaging()
-        {
+        public String getPackaging() {
             return "maven-plugin";
         }
 
-        public boolean isAddedToClasspath()
-        {
+        public boolean isAddedToClasspath() {
             return true;
         }
 
-        public boolean isIncludesDependencies()
-        {
+        public boolean isIncludesDependencies() {
             return false;
         }
     }
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java
index a3a8dd6..8d75eb7 100644
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java
+++ b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifact.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
 
 import java.util.Collections;
 import java.util.List;
@@ -31,76 +30,63 @@
 /**
  * ProjectArtifact
  */
-public class ProjectArtifact
-    extends DefaultArtifact
-    implements ArtifactWithDependencies
-{
+public class ProjectArtifact extends DefaultArtifact implements ArtifactWithDependencies {
     private MavenProject project;
 
-    public ProjectArtifact( MavenProject project )
-    {
-        super( project.getGroupId(), project.getArtifactId(), project.getVersion(), null, "pom", null,
-               new PomArtifactHandler() );
+    public ProjectArtifact(MavenProject project) {
+        super(
+                project.getGroupId(),
+                project.getArtifactId(),
+                project.getVersion(),
+                null,
+                "pom",
+                null,
+                new PomArtifactHandler());
         this.project = project;
-        setFile( project.getFile() );
-        setResolved( true );
+        setFile(project.getFile());
+        setResolved(true);
     }
 
-    public MavenProject getProject()
-    {
+    public MavenProject getProject() {
         return project;
     }
 
-    public List<Dependency> getDependencies()
-    {
-        return project.getDependencies();
+    public List<Dependency> getDependencies() {
+        return project.getModel().getDependencies();
     }
 
-    public List<Dependency> getManagedDependencies()
-    {
-        DependencyManagement depMngt = project.getDependencyManagement();
-        return ( depMngt != null )
-                   ? Collections.unmodifiableList( depMngt.getDependencies() )
-                   : Collections.emptyList();
-
+    public List<Dependency> getManagedDependencies() {
+        DependencyManagement depMngt = project.getModel().getDependencyManagement();
+        return (depMngt != null) ? Collections.unmodifiableList(depMngt.getDependencies()) : Collections.emptyList();
     }
 
     // TODO: this is duplicate of PomArtifactHandlerProvider provided one
-    static class PomArtifactHandler
-        implements ArtifactHandler
-    {
-        public String getClassifier()
-        {
+    static class PomArtifactHandler implements ArtifactHandler {
+        public String getClassifier() {
             return null;
         }
 
-        public String getDirectory()
-        {
+        public String getDirectory() {
             return null;
         }
 
-        public String getExtension()
-        {
+        public String getExtension() {
             return "pom";
         }
 
-        public String getLanguage()
-        {
+        public String getLanguage() {
             return "none";
         }
 
-        public String getPackaging()
-        {
+        public String getPackaging() {
             return "pom";
         }
 
-        public boolean isAddedToClasspath()
-        {
+        public boolean isAddedToClasspath() {
             return false;
         }
 
-        public boolean isIncludesDependencies()
-        {
+        public boolean isIncludesDependencies() {
             return false;
         }
     }
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifactMetadata.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifactMetadata.java
deleted file mode 100644
index 7ea99bf..0000000
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifactMetadata.java
+++ /dev/null
@@ -1,130 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.metadata.AbstractArtifactMetadata;
-import org.apache.maven.artifact.metadata.ArtifactMetadata;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadataStoreException;
-import org.codehaus.plexus.util.FileUtils;
-
-/**
- * Attach a POM to an artifact.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public class ProjectArtifactMetadata
-    extends AbstractArtifactMetadata
-{
-    private final File file;
-
-    public ProjectArtifactMetadata( Artifact artifact )
-    {
-        this( artifact, null );
-    }
-
-    public ProjectArtifactMetadata( Artifact artifact, File file )
-    {
-        super( artifact );
-        this.file = file;
-    }
-
-    public File getFile()
-    {
-        return file;
-    }
-
-    public String getRemoteFilename()
-    {
-        return getFilename();
-    }
-
-    public String getLocalFilename( ArtifactRepository repository )
-    {
-        return getFilename();
-    }
-
-    private String getFilename()
-    {
-        return getArtifactId() + "-" + artifact.getVersion() + ".pom";
-    }
-
-    public void storeInLocalRepository( ArtifactRepository localRepository, ArtifactRepository remoteRepository )
-        throws RepositoryMetadataStoreException
-    {
-        File destination =
-            new File( localRepository.getBasedir(), localRepository.pathOfLocalRepositoryMetadata( this,
-                                                                                                   remoteRepository ) );
-
-        // ----------------------------------------------------------------------------
-        // I'm fully aware that the file could just be moved using File.rename but
-        // there are bugs in various JVM that have problems doing this across
-        // different filesystem. So we'll incur the small hit to actually copy
-        // here and be safe. jvz.
-        // ----------------------------------------------------------------------------
-
-        try
-        {
-            FileUtils.copyFile( file, destination );
-        }
-        catch ( IOException e )
-        {
-            throw new RepositoryMetadataStoreException( "Error copying POM to the local repository.", e );
-        }
-    }
-
-    public String toString()
-    {
-        return "project information for " + artifact.getArtifactId() + " " + artifact.getVersion();
-    }
-
-    public boolean storedInArtifactVersionDirectory()
-    {
-        return true;
-    }
-
-    public String getBaseVersion()
-    {
-        return artifact.getBaseVersion();
-    }
-
-    public Object getKey()
-    {
-        return "project " + artifact.getGroupId() + ":" + artifact.getArtifactId();
-    }
-
-    public void merge( ArtifactMetadata metadata )
-    {
-        ProjectArtifactMetadata m = (ProjectArtifactMetadata) metadata;
-        if ( !m.file.equals( file ) )
-        {
-            throw new IllegalStateException( "Cannot add two different pieces of metadata for: " + getKey() );
-        }
-    }
-
-    public void merge( org.apache.maven.repository.legacy.metadata.ArtifactMetadata metadata )
-    {
-        this.merge( (ArtifactMetadata) metadata );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifactsCache.java b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifactsCache.java
index fa0f3c5..c51b383 100644
--- a/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifactsCache.java
+++ b/maven-core/src/main/java/org/apache/maven/project/artifact/ProjectArtifactsCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
 
 import java.util.Collection;
 import java.util.Set;
@@ -26,67 +25,62 @@
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.project.MavenProject;
 import org.eclipse.aether.RepositorySystemSession;
+
 /**
  * Caches project artifacts. <strong>Warning:</strong> This is an internal utility interface that is only public for
  * technical reasons, it is not part of the public API. In particular, this interface can be changed or deleted without
  * prior notice.
  *
- * @author Igor Fedorenko
- * @author Benjamin Bentmann
- * @author Anton Tanasenko
  */
-public interface ProjectArtifactsCache
-{
+public interface ProjectArtifactsCache {
 
     /**
      * A cache key.
      */
-    interface Key
-    {
+    interface Key {
         // marker interface for cache keys
     }
 
     /**
      * CacheRecord
      */
-    class CacheRecord
-    {
+    class CacheRecord {
 
-        public Set<Artifact> getArtifacts()
-        {
+        public Set<Artifact> getArtifacts() {
             return artifacts;
         }
 
         private final Set<Artifact> artifacts;
 
-        public LifecycleExecutionException getException()
-        {
+        public LifecycleExecutionException getException() {
             return exception;
         }
 
         private final LifecycleExecutionException exception;
 
-        CacheRecord( Set<Artifact> artifacts )
-        {
+        CacheRecord(Set<Artifact> artifacts) {
             this.artifacts = artifacts;
             this.exception = null;
         }
 
-        CacheRecord( LifecycleExecutionException exception )
-        {
+        CacheRecord(LifecycleExecutionException exception) {
             this.artifacts = null;
             this.exception = exception;
         }
     }
 
-    Key createKey( MavenProject project, Collection<String> scopesToCollect, Collection<String> scopesToResolve,
-        boolean aggregating, RepositorySystemSession session );
+    Key createKey(
+            MavenProject project,
+            Collection<String> scopesToCollect,
+            Collection<String> scopesToResolve,
+            boolean aggregating,
+            RepositorySystemSession session);
 
-    CacheRecord get( Key key ) throws LifecycleExecutionException;
+    CacheRecord get(Key key) throws LifecycleExecutionException;
 
-    CacheRecord put( Key key, Set<Artifact> pluginArtifacts );
+    CacheRecord put(Key key, Set<Artifact> pluginArtifacts);
 
-    CacheRecord put( Key key, LifecycleExecutionException e );
+    CacheRecord put(Key key, LifecycleExecutionException e);
 
     void flush();
 
@@ -98,6 +92,5 @@
      * @param project The project that employs the plugin realm, must not be {@code null}.
      * @param record The cache record being used for the project, must not be {@code null}.
      */
-    void register( MavenProject project, Key cacheKey, CacheRecord record );
-
+    void register(MavenProject project, Key cacheKey, CacheRecord record);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java b/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java
index 74be84a..69cca14 100644
--- a/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java
+++ b/maven-core/src/main/java/org/apache/maven/project/collector/DefaultProjectsSelector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.collector;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.collector;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.model.building.ModelProblem;
@@ -27,76 +34,62 @@
 import org.apache.maven.project.ProjectBuildingException;
 import org.apache.maven.project.ProjectBuildingRequest;
 import org.apache.maven.project.ProjectBuildingResult;
-import org.codehaus.plexus.util.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Utility to select projects for a given set of pom.xml files.
  */
 @Named
 @Singleton
-public class DefaultProjectsSelector implements ProjectsSelector
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultProjectsSelector.class );
+public class DefaultProjectsSelector implements ProjectsSelector {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultProjectsSelector.class);
     private final ProjectBuilder projectBuilder;
 
     @Inject
-    public DefaultProjectsSelector( ProjectBuilder projectBuilder )
-    {
+    public DefaultProjectsSelector(ProjectBuilder projectBuilder) {
         this.projectBuilder = projectBuilder;
     }
 
     @Override
-    public List<MavenProject> selectProjects( List<File> files, MavenExecutionRequest request )
-            throws ProjectBuildingException
-    {
+    public List<MavenProject> selectProjects(List<File> files, MavenExecutionRequest request)
+            throws ProjectBuildingException {
         ProjectBuildingRequest projectBuildingRequest = request.getProjectBuildingRequest();
 
         boolean hasProjectSelection = !request.getProjectActivation().isEmpty();
         boolean isRecursive = hasProjectSelection || request.isRecursive();
-        List<ProjectBuildingResult> results = projectBuilder.build( files, isRecursive, projectBuildingRequest );
+        List<ProjectBuildingResult> results = projectBuilder.build(files, isRecursive, projectBuildingRequest);
 
-        List<MavenProject> projects = new ArrayList<>( results.size() );
+        List<MavenProject> projects = new ArrayList<>(results.size());
 
         boolean problems = false;
 
-        for ( ProjectBuildingResult result : results )
-        {
-            projects.add( result.getProject() );
+        for (ProjectBuildingResult result : results) {
+            projects.add(result.getProject());
 
-            if ( !result.getProblems().isEmpty() && LOGGER.isWarnEnabled() )
-            {
-                LOGGER.warn( "" );
-                LOGGER.warn( "Some problems were encountered while building the effective model for '{}'",
-                        result.getProject().getId() );
+            if (!result.getProblems().isEmpty() && LOGGER.isWarnEnabled()) {
+                LOGGER.warn("");
+                LOGGER.warn(
+                        "Some problems were encountered while building the effective model for '{}'",
+                        result.getProject().getId());
 
-                for ( ModelProblem problem : result.getProblems() )
-                {
-                    String loc = ModelProblemUtils.formatLocation( problem, result.getProjectId() );
-                    LOGGER.warn( "{}{}", problem.getMessage(), ( StringUtils.isNotEmpty( loc ) ? " @ " + loc : "" ) );
+                for (ModelProblem problem : result.getProblems()) {
+                    String loc = ModelProblemUtils.formatLocation(problem, result.getProjectId());
+                    LOGGER.warn("{}{}", problem.getMessage(), ((loc != null && !loc.isEmpty()) ? " @ " + loc : ""));
                 }
 
                 problems = true;
             }
         }
 
-        if ( problems )
-        {
-            LOGGER.warn( "" );
-            LOGGER.warn( "It is highly recommended to fix these problems"
-                    + " because they threaten the stability of your build." );
-            LOGGER.warn( "" );
-            LOGGER.warn( "For this reason, future Maven versions might no"
-                    + " longer support building such malformed projects." );
-            LOGGER.warn( "" );
+        if (problems) {
+            LOGGER.warn("");
+            LOGGER.warn("It is highly recommended to fix these problems"
+                    + " because they threaten the stability of your build.");
+            LOGGER.warn("");
+            LOGGER.warn("For this reason, future Maven versions might no"
+                    + " longer support building such malformed projects.");
+            LOGGER.warn("");
         }
 
         return projects;
diff --git a/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java b/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java
index d6c4cd7..1216f08 100644
--- a/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java
+++ b/maven-core/src/main/java/org/apache/maven/project/collector/MultiModuleCollectionStrategy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.collector;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.collector;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
 
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.model.Plugin;
@@ -33,69 +43,52 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Objects;
-import java.util.function.Predicate;
-
 /**
  * Strategy for collecting Maven projects from the multi-module project root, even when executed in a submodule.
  */
-@Named( "MultiModuleCollectionStrategy" )
+@Named("MultiModuleCollectionStrategy")
 @Singleton
-public class MultiModuleCollectionStrategy implements ProjectCollectionStrategy
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( MultiModuleCollectionStrategy.class );
+public class MultiModuleCollectionStrategy implements ProjectCollectionStrategy {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MultiModuleCollectionStrategy.class);
     private final ModelLocator modelLocator;
     private final ProjectsSelector projectsSelector;
 
     @Inject
-    public MultiModuleCollectionStrategy( ModelLocator modelLocator, ProjectsSelector projectsSelector )
-    {
+    public MultiModuleCollectionStrategy(ModelLocator modelLocator, ProjectsSelector projectsSelector) {
         this.modelLocator = modelLocator;
         this.projectsSelector = projectsSelector;
     }
 
     @Override
-    public List<MavenProject> collectProjects( MavenExecutionRequest request ) throws ProjectBuildingException
-    {
-        File moduleProjectPomFile = getMultiModuleProjectPomFile( request );
-        List<File> files = Collections.singletonList( moduleProjectPomFile.getAbsoluteFile() );
-        try
-        {
-            List<MavenProject> projects = projectsSelector.selectProjects( files, request );
-            boolean isRequestedProjectCollected = isRequestedProjectCollected( request, projects );
-            if ( isRequestedProjectCollected )
-            {
+    public List<MavenProject> collectProjects(MavenExecutionRequest request) throws ProjectBuildingException {
+        File moduleProjectPomFile = getMultiModuleProjectPomFile(request);
+        List<File> files = Collections.singletonList(moduleProjectPomFile.getAbsoluteFile());
+        try {
+            List<MavenProject> projects = projectsSelector.selectProjects(files, request);
+            boolean isRequestedProjectCollected = isRequestedProjectCollected(request, projects);
+            if (isRequestedProjectCollected) {
                 return projects;
-            }
-            else
-            {
-                LOGGER.debug( "Multi module project collection failed:{}"
-                        + "Detected a POM file next to a .mvn directory in a parent directory ({}). "
-                        + "Maven assumed that POM file to be the parent of the requested project ({}), but it turned "
-                        + "out that it was not. Another project collection strategy will be executed as result.",
-                        System.lineSeparator(), moduleProjectPomFile.getAbsolutePath(),
-                        request.getPom().getAbsolutePath() );
+            } else {
+                LOGGER.debug(
+                        "Multi module project collection failed:{}"
+                                + "Detected a POM file next to a .mvn directory in a parent directory ({}). "
+                                + "Maven assumed that POM file to be the parent of the requested project ({}), but it turned "
+                                + "out that it was not. Another project collection strategy will be executed as result.",
+                        System.lineSeparator(),
+                        moduleProjectPomFile.getAbsolutePath(),
+                        request.getPom().getAbsolutePath());
                 return Collections.emptyList();
             }
-        }
-        catch ( ProjectBuildingException e )
-        {
-            boolean fallThrough = isModuleOutsideRequestScopeDependingOnPluginModule( request, e );
+        } catch (ProjectBuildingException e) {
+            boolean fallThrough = isModuleOutsideRequestScopeDependingOnPluginModule(request, e);
 
-            if ( fallThrough )
-            {
-                LOGGER.debug( "Multi module project collection failed:{}"
-                        + "Detected that one of the modules of this multi-module project uses another module as "
-                        + "plugin extension which still needed to be built. This is not possible within the same "
-                        + "reactor build. Another project collection strategy will be executed as result.",
-                        System.lineSeparator() );
+            if (fallThrough) {
+                LOGGER.debug(
+                        "Multi module project collection failed:{}"
+                                + "Detected that one of the modules of this multi-module project uses another module as "
+                                + "plugin extension which still needed to be built. This is not possible within the same "
+                                + "reactor build. Another project collection strategy will be executed as result.",
+                        System.lineSeparator());
                 return Collections.emptyList();
             }
 
@@ -103,21 +96,20 @@
         }
     }
 
-    private File getMultiModuleProjectPomFile( MavenExecutionRequest request )
-    {
-        if ( request.getPom().getParentFile().equals( request.getMultiModuleProjectDirectory() ) )
-        {
+    private File getMultiModuleProjectPomFile(MavenExecutionRequest request) {
+        File multiModuleProjectDirectory = request.getMultiModuleProjectDirectory();
+        if (request.getPom().getParentFile().equals(multiModuleProjectDirectory)) {
             return request.getPom();
-        }
-        else
-        {
-            File multiModuleProjectPom = modelLocator.locatePom( request.getMultiModuleProjectDirectory() );
-            if ( !multiModuleProjectPom.exists() )
-            {
-                LOGGER.info( "Maven detected that the requested POM file is part of a multi-module project, "
-                        + "but could not find a pom.xml file in the multi-module root directory '{}'.",
-                        request.getMultiModuleProjectDirectory() );
-                LOGGER.info( "The reactor is limited to all projects under: " + request.getPom().getParent() );
+        } else {
+            File multiModuleProjectPom = modelLocator.locateExistingPom(multiModuleProjectDirectory);
+            if (multiModuleProjectPom == null) {
+                LOGGER.info(
+                        "Maven detected that the requested POM file is part of a multi-module project, "
+                                + "but could not find a pom.xml file in the multi-module root directory '{}'.",
+                        multiModuleProjectDirectory);
+                LOGGER.info(
+                        "The reactor is limited to all projects under: {}",
+                        request.getPom().getParent());
                 return request.getPom();
             }
 
@@ -132,11 +124,8 @@
      *
      * @return true if the collected projects contain the requested project (for example with -f)
      */
-    private boolean isRequestedProjectCollected( MavenExecutionRequest request, List<MavenProject> projects )
-    {
-        return projects.stream()
-                .map( MavenProject::getFile )
-                .anyMatch( request.getPom()::equals );
+    private boolean isRequestedProjectCollected(MavenExecutionRequest request, List<MavenProject> projects) {
+        return projects.stream().map(MavenProject::getFile).anyMatch(request.getPom()::equals);
     }
 
     /**
@@ -153,42 +142,41 @@
      *
      * @return true if the module which fails to collect the inter-module plugin is not part of the build.
      */
-    private boolean isModuleOutsideRequestScopeDependingOnPluginModule( MavenExecutionRequest request,
-                                                                        ProjectBuildingException exception )
-    {
+    private boolean isModuleOutsideRequestScopeDependingOnPluginModule(
+            MavenExecutionRequest request, ProjectBuildingException exception) {
         return exception.getResults().stream()
-                .map( ProjectBuildingResult::getProject )
-                .filter( Objects::nonNull )
-                .filter( project -> request.getPom().equals( project.getFile() ) )
+                .map(ProjectBuildingResult::getProject)
+                .filter(Objects::nonNull)
+                .filter(project -> request.getPom().equals(project.getFile()))
                 .findFirst()
-                .map( requestPomProject ->
-                {
+                .map(requestPomProject -> {
                     List<MavenProject> modules = requestPomProject.getCollectedProjects() != null
-                            ? requestPomProject.getCollectedProjects() : Collections.emptyList();
-                    List<MavenProject> projectsInRequestScope = new ArrayList<>( modules );
-                    projectsInRequestScope.add( requestPomProject );
+                            ? requestPomProject.getCollectedProjects()
+                            : Collections.emptyList();
+                    List<MavenProject> projectsInRequestScope = new ArrayList<>(modules);
+                    projectsInRequestScope.add(requestPomProject);
 
                     Predicate<ProjectBuildingResult> projectsOutsideOfRequestScope =
-                            pr -> !projectsInRequestScope.contains( pr.getProject() );
+                            pr -> !projectsInRequestScope.contains(pr.getProject());
 
-                    Predicate<Exception> pluginArtifactNotFoundException =
-                            exc -> exc instanceof PluginManagerException
-                                    && exc.getCause() instanceof PluginResolutionException
-                                    && exc.getCause().getCause() instanceof ArtifactResolutionException
-                                    && exc.getCause().getCause().getCause() instanceof ArtifactNotFoundException;
+                    Predicate<Exception> pluginArtifactNotFoundException = exc -> exc instanceof PluginManagerException
+                            && exc.getCause() instanceof PluginResolutionException
+                            && exc.getCause().getCause() instanceof ArtifactResolutionException
+                            && exc.getCause().getCause().getCause() instanceof ArtifactNotFoundException;
 
                     Predicate<Plugin> isPluginPartOfRequestScope = plugin -> projectsInRequestScope.stream()
-                            .anyMatch( project -> project.getGroupId().equals( plugin.getGroupId() )
-                                    && project.getArtifactId().equals( plugin.getArtifactId() )
-                                    && project.getVersion().equals( plugin.getVersion() ) );
+                            .anyMatch(project -> project.getGroupId().equals(plugin.getGroupId())
+                                    && project.getArtifactId().equals(plugin.getArtifactId())
+                                    && project.getVersion().equals(plugin.getVersion()));
 
                     return exception.getResults().stream()
-                            .filter( projectsOutsideOfRequestScope )
-                            .flatMap( projectBuildingResult -> projectBuildingResult.getProblems().stream() )
-                            .map( ModelProblem::getException )
-                            .filter( pluginArtifactNotFoundException )
-                            .map( exc -> ( ( PluginResolutionException ) exc.getCause() ).getPlugin() )
-                            .anyMatch( isPluginPartOfRequestScope );
-                } ).orElse( false );
+                            .filter(projectsOutsideOfRequestScope)
+                            .flatMap(projectBuildingResult -> projectBuildingResult.getProblems().stream())
+                            .map(ModelProblem::getException)
+                            .filter(pluginArtifactNotFoundException)
+                            .map(exc -> ((PluginResolutionException) exc.getCause()).getPlugin())
+                            .anyMatch(isPluginPartOfRequestScope);
+                })
+                .orElse(false);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/collector/PomlessCollectionStrategy.java b/maven-core/src/main/java/org/apache/maven/project/collector/PomlessCollectionStrategy.java
index 828485a..bae54f3 100644
--- a/maven-core/src/main/java/org/apache/maven/project/collector/PomlessCollectionStrategy.java
+++ b/maven-core/src/main/java/org/apache/maven/project/collector/PomlessCollectionStrategy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.collector;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.collector;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Arrays;
+import java.util.List;
 
 import org.apache.maven.DefaultMaven;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -28,38 +34,28 @@
 import org.apache.maven.project.ProjectBuildingException;
 import org.apache.maven.project.ProjectBuildingRequest;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.util.Arrays;
-import java.util.List;
-
 /**
  * Strategy to collect projects for building when the Maven invocation is not in a directory that contains a pom.xml.
  */
-@Named( "PomlessCollectionStrategy" )
+@Named("PomlessCollectionStrategy")
 @Singleton
-public class PomlessCollectionStrategy
-    implements ProjectCollectionStrategy
-{
+public class PomlessCollectionStrategy implements ProjectCollectionStrategy {
     private final ProjectBuilder projectBuilder;
 
     @Inject
-    public PomlessCollectionStrategy( ProjectBuilder projectBuilder )
-    {
+    public PomlessCollectionStrategy(ProjectBuilder projectBuilder) {
         this.projectBuilder = projectBuilder;
     }
 
     @Override
-    public List<MavenProject> collectProjects( final MavenExecutionRequest request )
-            throws ProjectBuildingException
-    {
+    public List<MavenProject> collectProjects(final MavenExecutionRequest request) throws ProjectBuildingException {
         ProjectBuildingRequest buildingRequest = request.getProjectBuildingRequest();
-        ModelSource modelSource = new UrlModelSource( DefaultMaven.class.getResource( "project/standalone.xml" ) );
-        MavenProject project = projectBuilder.build( modelSource,  buildingRequest ).getProject();
-        project.setExecutionRoot( true );
-        request.setProjectPresent( false );
+        ModelSource modelSource = new UrlModelSource(DefaultMaven.class.getResource("project/standalone.xml"));
+        MavenProject project =
+                projectBuilder.build(modelSource, buildingRequest).getProject();
+        project.setExecutionRoot(true);
+        request.setProjectPresent(false);
 
-        return Arrays.asList( project );
+        return Arrays.asList(project);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/collector/ProjectCollectionStrategy.java b/maven-core/src/main/java/org/apache/maven/project/collector/ProjectCollectionStrategy.java
index 53521f0..d9bc2f1 100644
--- a/maven-core/src/main/java/org/apache/maven/project/collector/ProjectCollectionStrategy.java
+++ b/maven-core/src/main/java/org/apache/maven/project/collector/ProjectCollectionStrategy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.collector;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,24 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.collector;
+
+import java.util.List;
 
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingException;
 
-import java.util.List;
-
 /**
  * Describes strategies for finding projects that Maven could build.
  */
-public interface ProjectCollectionStrategy
-{
+public interface ProjectCollectionStrategy {
     /**
      *
      * @param request
      * @return
      * @throws ProjectBuildingException
      */
-    List<MavenProject> collectProjects( MavenExecutionRequest request )
-            throws ProjectBuildingException;
+    List<MavenProject> collectProjects(MavenExecutionRequest request) throws ProjectBuildingException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/collector/ProjectsSelector.java b/maven-core/src/main/java/org/apache/maven/project/collector/ProjectsSelector.java
index 1731021..74425f9 100644
--- a/maven-core/src/main/java/org/apache/maven/project/collector/ProjectsSelector.java
+++ b/maven-core/src/main/java/org/apache/maven/project/collector/ProjectsSelector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.collector;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,19 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.collector;
+
+import java.io.File;
+import java.util.List;
 
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingException;
 
-import java.io.File;
-import java.util.List;
-
 /**
  * Facade to select projects for a given set of pom.xml files.
  */
-public interface ProjectsSelector
-{
+public interface ProjectsSelector {
     /**
      * Select Maven projects from a list of POM files.
      * @param files List of POM files.
@@ -38,6 +36,5 @@
      * @return A list of projects that have been found in the specified POM files.
      * @throws ProjectBuildingException In case the POMs are not used.
      */
-    List<MavenProject> selectProjects( List<File> files, MavenExecutionRequest request )
-            throws ProjectBuildingException;
+    List<MavenProject> selectProjects(List<File> files, MavenExecutionRequest request) throws ProjectBuildingException;
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/collector/RequestPomCollectionStrategy.java b/maven-core/src/main/java/org/apache/maven/project/collector/RequestPomCollectionStrategy.java
index bf50856..8ba724e 100644
--- a/maven-core/src/main/java/org/apache/maven/project/collector/RequestPomCollectionStrategy.java
+++ b/maven-core/src/main/java/org/apache/maven/project/collector/RequestPomCollectionStrategy.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.collector;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,37 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.collector;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
 
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingException;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-
 /**
  * Strategy to collect projects based on the <code>-f</code> CLI parameter or the pom.xml in the working directory.
  */
-@Named( "RequestPomCollectionStrategy" )
+@Named("RequestPomCollectionStrategy")
 @Singleton
-public class RequestPomCollectionStrategy implements ProjectCollectionStrategy
-{
+public class RequestPomCollectionStrategy implements ProjectCollectionStrategy {
     private final ProjectsSelector projectsSelector;
 
     @Inject
-    public RequestPomCollectionStrategy( ProjectsSelector projectsSelector )
-    {
+    public RequestPomCollectionStrategy(ProjectsSelector projectsSelector) {
         this.projectsSelector = projectsSelector;
     }
 
     @Override
-    public List<MavenProject> collectProjects( MavenExecutionRequest request ) throws ProjectBuildingException
-    {
-        List<File> files = Collections.singletonList( request.getPom().getAbsoluteFile() );
-        return projectsSelector.selectProjects( files, request );
+    public List<MavenProject> collectProjects(MavenExecutionRequest request) throws ProjectBuildingException {
+        List<File> files = Collections.singletonList(request.getPom().getAbsoluteFile());
+        return projectsSelector.selectProjects(files, request);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/project/path/PathTranslator.java b/maven-core/src/main/java/org/apache/maven/project/path/PathTranslator.java
deleted file mode 100644
index 18e349a..0000000
--- a/maven-core/src/main/java/org/apache/maven/project/path/PathTranslator.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package org.apache.maven.project.path;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-
-import org.apache.maven.model.Model;
-
-/**
- * @author Jason van Zyl
- */
-@Deprecated
-public interface PathTranslator
-{
-    String ROLE = PathTranslator.class.getName();
-
-    void alignToBaseDirectory( Model model, File basedir );
-
-    String alignToBaseDirectory( String path, File basedir );
-
-    void unalignFromBaseDirectory( Model model, File basedir );
-
-    String unalignFromBaseDirectory( String directory, File basedir );
-}
diff --git a/maven-core/src/main/java/org/apache/maven/properties/internal/EnvironmentUtils.java b/maven-core/src/main/java/org/apache/maven/properties/internal/EnvironmentUtils.java
index 2c3196f..027b0a0 100644
--- a/maven-core/src/main/java/org/apache/maven/properties/internal/EnvironmentUtils.java
+++ b/maven-core/src/main/java/org/apache/maven/properties/internal/EnvironmentUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.properties.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.properties.internal;
 
 import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 
-import org.codehaus.plexus.util.Os;
+import org.apache.maven.utils.Os;
 
 /**
  * Assists the project builder. <strong>Warning:</strong> This is an internal utility class that is only public for
@@ -31,10 +30,8 @@
  * prior notice.
  *
  * @since 3.0
- * @author Benjamin Bentmann
  */
-public class EnvironmentUtils
-{
+public class EnvironmentUtils {
 
     private static Properties envVars;
 
@@ -46,25 +43,20 @@
      *
      * @param props The properties to add the environment variables to, may be {@code null}.
      */
-    public static void addEnvVars( Properties props )
-    {
-        if ( props != null )
-        {
-            if ( envVars == null )
-            {
+    public static void addEnvVars(Properties props) {
+        if (props != null) {
+            if (envVars == null) {
                 Properties tmp = new Properties();
-                boolean caseSensitive = !Os.isFamily( Os.FAMILY_WINDOWS );
-                for ( Map.Entry<String, String> entry : System.getenv().entrySet() )
-                {
-                    String key =
-                        "env." + ( caseSensitive ? entry.getKey() : entry.getKey().toUpperCase( Locale.ENGLISH ) );
-                    tmp.setProperty( key, entry.getValue() );
+                boolean caseSensitive = !Os.IS_WINDOWS;
+                for (Map.Entry<String, String> entry : System.getenv().entrySet()) {
+                    String key = "env."
+                            + (caseSensitive ? entry.getKey() : entry.getKey().toUpperCase(Locale.ENGLISH));
+                    tmp.setProperty(key, entry.getValue());
                 }
                 envVars = tmp;
             }
 
-            props.putAll( envVars );
+            props.putAll(envVars);
         }
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/properties/internal/SystemProperties.java b/maven-core/src/main/java/org/apache/maven/properties/internal/SystemProperties.java
index c7ab086..84b68a4 100644
--- a/maven-core/src/main/java/org/apache/maven/properties/internal/SystemProperties.java
+++ b/maven-core/src/main/java/org/apache/maven/properties/internal/SystemProperties.java
@@ -1,5 +1,3 @@
-package org.apache.maven.properties.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,20 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.properties.internal;
 
 import java.util.Properties;
 
 /**
  * @since 3.2.3
  */
-public class SystemProperties
-{
+public class SystemProperties {
     /**
      * Thread-safe System.properties copy implementation.
      */
-    public static void addSystemProperties( Properties props )
-    {
-        props.putAll( getSystemProperties() );
+    public static void addSystemProperties(Properties props) {
+        props.putAll(getSystemProperties());
     }
 
     /**
@@ -39,9 +36,8 @@
      *
      * @return {@link System#getProperties()} obtained in a thread-safe manner.
      */
-    public static Properties getSystemProperties()
-    {
-        return copyProperties( System.getProperties() );
+    public static Properties getSystemProperties() {
+        return copyProperties(System.getProperties());
     }
 
     /**
@@ -49,15 +45,12 @@
      * @param properties Properties to copy.
      * @return Copy of the given properties.
      */
-    public static Properties copyProperties( Properties properties )
-    {
+    public static Properties copyProperties(Properties properties) {
         final Properties copyProperties = new Properties();
         // guard against modification/removal of keys in the given properties (MNG-5670, MNG-6053, MNG-6105)
-        synchronized ( properties )
-        {
-            copyProperties.putAll( properties );
+        synchronized (properties) {
+            copyProperties.putAll(properties);
         }
         return copyProperties;
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/repository/ArtifactDoesNotExistException.java b/maven-core/src/main/java/org/apache/maven/repository/ArtifactDoesNotExistException.java
deleted file mode 100644
index 3e72387..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/ArtifactDoesNotExistException.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * ArtifactDoesNotExistException
- */
-public class ArtifactDoesNotExistException
-    extends Exception
-{
-    public ArtifactDoesNotExistException( final String message )
-    {
-        super( message );
-    }
-
-    public ArtifactDoesNotExistException( final String message, final Throwable cause )
-    {
-        super( message, cause );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferEvent.java b/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferEvent.java
deleted file mode 100644
index f560c54..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferEvent.java
+++ /dev/null
@@ -1,339 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-import java.io.File;
-import java.util.EventObject;
-
-/**
- * TransferEvent is used to notify TransferListeners about progress
- * in transfer of resources form/to the repository
- *
- * @author <a href="michal.maczka@dimatics.com">Michal Maczka</a>
- */
-public class ArtifactTransferEvent
-    extends EventObject
-{
-    /**
-     * A transfer was attempted, but has not yet commenced.
-     */
-    public static final int TRANSFER_INITIATED = 0;
-
-    /**
-     * A transfer was started.
-     */
-    public static final int TRANSFER_STARTED = 1;
-
-    /**
-     * A transfer is completed.
-     */
-    public static final int TRANSFER_COMPLETED = 2;
-
-    /**
-     * A transfer is in progress.
-     */
-    public static final int TRANSFER_PROGRESS = 3;
-
-    /**
-     * An error occurred during transfer
-     */
-    public static final int TRANSFER_ERROR = 4;
-
-    /**
-     * Indicates GET transfer  (from the repository)
-     */
-    public static final int REQUEST_GET = 5;
-
-    /**
-     * Indicates PUT transfer (to the repository)
-     */
-    public static final int REQUEST_PUT = 6;
-
-    private int eventType;
-
-    private int requestType;
-
-    private Exception exception;
-
-    private File localFile;
-
-    private ArtifactTransferResource artifact;
-
-    private long transferredBytes;
-
-    private byte[] dataBuffer;
-
-    private int dataOffset;
-
-    private int dataLength;
-
-    public ArtifactTransferEvent( String wagon, final int eventType, final int requestType,
-                                  ArtifactTransferResource artifact )
-    {
-        super( wagon );
-
-        setEventType( eventType );
-
-        setRequestType( requestType );
-
-        this.artifact = artifact;
-    }
-
-    public ArtifactTransferEvent( String wagon, final Exception exception, final int requestType,
-                                  ArtifactTransferResource artifact )
-    {
-        this( wagon, TRANSFER_ERROR, requestType, artifact );
-
-        this.exception = exception;
-    }
-
-    public ArtifactTransferResource getResource()
-    {
-        return artifact;
-    }
-
-    /**
-     * @return Returns the exception.
-     */
-    public Exception getException()
-    {
-        return exception;
-    }
-
-    /**
-     * Returns the request type.
-     *
-     * @return Returns the request type. The Request type is one of
-     *         <code>TransferEvent.REQUEST_GET</code> or <code>TransferEvent.REQUEST_PUT</code>
-     */
-    public int getRequestType()
-    {
-        return requestType;
-    }
-
-    /**
-     * Sets the request type
-     *
-     * @param requestType The requestType to set.
-     *                    The Request type value should be either
-     *                    <code>TransferEvent.REQUEST_GET</code> or <code>TransferEvent.REQUEST_PUT</code>.
-     * @throws IllegalArgumentException when
-     */
-    public void setRequestType( final int requestType )
-    {
-        switch ( requestType )
-        {
-            case REQUEST_PUT:
-                break;
-            case REQUEST_GET:
-                break;
-            default :
-                throw new IllegalArgumentException( "Illegal request type: " + requestType );
-        }
-
-        this.requestType = requestType;
-    }
-
-    /**
-     * @return Returns the eventType.
-     */
-    public int getEventType()
-    {
-        return eventType;
-    }
-
-    /**
-     * @param eventType The eventType to set.
-     */
-    public void setEventType( final int eventType )
-    {
-        switch ( eventType )
-        {
-            case TRANSFER_INITIATED:
-                break;
-            case TRANSFER_STARTED:
-                break;
-            case TRANSFER_COMPLETED:
-                break;
-            case TRANSFER_PROGRESS:
-                break;
-            case TRANSFER_ERROR:
-                break;
-            default :
-                throw new IllegalArgumentException( "Illegal event type: " + eventType );
-        }
-
-        this.eventType = eventType;
-    }
-
-    /**
-     * @return Returns the local file.
-     */
-    public File getLocalFile()
-    {
-        return localFile;
-    }
-
-    /**
-     * @param localFile The local file to set.
-     */
-    public void setLocalFile( File localFile )
-    {
-        this.localFile = localFile;
-    }
-
-    public long getTransferredBytes()
-    {
-        return transferredBytes;
-    }
-
-    public void setTransferredBytes( long transferredBytes )
-    {
-        this.transferredBytes = transferredBytes;
-    }
-
-    public byte[] getDataBuffer()
-    {
-        return dataBuffer;
-    }
-
-    public void setDataBuffer( byte[] dataBuffer )
-    {
-        this.dataBuffer = dataBuffer;
-    }
-
-    public int getDataOffset()
-    {
-        return dataOffset;
-    }
-
-    public void setDataOffset( int dataOffset )
-    {
-        this.dataOffset = dataOffset;
-    }
-
-    public int getDataLength()
-    {
-        return dataLength;
-    }
-
-    public void setDataLength( int dataLength )
-    {
-        this.dataLength = dataLength;
-    }
-
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 64 );
-
-        sb.append( "TransferEvent[" );
-
-        switch ( this.getRequestType() )
-        {
-            case REQUEST_GET:
-                sb.append( "GET" );
-                break;
-            case REQUEST_PUT:
-                sb.append( "PUT" );
-                break;
-            default:
-                sb.append( this.getRequestType() );
-                break;
-        }
-
-        sb.append( '|' );
-        switch ( this.getEventType() )
-        {
-            case TRANSFER_COMPLETED:
-                sb.append( "COMPLETED" );
-                break;
-            case TRANSFER_ERROR:
-                sb.append( "ERROR" );
-                break;
-            case TRANSFER_INITIATED:
-                sb.append( "INITIATED" );
-                break;
-            case TRANSFER_PROGRESS:
-                sb.append( "PROGRESS" );
-                break;
-            case TRANSFER_STARTED:
-                sb.append( "STARTED" );
-                break;
-            default:
-                sb.append( this.getEventType() );
-                break;
-        }
-
-        sb.append( '|' );
-        sb.append( this.getLocalFile() ).append( '|' );
-        sb.append( ']' );
-
-        return sb.toString();
-    }
-
-    public int hashCode()
-    {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + eventType;
-        result = prime * result + ( ( exception == null ) ? 0 : exception.hashCode() );
-        result = prime * result + ( ( localFile == null ) ? 0 : localFile.hashCode() );
-        result = prime * result + requestType;
-        return result;
-    }
-
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
-            return true;
-        }
-        if ( ( obj == null ) || ( getClass() != obj.getClass() ) )
-        {
-            return false;
-        }
-        final ArtifactTransferEvent other = (ArtifactTransferEvent) obj;
-        if ( eventType != other.eventType )
-        {
-            return false;
-        }
-        if ( exception == null )
-        {
-            if ( other.exception != null )
-            {
-                return false;
-            }
-        }
-        else if ( !exception.getClass().equals( other.exception.getClass() ) )
-        {
-            return false;
-        }
-        if ( requestType != other.requestType )
-        {
-            return false;
-        }
-        else
-        {
-            return source.equals( other.source );
-        }
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferFailedException.java b/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferFailedException.java
deleted file mode 100644
index f35de65..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferFailedException.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * ArtifactTransferFailedException
- */
-public class ArtifactTransferFailedException
-    extends Exception
-{
-    public ArtifactTransferFailedException( final String message )
-    {
-        super( message );
-    }
-
-    public ArtifactTransferFailedException( final String message, final Throwable cause )
-    {
-        super( message, cause );
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferListener.java b/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferListener.java
deleted file mode 100644
index c6d2446..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * ArtifactTransferListener
- */
-public interface ArtifactTransferListener
-{
-    boolean isShowChecksumEvents();
-
-    void setShowChecksumEvents( boolean showChecksumEvents );
-
-    void transferInitiated( ArtifactTransferEvent transferEvent );
-
-    void transferStarted( ArtifactTransferEvent transferEvent );
-
-    void transferProgress( ArtifactTransferEvent transferEvent );
-
-    void transferCompleted( ArtifactTransferEvent transferEvent );
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferResource.java b/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferResource.java
deleted file mode 100644
index 8ed081f..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/ArtifactTransferResource.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Describes a resource being uploaded or downloaded by the repository system.
- *
- * @author Benjamin Bentmann
- */
-public interface ArtifactTransferResource
-{
-
-    /**
-     * The base URL of the repository, e.g. "http://repo1.maven.org/maven2/". Unless the URL is unknown, it will be
-     * terminated by a trailing slash.
-     *
-     * @return The base URL of the repository or an empty string if unknown, never {@code null}.
-     */
-    String getRepositoryUrl();
-
-    /**
-     * The path of the artifact relative to the repository's base URL.
-     *
-     * @return The path of the artifact, never {@code null}.
-     */
-    String getName();
-
-    /**
-     * Gets the full URL of the artifact.
-     *
-     * @return The full URL of the artifact, never {@code null}.
-     */
-    String getUrl();
-
-    /**
-     * The size of the artifact in bytes.
-     *
-     * @return The of the artifact in bytes or a negative value if unknown.
-     */
-    long getContentLength();
-
-    /**
-     * Gets the timestamp when the transfer of this artifact was started.
-     *
-     * @return The timestamp when the transfer of this artifact was started.
-     */
-    long getTransferStartTime();
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/DelegatingLocalArtifactRepository.java b/maven-core/src/main/java/org/apache/maven/repository/DelegatingLocalArtifactRepository.java
deleted file mode 100644
index eb8f5ea..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/DelegatingLocalArtifactRepository.java
+++ /dev/null
@@ -1,204 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.metadata.ArtifactMetadata;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-import org.apache.maven.artifact.repository.MavenArtifactRepository;
-import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
-
-/**
- * Delegating local artifact repository chains the reactor, IDE workspace
- * and user local repository.
- */
-@Deprecated
-public class DelegatingLocalArtifactRepository
-    extends MavenArtifactRepository
-{
-    private LocalArtifactRepository buildReactor;
-
-    private LocalArtifactRepository ideWorkspace;
-
-    private ArtifactRepository userLocalArtifactRepository;
-
-    public DelegatingLocalArtifactRepository( ArtifactRepository artifactRepository )
-    {
-        this.userLocalArtifactRepository = artifactRepository;
-    }
-
-    public void setBuildReactor( LocalArtifactRepository localRepository )
-    {
-        this.buildReactor = localRepository;
-    }
-
-    public void setIdeWorkspace( LocalArtifactRepository localRepository )
-    {
-        this.ideWorkspace = localRepository;
-    }
-
-    /**
-     * @deprecated instead use {@link #getIdeWorkspace()}
-     */
-    @Deprecated
-    public LocalArtifactRepository getIdeWorspace()
-    {
-        return ideWorkspace;
-    }
-
-    public LocalArtifactRepository getIdeWorkspace()
-    {
-        return getIdeWorspace();
-    }
-
-    @Override
-    public Artifact find( Artifact artifact )
-    {
-        if ( !artifact.isRelease() && buildReactor != null )
-        {
-            artifact = buildReactor.find( artifact );
-        }
-
-        if ( !artifact.isResolved() && ideWorkspace != null )
-        {
-            artifact = ideWorkspace.find( artifact );
-        }
-
-        if ( !artifact.isResolved() )
-        {
-            artifact = userLocalArtifactRepository.find( artifact );
-        }
-
-        return artifact;
-    }
-
-    @Override
-    public List<String> findVersions( Artifact artifact )
-    {
-        Collection<String> versions = new LinkedHashSet<>();
-
-        if ( buildReactor != null )
-        {
-            versions.addAll( buildReactor.findVersions( artifact ) );
-        }
-
-        if ( ideWorkspace != null )
-        {
-            versions.addAll( ideWorkspace.findVersions( artifact ) );
-        }
-
-        versions.addAll( userLocalArtifactRepository.findVersions( artifact ) );
-
-        return Collections.unmodifiableList( new ArrayList<>( versions ) );
-    }
-
-    public String pathOfLocalRepositoryMetadata( ArtifactMetadata metadata, ArtifactRepository repository )
-    {
-        return userLocalArtifactRepository.pathOfLocalRepositoryMetadata( metadata, repository );
-    }
-
-    public String getId()
-    {
-        return userLocalArtifactRepository.getId();
-    }
-
-    @Override
-    public String pathOf( Artifact artifact )
-    {
-        return userLocalArtifactRepository.pathOf( artifact );
-    }
-
-    @Override
-    public String getBasedir()
-    {
-        return ( userLocalArtifactRepository != null ) ? userLocalArtifactRepository.getBasedir() : null;
-    }
-
-    @Override
-    public ArtifactRepositoryLayout getLayout()
-    {
-        return userLocalArtifactRepository.getLayout();
-    }
-
-    @Override
-    public ArtifactRepositoryPolicy getReleases()
-    {
-        return userLocalArtifactRepository.getReleases();
-    }
-
-    @Override
-    public ArtifactRepositoryPolicy getSnapshots()
-    {
-        return userLocalArtifactRepository.getSnapshots();
-    }
-
-    @Override
-    public String getKey()
-    {
-        return userLocalArtifactRepository.getKey();
-    }
-
-    @Override
-    public String getUrl()
-    {
-        return userLocalArtifactRepository.getUrl();
-    }
-
-    @Override
-    public int hashCode()
-    {
-        int hash = 17;
-        hash = hash * 31 + ( buildReactor == null ? 0 : buildReactor.hashCode() );
-        hash = hash * 31 + ( ideWorkspace == null ? 0 : ideWorkspace.hashCode() );
-        hash = hash * 31 + ( userLocalArtifactRepository == null ? 0 : userLocalArtifactRepository.hashCode() );
-
-        return hash;
-    }
-
-    @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
-            return true;
-        }
-        if ( obj == null )
-        {
-            return false;
-        }
-        if ( getClass() != obj.getClass() )
-        {
-            return false;
-        }
-
-        DelegatingLocalArtifactRepository other = (DelegatingLocalArtifactRepository) obj;
-
-        return eq( buildReactor, other.buildReactor )
-            && eq( ideWorkspace, other.ideWorkspace )
-            && eq( userLocalArtifactRepository, other.userLocalArtifactRepository );
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/LocalArtifactRepository.java b/maven-core/src/main/java/org/apache/maven/repository/LocalArtifactRepository.java
deleted file mode 100644
index 6f1c934..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/LocalArtifactRepository.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.MavenArtifactRepository;
-
-/**
- * LocalArtifactRepository
- */
-public abstract class LocalArtifactRepository
-    extends MavenArtifactRepository
-{
-    public static final String IDE_WORKSPACE = "ide-workspace";
-
-    public abstract Artifact find( Artifact artifact );
-
-    public abstract boolean hasLocalMetadata();
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/LocalRepositoryNotAccessibleException.java b/maven-core/src/main/java/org/apache/maven/repository/LocalRepositoryNotAccessibleException.java
deleted file mode 100644
index 54e4ef4..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/LocalRepositoryNotAccessibleException.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-
-/**
- * Signals a failure to store files within the local repository.
- *
- * @author Benjamin Bentmann
- */
-public class LocalRepositoryNotAccessibleException
-    extends IOException
-{
-
-    public LocalRepositoryNotAccessibleException( String message, Throwable cause )
-    {
-        super( message );
-        initCause( cause );
-    }
-
-    public LocalRepositoryNotAccessibleException( String message )
-    {
-        super( message );
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/RepositorySystem.java b/maven-core/src/main/java/org/apache/maven/repository/RepositorySystem.java
deleted file mode 100644
index 30b4925..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/RepositorySystem.java
+++ /dev/null
@@ -1,167 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.util.List;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.InvalidRepositoryException;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
-import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
-import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.Repository;
-import org.apache.maven.settings.Mirror;
-import org.apache.maven.settings.Server;
-import org.eclipse.aether.RepositorySystemSession;
-
-/**
- * @author Jason van Zyl
- * @since 3.0-alpha
- */
-public interface RepositorySystem
-{
-    String DEFAULT_LOCAL_REPO_ID = "local";
-
-    @SuppressWarnings( "checkstyle:constantname" )
-    String userHome = System.getProperty( "user.home" );
-
-    @SuppressWarnings( "checkstyle:constantname" )
-    File userMavenConfigurationHome = new File( userHome, ".m2" );
-
-    @SuppressWarnings( "checkstyle:constantname" )
-    File defaultUserLocalRepository = new File( userMavenConfigurationHome, "repository" );
-
-    String DEFAULT_REMOTE_REPO_ID = "central";
-
-    String DEFAULT_REMOTE_REPO_URL = "https://repo.maven.apache.org/maven2";
-
-    Artifact createArtifact( String groupId, String artifactId, String version, String packaging );
-
-    Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type );
-
-    Artifact createProjectArtifact( String groupId, String artifactId, String version );
-
-    Artifact createArtifactWithClassifier( String groupId, String artifactId, String version, String type,
-                                           String classifier );
-
-    Artifact createPluginArtifact( Plugin plugin );
-
-    Artifact createDependencyArtifact( Dependency dependency );
-
-    ArtifactRepository buildArtifactRepository( Repository repository )
-        throws InvalidRepositoryException;
-
-    ArtifactRepository createDefaultRemoteRepository()
-        throws InvalidRepositoryException;
-
-    ArtifactRepository createDefaultLocalRepository()
-        throws InvalidRepositoryException;
-
-    ArtifactRepository createLocalRepository( File localRepository )
-        throws InvalidRepositoryException;
-
-    ArtifactRepository createArtifactRepository( String id, String url, ArtifactRepositoryLayout repositoryLayout,
-                                                 ArtifactRepositoryPolicy snapshots,
-                                                 ArtifactRepositoryPolicy releases );
-
-    /**
-     * Calculates the effective repositories for the given input repositories which are assumed to be already mirrored
-     * (if applicable). This process will essentially remove duplicate repositories by merging them into one equivalent
-     * repository. It is worth to point out that merging does not simply choose one of the input repositories and
-     * discards the others but actually combines their possibly different policies.
-     *
-     * @param repositories The original repositories, may be {@code null}.
-     * @return The effective repositories or {@code null} if the input was {@code null}.
-     */
-    List<ArtifactRepository> getEffectiveRepositories( List<ArtifactRepository> repositories );
-
-    /**
-     * Determines the mirror for the specified repository.
-     *
-     * @param repository The repository to determine the mirror for, must not be {@code null}.
-     * @param mirrors The available mirrors, may be {@code null}.
-     * @return The mirror specification for the repository or {@code null} if no mirror matched.
-     */
-    Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors );
-
-    /**
-     * Injects the mirroring information into the specified repositories. For each repository that is matched by a
-     * mirror, its URL and ID will be updated to match the values from the mirror specification. Repositories without a
-     * matching mirror will pass through unchanged. <em>Note:</em> This method must be called before
-     * {@link #injectAuthentication(List, List)} or the repositories will end up with the wrong credentials.
-     *
-     * @param repositories The repositories into which to inject the mirror information, may be {@code null}.
-     * @param mirrors The available mirrors, may be {@code null}.
-     */
-    void injectMirror( List<ArtifactRepository> repositories, List<Mirror> mirrors );
-
-    /**
-     * Injects the proxy information into the specified repositories. For each repository that is matched by a proxy,
-     * its proxy data will be set accordingly. Repositories without a matching proxy will have their proxy cleared.
-     * <em>Note:</em> This method must be called after {@link #injectMirror(List, List)} or the repositories will end up
-     * with the wrong proxies.
-     *
-     * @param repositories The repositories into which to inject the proxy information, may be {@code null}.
-     * @param proxies The available proxies, may be {@code null}.
-     */
-    void injectProxy( List<ArtifactRepository> repositories, List<org.apache.maven.settings.Proxy> proxies );
-
-    /**
-     * Injects the authentication information into the specified repositories. For each repository that is matched by a
-     * server, its credentials will be updated to match the values from the server specification. Repositories without a
-     * matching server will have their credentials cleared. <em>Note:</em> This method must be called after
-     * {@link #injectMirror(List, List)} or the repositories will end up with the wrong credentials.
-     *
-     * @param repositories The repositories into which to inject the authentication information, may be {@code null}.
-     * @param servers The available servers, may be {@code null}.
-     */
-    void injectAuthentication( List<ArtifactRepository> repositories, List<Server> servers );
-
-    void injectMirror( RepositorySystemSession session, List<ArtifactRepository> repositories );
-
-    void injectProxy( RepositorySystemSession session, List<ArtifactRepository> repositories );
-
-    void injectAuthentication( RepositorySystemSession session, List<ArtifactRepository> repositories );
-
-    ArtifactResolutionResult resolve( ArtifactResolutionRequest request );
-
-    // Install
-
-    // Deploy
-
-    // Map types of artifacts
-
-    //
-    // Raw file transfers
-    //
-    void publish( ArtifactRepository repository, File source, String remotePath,
-                  ArtifactTransferListener transferListener )
-        throws ArtifactTransferFailedException;
-
-    void retrieve( ArtifactRepository repository, File destination, String remotePath,
-                   ArtifactTransferListener transferListener )
-        throws ArtifactTransferFailedException, ArtifactDoesNotExistException;
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/AbstractArtifactMetadata.java b/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/AbstractArtifactMetadata.java
deleted file mode 100644
index 36bde14..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/AbstractArtifactMetadata.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.apache.maven.repository.legacy.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-
-/**
- * Common elements of artifact metadata.
- *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- */
-public abstract class AbstractArtifactMetadata
-    implements ArtifactMetadata
-{
-    private static final String LS = System.lineSeparator();
-
-    protected Artifact artifact;
-
-    protected AbstractArtifactMetadata( Artifact artifact )
-    {
-        this.artifact = artifact;
-    }
-
-    public boolean storedInGroupDirectory()
-    {
-        return false;
-    }
-
-    public String getGroupId()
-    {
-        return artifact.getGroupId();
-    }
-
-    public String getArtifactId()
-    {
-        return artifact.getArtifactId();
-    }
-
-    public String extendedToString()
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-
-        buffer.append( LS ).append( "Artifact Metadata" ).append( LS ).append( "--------------------------" );
-        buffer.append( LS ).append( "GroupId: " ).append( getGroupId() );
-        buffer.append( LS ).append( "ArtifactId: " ).append( getArtifactId() );
-        buffer.append( LS ).append( "Metadata Type: " ).append( getClass().getName() );
-
-        return buffer.toString();
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException.java b/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException.java
deleted file mode 100644
index bc8ceac..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataRetrievalException.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.apache.maven.repository.legacy.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.Artifact;
-
-/**
- * Error while retrieving repository metadata from the repository.
- *
- * @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
- */
-public class ArtifactMetadataRetrievalException
-    extends Exception
-{
-    private Artifact artifact;
-
-    /**
-     * @param message a message
-     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
-     */
-    @Deprecated
-    public ArtifactMetadataRetrievalException( String message )
-    {
-        this( message, null, null );
-    }
-
-    /**
-     * @param cause a cause
-     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
-     */
-    @Deprecated
-    public ArtifactMetadataRetrievalException( Throwable cause )
-    {
-        this( null, cause, null );
-    }
-
-    /**
-     * @param message a message
-     * @param cause a cause
-     * @deprecated use {@link #ArtifactMetadataRetrievalException(String, Throwable, Artifact)}
-     */
-    @Deprecated
-    public ArtifactMetadataRetrievalException( String message,
-                                               Throwable cause )
-    {
-        this( message, cause, null );
-    }
-
-    public ArtifactMetadataRetrievalException( String message,
-                                               Throwable cause,
-                                               Artifact artifact )
-    {
-        super( message, cause );
-        this.artifact = artifact;
-    }
-
-    public Artifact getArtifact()
-    {
-        return artifact;
-    }
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource.java b/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource.java
deleted file mode 100644
index e46e33b..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ArtifactMetadataSource.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package org.apache.maven.repository.legacy.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.versioning.ArtifactVersion;
-
-/**
- * Provides some metadata operations, like querying the remote repository for a list of versions available for an
- * artifact.
- *
- * @author <a href="mailto:jason@maven.org">Jason van Zyl </a>
- */
-public interface ArtifactMetadataSource
-{
-
-    ResolutionGroup retrieve( MetadataResolutionRequest request )
-        throws ArtifactMetadataRetrievalException;
-
-    ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                              List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException;
-
-    /**
-     * Get a list of available versions for an artifact in the remote repository
-     *
-     * @param artifact           artifact we are interested in. Only <code>groupid</code> and <code>artifactId</code>
-     *                           are needed, for instance the following code will work
-     *                           <code>artifactFactory.createProjectArtifact( "org.apache.maven", "maven", "" )</code>
-     * @param localRepository    local repository
-     * @param remoteRepositories remote repositories, {@link List} $lt; {@link ArtifactRepository} &gt;
-     * @return {@link List} $lt; {@link ArtifactVersion} &gt;
-     * @throws ArtifactMetadataRetrievalException
-     *          in case of error while retrieving repository metadata from the repository.
-     */
-    List<ArtifactVersion> retrieveAvailableVersions( Artifact artifact, ArtifactRepository localRepository,
-                                                     List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException;
-
-    /**
-     * Get a list of available versions for an artifact in the remote deployment repository. This ignores any update
-     * policy checks and mirrors and always retrieves the latest information from the given repository.
-     *
-     * @param artifact artifact we are interested in. Only <code>groupid</code> and <code>artifactId</code> are
-     *            needed, for instance the following code will work
-     *            <code>artifactFactory.createProjectArtifact( "org.apache.maven", "maven", "" )</code>
-     * @param localRepository    local repository
-     * @param remoteRepository   remote repository
-     * @return {@link List} $lt; {@link ArtifactVersion} &gt;
-     * @throws ArtifactMetadataRetrievalException
-     *          in case of error while retrieving repository metadata from the repository.
-     */
-    List<ArtifactVersion> retrieveAvailableVersionsFromDeploymentRepository( Artifact artifact,
-                                                                             ArtifactRepository localRepository,
-                                                                             ArtifactRepository remoteRepository )
-        throws ArtifactMetadataRetrievalException;
-
-}
\ No newline at end of file
diff --git a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/DefaultMetadataResolutionRequest.java b/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/DefaultMetadataResolutionRequest.java
deleted file mode 100644
index 93b9d5d..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/DefaultMetadataResolutionRequest.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.apache.maven.repository.legacy.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.DefaultRepositoryRequest;
-import org.apache.maven.artifact.repository.RepositoryRequest;
-import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
-
-/**
- * Forms a request to retrieve artifact metadata.
- *
- * @author Benjamin Bentmann
- */
-public class DefaultMetadataResolutionRequest
-    implements MetadataResolutionRequest
-{
-
-    private Artifact artifact;
-
-    private boolean resolveManagedVersions;
-
-    private RepositoryRequest repositoryRequest;
-
-    public DefaultMetadataResolutionRequest()
-    {
-        repositoryRequest = new DefaultRepositoryRequest();
-    }
-
-    public DefaultMetadataResolutionRequest( RepositoryRequest repositoryRequest )
-    {
-        this.repositoryRequest = new DefaultRepositoryRequest( repositoryRequest );
-    }
-
-    public DefaultMetadataResolutionRequest( ArtifactResolutionRequest resolutionRequest )
-    {
-        this.repositoryRequest = new DefaultRepositoryRequest( resolutionRequest );
-    }
-
-    public Artifact getArtifact()
-    {
-        return artifact;
-    }
-
-    public DefaultMetadataResolutionRequest setArtifact( Artifact artifact )
-    {
-        this.artifact = artifact;
-
-        return this;
-    }
-
-    public ArtifactRepository getLocalRepository()
-    {
-        return repositoryRequest.getLocalRepository();
-    }
-
-    public DefaultMetadataResolutionRequest setLocalRepository( ArtifactRepository localRepository )
-    {
-        repositoryRequest.setLocalRepository( localRepository );
-
-        return this;
-    }
-
-    public List<ArtifactRepository> getRemoteRepositories()
-    {
-        return repositoryRequest.getRemoteRepositories();
-    }
-
-    public DefaultMetadataResolutionRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories )
-    {
-        repositoryRequest.setRemoteRepositories( remoteRepositories );
-
-        return this;
-    }
-
-    public boolean isResolveManagedVersions()
-    {
-        return resolveManagedVersions;
-    }
-
-    public DefaultMetadataResolutionRequest setResolveManagedVersions( boolean resolveManagedVersions )
-    {
-        this.resolveManagedVersions = resolveManagedVersions;
-
-        return this;
-    }
-
-    public boolean isOffline()
-    {
-        return repositoryRequest.isOffline();
-    }
-
-    public DefaultMetadataResolutionRequest setOffline( boolean offline )
-    {
-        repositoryRequest.setOffline( offline );
-
-        return this;
-    }
-
-    public boolean isForceUpdate()
-    {
-        return repositoryRequest.isForceUpdate();
-    }
-
-    public DefaultMetadataResolutionRequest setForceUpdate( boolean forceUpdate )
-    {
-        repositoryRequest.setForceUpdate( forceUpdate );
-
-        return this;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest.java b/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest.java
deleted file mode 100644
index 028c4d4..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/MetadataResolutionRequest.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.apache.maven.repository.legacy.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.RepositoryRequest;
-
-/**
- * Forms a request to retrieve artifact metadata.
- *
- * @author Benjamin Bentmann
- */
-public interface MetadataResolutionRequest
-    extends RepositoryRequest
-{
-
-    /**
-     * Indicates whether network access to remote repositories has been disabled.
-     *
-     * @return {@code true} if remote access has been disabled, {@code false} otherwise.
-     */
-    boolean isOffline();
-
-    /**
-     * Enables/disables network access to remote repositories.
-     *
-     * @param offline {@code true} to disable remote access, {@code false} to allow network access.
-     * @return This request, never {@code null}.
-     */
-    MetadataResolutionRequest setOffline( boolean offline );
-
-    /**
-     * Gets the artifact to resolve metadata for.
-     *
-     * @return The artifact to resolve metadata for or {@code null} if not set.
-     */
-    Artifact getArtifact();
-
-    /**
-     * Sets the artifact for which to resolve metadata.
-     *
-     * @param artifact The artifact for which to resolve metadata.
-     * @return This request, never {@code null}.
-     */
-    MetadataResolutionRequest setArtifact( Artifact artifact );
-
-    /**
-     * Gets the local repository to use for the resolution.
-     *
-     * @return The local repository to use for the resolution or {@code null} if not set.
-     */
-    ArtifactRepository getLocalRepository();
-
-    /**
-     * Sets the local repository to use for the resolution.
-     *
-     * @param localRepository The local repository to use for the resolution.
-     * @return This request, never {@code null}.
-     */
-    MetadataResolutionRequest setLocalRepository( ArtifactRepository localRepository );
-
-    /**
-     * Gets the remote repositories to use for the resolution.
-     *
-     * @return The remote repositories to use for the resolution, never {@code null}.
-     */
-    List<ArtifactRepository> getRemoteRepositories();
-
-    /**
-     * Sets the remote repositories to use for the resolution.
-     *
-     * @param remoteRepositories The remote repositories to use for the resolution.
-     * @return This request, never {@code null}.
-     */
-    MetadataResolutionRequest setRemoteRepositories( List<ArtifactRepository> remoteRepositories );
-
-    /**
-     * Determines whether the managed version information should be retrieved.
-     *
-     * @return {@code true} if the dependency management information should be retrieved, {@code false} otherwise.
-     */
-    boolean isResolveManagedVersions();
-
-    /**
-     * Enables/disables resolution of the dependency management information.
-     *
-     * @param resolveManagedVersions {@code true} if the dependency management information should be retrieved, {@code
-     *            false} otherwise.
-     * @return This request, never {@code null}.
-     */
-    MetadataResolutionRequest setResolveManagedVersions( boolean resolveManagedVersions );
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ResolutionGroup.java b/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ResolutionGroup.java
deleted file mode 100644
index ae1019a..0000000
--- a/maven-core/src/main/java/org/apache/maven/repository/legacy/metadata/ResolutionGroup.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.apache.maven.repository.legacy.metadata;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-
-/**
- * ResolutionGroup
- */
-public class ResolutionGroup
-{
-
-    private final Set<Artifact> artifacts;
-
-    private final List<ArtifactRepository> resolutionRepositories;
-
-    private final Artifact pomArtifact;
-
-    private final Artifact relocatedArtifact;
-
-    private final Map<String, Artifact> managedVersions;
-
-    public ResolutionGroup( Artifact pomArtifact, Set<Artifact> artifacts,
-                            List<ArtifactRepository> resolutionRepositories )
-    {
-        this( pomArtifact, null, artifacts, null, resolutionRepositories );
-    }
-
-    public ResolutionGroup( Artifact pomArtifact, Artifact relocatedArtifact, Set<Artifact> artifacts,
-                            Map<String, Artifact> managedVersions, List<ArtifactRepository> resolutionRepositories )
-    {
-        this.pomArtifact = pomArtifact;
-        this.relocatedArtifact = relocatedArtifact;
-        this.artifacts = artifacts;
-        this.managedVersions = managedVersions;
-        this.resolutionRepositories = resolutionRepositories;
-    }
-
-    public Artifact getPomArtifact()
-    {
-        return pomArtifact;
-    }
-
-    public Artifact getRelocatedArtifact()
-    {
-        return relocatedArtifact;
-    }
-
-    public Set<Artifact> getArtifacts()
-    {
-        return artifacts;
-    }
-
-    public List<ArtifactRepository> getResolutionRepositories()
-    {
-        return resolutionRepositories;
-    }
-
-    public Map<String, Artifact> getManagedVersions()
-    {
-        return managedVersions;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/rtinfo/RuntimeInformation.java b/maven-core/src/main/java/org/apache/maven/rtinfo/RuntimeInformation.java
index 4e3520d..847c8b0 100644
--- a/maven-core/src/main/java/org/apache/maven/rtinfo/RuntimeInformation.java
+++ b/maven-core/src/main/java/org/apache/maven/rtinfo/RuntimeInformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.rtinfo;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.rtinfo;
 
 /**
  * Provides information about the current Maven runtime.
  *
  * @since 3.0.2
  */
-public interface RuntimeInformation
-{
+public interface RuntimeInformation {
 
     /**
      * Retrieves the current Maven version, for example "3.0.2".
@@ -44,6 +42,5 @@
      * @throws IllegalArgumentException If the specified version range is {@code null}, empty or otherwise not a valid
      *             version specification.
      */
-    boolean isMavenVersion( String versionRange );
-
+    boolean isMavenVersion(String versionRange);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformation.java b/maven-core/src/main/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformation.java
index fc0a8bf..9211c61 100644
--- a/maven-core/src/main/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformation.java
+++ b/maven-core/src/main/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformation.java
@@ -1,5 +1,3 @@
-package org.apache.maven.rtinfo.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.rtinfo.internal;
 
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+import java.util.Properties;
+
 import org.apache.maven.rtinfo.RuntimeInformation;
 import org.eclipse.aether.version.InvalidVersionSpecificationException;
 import org.eclipse.aether.version.Version;
@@ -29,117 +35,86 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 /**
  * Provides information about the current Maven runtime.
  */
 @Named
 @Singleton
-public class DefaultRuntimeInformation
-    implements RuntimeInformation
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class DefaultRuntimeInformation implements RuntimeInformation {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
     private final VersionScheme versionScheme;
 
     private final String mavenVersion;
 
     @Inject
-    public DefaultRuntimeInformation( final VersionScheme versionScheme )
-    {
+    public DefaultRuntimeInformation(final VersionScheme versionScheme) {
         this.versionScheme = versionScheme;
         this.mavenVersion = loadMavenVersion();
     }
 
     @Override
-    public String getMavenVersion()
-    {
+    public String getMavenVersion() {
         return mavenVersion;
     }
 
-    private String loadMavenVersion()
-    {
+    private String loadMavenVersion() {
         Properties props = new Properties();
 
         String resource = "META-INF/maven/org.apache.maven/maven-core/pom.properties";
 
-        try ( InputStream is = DefaultRuntimeInformation.class.getResourceAsStream( "/" + resource ) )
-        {
-            if ( is != null )
-            {
-                props.load( is );
+        try (InputStream is = DefaultRuntimeInformation.class.getResourceAsStream("/" + resource)) {
+            if (is != null) {
+                props.load(is);
+            } else {
+                logger.warn("Could not locate " + resource + " on classpath, Maven runtime information not available");
             }
-            else
-            {
-                logger.warn(
-                    "Could not locate " + resource + " on classpath, Maven runtime information not available" );
-            }
-        }
-        catch ( IOException e )
-        {
+        } catch (IOException e) {
             String msg = "Could not parse " + resource + ", Maven runtime information not available";
-            if ( logger.isDebugEnabled() )
-            {
-                logger.warn( msg, e );
-            }
-            else
-            {
-                logger.warn( msg );
+            if (logger.isDebugEnabled()) {
+                logger.warn(msg, e);
+            } else {
+                logger.warn(msg);
             }
         }
 
-        String version = props.getProperty( "version", "" ).trim();
+        String version = props.getProperty("version", "").trim();
 
-        if ( !version.startsWith( "${" ) )
-        {
+        if (!version.startsWith("${")) {
             return version;
-        }
-        else
-        {
+        } else {
             return "";
         }
     }
 
     @Override
-    public boolean isMavenVersion( String versionRange )
-    {
-        Validate.notBlank( versionRange, "versionRange can neither be null, empty nor blank" );
+    public boolean isMavenVersion(String versionRange) {
+        if (Objects.requireNonNull(versionRange, "versionRange cannot be null").isEmpty()) {
+            throw new IllegalArgumentException("versionRange cannot be empty");
+        }
 
         VersionConstraint constraint;
-        try
-        {
-            constraint = versionScheme.parseVersionConstraint( versionRange );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
-            throw new IllegalArgumentException( e.getMessage(), e );
+        try {
+            constraint = versionScheme.parseVersionConstraint(versionRange);
+        } catch (InvalidVersionSpecificationException e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
         }
 
         Version current;
-        try
-        {
+        try {
             String mavenVersion = getMavenVersion();
-            Validate.validState( StringUtils.isNotEmpty( mavenVersion ), "Could not determine current Maven version" );
+            if (mavenVersion.isEmpty()) {
+                throw new IllegalArgumentException("Could not determine current Maven version");
+            }
 
-            current = versionScheme.parseVersion( mavenVersion );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
-            throw new IllegalStateException( "Could not parse current Maven version: " + e.getMessage(), e );
+            current = versionScheme.parseVersion(mavenVersion);
+        } catch (InvalidVersionSpecificationException e) {
+            throw new IllegalStateException("Could not parse current Maven version: " + e.getMessage(), e);
         }
 
-        if ( constraint.getRange() == null )
-        {
-            return constraint.getVersion().compareTo( current ) <= 0;
+        if (constraint.getRange() == null) {
+            return constraint.getVersion().compareTo(current) <= 0;
         }
-        return constraint.containsVersion( current );
+        return constraint.containsVersion(current);
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java
index 7bbf477..a29b16f 100644
--- a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java
+++ b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScope.java
@@ -1,5 +1,3 @@
-package org.apache.maven.session.scope.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.session.scope.internal;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import com.google.inject.Key;
 import com.google.inject.OutOfScopeException;
@@ -33,109 +37,137 @@
 /**
  * SessionScope
  */
-public class SessionScope
-    implements Scope
-{
+public class SessionScope implements Scope {
 
-    private static final Provider<Object> SEEDED_KEY_PROVIDER = () ->
-    {
+    private static final Provider<Object> SEEDED_KEY_PROVIDER = () -> {
         throw new IllegalStateException();
     };
 
     /**
      * ScopeState
      */
-    protected static final class ScopeState
-    {
+    protected static final class ScopeState {
         private final Map<Key<?>, CachingProvider<?>> provided = new ConcurrentHashMap<>();
 
-        public <T> void seed( Class<T> clazz, Provider<T> value )
-        {
-            provided.put( Key.get( clazz ), new CachingProvider<>( value ) );
+        public <T> void seed(Class<T> clazz, Provider<T> value) {
+            provided.put(Key.get(clazz), new CachingProvider<>(value));
         }
 
-        @SuppressWarnings( "unchecked" )
-        public <T> Provider<T> scope( Key<T> key, Provider<T> unscoped )
-        {
-            Provider<?> provider = provided.computeIfAbsent( key, k -> new CachingProvider<>( unscoped ) );
-            return ( Provider<T> ) provider;
+        @SuppressWarnings("unchecked")
+        public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
+            Provider<?> provider = provided.computeIfAbsent(key, k -> new CachingProvider<>(unscoped));
+            return (Provider<T>) provider;
         }
 
-        public Collection<CachingProvider<?>> providers()
-        {
+        public Collection<CachingProvider<?>> providers() {
             return provided.values();
         }
     }
 
     private final List<ScopeState> values = new CopyOnWriteArrayList<>();
 
-    public void enter()
-    {
-        values.add( 0, new ScopeState() );
+    public void enter() {
+        values.add(0, new ScopeState());
     }
 
-    protected ScopeState getScopeState()
-    {
-        if ( values.isEmpty() )
-        {
-            throw new OutOfScopeException( "Cannot access session scope outside of a scoping block" );
+    protected ScopeState getScopeState() {
+        if (values.isEmpty()) {
+            throw new OutOfScopeException("Cannot access session scope outside of a scoping block");
         }
-        return values.get( 0 );
+        return values.get(0);
     }
 
-    public void exit()
-    {
-        if ( values.isEmpty() )
-        {
+    public void exit() {
+        if (values.isEmpty()) {
             throw new IllegalStateException();
         }
-        values.remove( 0 );
+        values.remove(0);
     }
 
-    public <T> void seed( Class<T> clazz, Provider<T> value )
-    {
-        getScopeState().seed( clazz, value );
+    public <T> void seed(Class<T> clazz, Provider<T> value) {
+        getScopeState().seed(clazz, value);
     }
 
-    public <T> void seed( Class<T> clazz, final T value )
-    {
-        seed( clazz, ( Provider<T> ) () -> value );
+    public <T> void seed(Class<T> clazz, final T value) {
+        seed(clazz, (Provider<T>) () -> value);
     }
 
-    public <T> Provider<T> scope( final Key<T> key, final Provider<T> unscoped )
-    {
+    public <T> Provider<T> scope(final Key<T> key, final Provider<T> unscoped) {
         // Lazy evaluating provider
-        return () -> getScopeState().scope( key, unscoped ).get();
+        return () -> {
+            if (values.isEmpty()) {
+                return createProxy(key, unscoped);
+            } else {
+                return getScopeState().scope(key, unscoped).get();
+            }
+        };
+    }
+
+    @SuppressWarnings("unchecked")
+    private <T> T createProxy(Key<T> key, Provider<T> unscoped) {
+        InvocationHandler dispatcher = (proxy, method, args) -> {
+            method.setAccessible(true);
+            return method.invoke(getScopeState().scope(key, unscoped).get(), args);
+        };
+        Class<T> superType = (Class<T>) key.getTypeLiteral().getRawType();
+        Class<?>[] interfaces = getInterfaces(superType);
+        return (T) java.lang.reflect.Proxy.newProxyInstance(superType.getClassLoader(), interfaces, dispatcher);
+    }
+
+    private Class<?>[] getInterfaces(Class<?> superType) {
+        if (superType.isInterface()) {
+            return new Class<?>[] {superType};
+        } else {
+            for (Annotation a : superType.getAnnotations()) {
+                Class<? extends Annotation> annotationType = a.annotationType();
+                if ("org.eclipse.sisu.Typed".equals(annotationType.getName())
+                        || "javax.enterprise.inject.Typed".equals(annotationType.getName())
+                        || "jakarta.enterprise.inject.Typed".equals(annotationType.getName())) {
+                    try {
+                        Class<?>[] value =
+                                (Class<?>[]) annotationType.getMethod("value").invoke(a);
+                        if (value.length == 0) {
+                            value = superType.getInterfaces();
+                        }
+                        List<Class<?>> nonInterfaces =
+                                Stream.of(value).filter(c -> !c.isInterface()).collect(Collectors.toList());
+                        if (!nonInterfaces.isEmpty()) {
+                            throw new IllegalArgumentException(
+                                    "The Typed annotation must contain only interfaces but the following types are not: "
+                                            + nonInterfaces);
+                        }
+                        return value;
+                    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+                        throw new IllegalStateException(e);
+                    }
+                }
+            }
+            throw new IllegalArgumentException("The use of session scoped proxies require "
+                    + "a org.eclipse.sisu.Typed or javax.enterprise.inject.Typed annotation");
+        }
     }
 
     /**
      * A provider wrapping an existing provider with a cache
      * @param <T> the provided type
      */
-    protected static class CachingProvider<T> implements Provider<T>
-    {
+    protected static class CachingProvider<T> implements Provider<T> {
         private final Provider<T> provider;
         private volatile T value;
 
-        CachingProvider( Provider<T> provider )
-        {
+        CachingProvider(Provider<T> provider) {
             this.provider = provider;
         }
 
-        public T value()
-        {
+        public T value() {
             return value;
         }
 
         @Override
-        public T get()
-        {
-            if ( value == null )
-            {
-                synchronized ( this )
-                {
-                    if ( value == null )
-                    {
+        public T get() {
+            if (value == null) {
+                synchronized (this) {
+                    if (value == null) {
                         value = provider.get();
                     }
                 }
@@ -144,9 +176,14 @@
         }
     }
 
-    @SuppressWarnings( { "unchecked" } )
-    public static <T> Provider<T> seededKeyProvider()
-    {
+    @SuppressWarnings({"unchecked"})
+    public static <T> Provider<T> seededKeyProvider() {
         return (Provider<T>) SEEDED_KEY_PROVIDER;
     }
+
+    public static <T> Provider<T> seededKeyProvider(Class<? extends T> clazz) {
+        return () -> {
+            throw new IllegalStateException("No instance of " + clazz.getName() + " is bound to the session scope.");
+        };
+    }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java
index b00c588..7325dfc 100644
--- a/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java
+++ b/maven-core/src/main/java/org/apache/maven/session/scope/internal/SessionScopeModule.java
@@ -1,5 +1,3 @@
-package org.apache.maven.session.scope.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,49 +16,53 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.session.scope.internal;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import com.google.inject.AbstractModule;
 import org.apache.maven.SessionScoped;
+import org.apache.maven.api.Session;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.impl.InternalSession;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 
-import com.google.inject.AbstractModule;
-
 /**
  * SessionScopeModule
  */
 @Named
-public class SessionScopeModule
-    extends AbstractModule
-{
+public class SessionScopeModule extends AbstractModule {
     private final SessionScope scope;
 
     @Inject
-    public SessionScopeModule()
-    {
-        this( new SessionScope() );
+    public SessionScopeModule() {
+        this(new SessionScope());
     }
 
-    public SessionScopeModule( PlexusContainer container )
-        throws ComponentLookupException
-    {
-        this( container.lookup( SessionScope.class ) );
+    public SessionScopeModule(PlexusContainer container) throws ComponentLookupException {
+        this(container.lookup(SessionScope.class));
     }
 
-    private SessionScopeModule( SessionScope scope )
-    {
+    private SessionScopeModule(SessionScope scope) {
         this.scope = scope;
     }
 
     @Override
-    protected void configure()
-    {
-        bindScope( SessionScoped.class, scope );
-        bind( SessionScope.class ).toInstance( scope );
+    protected void configure() {
+        bindScope(SessionScoped.class, scope);
+        bindScope(org.apache.maven.api.di.SessionScoped.class, scope);
+        bind(SessionScope.class).toInstance(scope);
 
-        bind( MavenSession.class ).toProvider( SessionScope.seededKeyProvider() ).in( scope );
+        bind(MavenSession.class)
+                .toProvider(SessionScope.seededKeyProvider(MavenSession.class))
+                .in(scope);
+        bind(Session.class)
+                .toProvider(SessionScope.seededKeyProvider(Session.class))
+                .in(scope);
+        bind(InternalSession.class)
+                .toProvider(SessionScope.seededKeyProvider(InternalSession.class))
+                .in(scope);
     }
 }
diff --git a/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java
deleted file mode 100644
index 2f2c407..0000000
--- a/maven-core/src/main/java/org/apache/maven/settings/DefaultMavenSettingsBuilder.java
+++ /dev/null
@@ -1,162 +0,0 @@
-package org.apache.maven.settings;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.io.IOException;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.execution.MavenExecutionRequest;
-import org.apache.maven.properties.internal.SystemProperties;
-import org.apache.maven.settings.building.DefaultSettingsBuildingRequest;
-import org.apache.maven.settings.building.SettingsBuilder;
-import org.apache.maven.settings.building.SettingsBuildingException;
-import org.apache.maven.settings.building.SettingsBuildingRequest;
-import org.codehaus.plexus.logging.AbstractLogEnabled;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * @author jdcasey
- */
-@Named
-@Singleton
-public class DefaultMavenSettingsBuilder
-    extends AbstractLogEnabled
-    implements MavenSettingsBuilder
-{
-
-    private final SettingsBuilder settingsBuilder;
-
-    @Inject
-    public DefaultMavenSettingsBuilder( SettingsBuilder settingsBuilder )
-    {
-        this.settingsBuilder = settingsBuilder;
-    }
-
-    public Settings buildSettings()
-        throws IOException, XmlPullParserException
-    {
-        File userSettingsFile =
-            getFile( "${user.home}/.m2/settings.xml", "user.home",
-                     MavenSettingsBuilder.ALT_USER_SETTINGS_XML_LOCATION );
-
-        return buildSettings( userSettingsFile );
-    }
-
-    public Settings buildSettings( boolean useCachedSettings )
-        throws IOException, XmlPullParserException
-    {
-        return buildSettings();
-    }
-
-    public Settings buildSettings( File userSettingsFile )
-        throws IOException, XmlPullParserException
-    {
-        File globalSettingsFile =
-            getFile( "${maven.conf}/settings.xml", "maven.conf",
-                     MavenSettingsBuilder.ALT_GLOBAL_SETTINGS_XML_LOCATION );
-
-        SettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
-        request.setUserSettingsFile( userSettingsFile );
-        request.setGlobalSettingsFile( globalSettingsFile );
-        request.setSystemProperties( SystemProperties.getSystemProperties() );
-        return build( request );
-    }
-
-    public Settings buildSettings( File userSettingsFile, boolean useCachedSettings )
-        throws IOException, XmlPullParserException
-    {
-        return buildSettings( userSettingsFile );
-    }
-
-    private Settings build( SettingsBuildingRequest request )
-        throws IOException, XmlPullParserException
-    {
-        try
-        {
-            return settingsBuilder.build( request ).getEffectiveSettings();
-        }
-        catch ( SettingsBuildingException e )
-        {
-            throw new IOException( e.getMessage(), e );
-        }
-    }
-
-    /** @since 2.1 */
-    public Settings buildSettings( MavenExecutionRequest request )
-        throws IOException, XmlPullParserException
-    {
-        SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest();
-        settingsRequest.setUserSettingsFile( request.getUserSettingsFile() );
-        settingsRequest.setGlobalSettingsFile( request.getGlobalSettingsFile() );
-        settingsRequest.setUserProperties( request.getUserProperties() );
-        settingsRequest.setSystemProperties( request.getSystemProperties() );
-
-        return build( settingsRequest );
-    }
-
-    private File getFile( String pathPattern, String basedirSysProp, String altLocationSysProp )
-    {
-        // -------------------------------------------------------------------------------------
-        // Alright, here's the justification for all the regexp wizardry below...
-        //
-        // Continuum and other server-like apps may need to locate the user-level and
-        // global-level settings somewhere other than ${user.home} and ${maven.home},
-        // respectively. Using a simple replacement of these patterns will allow them
-        // to specify the absolute path to these files in a customized components.xml
-        // file. Ideally, we'd do full pattern-evaluation against the sysprops, but this
-        // is a first step. There are several replacements below, in order to normalize
-        // the path character before we operate on the string as a regex input, and
-        // in order to avoid surprises with the File construction...
-        // -------------------------------------------------------------------------------------
-
-        String path = System.getProperty( altLocationSysProp );
-
-        if ( StringUtils.isEmpty( path ) )
-        {
-            // TODO This replacing shouldn't be necessary as user.home should be in the
-            // context of the container and thus the value would be interpolated by Plexus
-            String basedir = System.getProperty( basedirSysProp );
-            if ( basedir == null )
-            {
-                basedir = System.getProperty( "user.dir" );
-            }
-
-            basedir = basedir.replaceAll( "\\\\", "/" );
-            basedir = basedir.replaceAll( "\\$", "\\\\\\$" );
-
-            path = pathPattern.replaceAll( "\\$\\{" + basedirSysProp + "\\}", basedir );
-            path = path.replaceAll( "\\\\", "/" );
-            // ---------------------------------------------------------------------------------
-            // I'm not sure if this last regexp was really intended to disallow the usage of
-            // network paths as user.home directory. Unfortunately it did. I removed it and
-            // have not detected any problems yet.
-            // ---------------------------------------------------------------------------------
-            // path = path.replaceAll( "//", "/" );
-
-        }
-        return new File( path ).getAbsoluteFile();
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java b/maven-core/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java
deleted file mode 100644
index c79a843..0000000
--- a/maven-core/src/main/java/org/apache/maven/settings/MavenSettingsBuilder.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.apache.maven.settings;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.maven.execution.MavenExecutionRequest;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * @author jdcasey
- * @author Jason van Zyl
- */
-@Deprecated
-public interface MavenSettingsBuilder
-{
-
-    String ROLE = MavenSettingsBuilder.class.getName();
-
-    String ALT_USER_SETTINGS_XML_LOCATION = "org.apache.maven.user-settings";
-    String ALT_GLOBAL_SETTINGS_XML_LOCATION = "org.apache.maven.global-settings";
-    String ALT_LOCAL_REPOSITORY_LOCATION = "maven.repo.local";
-
-    Settings buildSettings( MavenExecutionRequest request )
-        throws IOException, XmlPullParserException;
-
-    /**
-     * @return a <code>Settings</code> object from the user settings file.
-     * @throws IOException if any
-     * @throws XmlPullParserException if any
-     */
-    Settings buildSettings()
-        throws IOException, XmlPullParserException;
-
-    /**
-     * @param useCachedSettings if true, doesn't reload the user settings
-     * @return a <code>Settings</code> object from the user settings file.
-     * @throws IOException if any
-     * @throws XmlPullParserException if any
-     */
-    Settings buildSettings( boolean useCachedSettings )
-        throws IOException, XmlPullParserException;
-
-    /**
-     * @param userSettingsFile a given user settings file
-     * @return a <code>Settings</code> object from the user settings file.
-     * @throws IOException if any
-     * @throws XmlPullParserException if any
-     */
-    Settings buildSettings( File userSettingsFile )
-        throws IOException, XmlPullParserException;
-
-    /**
-     * @param userSettingsFile a given user settings file
-     * @param useCachedSettings if true, doesn't reload the user settings
-     * @return a <code>Settings</code> object from the user settings file.
-     * @throws IOException if any
-     * @throws XmlPullParserException if any
-     */
-    Settings buildSettings( File userSettingsFile, boolean useCachedSettings )
-        throws IOException, XmlPullParserException;
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/settings/SettingsConfigurationException.java b/maven-core/src/main/java/org/apache/maven/settings/SettingsConfigurationException.java
index 7e03bfc..e0fd1ca 100644
--- a/maven-core/src/main/java/org/apache/maven/settings/SettingsConfigurationException.java
+++ b/maven-core/src/main/java/org/apache/maven/settings/SettingsConfigurationException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,46 +16,40 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings;
 
 /**
  * If there was an error in the settings file.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class SettingsConfigurationException
-    extends Exception
-{
+public class SettingsConfigurationException extends Exception {
     private int lineNumber;
 
     private int columnNumber;
 
-    public SettingsConfigurationException( String message )
-    {
-        super( message );
+    public SettingsConfigurationException(String message) {
+        super(message);
     }
 
-    public SettingsConfigurationException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public SettingsConfigurationException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public SettingsConfigurationException( String message, Throwable cause, int lineNumber, int columnNumber )
-    {
-        super( message + ( lineNumber > 0 ? System.lineSeparator() + "  Line:   " + lineNumber : "" )
-            + ( columnNumber > 0 ? System.lineSeparator() + "  Column: " + columnNumber : "" ), cause );
+    public SettingsConfigurationException(String message, Throwable cause, int lineNumber, int columnNumber) {
+        super(
+                message
+                        + (lineNumber > 0 ? System.lineSeparator() + "  Line:   " + lineNumber : "")
+                        + (columnNumber > 0 ? System.lineSeparator() + "  Column: " + columnNumber : ""),
+                cause);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
 
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
 
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
-
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java
index 8da696e..dc9d04e 100644
--- a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java
+++ b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.model.ActivationFile;
-import org.apache.maven.settings.merge.MavenSettingsMerger;
-
-import java.util.List;
+package org.apache.maven.settings;
 
 /**
  * Several convenience methods to handle settings
  *
- * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
  */
-public final class SettingsUtils
-{
+public final class SettingsUtils {
 
-    private SettingsUtils()
-    {
+    private SettingsUtils() {
         // don't allow construction.
     }
 
@@ -42,279 +33,50 @@
      * @param recessive
      * @param recessiveSourceLevel
      */
-    public static void merge( Settings dominant, Settings recessive, String recessiveSourceLevel )
-    {
-        new MavenSettingsMerger().merge( dominant, recessive, recessiveSourceLevel );
+    public static void merge(Settings dominant, Settings recessive, String recessiveSourceLevel) {
+        if (dominant != null && recessive != null) {
+            dominant.delegate = SettingsUtilsV4.merge(dominant.getDelegate(), recessive.getDelegate());
+        }
     }
 
     /**
      * @param modelProfile
      * @return a profile
      */
-    public static Profile convertToSettingsProfile( org.apache.maven.model.Profile modelProfile )
-    {
-        Profile profile = new Profile();
-
-        profile.setId( modelProfile.getId() );
-
-        org.apache.maven.model.Activation modelActivation = modelProfile.getActivation();
-
-        if ( modelActivation != null )
-        {
-            Activation activation = new Activation();
-
-            activation.setActiveByDefault( modelActivation.isActiveByDefault() );
-
-            activation.setJdk( modelActivation.getJdk() );
-
-            org.apache.maven.model.ActivationProperty modelProp = modelActivation.getProperty();
-
-            if ( modelProp != null )
-            {
-                ActivationProperty prop = new ActivationProperty();
-                prop.setName( modelProp.getName() );
-                prop.setValue( modelProp.getValue() );
-                activation.setProperty( prop );
-            }
-
-            org.apache.maven.model.ActivationOS modelOs = modelActivation.getOs();
-
-            if ( modelOs != null )
-            {
-                ActivationOS os = new ActivationOS();
-
-                os.setArch( modelOs.getArch() );
-                os.setFamily( modelOs.getFamily() );
-                os.setName( modelOs.getName() );
-                os.setVersion( modelOs.getVersion() );
-
-                activation.setOs( os );
-            }
-
-            ActivationFile modelFile = modelActivation.getFile();
-
-            if ( modelFile != null )
-            {
-                org.apache.maven.settings.ActivationFile file = new org.apache.maven.settings.ActivationFile();
-
-                file.setExists( modelFile.getExists() );
-                file.setMissing( modelFile.getMissing() );
-
-                activation.setFile( file );
-            }
-
-            profile.setActivation( activation );
-        }
-
-        profile.setProperties( modelProfile.getProperties() );
-
-        List<org.apache.maven.model.Repository> repos = modelProfile.getRepositories();
-        if ( repos != null )
-        {
-            for ( org.apache.maven.model.Repository repo : repos )
-            {
-                profile.addRepository( convertToSettingsRepository( repo ) );
-            }
-        }
-
-        List<org.apache.maven.model.Repository> pluginRepos = modelProfile.getPluginRepositories();
-        if ( pluginRepos != null )
-        {
-            for ( org.apache.maven.model.Repository pluginRepo : pluginRepos )
-            {
-                profile.addPluginRepository( convertToSettingsRepository( pluginRepo ) );
-            }
-        }
-
-        return profile;
+    public static Profile convertToSettingsProfile(org.apache.maven.model.Profile modelProfile) {
+        return new Profile(SettingsUtilsV4.convertToSettingsProfile(modelProfile.getDelegate()));
     }
 
     /**
      * @param settingsProfile
      * @return a profile
      */
-    public static org.apache.maven.model.Profile convertFromSettingsProfile( Profile settingsProfile )
-    {
-        org.apache.maven.model.Profile profile = new org.apache.maven.model.Profile();
-
-        profile.setId( settingsProfile.getId() );
-
-        profile.setSource( "settings.xml" );
-
-        Activation settingsActivation = settingsProfile.getActivation();
-
-        if ( settingsActivation != null )
-        {
-            org.apache.maven.model.Activation activation = new org.apache.maven.model.Activation();
-
-            activation.setActiveByDefault( settingsActivation.isActiveByDefault() );
-
-            activation.setJdk( settingsActivation.getJdk() );
-
-            ActivationProperty settingsProp = settingsActivation.getProperty();
-
-            if ( settingsProp != null )
-            {
-                org.apache.maven.model.ActivationProperty prop = new org.apache.maven.model.ActivationProperty();
-
-                prop.setName( settingsProp.getName() );
-                prop.setValue( settingsProp.getValue() );
-
-                activation.setProperty( prop );
-            }
-
-            ActivationOS settingsOs = settingsActivation.getOs();
-
-            if ( settingsOs != null )
-            {
-                org.apache.maven.model.ActivationOS os = new org.apache.maven.model.ActivationOS();
-
-                os.setArch( settingsOs.getArch() );
-                os.setFamily( settingsOs.getFamily() );
-                os.setName( settingsOs.getName() );
-                os.setVersion( settingsOs.getVersion() );
-
-                activation.setOs( os );
-            }
-
-            org.apache.maven.settings.ActivationFile settingsFile = settingsActivation.getFile();
-
-            if ( settingsFile != null )
-            {
-                ActivationFile file = new ActivationFile();
-
-                file.setExists( settingsFile.getExists() );
-                file.setMissing( settingsFile.getMissing() );
-
-                activation.setFile( file );
-            }
-
-            profile.setActivation( activation );
-        }
-
-        profile.setProperties( settingsProfile.getProperties() );
-
-        List<Repository> repos = settingsProfile.getRepositories();
-        if ( repos != null )
-        {
-            for ( Repository repo : repos )
-            {
-                profile.addRepository( convertFromSettingsRepository( repo ) );
-            }
-        }
-
-        List<Repository> pluginRepos = settingsProfile.getPluginRepositories();
-        if ( pluginRepos != null )
-        {
-            for ( Repository pluginRepo : pluginRepos )
-            {
-                profile.addPluginRepository( convertFromSettingsRepository( pluginRepo ) );
-            }
-        }
-
-        return profile;
-    }
-
-    /**
-     * @param settingsRepo
-     * @return a repository
-     */
-    private static org.apache.maven.model.Repository convertFromSettingsRepository( Repository settingsRepo )
-    {
-        org.apache.maven.model.Repository repo = new org.apache.maven.model.Repository();
-
-        repo.setId( settingsRepo.getId() );
-        repo.setLayout( settingsRepo.getLayout() );
-        repo.setName( settingsRepo.getName() );
-        repo.setUrl( settingsRepo.getUrl() );
-
-        if ( settingsRepo.getSnapshots() != null )
-        {
-            repo.setSnapshots( convertRepositoryPolicy( settingsRepo.getSnapshots() ) );
-        }
-        if ( settingsRepo.getReleases() != null )
-        {
-            repo.setReleases( convertRepositoryPolicy( settingsRepo.getReleases() ) );
-        }
-
-        return repo;
-    }
-
-    /**
-     * @param settingsPolicy
-     * @return a RepositoryPolicy
-     */
-    private static org.apache.maven.model.RepositoryPolicy convertRepositoryPolicy( RepositoryPolicy settingsPolicy )
-    {
-        org.apache.maven.model.RepositoryPolicy policy = new org.apache.maven.model.RepositoryPolicy();
-        policy.setEnabled( settingsPolicy.isEnabled() );
-        policy.setUpdatePolicy( settingsPolicy.getUpdatePolicy() );
-        policy.setChecksumPolicy( settingsPolicy.getChecksumPolicy() );
-        return policy;
-    }
-
-    /**
-     * @param modelRepo
-     * @return a repository
-     */
-    private static Repository convertToSettingsRepository( org.apache.maven.model.Repository modelRepo )
-    {
-        Repository repo = new Repository();
-
-        repo.setId( modelRepo.getId() );
-        repo.setLayout( modelRepo.getLayout() );
-        repo.setName( modelRepo.getName() );
-        repo.setUrl( modelRepo.getUrl() );
-
-        if ( modelRepo.getSnapshots() != null )
-        {
-            repo.setSnapshots( convertRepositoryPolicy( modelRepo.getSnapshots() ) );
-        }
-        if ( modelRepo.getReleases() != null )
-        {
-            repo.setReleases( convertRepositoryPolicy( modelRepo.getReleases() ) );
-        }
-
-        return repo;
-    }
-
-    /**
-     * @param modelPolicy
-     * @return a RepositoryPolicy
-     */
-    private static RepositoryPolicy convertRepositoryPolicy( org.apache.maven.model.RepositoryPolicy modelPolicy )
-    {
-        RepositoryPolicy policy = new RepositoryPolicy();
-        policy.setEnabled( modelPolicy.isEnabled() );
-        policy.setUpdatePolicy( modelPolicy.getUpdatePolicy() );
-        policy.setChecksumPolicy( modelPolicy.getChecksumPolicy() );
-        return policy;
+    public static org.apache.maven.model.Profile convertFromSettingsProfile(Profile settingsProfile) {
+        return new org.apache.maven.model.Profile(
+                SettingsUtilsV4.convertFromSettingsProfile(settingsProfile.getDelegate()));
     }
 
     /**
      * @param settings could be null
      * @return a new instance of settings or null if settings was null.
      */
-    public static Settings copySettings( Settings settings )
-    {
-        if ( settings == null )
-        {
+    public static Settings copySettings(Settings settings) {
+        if (settings == null) {
             return null;
         }
 
         Settings clone = new Settings();
-        clone.setActiveProfiles( settings.getActiveProfiles() );
-        clone.setInteractiveMode( settings.isInteractiveMode() );
-        clone.setLocalRepository( settings.getLocalRepository() );
-        clone.setMirrors( settings.getMirrors() );
-        clone.setModelEncoding( settings.getModelEncoding() );
-        clone.setOffline( settings.isOffline() );
-        clone.setPluginGroups( settings.getPluginGroups() );
-        clone.setProfiles( settings.getProfiles() );
-        clone.setProxies( settings.getProxies() );
-        clone.setServers( settings.getServers() );
-        clone.setSourceLevel( settings.getSourceLevel() );
-        clone.setUsePluginRegistry( settings.isUsePluginRegistry() );
+        clone.setActiveProfiles(settings.getActiveProfiles());
+        clone.setInteractiveMode(settings.isInteractiveMode());
+        clone.setLocalRepository(settings.getLocalRepository());
+        clone.setMirrors(settings.getMirrors());
+        clone.setOffline(settings.isOffline());
+        clone.setPluginGroups(settings.getPluginGroups());
+        clone.setProfiles(settings.getProfiles());
+        clone.setProxies(settings.getProxies());
+        clone.setServers(settings.getServers());
+        clone.setSourceLevel(settings.getSourceLevel());
+        clone.setUsePluginRegistry(settings.isUsePluginRegistry());
 
         return clone;
     }
diff --git a/maven-core/src/main/java/org/apache/maven/settings/SettingsUtilsV4.java b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtilsV4.java
new file mode 100644
index 0000000..355fb4f
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/settings/SettingsUtilsV4.java
@@ -0,0 +1,336 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.settings;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.model.ActivationFile;
+import org.apache.maven.api.model.InputLocation;
+import org.apache.maven.api.settings.Activation;
+import org.apache.maven.api.settings.ActivationOS;
+import org.apache.maven.api.settings.ActivationProperty;
+import org.apache.maven.api.settings.Profile;
+import org.apache.maven.api.settings.Repository;
+import org.apache.maven.api.settings.RepositoryPolicy;
+import org.apache.maven.api.settings.Settings;
+import org.apache.maven.settings.v4.SettingsMerger;
+
+/**
+ * Several convenience methods to handle settings
+ *
+ */
+public final class SettingsUtilsV4 {
+
+    private SettingsUtilsV4() {
+        // don't allow construction.
+    }
+
+    /**
+     * @param dominant
+     * @param recessive
+     */
+    public static Settings merge(Settings dominant, Settings recessive) {
+        return new SettingsMerger().merge(dominant, recessive, true, Collections.emptyMap());
+    }
+
+    /**
+     * @param modelProfile
+     * @return a profile
+     */
+    public static Profile convertToSettingsProfile(org.apache.maven.api.model.Profile modelProfile) {
+        Profile.Builder profile = Profile.newBuilder();
+
+        profile.id(modelProfile.getId());
+
+        org.apache.maven.api.model.Activation modelActivation = modelProfile.getActivation();
+
+        if (modelActivation != null) {
+            Activation.Builder activation = Activation.newBuilder();
+
+            activation.activeByDefault(modelActivation.isActiveByDefault());
+
+            activation.jdk(modelActivation.getJdk());
+
+            org.apache.maven.api.model.ActivationProperty modelProp = modelActivation.getProperty();
+
+            if (modelProp != null) {
+                ActivationProperty prop = ActivationProperty.newBuilder()
+                        .name(modelProp.getName())
+                        .value(modelProp.getValue())
+                        .build();
+                activation.property(prop);
+            }
+
+            org.apache.maven.api.model.ActivationOS modelOs = modelActivation.getOs();
+
+            if (modelOs != null) {
+                ActivationOS os = ActivationOS.newBuilder()
+                        .arch(modelOs.getArch())
+                        .family(modelOs.getFamily())
+                        .name(modelOs.getName())
+                        .version(modelOs.getVersion())
+                        .build();
+
+                activation.os(os);
+            }
+
+            org.apache.maven.api.model.ActivationFile modelFile = modelActivation.getFile();
+
+            if (modelFile != null) {
+                org.apache.maven.api.settings.ActivationFile file =
+                        org.apache.maven.api.settings.ActivationFile.newBuilder()
+                                .exists(modelFile.getExists())
+                                .missing(modelFile.getMissing())
+                                .build();
+
+                activation.file(file);
+            }
+
+            profile.activation(activation.build());
+        }
+
+        profile.properties(modelProfile.getProperties().entrySet().stream()
+                .collect(Collectors.toMap(
+                        e -> e.getKey().toString(), e -> e.getValue().toString())));
+
+        List<org.apache.maven.api.model.Repository> repos = modelProfile.getRepositories();
+        if (repos != null) {
+            List<Repository> repositories = new ArrayList<>();
+            for (org.apache.maven.api.model.Repository repo : repos) {
+                repositories.add(convertToSettingsRepository(repo));
+            }
+            profile.repositories(repositories);
+        }
+
+        List<org.apache.maven.api.model.Repository> pluginRepos = modelProfile.getPluginRepositories();
+        if (pluginRepos != null) {
+            List<Repository> repositories = new ArrayList<>();
+            for (org.apache.maven.api.model.Repository pluginRepo : pluginRepos) {
+                repositories.add(convertToSettingsRepository(pluginRepo));
+            }
+            profile.pluginRepositories(repositories);
+        }
+
+        return profile.build();
+    }
+
+    /**
+     * @param settingsProfile
+     * @return a profile
+     */
+    public static org.apache.maven.api.model.Profile convertFromSettingsProfile(Profile settingsProfile) {
+        org.apache.maven.api.model.Profile.Builder profile = org.apache.maven.api.model.Profile.newBuilder();
+
+        profile.id(settingsProfile.getId());
+
+        Activation settingsActivation = settingsProfile.getActivation();
+
+        if (settingsActivation != null) {
+            org.apache.maven.api.model.Activation.Builder activation =
+                    org.apache.maven.api.model.Activation.newBuilder();
+
+            activation.activeByDefault(settingsActivation.isActiveByDefault());
+            activation.location("activeByDefault", toLocation(settingsActivation.getLocation("activeByDefault")));
+
+            activation.jdk(settingsActivation.getJdk());
+            activation.location("jdk", toLocation(settingsActivation.getLocation("jdk")));
+
+            ActivationProperty settingsProp = settingsActivation.getProperty();
+            if (settingsProp != null) {
+                activation.property(org.apache.maven.api.model.ActivationProperty.newBuilder()
+                        .name(settingsProp.getName())
+                        .value(settingsProp.getValue())
+                        .location("name", toLocation(settingsProp.getLocation("name")))
+                        .location("value", toLocation(settingsProp.getLocation("value")))
+                        .build());
+            }
+
+            ActivationOS settingsOs = settingsActivation.getOs();
+            if (settingsOs != null) {
+                activation.os(org.apache.maven.api.model.ActivationOS.newBuilder()
+                        .arch(settingsOs.getArch())
+                        .family(settingsOs.getFamily())
+                        .name(settingsOs.getName())
+                        .version(settingsOs.getVersion())
+                        .location("arch", toLocation(settingsOs.getLocation("arch")))
+                        .location("family", toLocation(settingsOs.getLocation("family")))
+                        .location("name", toLocation(settingsOs.getLocation("name")))
+                        .location("version", toLocation(settingsOs.getLocation("version")))
+                        .build());
+            }
+
+            org.apache.maven.api.settings.ActivationFile settingsFile = settingsActivation.getFile();
+            if (settingsFile != null) {
+                activation.file(ActivationFile.newBuilder()
+                        .exists(settingsFile.getExists())
+                        .missing(settingsFile.getMissing())
+                        .location("exists", toLocation(settingsFile.getLocation("exists")))
+                        .location("missing", toLocation(settingsFile.getLocation("missing")))
+                        .build());
+            }
+
+            profile.activation(activation.build());
+        }
+
+        profile.properties(settingsProfile.getProperties());
+        profile.location("properties", toLocation(settingsProfile.getLocation("properties")));
+
+        List<Repository> repos = settingsProfile.getRepositories();
+        if (repos != null) {
+            profile.repositories(repos.stream()
+                    .map(SettingsUtilsV4::convertFromSettingsRepository)
+                    .collect(Collectors.toList()));
+        }
+
+        List<Repository> pluginRepos = settingsProfile.getPluginRepositories();
+        if (pluginRepos != null) {
+            profile.pluginRepositories(pluginRepos.stream()
+                    .map(SettingsUtilsV4::convertFromSettingsRepository)
+                    .collect(Collectors.toList()));
+        }
+
+        org.apache.maven.api.model.Profile value = profile.build();
+        value.setSource("settings.xml");
+        return value;
+    }
+
+    /**
+     * @param settingsRepo
+     * @return a repository
+     */
+    private static org.apache.maven.api.model.Repository convertFromSettingsRepository(Repository settingsRepo) {
+        org.apache.maven.api.model.Repository.Builder repo = org.apache.maven.api.model.Repository.newBuilder();
+
+        repo.id(settingsRepo.getId());
+        repo.layout(settingsRepo.getLayout());
+        repo.name(settingsRepo.getName());
+        repo.url(settingsRepo.getUrl());
+
+        repo.location("id", toLocation(settingsRepo.getLocation("id")));
+        repo.location("layout", toLocation(settingsRepo.getLocation("layout")));
+        repo.location("name", toLocation(settingsRepo.getLocation("name")));
+        repo.location("url", toLocation(settingsRepo.getLocation("url")));
+
+        if (settingsRepo.getSnapshots() != null) {
+            repo.snapshots(convertRepositoryPolicy(settingsRepo.getSnapshots()));
+        }
+        if (settingsRepo.getReleases() != null) {
+            repo.releases(convertRepositoryPolicy(settingsRepo.getReleases()));
+        }
+
+        return repo.build();
+    }
+
+    /**
+     * @param settingsPolicy
+     * @return a RepositoryPolicy
+     */
+    private static org.apache.maven.api.model.RepositoryPolicy convertRepositoryPolicy(
+            RepositoryPolicy settingsPolicy) {
+        org.apache.maven.api.model.RepositoryPolicy policy = org.apache.maven.api.model.RepositoryPolicy.newBuilder()
+                .enabled(Boolean.toString(settingsPolicy.isEnabled()))
+                .updatePolicy(settingsPolicy.getUpdatePolicy())
+                .checksumPolicy(settingsPolicy.getChecksumPolicy())
+                .location("enabled", toLocation(settingsPolicy.getLocation("enabled")))
+                .location("updatePolicy", toLocation(settingsPolicy.getLocation("updatePolicy")))
+                .location("checksumPolicy", toLocation(settingsPolicy.getLocation("checksumPolicy")))
+                .build();
+        return policy;
+    }
+
+    /**
+     * @param modelRepo
+     * @return a repository
+     */
+    private static Repository convertToSettingsRepository(org.apache.maven.api.model.Repository modelRepo) {
+        Repository repo = Repository.newBuilder()
+                .id(modelRepo.getId())
+                .layout(modelRepo.getLayout())
+                .name(modelRepo.getName())
+                .url(modelRepo.getUrl())
+                .snapshots(modelRepo.getSnapshots() != null ? convertRepositoryPolicy(modelRepo.getSnapshots()) : null)
+                .releases(modelRepo.getReleases() != null ? convertRepositoryPolicy(modelRepo.getReleases()) : null)
+                .build();
+
+        return repo;
+    }
+
+    /**
+     * @param modelPolicy
+     * @return a RepositoryPolicy
+     */
+    private static RepositoryPolicy convertRepositoryPolicy(org.apache.maven.api.model.RepositoryPolicy modelPolicy) {
+        RepositoryPolicy policy = RepositoryPolicy.newBuilder()
+                .enabled(modelPolicy.isEnabled())
+                .updatePolicy(modelPolicy.getUpdatePolicy())
+                .checksumPolicy(modelPolicy.getChecksumPolicy())
+                .build();
+        return policy;
+    }
+
+    /**
+     * @param settings could be null
+     * @return a new instance of settings or null if settings was null.
+     */
+    public static org.apache.maven.settings.Settings copySettings(org.apache.maven.settings.Settings settings) {
+        if (settings == null) {
+            return null;
+        }
+        return new org.apache.maven.settings.Settings(settings.getDelegate());
+    }
+
+    private static org.apache.maven.api.model.InputLocation toLocation(
+            org.apache.maven.api.settings.InputLocation location) {
+        if (location != null) {
+            org.apache.maven.api.settings.InputSource source = location.getSource();
+            Map<Object, InputLocation> locs = location.getLocations().entrySet().stream()
+                    .collect(Collectors.toMap(Map.Entry::getKey, e -> toLocation(e.getValue())));
+            return new org.apache.maven.api.model.InputLocation(
+                    location.getLineNumber(),
+                    location.getColumnNumber(),
+                    source != null ? new org.apache.maven.api.model.InputSource("", source.getLocation()) : null,
+                    locs);
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchain.java b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchain.java
index 8b44552..96789c4 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchain.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchain.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,12 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Properties;
 import java.util.Objects;
+import java.util.Properties;
 
 import org.apache.maven.toolchain.model.ToolchainModel;
 import org.slf4j.Logger;
@@ -32,19 +31,17 @@
  * Default abstract toolchain implementation, to be used as base class for any toolchain implementation
  * to avoid rewriting usual code.
  *
- * @author mkleint
  * @since 2.0.9
  */
 public abstract class DefaultToolchain // should have been AbstractToolchain...
-    implements Toolchain, ToolchainPrivate
-{
+implements Toolchain, ToolchainPrivate {
     private final Logger logger;
 
     private String type;
 
     private Map<String, RequirementMatcher> provides = new HashMap<>();
 
-    public static final String KEY_TYPE = "type"; //NOI18N
+    public static final String KEY_TYPE = "type"; // NOI18N
 
     private ToolchainModel model;
 
@@ -53,8 +50,7 @@
      * @param model the model, must not be {@code null}
      * @param logger the logger, must not be {@code null}
      */
-    protected DefaultToolchain( ToolchainModel model, Logger logger )
-    {
+    protected DefaultToolchain(ToolchainModel model, Logger logger) {
         this.model = model;
         this.logger = logger;
     }
@@ -65,119 +61,101 @@
      * @param type the type
      * @param logger the logger, must not be {@code null}
      */
-    protected DefaultToolchain( ToolchainModel model, String type, Logger logger )
-    {
-        this( model, logger );
+    protected DefaultToolchain(ToolchainModel model, String type, Logger logger) {
+        this(model, logger);
         this.type = type;
     }
 
     @Override
-    public final String getType()
-    {
+    public final String getType() {
         return type != null ? type : model.getType();
     }
 
     @Override
-    public final ToolchainModel getModel()
-    {
+    public final ToolchainModel getModel() {
         return model;
     }
 
-    public final void addProvideToken( String type, RequirementMatcher matcher )
-    {
-        provides.put( type, matcher );
+    public final void addProvideToken(String type, RequirementMatcher matcher) {
+        provides.put(type, matcher);
     }
 
     @Override
-    public boolean matchesRequirements( Map<String, String> requirements )
-    {
-        for ( Map.Entry<String, String> requirement : requirements.entrySet() )
-        {
+    public boolean matchesRequirements(Map<String, String> requirements) {
+        for (Map.Entry<String, String> requirement : requirements.entrySet()) {
             String key = requirement.getKey();
 
-            RequirementMatcher matcher = provides.get( key );
+            RequirementMatcher matcher = provides.get(key);
 
-            if ( matcher == null )
-            {
-                getLog().debug( "Toolchain " + this + " is missing required property: " + key );
+            if (matcher == null) {
+                getLog().debug("Toolchain {} is missing required property: {}", this, key);
                 return false;
             }
-            if ( !matcher.matches( requirement.getValue() ) )
-            {
-                getLog().debug( "Toolchain " + this + " doesn't match required property: " + key );
+            if (!matcher.matches(requirement.getValue())) {
+                getLog().debug("Toolchain {} doesn't match required property: {}", this, key);
                 return false;
             }
         }
         return true;
     }
 
-    protected Logger getLog()
-    {
+    protected Logger getLog() {
         return logger;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( obj == null )
-        {
+    public boolean equals(Object obj) {
+        if (obj == null) {
             return false;
         }
 
-        if ( this == obj )
-        {
+        if (this == obj) {
             return true;
         }
 
-        if ( !( obj instanceof DefaultToolchain ) )
-        {
+        if (!(obj instanceof DefaultToolchain)) {
             return false;
         }
 
         DefaultToolchain other = (DefaultToolchain) obj;
 
-        if ( !Objects.equals( type, other.type ) )
-        {
+        if (!Objects.equals(type, other.type)) {
             return false;
         }
 
         Properties thisProvides = this.getModel().getProvides();
         Properties otherProvides = other.getModel().getProvides();
 
-        return Objects.equals( thisProvides, otherProvides );
+        return Objects.equals(thisProvides, otherProvides);
     }
 
     @Override
-    public int hashCode()
-    {
-        int hashCode = ( type == null ) ? 0 : type.hashCode();
+    public int hashCode() {
+        int hashCode = (type == null) ? 0 : type.hashCode();
 
-        if ( this.getModel().getProvides() != null )
-        {
+        if (this.getModel().getProvides() != null) {
             hashCode = 31 * hashCode + this.getModel().getProvides().hashCode();
         }
         return hashCode;
     }
 
     @Override
-    public String toString()
-    {
+    public String toString() {
         StringBuilder builder = new StringBuilder();
-        builder.append( "type:" ).append( getType() );
-        builder.append( '{' );
+        builder.append("type:").append(getType());
+        builder.append('{');
 
-        Iterator<Map.Entry<String, RequirementMatcher>> providesIter = provides.entrySet().iterator();
-        while ( providesIter.hasNext() )
-        {
+        Iterator<Map.Entry<String, RequirementMatcher>> providesIter =
+                provides.entrySet().iterator();
+        while (providesIter.hasNext()) {
             Map.Entry<String, RequirementMatcher> provideEntry = providesIter.next();
-            builder.append( provideEntry.getKey() ).append( " = " ).append( provideEntry.getValue() );
-            if ( providesIter.hasNext() )
-            {
-                builder.append( ';' );
+            builder.append(provideEntry.getKey()).append(" = ").append(provideEntry.getValue());
+            if (providesIter.hasNext()) {
+                builder.append(';');
             }
         }
 
-        builder.append( '}' );
+        builder.append('}');
 
         return builder.toString();
     }
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManager.java b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManager.java
index 74cb9c6..4cdc6f3 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManager.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -25,10 +28,6 @@
 import java.util.List;
 import java.util.Map;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.project.MavenProject;
@@ -39,47 +38,39 @@
 import static java.util.Objects.requireNonNull;
 
 /**
- * @author mkleint
  */
 @Named
 @Singleton
-public class DefaultToolchainManager
-    implements ToolchainManager
-{
+public class DefaultToolchainManager implements ToolchainManager {
     protected final Logger logger; // TODO this class is extended, needs refactoring
 
     final Map<String, ToolchainFactory> factories;
 
     @Inject
-    public DefaultToolchainManager( Map<String, ToolchainFactory> factories )
-    {
+    public DefaultToolchainManager(Map<String, ToolchainFactory> factories) {
         this.factories = factories;
-        this.logger = LoggerFactory.getLogger( DefaultToolchainManager.class );
+        this.logger = LoggerFactory.getLogger(DefaultToolchainManager.class);
     }
 
     /**
      * Ctor needed for UT.
      */
-    DefaultToolchainManager( Map<String, ToolchainFactory> factories, Logger logger )
-    {
+    DefaultToolchainManager(Map<String, ToolchainFactory> factories, Logger logger) {
         this.factories = factories;
-        this.logger = requireNonNull( logger );
+        this.logger = requireNonNull(logger);
     }
 
     @Override
-    public Toolchain getToolchainFromBuildContext( String type, MavenSession session )
-    {
-        Map<String, Object> context = retrieveContext( session );
+    public Toolchain getToolchainFromBuildContext(String type, MavenSession session) {
+        Map<String, Object> context = retrieveContext(session);
 
-        ToolchainModel model = (ToolchainModel) context.get( getStorageKey( type ) );
+        ToolchainModel model = (ToolchainModel) context.get(getStorageKey(type));
 
-        if ( model != null )
-        {
-            List<Toolchain> toolchains = selectToolchains( Collections.singletonList( model ), type, null );
+        if (model != null) {
+            List<Toolchain> toolchains = selectToolchains(Collections.singletonList(model), type, null);
 
-            if ( !toolchains.isEmpty() )
-            {
-                return toolchains.get( 0 );
+            if (!toolchains.isEmpty()) {
+                return toolchains.get(0);
             }
         }
 
@@ -87,42 +78,31 @@
     }
 
     @Override
-    public List<Toolchain> getToolchains( MavenSession session, String type, Map<String, String> requirements )
-    {
-        List<ToolchainModel> models = session.getRequest().getToolchains().get( type );
+    public List<Toolchain> getToolchains(MavenSession session, String type, Map<String, String> requirements) {
+        List<ToolchainModel> models = session.getRequest().getToolchains().get(type);
 
-        return selectToolchains( models, type, requirements );
+        return selectToolchains(models, type, requirements);
     }
 
-    private List<Toolchain> selectToolchains( List<ToolchainModel> models, String type,
-                                              Map<String, String> requirements )
-    {
+    private List<Toolchain> selectToolchains(
+            List<ToolchainModel> models, String type, Map<String, String> requirements) {
         List<Toolchain> toolchains = new ArrayList<>();
 
-        if ( models != null )
-        {
-            ToolchainFactory fact = factories.get( type );
+        if (models != null) {
+            ToolchainFactory fact = factories.get(type);
 
-            if ( fact == null )
-            {
-                logger.error( "Missing toolchain factory for type: " + type
-                    + ". Possibly caused by misconfigured project." );
-            }
-            else
-            {
-                for ( ToolchainModel model : models )
-                {
-                    try
-                    {
-                        ToolchainPrivate toolchain = fact.createToolchain( model );
-                        if ( requirements == null || toolchain.matchesRequirements( requirements ) )
-                        {
-                            toolchains.add( toolchain );
+            if (fact == null) {
+                logger.error(
+                        "Missing toolchain factory for type: " + type + ". Possibly caused by misconfigured project.");
+            } else {
+                for (ToolchainModel model : models) {
+                    try {
+                        ToolchainPrivate toolchain = fact.createToolchain(model);
+                        if (requirements == null || toolchain.matchesRequirements(requirements)) {
+                            toolchains.add(toolchain);
                         }
-                    }
-                    catch ( MisconfiguredToolchainException ex )
-                    {
-                        logger.error( "Misconfigured toolchain.", ex );
+                    } catch (MisconfiguredToolchainException ex) {
+                        logger.error("Misconfigured toolchain.", ex);
                     }
                 }
             }
@@ -130,31 +110,26 @@
         return toolchains;
     }
 
-    Map<String, Object> retrieveContext( MavenSession session )
-    {
+    Map<String, Object> retrieveContext(MavenSession session) {
         Map<String, Object> context = null;
 
-        if ( session != null )
-        {
+        if (session != null) {
             PluginDescriptor desc = new PluginDescriptor();
-            desc.setGroupId( PluginDescriptor.getDefaultPluginGroupId() );
-            desc.setArtifactId( PluginDescriptor.getDefaultPluginArtifactId( "toolchains" ) );
+            desc.setGroupId(PluginDescriptor.getDefaultPluginGroupId());
+            desc.setArtifactId(PluginDescriptor.getDefaultPluginArtifactId("toolchains"));
 
             MavenProject current = session.getCurrentProject();
 
-            if ( current != null )
-            {
-                //TODO why is this using the context
-                context = session.getPluginContext( desc, current );
+            if (current != null) {
+                // TODO why is this using the context
+                context = session.getPluginContext(desc, current);
             }
         }
 
-        return ( context != null ) ? context : new HashMap<>();
+        return (context != null) ? context : new HashMap<>();
     }
 
-    public static final String getStorageKey( String type )
-    {
+    public static final String getStorageKey(String type) {
         return "toolchain-" + type; // NOI18N
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java
index 8a90f18..c5e8cf6 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivate.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,85 +16,73 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
+package org.apache.maven.toolchain;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.toolchain.ToolchainModel;
 import org.apache.maven.execution.MavenSession;
-import org.apache.maven.toolchain.model.ToolchainModel;
 import org.slf4j.Logger;
 
 /**
  * TODO: refactor this, component extending component is bad practice.
  *
- * @author mkleint
- * @author Robert Scholte
  */
 @Named
 @Singleton
-public class DefaultToolchainManagerPrivate
-    extends DefaultToolchainManager
-    implements ToolchainManagerPrivate
-{
+public class DefaultToolchainManagerPrivate extends DefaultToolchainManager implements ToolchainManagerPrivate {
     @Inject
-    public DefaultToolchainManagerPrivate( Map<String, ToolchainFactory> factories )
-    {
-        super( factories );
+    public DefaultToolchainManagerPrivate(Map<String, ToolchainFactory> factories) {
+        super(factories);
     }
 
     /**
      * Ctor needed for UT.
      */
-    DefaultToolchainManagerPrivate( Map<String, ToolchainFactory> factories, Logger logger )
-    {
-        super( factories, logger );
+    DefaultToolchainManagerPrivate(Map<String, ToolchainFactory> factories, Logger logger) {
+        super(factories, logger);
     }
 
     @Override
-    public ToolchainPrivate[] getToolchainsForType( String type, MavenSession context )
-        throws MisconfiguredToolchainException
-    {
+    public ToolchainPrivate[] getToolchainsForType(String type, MavenSession session)
+            throws MisconfiguredToolchainException {
         List<ToolchainPrivate> toRet = new ArrayList<>();
 
-        ToolchainFactory fact = factories.get( type );
-        if ( fact == null )
-        {
-            logger.error( "Missing toolchain factory for type: " + type
-                + ". Possibly caused by misconfigured project." );
-        }
-        else
-        {
-            List<ToolchainModel> availableToolchains = context.getRequest().getToolchains().get( type );
+        ToolchainFactory fact = factories.get(type);
+        if (fact == null) {
+            logger.error("Missing toolchain factory for type: " + type + ". Possibly caused by misconfigured project.");
+        } else {
+            List<ToolchainModel> availableToolchains =
+                    org.apache.maven.toolchain.model.ToolchainModel.toolchainModelToApiV4(
+                            session.getRequest().getToolchains().get(type));
 
-            if ( availableToolchains != null )
-            {
-                for ( ToolchainModel toolchainModel : availableToolchains )
-                {
-                    toRet.add( fact.createToolchain( toolchainModel ) );
+            if (availableToolchains != null) {
+                for (ToolchainModel toolchainModel : availableToolchains) {
+                    org.apache.maven.toolchain.model.ToolchainModel tm =
+                            new org.apache.maven.toolchain.model.ToolchainModel(toolchainModel);
+                    toRet.add(fact.createToolchain(tm));
                 }
             }
 
             // add default toolchain
             ToolchainPrivate tool = fact.createDefaultToolchain();
-            if ( tool != null )
-            {
-                toRet.add( tool );
+            if (tool != null) {
+                toRet.add(tool);
             }
         }
 
-        return toRet.toArray( new ToolchainPrivate[0] );
+        return toRet.toArray(new ToolchainPrivate[0]);
     }
 
     @Override
-    public void storeToolchainToBuildContext( ToolchainPrivate toolchain, MavenSession session )
-    {
-        Map<String, Object> context = retrieveContext( session );
-        context.put( getStorageKey( toolchain.getType() ), toolchain.getModel() );
+    public void storeToolchainToBuildContext(ToolchainPrivate toolchain, MavenSession session) {
+        Map<String, Object> context = retrieveContext(session);
+        context.put(getStorageKey(toolchain.getType()), toolchain.getModel());
     }
-
 }
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java b/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java
deleted file mode 100644
index 84a31e4..0000000
--- a/maven-core/src/main/java/org/apache/maven/toolchain/DefaultToolchainsBuilder.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package org.apache.maven.toolchain;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.toolchain.model.PersistedToolchains;
-import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.Reader;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-/**
- * @author Benjamin Bentmann
- * @deprecated instead use {@link org.apache.maven.toolchain.building.DefaultToolchainsBuilder}
- */
-@Deprecated
-@Named( "default" )
-@Singleton
-public class DefaultToolchainsBuilder
-    implements ToolchainsBuilder
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
-
-    public PersistedToolchains build( File userToolchainsFile )
-        throws MisconfiguredToolchainException
-    {
-        PersistedToolchains toolchains = null;
-
-        if ( userToolchainsFile != null && userToolchainsFile.isFile() )
-        {
-            try ( Reader in = ReaderFactory.newXmlReader( userToolchainsFile ) )
-            {
-                toolchains = new MavenToolchainsXpp3Reader().read( in );
-            }
-            catch ( Exception e )
-            {
-                throw new MisconfiguredToolchainException(
-                    "Cannot read toolchains file at " + userToolchainsFile.getAbsolutePath(), e );
-            }
-
-        }
-        else if ( userToolchainsFile != null )
-        {
-            logger.debug( "Toolchains configuration was not found at " + userToolchainsFile );
-        }
-
-        return toolchains;
-    }
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/MisconfiguredToolchainException.java b/maven-core/src/main/java/org/apache/maven/toolchain/MisconfiguredToolchainException.java
index 140bc80..1cffaf9 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/MisconfiguredToolchainException.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/MisconfiguredToolchainException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 /**
  *
- * @author mkleint
  */
-public class MisconfiguredToolchainException
-    extends Exception
-{
+public class MisconfiguredToolchainException extends Exception {
 
-    public MisconfiguredToolchainException( String message )
-    {
-        super( message );
+    public MisconfiguredToolchainException(String message) {
+        super(message);
     }
 
-    public MisconfiguredToolchainException( String message, Throwable orig )
-    {
-        super( message, orig );
+    public MisconfiguredToolchainException(String message, Throwable orig) {
+        super(message, orig);
     }
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcher.java b/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcher.java
index 26390e4..131a91a 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcher.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcher.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 /**
  *
- * @author mkleint
  */
-public interface RequirementMatcher
-{
+public interface RequirementMatcher {
 
-    boolean matches( String requirement );
-}
\ No newline at end of file
+    boolean matches(String requirement);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcherFactory.java b/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcherFactory.java
index 02f5cc0..228aed2 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcherFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/RequirementMatcherFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
@@ -25,85 +24,61 @@
 
 /**
  *
- * @author mkleint
  */
-public final class RequirementMatcherFactory
-{
-    private RequirementMatcherFactory()
-    {
+public final class RequirementMatcherFactory {
+    private RequirementMatcherFactory() {}
+
+    public static RequirementMatcher createExactMatcher(String provideValue) {
+        return new ExactMatcher(provideValue);
     }
 
-    public static RequirementMatcher createExactMatcher( String provideValue )
-    {
-        return new ExactMatcher( provideValue );
+    public static RequirementMatcher createVersionMatcher(String provideValue) {
+        return new VersionMatcher(provideValue);
     }
 
-    public static RequirementMatcher createVersionMatcher( String provideValue )
-    {
-        return new VersionMatcher( provideValue );
-    }
-
-    private static final class ExactMatcher
-        implements RequirementMatcher
-    {
+    private static final class ExactMatcher implements RequirementMatcher {
 
         private String provides;
 
-        private ExactMatcher( String provides )
-        {
+        private ExactMatcher(String provides) {
             this.provides = provides;
         }
 
         @Override
-        public boolean matches( String requirement )
-        {
-            return provides.equalsIgnoreCase( requirement );
+        public boolean matches(String requirement) {
+            return provides.equalsIgnoreCase(requirement);
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return provides;
         }
     }
 
-    private static final class VersionMatcher
-        implements RequirementMatcher
-    {
+    private static final class VersionMatcher implements RequirementMatcher {
         DefaultArtifactVersion version;
 
-        private VersionMatcher( String version )
-        {
-            this.version = new DefaultArtifactVersion( version );
+        private VersionMatcher(String version) {
+            this.version = new DefaultArtifactVersion(version);
         }
 
         @Override
-        public boolean matches( String requirement )
-        {
-            try
-            {
-                VersionRange range = VersionRange.createFromVersionSpec( requirement );
-                if ( range.hasRestrictions() )
-                {
-                    return range.containsVersion( version );
+        public boolean matches(String requirement) {
+            try {
+                VersionRange range = VersionRange.createFromVersionSpec(requirement);
+                if (range.hasRestrictions()) {
+                    return range.containsVersion(version);
+                } else {
+                    return range.getRecommendedVersion().compareTo(version) == 0;
                 }
-                else
-                {
-                    return range.getRecommendedVersion().compareTo( version ) == 0;
-                }
-            }
-            catch ( InvalidVersionSpecificationException ex )
-            {
-                //TODO error reporting
-                ex.printStackTrace();
+            } catch (InvalidVersionSpecificationException ex) {
                 return false;
             }
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return version.toString();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/Toolchain.java b/maven-core/src/main/java/org/apache/maven/toolchain/Toolchain.java
index 2a71346..13a6135 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/Toolchain.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/Toolchain.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 /**
  * Toolchain interface.
  *
- * @author Milos Kleint
- * @author Jason van Zyl
  * @since 2.0.9
  */
-public interface Toolchain
-{
+public interface Toolchain {
 
     /**
      * get the type of toolchain.
@@ -42,5 +38,5 @@
      * @param toolName the tool platform independent tool name.
      * @return file representing the tool executable, or null if the tool can not be found
      */
-    String findTool( String toolName );
-}
\ No newline at end of file
+    String findTool(String toolName);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainFactory.java b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainFactory.java
index 115eede..ab5c73a 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 import org.apache.maven.toolchain.model.ToolchainModel;
 
 /**
  * Internal toolchain factory, to prepare toolchains instances.
  *
- * @author mkleint
  * @since 2.0.9
  */
-public interface ToolchainFactory
-{
+public interface ToolchainFactory {
     /**
      * Create instance of toolchain.
      **/
-    ToolchainPrivate createToolchain( ToolchainModel model )
-        throws MisconfiguredToolchainException;
+    ToolchainPrivate createToolchain(ToolchainModel model) throws MisconfiguredToolchainException;
 
     /**
      * Returns the default instance of the particular type of toolchain, can return <code>null</code>
@@ -41,4 +37,4 @@
      * TODO keep around??
      **/
     ToolchainPrivate createDefaultToolchain();
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManager.java b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManager.java
index 134c24d..61a81f6 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManager.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,22 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 import java.util.List;
 import java.util.Map;
 
 import org.apache.maven.execution.MavenSession;
 
-
 /**
  * Public API for a toolchain-aware plugin to get expected toolchain instance.
  *
- * @author mkleint
- * @author Robert Scholte
  * @since 2.0.9
  */
-public interface ToolchainManager
-{
+public interface ToolchainManager {
 
     // NOTE: Some plugins like Surefire access this field directly!
     @Deprecated
@@ -48,7 +43,7 @@
      * @param context the Maven session, must not be {@code null}
      * @return the toolchain selected by <code>maven-toolchains-plugin</code>
      */
-    Toolchain getToolchainFromBuildContext( String type, MavenSession context );
+    Toolchain getToolchainFromBuildContext(String type, MavenSession context);
 
     /**
      * Select all toolchains available in user settings matching the type and requirements,
@@ -60,5 +55,5 @@
      * @return the matching toolchains, never {@code null}
      * @since 3.3.0
      */
-    List<Toolchain> getToolchains( MavenSession session, String type, Map<String, String> requirements );
+    List<Toolchain> getToolchains(MavenSession session, String type, Map<String, String> requirements);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManagerPrivate.java b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManagerPrivate.java
index ed50bd4..989f5a4 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManagerPrivate.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainManagerPrivate.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 import org.apache.maven.execution.MavenSession;
 
@@ -28,12 +27,10 @@
  * <li>to store chosen toolchain into build context for later use by toolchain-aware plugins.</li>
  * </ol>
  *
- * @author mkleint
  * @since 2.0.9
  * @see ToolchainManager#getToolchainFromBuildContext(String, MavenSession)
  */
-public interface ToolchainManagerPrivate
-{
+public interface ToolchainManagerPrivate {
 
     /**
      * Retrieves every toolchains of given type available in user settings.
@@ -42,8 +39,7 @@
      * @param context the Maven session, must not be {@code null}
      * @since 3.0 (addition of the <code>MavenSession</code> parameter)
      */
-    ToolchainPrivate[] getToolchainsForType( String type, MavenSession context )
-        throws MisconfiguredToolchainException;
+    ToolchainPrivate[] getToolchainsForType(String type, MavenSession context) throws MisconfiguredToolchainException;
 
     /**
      * Stores the toolchain into build context for later use by toolchain-aware plugins.
@@ -53,6 +49,5 @@
      * @since 2.0.9
      * @see ToolchainManager#getToolchainFromBuildContext(String, MavenSession)
      */
-    void storeToolchainToBuildContext( ToolchainPrivate toolchain, MavenSession context );
-
+    void storeToolchainToBuildContext(ToolchainPrivate toolchain, MavenSession context);
 }
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainPrivate.java b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainPrivate.java
index 90e0f30..b52a571 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainPrivate.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainPrivate.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain;
 
 import java.util.Map;
 
@@ -25,11 +24,8 @@
 
 /**
  * a private contract between the toolchains plugin and the components.
- * @author mkleint
  */
-public interface ToolchainPrivate
-    extends Toolchain
-{
+public interface ToolchainPrivate extends Toolchain {
 
     /**
      * Let the toolchain decide if it matches requirements defined
@@ -37,12 +33,11 @@
      * @param requirements Map&lt;String, String&gt; key value pair, may not be {@code null}
      * @return {@code true} if the requirements match, otherwise {@code false}
      */
-    boolean matchesRequirements( Map<String, String> requirements );
+    boolean matchesRequirements(Map<String, String> requirements);
 
     /**
      *
      * @return the original model wrapped by this interface
      */
     ToolchainModel getModel();
-
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainsBuilder.java b/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainsBuilder.java
deleted file mode 100644
index 4bb4052..0000000
--- a/maven-core/src/main/java/org/apache/maven/toolchain/ToolchainsBuilder.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.apache.maven.toolchain;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-
-import org.apache.maven.toolchain.model.PersistedToolchains;
-
-/**
- * Builds the toolchains model from a previously configured filesystem path to the toolchains file.
- * <strong>Note:</strong> This is an internal component whose interface can change without prior notice.
- *
- * @author Benjamin Bentmann
- */
-public interface ToolchainsBuilder
-{
-
-    /**
-     * Builds the toolchains model from the configured toolchain files.
-     *
-     * @param userToolchainsFile The path to the toolchains file, may be <code>null</code> to disable parsing.
-     * @return The toolchains model or <code>null</code> if no toolchain file was configured or the configured file does
-     *         not exist.
-     * @throws MisconfiguredToolchainException If the toolchain file exists but cannot be parsed.
-     */
-    PersistedToolchains build( File userToolchainsFile )
-        throws MisconfiguredToolchainException;
-
-}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/java/DefaultJavaToolChain.java b/maven-core/src/main/java/org/apache/maven/toolchain/java/DefaultJavaToolChain.java
index e264e60..0434bc0 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/java/DefaultJavaToolChain.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/java/DefaultJavaToolChain.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.java;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.java;
 
 import org.apache.maven.toolchain.model.ToolchainModel;
 import org.slf4j.Logger;
@@ -30,26 +29,21 @@
  * @deprecated clients that do not require compatibility with Maven 3.2.3 and earlier should link to
  *             {@link JavaToolchainImpl} instead.
  */
-public class DefaultJavaToolChain
-    extends JavaToolchainImpl
-{
+@Deprecated
+public class DefaultJavaToolChain extends JavaToolchainImpl {
     public static final String KEY_JAVAHOME = JavaToolchainImpl.KEY_JAVAHOME;
 
-    public DefaultJavaToolChain( ToolchainModel model, Logger logger )
-    {
-        super( model, logger );
+    public DefaultJavaToolChain(ToolchainModel model, Logger logger) {
+        super(model, logger);
     }
 
     @Override
-    public String getJavaHome()
-    {
+    public String getJavaHome() {
         return super.getJavaHome();
     }
 
     @Override
-    public void setJavaHome( String javaHome )
-    {
-        super.setJavaHome( javaHome );
+    public void setJavaHome(String javaHome) {
+        super.setJavaHome(javaHome);
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java b/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java
index cb14ada..0979221 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchain.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.java;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,50 +16,47 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.java;
 
 import org.apache.maven.toolchain.Toolchain;
 
 /**
  * JDK toolchain interface.
  *
- * @author Jason van Zyl
- * @author Milos Kleint
  * @since 2.0.9, renamed from JavaToolChain in 3.2.4
  */
-public interface JavaToolchain
-    extends Toolchain
-{
-//    /**
-//     * Returns a list of {@link java.io.File}s which represents the bootstrap libraries for the
-//     * runtime environment. The Bootstrap libraries include libraries in JRE's
-//     * extension directory, if there are any.
-//     *
-//     * @return List
-//     */
-//    List getBootstrapLibraries();
-//
-//    /**
-//     * Returns a list of {@link java.io.File}s which represent the libraries recognized by
-//     * default by the platform. Usually it corresponds to contents of CLASSPATH
-//     * environment variable.
-//     *
-//     * @return List
-//     */
-//    List getStandardLibraries();
-//
-//    /**
-//     * Returns a {@link java.io.File}s which represent the locations of the source of the JDK,
-//     * or an empty collection when the location is not set or is invalid.
-//     *
-//     * @return List
-//     */
-//    List getSourceDirectories();
-//
-//    /**
-//     * Returns a {@link java.io.File}s which represent the locations of the Javadoc for this platform,
-//     * or empty collection if the location is not set or invalid
-//     *
-//     * @return List
-//     */
-//    List getJavadocFolders();
+public interface JavaToolchain extends Toolchain {
+    //    /**
+    //     * Returns a list of {@link java.io.File}s which represents the bootstrap libraries for the
+    //     * runtime environment. The Bootstrap libraries include libraries in JRE's
+    //     * extension directory, if there are any.
+    //     *
+    //     * @return List
+    //     */
+    //    List getBootstrapLibraries();
+    //
+    //    /**
+    //     * Returns a list of {@link java.io.File}s which represent the libraries recognized by
+    //     * default by the platform. Usually it corresponds to contents of CLASSPATH
+    //     * environment variable.
+    //     *
+    //     * @return List
+    //     */
+    //    List getStandardLibraries();
+    //
+    //    /**
+    //     * Returns a {@link java.io.File}s which represent the locations of the source of the JDK,
+    //     * or an empty collection when the location is not set or is invalid.
+    //     *
+    //     * @return List
+    //     */
+    //    List getSourceDirectories();
+    //
+    //    /**
+    //     * Returns a {@link java.io.File}s which represent the locations of the Javadoc for this platform,
+    //     * or empty collection if the location is not set or invalid
+    //     *
+    //     * @return List
+    //     */
+    //    List getJavadocDirectories();
 }
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java b/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java
index 71d0a02..e9ddf15 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.java;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,21 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.util.Map.Entry;
-import java.util.Properties;
+package org.apache.maven.toolchain.java;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Map.Entry;
+import java.util.Properties;
+
 import org.apache.maven.toolchain.MisconfiguredToolchainException;
 import org.apache.maven.toolchain.RequirementMatcher;
 import org.apache.maven.toolchain.RequirementMatcherFactory;
 import org.apache.maven.toolchain.ToolchainFactory;
 import org.apache.maven.toolchain.ToolchainPrivate;
 import org.apache.maven.toolchain.model.ToolchainModel;
-import org.codehaus.plexus.util.FileUtils;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,87 +42,69 @@
  * This is a <code>ToolchainFactory</code> Plexus component registered with
  * <code>jdk</code> hint.
  *
- * @author mkleint
  * @since 2.0.9, renamed from <code>DefaultJavaToolchainFactory</code> in 3.2.4
  */
-@Named( "jdk" )
+@Named("jdk")
 @Singleton
-public class JavaToolchainFactory
-    implements ToolchainFactory
-{
-    private final Logger logger = LoggerFactory.getLogger( getClass() );
+public class JavaToolchainFactory implements ToolchainFactory {
+    private final Logger logger = LoggerFactory.getLogger(getClass());
 
-    public ToolchainPrivate createToolchain( ToolchainModel model )
-        throws MisconfiguredToolchainException
-    {
-        if ( model == null )
-        {
+    public ToolchainPrivate createToolchain(ToolchainModel model) throws MisconfiguredToolchainException {
+        if (model == null) {
             return null;
         }
 
         // use DefaultJavaToolChain for compatibility with maven 3.2.3 and earlier
 
-        @SuppressWarnings( "deprecation" )
-        JavaToolchainImpl jtc = new DefaultJavaToolChain( model, logger );
+        @SuppressWarnings("deprecation")
+        JavaToolchainImpl jtc = new DefaultJavaToolChain(model, logger);
 
         // populate the provides section
         Properties provides = model.getProvides();
-        for ( Entry<Object, Object> provide : provides.entrySet() )
-        {
+        for (Entry<Object, Object> provide : provides.entrySet()) {
             String key = (String) provide.getKey();
             String value = (String) provide.getValue();
 
-            if ( value == null )
-            {
+            if (value == null) {
                 throw new MisconfiguredToolchainException(
-                    "Provides token '" + key + "' doesn't have any value configured." );
+                        "Provides token '" + key + "' doesn't have any value configured.");
             }
 
             RequirementMatcher matcher;
-            if ( "version".equals( key ) )
-            {
-                matcher = RequirementMatcherFactory.createVersionMatcher( value );
-            }
-            else
-            {
-                matcher = RequirementMatcherFactory.createExactMatcher( value );
+            if ("version".equals(key)) {
+                matcher = RequirementMatcherFactory.createVersionMatcher(value);
+            } else {
+                matcher = RequirementMatcherFactory.createExactMatcher(value);
             }
 
-            jtc.addProvideToken( key, matcher );
+            jtc.addProvideToken(key, matcher);
         }
 
         // populate the configuration section
         Xpp3Dom dom = (Xpp3Dom) model.getConfiguration();
-        Xpp3Dom javahome = dom.getChild( JavaToolchainImpl.KEY_JAVAHOME );
-        if ( javahome == null )
-        {
-            throw new MisconfiguredToolchainException( "Java toolchain without the "
-                + JavaToolchainImpl.KEY_JAVAHOME + " configuration element." );
+        Xpp3Dom javahome = dom != null ? dom.getChild(JavaToolchainImpl.KEY_JAVAHOME) : null;
+        if (javahome == null) {
+            throw new MisconfiguredToolchainException(
+                    "Java toolchain without the " + JavaToolchainImpl.KEY_JAVAHOME + " configuration element.");
         }
-        File normal = new File( FileUtils.normalize( javahome.getValue() ) );
-        if ( normal.exists() )
-        {
-            jtc.setJavaHome( FileUtils.normalize( javahome.getValue() ) );
-        }
-        else
-        {
-            throw new MisconfiguredToolchainException( "Non-existing JDK home configuration at "
-                + normal.getAbsolutePath() );
+        Path normal = Paths.get(javahome.getValue()).normalize();
+        if (Files.exists(normal)) {
+            jtc.setJavaHome(Paths.get(javahome.getValue()).normalize().toString());
+        } else {
+            throw new MisconfiguredToolchainException(
+                    "Non-existing JDK home configuration at " + normal.toAbsolutePath());
         }
 
         return jtc;
     }
 
-    public ToolchainPrivate createDefaultToolchain()
-    {
-        //not sure it's necessary to provide a default toolchain here.
-        //only version can be eventually supplied, and
+    public ToolchainPrivate createDefaultToolchain() {
+        // not sure it's necessary to provide a default toolchain here.
+        // only version can be eventually supplied, and
         return null;
     }
 
-    protected Logger getLogger()
-    {
+    protected Logger getLogger() {
         return logger;
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java b/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java
index af5a88c..5a7b331 100644
--- a/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java
+++ b/maven-core/src/main/java/org/apache/maven/toolchain/java/JavaToolchainImpl.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.java;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,70 +16,65 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.java;
 
-import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 
 import org.apache.maven.toolchain.DefaultToolchain;
 import org.apache.maven.toolchain.model.ToolchainModel;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.Os;
+import org.apache.maven.utils.Os;
 import org.slf4j.Logger;
 
 /**
  * JDK toolchain implementation.
  *
- * @author Milos Kleint
  * @since 2.0.9, renamed from DefaultJavaToolChain in 3.2.4
  */
-class JavaToolchainImpl
-    extends DefaultToolchain
-    implements JavaToolchain
-{
+public class JavaToolchainImpl extends DefaultToolchain implements JavaToolchain {
     private String javaHome;
 
-    public static final String KEY_JAVAHOME = "jdkHome"; //NOI18N
+    public static final String KEY_JAVAHOME = "jdkHome"; // NOI18N
 
-    JavaToolchainImpl( ToolchainModel model, Logger logger )
-    {
-        super( model, "jdk", logger );
+    JavaToolchainImpl(ToolchainModel model, Logger logger) {
+        super(model, "jdk", logger);
     }
 
-    public String getJavaHome()
-    {
+    public String getJavaHome() {
         return javaHome;
     }
 
-    public void setJavaHome( String javaHome )
-    {
+    public void setJavaHome(String javaHome) {
         this.javaHome = javaHome;
     }
 
-    public String toString()
-    {
+    public String toString() {
         return "JDK[" + getJavaHome() + "]";
     }
 
-    public String findTool( String toolName )
-    {
-        File toRet = findTool( toolName, new File( FileUtils.normalize( getJavaHome() ) ) );
-        if ( toRet != null )
-        {
-            return toRet.getAbsolutePath();
+    public String findTool(String toolName) {
+        Path toRet = findTool(toolName, Paths.get(getJavaHome()).normalize());
+        if (toRet != null) {
+            return toRet.toAbsolutePath().toString();
         }
         return null;
     }
 
-    private static File findTool( String toolName, File installFolder )
-    {
-        File bin = new File( installFolder, "bin" ); //NOI18N
-        if ( bin.exists() )
-        {
-            File tool = new File( bin, toolName + ( Os.isFamily( "windows" ) ? ".exe" : "" ) ); // NOI18N
-            if ( tool.exists() )
-            {
+    private static Path findTool(String toolName, Path installDir) {
+        Path bin = installDir.resolve("bin"); // NOI18N
+        if (Files.isDirectory(bin)) {
+            if (Os.IS_WINDOWS) {
+                Path tool = bin.resolve(toolName + ".exe");
+                if (Files.exists(tool)) {
+                    return tool;
+                }
+            }
+            Path tool = bin.resolve(toolName);
+            if (Files.exists(tool)) {
                 return tool;
             }
         }
         return null;
-   }
-}
\ No newline at end of file
+    }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultConsumerPomXMLFilterFactory.java b/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultConsumerPomXMLFilterFactory.java
deleted file mode 100644
index fa21591..0000000
--- a/maven-core/src/main/java/org/apache/maven/xml/internal/DefaultConsumerPomXMLFilterFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package org.apache.maven.xml.internal;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.model.building.DefaultBuildPomXMLFilterFactory;
-import org.apache.maven.model.transform.RawToConsumerPomXMLFilterFactory;
-
-/**
- * The default implementation of the {@link RawToConsumerPomXMLFilterFactory}
- * It will provide several values for the consumer pom based on its context.
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class DefaultConsumerPomXMLFilterFactory extends RawToConsumerPomXMLFilterFactory
-{
-    public DefaultConsumerPomXMLFilterFactory( DefaultBuildPomXMLFilterFactory buildPomXMLFilterFactory )
-    {
-        super( buildPomXMLFilterFactory );
-    }
-}
diff --git a/maven-core/src/main/mdo/extension.mdo b/maven-core/src/main/mdo/extension.mdo
index 9e94581..3b64283 100644
--- a/maven-core/src/main/mdo/extension.mdo
+++ b/maven-core/src/main/mdo/extension.mdo
@@ -23,7 +23,9 @@
   <name>ExtensionDescriptor</name>
   <description><![CDATA[
     Extension descriptor, stored in <code>META-INF/maven/extension.xml</code> in an extension's jar artifact to
-    precisely control parts of the extension and dependencies to expose.
+    precisely control parts of the extension and dependencies to expose in the API class loader.
+    Maven uses Plexus Classworlds to build the class loader hierarchy, therefore some concepts used in this extensions
+    stem from Plexus Classworlds originally.
     <p><i>Notice:</i> this documentation is generated from a Modello model but the code executed is not generated
     from this descriptor. Please report if you find anything wrong.</p>
   ]]></description>
@@ -46,8 +48,10 @@
             <type>String</type>
             <multiplicity>*</multiplicity>
           </association>
-          <description>Packages from the artifact that are exposed.</description>
-          <!-- TODO explain package vs package.class vs package.* -->
+          <description><![CDATA[Restricts the classes/resources from the current artifact's CoreExtension class realm that are exposed. Values ending with ".*" expose all classes/resources which are directly contained in the given package in binary form. 
+            Other values define only the prefix of classes/resources being exposed. Their binary name must be equal to the prefix or starting with the prefix (followed by "." or "$").
+            In particular this includes all subpackages. Despite the element name one can also only expose individual classes of a particular package by adding its binary name as value.
+          ]]></description>
         </field>
         <field>
           <name>exportedArtifacts</name>
@@ -56,7 +60,8 @@
             <type>String</type>
             <multiplicity>*</multiplicity>
           </association>
-          <description><![CDATA[Artifacts that are exposed: <code>groupId:artifactId</code> file.]]>
+          <description><![CDATA[Artifacts in the format <code>groupId:artifactId</code>. All the ones listed here are filtered (i.e. removed) from plugin and build extension class realms,
+          i.e. referencing any of those coordinates in plugin/build extension dependencies has no effect.]]>
           </description>
         </field>
       </fields>
diff --git a/maven-core/src/main/resources/META-INF/maven/extension.xml b/maven-core/src/main/resources/META-INF/maven/extension.xml
index 2fdf4f2..1823336 100644
--- a/maven-core/src/main/resources/META-INF/maven/extension.xml
+++ b/maven-core/src/main/resources/META-INF/maven/extension.xml
@@ -22,6 +22,8 @@
 <extension>
   <exportedPackages>
     <!-- maven-* -->
+    <exportedPackage>org.apache.maven.api</exportedPackage>
+
     <exportedPackage>org.apache.maven.*</exportedPackage>
     <exportedPackage>org.apache.maven.artifact</exportedPackage>
     <exportedPackage>org.apache.maven.classrealm</exportedPackage>
@@ -82,6 +84,7 @@
 
     <!-- plexus-utils (for DOM-type fields in maven-model) -->
     <exportedPackage>org.codehaus.plexus.util.xml.Xpp3Dom</exportedPackage>
+    <exportedPackage>org.codehaus.plexus.util.xml.Xpp3DomBuilder</exportedPackage>
     <exportedPackage>org.codehaus.plexus.util.xml.pull.XmlPullParser</exportedPackage>
     <exportedPackage>org.codehaus.plexus.util.xml.pull.XmlPullParserException</exportedPackage>
     <exportedPackage>org.codehaus.plexus.util.xml.pull.XmlSerializer</exportedPackage>
@@ -108,6 +111,9 @@
     <exportedPackage>javax.annotation.*</exportedPackage>
     <exportedPackage>javax.annotation.security.*</exportedPackage>
 
+    <exportedPackage>jakarta.inject.*</exportedPackage>
+    <exportedPackage>jakarta.annotation.*</exportedPackage>
+
     <!--
       | We may potentially want to export these, but right now I'm not sure that anything Guice specific needs
       | to be made available to plugin authors. If we find people are getting fancy and want to take advantage of
@@ -133,6 +139,14 @@
   </exportedPackages>
 
   <exportedArtifacts>
+    <!-- maven 4 api -->
+    <exportedArtifact>org.apache.maven:maven-api-core</exportedArtifact>
+    <exportedArtifact>org.apache.maven:maven-api-meta</exportedArtifact>
+    <exportedArtifact>org.apache.maven:maven-api-model</exportedArtifact>
+    <exportedArtifact>org.apache.maven:maven-api-settings</exportedArtifact>
+    <exportedArtifact>org.apache.maven:maven-api-toolchain</exportedArtifact>
+    <exportedArtifact>org.apache.maven:maven-api-xml</exportedArtifact>
+
     <exportedArtifact>classworlds:classworlds</exportedArtifact>
     <exportedArtifact>org.codehaus.plexus:plexus-classworlds</exportedArtifact>
     <exportedArtifact>org.codehaus.plexus:plexus-component-api</exportedArtifact>
diff --git a/maven-core/src/site/apt/core-extensions.apt.vm b/maven-core/src/site/apt/core-extensions.apt.vm
index 3d7abca..164ec13 100644
--- a/maven-core/src/site/apt/core-extensions.apt.vm
+++ b/maven-core/src/site/apt/core-extensions.apt.vm
@@ -25,6 +25,6 @@
 
 Maven Core Extensions Reference
 
-  Maven core provides default extensions as defined in <<</META-INF/maven/extension.xml>>>:
+  Maven core provides default {{{./extension.html}extensions}} as defined in <<</META-INF/maven/extension.xml>>>:
 
 %{snippet|id=core-extension|file=${project.basedir}/src/main/resources/META-INF/maven/extension.xml}
diff --git a/maven-core/src/site/apt/default-bindings.apt.vm b/maven-core/src/site/apt/default-bindings.apt.vm
index 1ad708f..c917d0c 100644
--- a/maven-core/src/site/apt/default-bindings.apt.vm
+++ b/maven-core/src/site/apt/default-bindings.apt.vm
@@ -31,6 +31,10 @@
 
 %{toc|fromDepth=2}
 
+  Versions of the plugins are shared in a few constants:
+
+%{snippet|id=versions|file=${project.basedir}/src/main/java/org/apache/maven/lifecycle/providers/packaging/AbstractLifecycleMappingProvider.java}
+
 * Plugin bindings for <<<pom>>> packaging
 
 %{snippet|id=pom|file=${project.basedir}/src/main/java/org/apache/maven/lifecycle/providers/packaging/PomLifecycleMappingProvider.java}
diff --git a/maven-core/src/site/apt/getting-to-container-configured-mojos.apt b/maven-core/src/site/apt/getting-to-container-configured-mojos.apt
index 1c4a487..8b8a975 100644
--- a/maven-core/src/site/apt/getting-to-container-configured-mojos.apt
+++ b/maven-core/src/site/apt/getting-to-container-configured-mojos.apt
@@ -20,7 +20,7 @@
   ---
   John Casey
   ---
-  29-April-2005
+  2005-04-29
 
 Abstract
 
@@ -30,7 +30,7 @@
 
   In order to really achieve this, we need mojo configurations (which are
   provided both in terms of static expressions that are just looked up, and
-  in terms of user-provided configuration from system properties or the POM).
+  in terms of user-provided configuration from properties or the POM).
   If these mojos are to be first-class components, the configuration from these
   various sources must be consolidated and injected using the container.
 
diff --git a/maven-core/src/site/apt/index.apt b/maven-core/src/site/apt/index.apt
index 47b884f..7988dcc 100644
--- a/maven-core/src/site/apt/index.apt
+++ b/maven-core/src/site/apt/index.apt
@@ -49,7 +49,24 @@
 
  * <<<ProjectBuilder>>> component ({{{./apidocs/org/apache/maven/project/ProjectBuilder.html}javadoc}}),
  with its <<<DefaultProjectBuilder>>> implementation
- ({{{./xref/org/apache/maven/project/DefaultProjectBuilder.html}source}}),
+ ({{{./xref/org/apache/maven/project/DefaultProjectBuilder.html}source}}), to prepare {{{./apidocs/org/apache/maven/project/MavenProject.html}<<<MavenProject>>> descriptor}} from POM files,
+
+ * <<<LifecycleExecutor>>> component ({{{./apidocs/org/apache/maven/lifecycle/LifecycleExecutor.html}javadoc}}),
+ with its <<<DefaultLifecycleExecutor>>> implementation({{{/xref/org/apache/maven/lifecycle/DefaultLifecycleExecutor.html}source}}), to plan or execute tasks.\
+   on plugin goals execution order:
+
+   * <<in a given phase, goals order is not expected to be guaranteed nor finely tuned>>:
+     it is just a consequence of the order obtained during {{{../maven-model-builder/}effective model building}},
+     which combines profile activation+injection and inheritance assembly from parents,
+
+   * known limitations are notably that:
+
+     1. plugin goal execution in a child is usually simply appended (at end): you can't try to insert in the middle of pre-existing inherited executions,
+
+     2. append happens at plugin level first, then goal level, independently from phases.
+        This means for example that adding pluginA:goal2 to pre-existing (pluginA:goal1, pluginB:goal) will lead to (pluginA:goal1, pluginA:goal2, pluginB:goal)
+
+   * see effective POM as shown by {{{/plugins/maven-help-plugin/effective-pom-mojo.html}<<<help:effective-pom>>>}} to see the effective plugins then goals order.
 
  * <<<MavenPluginManager>>> component ({{{./apidocs/org/apache/maven/plugin/MavenPluginManager.html}javadoc}}),
  with its <<<DefaultMavenPluginManager>>> implementation
diff --git a/maven-core/src/site/apt/offline-mode.apt b/maven-core/src/site/apt/offline-mode.apt
index ec596c0..13e54af 100644
--- a/maven-core/src/site/apt/offline-mode.apt
+++ b/maven-core/src/site/apt/offline-mode.apt
@@ -20,7 +20,7 @@
   ---
   John Casey
   ---
-  08-April-2005
+  2005-04-08
   ---
 
 Offline Mode Design
diff --git a/maven-core/src/site/site.xml b/maven-core/src/site/site.xml
index 4ddb7aa..09663df 100644
--- a/maven-core/src/site/site.xml
+++ b/maven-core/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
@@ -37,6 +37,7 @@
       <item name="Plugin Bindings to Default Lifecycle" href="default-bindings.html"/>
       <item name="Artifact Handlers" href="artifact-handlers.html"/>
       <item name="Core Extensions" href="core-extensions.html"/>
+      <item name="Extension Descriptor" href="extension.html"/>
     </menu>
 
     <menu ref="parent"/>
diff --git a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java
index bb3574a..51f9969 100644
--- a/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java
+++ b/maven-core/src/test/java/org/apache/maven/AbstractCoreMavenComponentTestCase.java
@@ -1,5 +1,3 @@
-package org.apache.maven;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven;
+
+import javax.inject.Inject;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -28,10 +29,12 @@
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.InvalidRepositoryException;
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.impl.DefaultSessionFactory;
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Exclusion;
@@ -42,63 +45,56 @@
 import org.apache.maven.project.DefaultProjectBuildingRequest;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuildingRequest;
-import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
-import org.codehaus.plexus.testing.PlexusTest;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.codehaus.plexus.util.FileUtils;
 import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
 import org.eclipse.aether.repository.LocalRepository;
 
-import javax.inject.Inject;
-
 import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
+import static org.mockito.Mockito.mock;
 
 @PlexusTest
-public abstract class AbstractCoreMavenComponentTestCase
-{
+public abstract class AbstractCoreMavenComponentTestCase {
 
     @Inject
     protected PlexusContainer container;
 
     @Inject
-    protected RepositorySystem repositorySystem;
+    protected MavenRepositorySystem repositorySystem;
 
     @Inject
     protected org.apache.maven.project.ProjectBuilder projectBuilder;
 
-    abstract protected String getProjectsDirectory();
+    protected abstract String getProjectsDirectory();
 
     protected PlexusContainer getContainer() {
         return container;
     }
 
-    protected File getProject(String name )
-        throws Exception
-    {
-        File source = new File( new File( getBasedir(), getProjectsDirectory() ), name );
-        File target = new File( new File( getBasedir(), "target" ), name );
-        FileUtils.copyDirectoryStructureIfModified( source, target );
-        return new File( target, "pom.xml" );
+    protected File getProject(String name) throws Exception {
+        File source = new File(new File(getBasedir(), getProjectsDirectory()), name);
+        File target = new File(new File(getBasedir(), "target"), name);
+        FileUtils.copyDirectoryStructureIfModified(source, target);
+        return new File(target, "pom.xml");
     }
 
-    protected MavenExecutionRequest createMavenExecutionRequest( File pom )
-        throws Exception
-    {
+    protected MavenExecutionRequest createMavenExecutionRequest(File pom) throws Exception {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest()
-            .setPom( pom )
-            .setProjectPresent( true )
-            .setShowErrors( true )
-            .setPluginGroups( Arrays.asList( "org.apache.maven.plugins" ) )
-            .setLocalRepository( getLocalRepository() )
-            .setRemoteRepositories( getRemoteRepositories() )
-            .setPluginArtifactRepositories( getPluginArtifactRepositories() )
-            .setGoals( Arrays.asList( "package" ) );
+                .setPom(pom)
+                .setProjectPresent(true)
+                .setShowErrors(true)
+                .setPluginGroups(Arrays.asList("org.apache.maven.plugins"))
+                .setLocalRepository(getLocalRepository())
+                .setRemoteRepositories(getRemoteRepositories())
+                .setPluginArtifactRepositories(getPluginArtifactRepositories())
+                .setGoals(Arrays.asList("package"));
 
-        if ( pom != null )
-        {
-            request.setMultiModuleProjectDirectory( pom.getParentFile() );
+        if (pom != null) {
+            request.setMultiModuleProjectDirectory(pom.getParentFile());
         }
 
         return request;
@@ -107,209 +103,186 @@
     // layer the creation of a project builder configuration with a request, but this will need to be
     // a Maven subclass because we don't want to couple maven to the project builder which we need to
     // separate.
-    protected MavenSession createMavenSession( File pom )
-        throws Exception
-    {
-        return createMavenSession( pom, new Properties() );
+    protected MavenSession createMavenSession(File pom) throws Exception {
+        return createMavenSession(pom, new Properties());
     }
 
-    protected MavenSession createMavenSession( File pom, Properties executionProperties )
-                    throws Exception
-    {
-        return createMavenSession( pom, executionProperties, false );
+    protected MavenSession createMavenSession(File pom, Properties executionProperties) throws Exception {
+        return createMavenSession(pom, executionProperties, false);
     }
 
-    protected MavenSession createMavenSession( File pom, Properties executionProperties, boolean includeModules )
-        throws Exception
-    {
-        MavenExecutionRequest request = createMavenExecutionRequest( pom );
+    protected MavenSession createMavenSession(File pom, Properties executionProperties, boolean includeModules)
+            throws Exception {
+        MavenExecutionRequest request = createMavenExecutionRequest(pom);
 
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest()
-            .setLocalRepository( request.getLocalRepository() )
-            .setRemoteRepositories( request.getRemoteRepositories() )
-            .setPluginArtifactRepositories( request.getPluginArtifactRepositories() )
-            .setSystemProperties( executionProperties )
-            .setUserProperties( new Properties() );
+                .setLocalRepository(request.getLocalRepository())
+                .setRemoteRepositories(request.getRemoteRepositories())
+                .setPluginArtifactRepositories(request.getPluginArtifactRepositories())
+                .setSystemProperties(executionProperties)
+                .setUserProperties(new Properties());
 
         List<MavenProject> projects = new ArrayList<>();
 
-        if ( pom != null )
-        {
-            MavenProject project = projectBuilder.build( pom, configuration ).getProject();
+        if (pom != null) {
+            MavenProject project = projectBuilder.build(pom, configuration).getProject();
 
-            projects.add( project );
-            if ( includeModules )
-            {
-                for( String module : project.getModules() )
-                {
-                    File modulePom = new File( pom.getParentFile(), module );
-                    if( modulePom.isDirectory() )
-                    {
-                        modulePom = new File( modulePom, "pom.xml" );
+            projects.add(project);
+            if (includeModules) {
+                for (String module : project.getModules()) {
+                    File modulePom = new File(pom.getParentFile(), module);
+                    if (modulePom.isDirectory()) {
+                        modulePom = new File(modulePom, "pom.xml");
                     }
-                    projects.add( projectBuilder.build( modulePom, configuration ).getProject() );
+                    projects.add(projectBuilder.build(modulePom, configuration).getProject());
                 }
             }
-        }
-        else
-        {
+        } else {
             MavenProject project = createStubMavenProject();
-            project.setRemoteArtifactRepositories( request.getRemoteRepositories() );
-            project.setPluginArtifactRepositories( request.getPluginArtifactRepositories() );
-            projects.add( project );
+            project.setRemoteArtifactRepositories(request.getRemoteRepositories());
+            project.setPluginArtifactRepositories(request.getPluginArtifactRepositories());
+            projects.add(project);
         }
 
-        initRepoSession( configuration );
+        initRepoSession(configuration);
 
-        MavenSession session =
-            new MavenSession( getContainer(), configuration.getRepositorySession(), request,
-                              new DefaultMavenExecutionResult() );
-        session.setProjects( projects );
-        session.setAllProjects( session.getProjects() );
+        DefaultSessionFactory defaultSessionFactory =
+                new DefaultSessionFactory(mock(RepositorySystem.class), null, null, null);
+
+        MavenSession session = new MavenSession(
+                getContainer(), configuration.getRepositorySession(), request, new DefaultMavenExecutionResult());
+        session.setProjects(projects);
+        session.setAllProjects(session.getProjects());
+        session.setSession(defaultSessionFactory.getSession(session));
 
         return session;
     }
 
-    protected void initRepoSession( ProjectBuildingRequest request )
-        throws Exception
-    {
-        File localRepoDir = new File( request.getLocalRepository().getBasedir() );
-        LocalRepository localRepo = new LocalRepository( localRepoDir );
+    protected void initRepoSession(ProjectBuildingRequest request) throws Exception {
+        File localRepoDir = new File(request.getLocalRepository().getBasedir());
+        LocalRepository localRepo = new LocalRepository(localRepoDir);
         DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
-        session.setLocalRepositoryManager( new SimpleLocalRepositoryManagerFactory().newInstance( session, localRepo ) );
-        request.setRepositorySession( session );
+        session.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory().newInstance(session, localRepo));
+        request.setRepositorySession(session);
     }
 
-    protected MavenProject createStubMavenProject()
-    {
+    protected MavenProject createStubMavenProject() {
         Model model = new Model();
-        model.setGroupId( "org.apache.maven.test" );
-        model.setArtifactId( "maven-test" );
-        model.setVersion( "1.0" );
-        return new MavenProject( model );
+        model.setGroupId("org.apache.maven.test");
+        model.setArtifactId("maven-test");
+        model.setVersion("1.0");
+        return new MavenProject(model);
     }
 
-    protected List<ArtifactRepository> getRemoteRepositories()
-        throws InvalidRepositoryException
-    {
-        File repoDir = new File( getBasedir(), "src/test/remote-repo" ).getAbsoluteFile();
+    protected List<ArtifactRepository> getRemoteRepositories() throws InvalidRepositoryException {
+        File repoDir = new File(getBasedir(), "src/test/remote-repo").getAbsoluteFile();
 
         RepositoryPolicy policy = new RepositoryPolicy();
-        policy.setEnabled( true );
-        policy.setChecksumPolicy( "ignore" );
-        policy.setUpdatePolicy( "always" );
+        policy.setEnabled(true);
+        policy.setChecksumPolicy("ignore");
+        policy.setUpdatePolicy("always");
 
         Repository repository = new Repository();
-        repository.setId( RepositorySystem.DEFAULT_REMOTE_REPO_ID );
-        repository.setUrl( "file://" + repoDir.toURI().getPath() );
-        repository.setReleases( policy );
-        repository.setSnapshots( policy );
+        repository.setId(MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID);
+        repository.setUrl("file://" + repoDir.toURI().getPath());
+        repository.setReleases(policy);
+        repository.setSnapshots(policy);
 
-        return Arrays.asList( repositorySystem.buildArtifactRepository( repository ) );
+        return Arrays.asList(repositorySystem.buildArtifactRepository(repository));
     }
 
-    protected List<ArtifactRepository> getPluginArtifactRepositories()
-        throws InvalidRepositoryException
-    {
+    protected List<ArtifactRepository> getPluginArtifactRepositories() throws InvalidRepositoryException {
         return getRemoteRepositories();
     }
 
-    protected ArtifactRepository getLocalRepository()
-        throws InvalidRepositoryException
-    {
-        File repoDir = new File( getBasedir(), "target/local-repo" ).getAbsoluteFile();
+    protected ArtifactRepository getLocalRepository() throws InvalidRepositoryException {
+        File repoDir = new File(getBasedir(), "target/local-repo").getAbsoluteFile();
 
-        return repositorySystem.createLocalRepository( repoDir );
+        return repositorySystem.createLocalRepository(repoDir);
     }
 
-    protected class ProjectBuilder
-    {
+    protected class ProjectBuilder {
         private MavenProject project;
 
-        public ProjectBuilder( MavenProject project )
-        {
+        public ProjectBuilder(MavenProject project) {
             this.project = project;
         }
 
-        public ProjectBuilder( String groupId, String artifactId, String version )
-        {
+        public ProjectBuilder(String groupId, String artifactId, String version) {
             Model model = new Model();
-            model.setModelVersion( "4.0.0" );
-            model.setGroupId( groupId );
-            model.setArtifactId( artifactId );
-            model.setVersion( version );
-            model.setBuild(  new Build() );
-            project = new MavenProject( model );
+            model.setModelVersion("4.0.0");
+            model.setGroupId(groupId);
+            model.setArtifactId(artifactId);
+            model.setVersion(version);
+            model.setBuild(new Build());
+            project = new MavenProject(model);
         }
 
-        public ProjectBuilder setGroupId( String groupId )
-        {
-            project.setGroupId( groupId );
+        public ProjectBuilder setGroupId(String groupId) {
+            project.setGroupId(groupId);
             return this;
         }
 
-        public ProjectBuilder setArtifactId( String artifactId )
-        {
-            project.setArtifactId( artifactId );
+        public ProjectBuilder setArtifactId(String artifactId) {
+            project.setArtifactId(artifactId);
             return this;
         }
 
-        public ProjectBuilder setVersion( String version )
-        {
-            project.setVersion( version );
+        public ProjectBuilder setVersion(String version) {
+            project.setVersion(version);
             return this;
         }
 
         // Dependencies
         //
-        public ProjectBuilder addDependency( String groupId, String artifactId, String version, String scope )
-        {
-            return addDependency( groupId, artifactId, version, scope, (Exclusion)null );
+        public ProjectBuilder addDependency(String groupId, String artifactId, String version, String scope) {
+            return addDependency(groupId, artifactId, version, scope, (Exclusion) null);
         }
 
-        public ProjectBuilder addDependency( String groupId, String artifactId, String version, String scope, Exclusion exclusion )
-        {
-            return addDependency( groupId, artifactId, version, scope, null, exclusion );
+        public ProjectBuilder addDependency(
+                String groupId, String artifactId, String version, String scope, Exclusion exclusion) {
+            return addDependency(groupId, artifactId, version, scope, null, exclusion);
         }
 
-        public ProjectBuilder addDependency( String groupId, String artifactId, String version, String scope, String systemPath )
-        {
-            return addDependency( groupId, artifactId, version, scope, systemPath, null );
+        public ProjectBuilder addDependency(
+                String groupId, String artifactId, String version, String scope, String systemPath) {
+            return addDependency(groupId, artifactId, version, scope, systemPath, null);
         }
 
-        public ProjectBuilder addDependency( String groupId, String artifactId, String version, String scope, String systemPath, Exclusion exclusion )
-        {
+        public ProjectBuilder addDependency(
+                String groupId,
+                String artifactId,
+                String version,
+                String scope,
+                String systemPath,
+                Exclusion exclusion) {
             Dependency d = new Dependency();
-            d.setGroupId( groupId );
-            d.setArtifactId( artifactId );
-            d.setVersion( version );
-            d.setScope( scope );
+            d.setGroupId(groupId);
+            d.setArtifactId(artifactId);
+            d.setVersion(version);
+            d.setScope(scope);
 
-            if ( systemPath != null && scope.equals(  Artifact.SCOPE_SYSTEM ) )
-            {
-                d.setSystemPath( systemPath );
+            if (systemPath != null && scope.equals(Artifact.SCOPE_SYSTEM)) {
+                d.setSystemPath(systemPath);
             }
 
-            if ( exclusion != null )
-            {
-                d.addExclusion( exclusion );
+            if (exclusion != null) {
+                d.addExclusion(exclusion);
             }
 
-            project.getDependencies().add( d );
+            project.getDependencies().add(d);
 
             return this;
         }
 
         // Plugins
         //
-        public ProjectBuilder addPlugin( Plugin plugin )
-        {
-            project.getBuildPlugins().add( plugin );
+        public ProjectBuilder addPlugin(Plugin plugin) {
+            project.getBuildPlugins().add(plugin);
             return this;
         }
 
-        public MavenProject get()
-        {
+        public MavenProject get() {
             return project;
         }
     }
diff --git a/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java b/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java
index 9075e79..cb57bdf 100644
--- a/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java
+++ b/maven-core/src/test/java/org/apache/maven/DefaultMavenTest.java
@@ -7,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +18,14 @@
  */
 package org.apache.maven;
 
-import java.io.File;
-import java.nio.file.Files;
-import java.util.concurrent.atomic.AtomicReference;
-
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+import java.nio.file.Files;
+import java.util.concurrent.atomic.AtomicReference;
+
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.DefaultArtifact;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -41,19 +41,15 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class DefaultMavenTest
-        extends AbstractCoreMavenComponentTestCase
-{
+class DefaultMavenTest extends AbstractCoreMavenComponentTestCase {
     @Singleton
-    @Named( "WsrClassCatcher" )
-    private static final class WsrClassCatcher extends AbstractMavenLifecycleParticipant
-    {
-        private final AtomicReference<Class<?>> wsrClassRef = new AtomicReference<>( null );
+    @Named("WsrClassCatcher")
+    private static final class WsrClassCatcher extends AbstractMavenLifecycleParticipant {
+        private final AtomicReference<Class<?>> wsrClassRef = new AtomicReference<>(null);
 
         @Override
-        public void afterProjectsRead( MavenSession session ) throws MavenExecutionException
-        {
-            wsrClassRef.set( session.getRepositorySession().getWorkspaceReader().getClass() );
+        public void afterProjectsRead(MavenSession session) throws MavenExecutionException {
+            wsrClassRef.set(session.getRepositorySession().getWorkspaceReader().getClass());
         }
     }
 
@@ -61,56 +57,48 @@
     private Maven maven;
 
     @Override
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/default-maven";
     }
 
     @Test
-    public void testEnsureResolverSessionHasMavenWorkspaceReader()
-            throws Exception
-    {
-        WsrClassCatcher wsrClassCatcher = ( WsrClassCatcher ) getContainer()
-                .lookup( AbstractMavenLifecycleParticipant.class, "WsrClassCatcher" );
-        Maven maven = getContainer().lookup( Maven.class );
-        MavenExecutionRequest request = createMavenExecutionRequest( getProject( "simple" ) ).setGoals( asList("validate") );
+    void testEnsureResolverSessionHasMavenWorkspaceReader() throws Exception {
+        WsrClassCatcher wsrClassCatcher =
+                (WsrClassCatcher) getContainer().lookup(AbstractMavenLifecycleParticipant.class, "WsrClassCatcher");
+        Maven maven = getContainer().lookup(Maven.class);
+        MavenExecutionRequest request =
+                createMavenExecutionRequest(getProject("simple")).setGoals(asList("validate"));
 
-        MavenExecutionResult result = maven.execute( request );
+        MavenExecutionResult result = maven.execute(request);
 
         Class<?> wsrClass = wsrClassCatcher.wsrClassRef.get();
-        assertNotNull( wsrClass, "wsr cannot be null" );
-        assertTrue( MavenWorkspaceReader.class.isAssignableFrom( wsrClass ), String.valueOf( wsrClass ) );
+        assertNotNull(wsrClass, "wsr cannot be null");
+        assertTrue(MavenWorkspaceReader.class.isAssignableFrom(wsrClass), String.valueOf(wsrClass));
     }
 
     @Test
-    public void testThatErrorDuringProjectDependencyGraphCreationAreStored()
-            throws Exception
-    {
-        MavenExecutionRequest request = createMavenExecutionRequest( getProject( "cyclic-reference" ) ).setGoals( asList("validate") );
+    void testThatErrorDuringProjectDependencyGraphCreationAreStored() throws Exception {
+        MavenExecutionRequest request =
+                createMavenExecutionRequest(getProject("cyclic-reference")).setGoals(asList("validate"));
 
-        MavenExecutionResult result = maven.execute( request );
+        MavenExecutionResult result = maven.execute(request);
 
-        assertEquals( ProjectCycleException.class, result.getExceptions().get( 0 ).getClass() );
+        assertEquals(ProjectCycleException.class, result.getExceptions().get(0).getClass());
     }
 
     @Test
-    public void testMavenProjectNoDuplicateArtifacts()
-        throws Exception
-    {
-        MavenProjectHelper mavenProjectHelper = getContainer().lookup( MavenProjectHelper.class );
+    void testMavenProjectNoDuplicateArtifacts() throws Exception {
+        MavenProjectHelper mavenProjectHelper = getContainer().lookup(MavenProjectHelper.class);
         MavenProject mavenProject = new MavenProject();
-        mavenProject.setArtifact( new DefaultArtifact( "g", "a", "1.0", Artifact.SCOPE_TEST, "jar", "", null ) );
-        File artifactFile = Files.createTempFile( "foo", "tmp").toFile();
-        try
-        {
-            mavenProjectHelper.attachArtifact( mavenProject, "sources", artifactFile );
-            assertEquals( 1, mavenProject.getAttachedArtifacts().size() );
-            mavenProjectHelper.attachArtifact( mavenProject, "sources", artifactFile );
-            assertEquals( 1, mavenProject.getAttachedArtifacts().size() );
-        } finally
-        {
-            Files.deleteIfExists( artifactFile.toPath() );
+        mavenProject.setArtifact(new DefaultArtifact("g", "a", "1.0", Artifact.SCOPE_TEST, "jar", "", null));
+        File artifactFile = Files.createTempFile("foo", "tmp").toFile();
+        try {
+            mavenProjectHelper.attachArtifact(mavenProject, "sources", artifactFile);
+            assertEquals(1, mavenProject.getAttachedArtifacts().size());
+            mavenProjectHelper.attachArtifact(mavenProject, "sources", artifactFile);
+            assertEquals(1, mavenProject.getAttachedArtifacts().size());
+        } finally {
+            Files.deleteIfExists(artifactFile.toPath());
         }
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/MavenLifecycleParticipantTest.java b/maven-core/src/test/java/org/apache/maven/MavenLifecycleParticipantTest.java
index 6d8f975..b56822d 100644
--- a/maven-core/src/test/java/org/apache/maven/MavenLifecycleParticipantTest.java
+++ b/maven-core/src/test/java/org/apache/maven/MavenLifecycleParticipantTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven;
 
 import java.io.File;
 import java.io.IOException;
@@ -34,139 +37,115 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 
-public class MavenLifecycleParticipantTest
-    extends AbstractCoreMavenComponentTestCase
-{
+class MavenLifecycleParticipantTest extends AbstractCoreMavenComponentTestCase {
 
     private static final String INJECTED_ARTIFACT_ID = "injected";
 
-    public static class InjectDependencyLifecycleListener
-        extends AbstractMavenLifecycleParticipant
-    {
+    public static class InjectDependencyLifecycleListener extends AbstractMavenLifecycleParticipant {
 
         @Override
-        public void afterProjectsRead( MavenSession session )
-        {
-            MavenProject project = session.getProjects().get( 0 );
+        public void afterProjectsRead(MavenSession session) {
+            MavenProject project = session.getProjects().get(0);
 
             Dependency dependency = new Dependency();
-            dependency.setArtifactId( INJECTED_ARTIFACT_ID );
-            dependency.setGroupId( "foo" );
-            dependency.setVersion( "1.2.3" );
-            dependency.setScope( "system" );
-            try
-            {
-                dependency.setSystemPath( new File(
-                                                    "src/test/projects/lifecycle-executor/project-with-additional-lifecycle-elements/pom.xml" ).getCanonicalPath() );
-            }
-            catch ( IOException e )
-            {
-                throw new RuntimeException( e );
+            dependency.setArtifactId(INJECTED_ARTIFACT_ID);
+            dependency.setGroupId("foo");
+            dependency.setVersion("1.2.3");
+            dependency.setScope("system");
+            try {
+                dependency.setSystemPath(new File(
+                                "src/test/projects/lifecycle-executor/project-with-additional-lifecycle-elements/pom.xml")
+                        .getCanonicalPath());
+            } catch (IOException e) {
+                throw new RuntimeException(e);
             }
 
-            project.getModel().addDependency( dependency );
+            project.getModel().addDependency(dependency);
         }
 
         @Override
-        public void afterSessionStart( MavenSession session )
-        {
-            session.getUserProperties().setProperty( "injected", "bar" );
+        public void afterSessionStart(MavenSession session) {
+            session.getUserProperties().setProperty("injected", "bar");
         }
-
     }
 
-    public static class InjectReactorDependency
-        extends AbstractMavenLifecycleParticipant
-    {
+    public static class InjectReactorDependency extends AbstractMavenLifecycleParticipant {
         @Override
-        public void afterProjectsRead( MavenSession session )
-        {
-            injectReactorDependency( session.getProjects(), "module-a", "module-b" );
+        public void afterProjectsRead(MavenSession session) {
+            injectReactorDependency(session.getProjects(), "module-a", "module-b");
         }
 
-        private void injectReactorDependency( List<MavenProject> projects, String moduleFrom, String moduleTo )
-        {
-            for ( MavenProject project : projects )
-            {
-                if ( moduleFrom.equals( project.getArtifactId() ) )
-                {
+        private void injectReactorDependency(List<MavenProject> projects, String moduleFrom, String moduleTo) {
+            for (MavenProject project : projects) {
+                if (moduleFrom.equals(project.getArtifactId())) {
                     Dependency dependency = new Dependency();
-                    dependency.setArtifactId( moduleTo );
-                    dependency.setGroupId( project.getGroupId() );
-                    dependency.setVersion( project.getVersion() );
+                    dependency.setArtifactId(moduleTo);
+                    dependency.setGroupId(project.getGroupId());
+                    dependency.setVersion(project.getVersion());
 
-                    project.getModel().addDependency( dependency );
+                    project.getModel().addDependency(dependency);
                 }
             }
         }
     }
 
     @Override
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/lifecycle-listener";
     }
 
     @Test
-    public void testDependencyInjection()
-        throws Exception
-    {
+    void testDependencyInjection() throws Exception {
         PlexusContainer container = getContainer();
 
         ComponentDescriptor<? extends AbstractMavenLifecycleParticipant> cd =
-            new ComponentDescriptor<>( InjectDependencyLifecycleListener.class,
-                                                                        container.getContainerRealm() );
-        cd.setRoleClass( AbstractMavenLifecycleParticipant.class );
-        container.addComponentDescriptor( cd );
+                new ComponentDescriptor<>(InjectDependencyLifecycleListener.class, container.getContainerRealm());
+        cd.setRoleClass(AbstractMavenLifecycleParticipant.class);
+        container.addComponentDescriptor(cd);
 
-        Maven maven = container.lookup( Maven.class );
-        File pom = getProject( "lifecycle-listener-dependency-injection" );
-        MavenExecutionRequest request = createMavenExecutionRequest( pom );
-        request.setGoals( Arrays.asList( "validate" ) );
-        MavenExecutionResult result = maven.execute( request );
+        Maven maven = container.lookup(Maven.class);
+        File pom = getProject("lifecycle-listener-dependency-injection");
+        MavenExecutionRequest request = createMavenExecutionRequest(pom);
+        request.setGoals(Arrays.asList("validate"));
+        MavenExecutionResult result = maven.execute(request);
 
-        assertFalse( result.hasExceptions(), result.getExceptions().toString() );
+        assertFalse(result.hasExceptions(), result.getExceptions().toString());
 
         MavenProject project = result.getProject();
 
-        assertEquals( "bar", project.getProperties().getProperty( "foo" ) );
+        assertEquals("bar", project.getProperties().getProperty("foo"));
 
-        ArrayList<Artifact> artifacts = new ArrayList<>( project.getArtifacts() );
+        ArrayList<Artifact> artifacts = new ArrayList<>(project.getArtifacts());
 
-        assertEquals( 1, artifacts.size() );
-        assertEquals( INJECTED_ARTIFACT_ID, artifacts.get( 0 ).getArtifactId() );
+        assertEquals(1, artifacts.size());
+        assertEquals(INJECTED_ARTIFACT_ID, artifacts.get(0).getArtifactId());
     }
 
     @Test
-    public void testReactorDependencyInjection()
-        throws Exception
-    {
+    void testReactorDependencyInjection() throws Exception {
         List<String> reactorOrder =
-            getReactorOrder( "lifecycle-participant-reactor-dependency-injection", InjectReactorDependency.class );
-        assertEquals( Arrays.asList( "parent", "module-b", "module-a" ), reactorOrder );
+                getReactorOrder("lifecycle-participant-reactor-dependency-injection", InjectReactorDependency.class);
+        assertEquals(Arrays.asList("parent", "module-b", "module-a"), reactorOrder);
     }
 
-    private <T> List<String> getReactorOrder( String testProject, Class<T> participant )
-        throws Exception
-    {
+    private <T> List<String> getReactorOrder(String testProject, Class<T> participant) throws Exception {
         PlexusContainer container = getContainer();
 
-        ComponentDescriptor<T> cd = new ComponentDescriptor<>( participant, container.getContainerRealm() );
-        cd.setRoleClass( AbstractMavenLifecycleParticipant.class );
-        container.addComponentDescriptor( cd );
+        ComponentDescriptor<T> cd = new ComponentDescriptor<>(participant, container.getContainerRealm());
+        cd.setRoleClass(AbstractMavenLifecycleParticipant.class);
+        container.addComponentDescriptor(cd);
 
-        Maven maven = container.lookup( Maven.class );
-        File pom = getProject( testProject );
-        MavenExecutionRequest request = createMavenExecutionRequest( pom );
-        request.setGoals( Arrays.asList( "validate" ) );
-        MavenExecutionResult result = maven.execute( request );
+        Maven maven = container.lookup(Maven.class);
+        File pom = getProject(testProject);
+        MavenExecutionRequest request = createMavenExecutionRequest(pom);
+        request.setGoals(Arrays.asList("validate"));
+        MavenExecutionResult result = maven.execute(request);
 
-        assertFalse( result.hasExceptions(), result.getExceptions().toString() );
+        assertFalse(result.hasExceptions(), result.getExceptions().toString());
 
         List<String> order = new ArrayList<>();
-        for ( MavenProject project : result.getTopologicallySortedProjects() )
-        {
-            order.add( project.getArtifactId() );
+        for (MavenProject project : result.getTopologicallySortedProjects()) {
+            order.add(project.getArtifactId());
         }
         return order;
     }
diff --git a/maven-core/src/test/java/org/apache/maven/MavenTest.java b/maven-core/src/test/java/org/apache/maven/MavenTest.java
deleted file mode 100644
index 991e61d..0000000
--- a/maven-core/src/test/java/org/apache/maven/MavenTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.apache.maven;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-
-import org.apache.maven.exception.ExceptionHandler;
-import org.junit.jupiter.api.Test;
-
-import javax.inject.Inject;
-
-public class MavenTest
-    extends AbstractCoreMavenComponentTestCase
-{
-    @Inject
-    private Maven maven;
-
-    @Inject
-    private ExceptionHandler exceptionHandler;
-
-    protected String getProjectsDirectory()
-    {
-        return "src/test/projects/lifecycle-executor";
-    }
-
-    @Test
-    public void testLifecycleExecutionUsingADefaultLifecyclePhase()
-        throws Exception
-    {
-/*
-        File pom = getProject( "project-with-additional-lifecycle-elements" );
-        MavenExecutionRequest request = createMavenExecutionRequest( pom );
-        MavenExecutionResult result = maven.execute( request );
-        if ( result.hasExceptions() )
-        {
-            ExceptionSummary es = exceptionHandler.handleException( result.getExceptions().get( 0 ) );
-            System.out.println( es.getMessage() );
-            es.getException().printStackTrace();
-            fail( "Maven did not execute correctly." );
-        }
-*/
-    }
-}
diff --git a/maven-core/src/test/java/org/apache/maven/ProjectDependenciesResolverTest.java b/maven-core/src/test/java/org/apache/maven/ProjectDependenciesResolverTest.java
deleted file mode 100644
index b648f2a..0000000
--- a/maven-core/src/test/java/org/apache/maven/ProjectDependenciesResolverTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.apache.maven;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-import java.io.File;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.project.MavenProject;
-
-import javax.inject.Inject;
-import org.junit.jupiter.api.Test;
-
-import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
-import static org.hamcrest.Matchers.endsWith;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.hamcrest.MatcherAssert.assertThat;
-
-public class ProjectDependenciesResolverTest
-    extends AbstractCoreMavenComponentTestCase
-{
-    @Inject
-    private ProjectDependenciesResolver resolver;
-
-    protected String getProjectsDirectory()
-    {
-        return "src/test/projects/project-dependencies-resolver";
-    }
-
-    /*
-    @Test
-    public void testExclusionsInDependencies()
-        throws Exception
-    {
-        MavenSession session = createMavenSession( null );
-        MavenProject project = session.getCurrentProject();
-
-        Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "org.apache.maven.its" );
-        exclusion.setArtifactId( "a" );
-
-        new ProjectBuilder( project ).addDependency( "org.apache.maven.its", "b", "0.1", Artifact.SCOPE_RUNTIME,
-                                                     exclusion );
-
-        Set<Artifact> artifactDependencies =
-            resolver.resolve( project, Collections.singleton( Artifact.SCOPE_COMPILE ), session );
-        assertEquals( 0, artifactDependencies.size() );
-
-        artifactDependencies = resolver.resolve( project, Collections.singleton( Artifact.SCOPE_RUNTIME ), session );
-        assertEquals( 1, artifactDependencies.size() );
-        assertEquals( "b", artifactDependencies.iterator().next().getArtifactId() );
-    }
-    */
-
-    @Test
-    public void testSystemScopeDependencies()
-        throws Exception
-    {
-        MavenSession session = createMavenSession( null );
-        MavenProject project = session.getCurrentProject();
-
-        new ProjectBuilder( project )
-            .addDependency( "com.mycompany", "system-dependency", "1.0", Artifact.SCOPE_SYSTEM, new File( getBasedir(), "pom.xml" ).getAbsolutePath() );
-
-        Set<Artifact> artifactDependencies =
-            resolver.resolve( project, Collections.singleton( Artifact.SCOPE_COMPILE ), session );
-        assertEquals( 1, artifactDependencies.size() );
-    }
-
-    @Test
-    public void testSystemScopeDependencyIsPresentInTheCompileClasspathElements()
-        throws Exception
-    {
-        File pom = getProject( "it0063" );
-
-        Properties eps = new Properties();
-        eps.setProperty( "jre.home", new File( pom.getParentFile(), "jdk/jre" ).getPath() );
-
-        MavenSession session = createMavenSession( pom, eps );
-        MavenProject project = session.getCurrentProject();
-
-        project.setArtifacts( resolver.resolve( project, Collections.singleton( Artifact.SCOPE_COMPILE ), session ) );
-
-        List<String> elements = project.getCompileClasspathElements();
-        assertEquals( 2, elements.size() );
-
-        @SuppressWarnings( "deprecation" )
-        List<Artifact> artifacts = project.getCompileArtifacts();
-        assertEquals( 1, artifacts.size() );
-        assertThat( artifacts.get( 0 ).getFile().getName(), endsWith( "tools.jar" ) );
-    }
-}
diff --git a/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java b/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java
index 9dd5cf1..54d75a8 100644
--- a/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/artifact/handler/ArtifactHandlerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.handler;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,82 +16,89 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.util.List;
+package org.apache.maven.artifact.handler;
 
 import javax.inject.Inject;
 
-import org.codehaus.plexus.testing.PlexusTest;
+import java.io.File;
+import java.nio.file.Files;
+import java.util.List;
+
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
 import org.codehaus.plexus.PlexusContainer;
-import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.junit.jupiter.api.Test;
 
 import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 @PlexusTest
-public class ArtifactHandlerTest
-{
+class ArtifactHandlerTest {
     @Inject
     PlexusContainer container;
 
     @Test
-    public void testAptConsistency()
-        throws Exception
-    {
-        File apt = getTestFile( "src/site/apt/artifact-handlers.apt" );
+    void testAptConsistency() throws Exception {
+        File apt = getTestFile("src/site/apt/artifact-handlers.apt");
 
-        List<String> lines = FileUtils.loadFile( apt );
+        List<String> lines = Files.readAllLines(apt.toPath());
 
-        for ( String line : lines )
-        {
-            if ( line.startsWith( "||" ) )
-            {
-                String[] cols = line.split( "\\|\\|" );
-                String[] expected =
-                    new String[] { "", "type", "classifier", "extension", "packaging", "language", "added to classpath",
-                        "includesDependencies", "" };
+        for (String line : lines) {
+            if (line.startsWith("||")) {
+                String[] cols = line.split("\\|\\|");
+                String[] expected = new String[] {
+                    "",
+                    "type",
+                    "classifier",
+                    "extension",
+                    "packaging",
+                    "language",
+                    "added to classpath",
+                    "includesDependencies",
+                    ""
+                };
 
                 int i = 0;
-                for ( String col : cols )
-                {
-                    assertEquals( expected[i++], col.trim(), "Wrong column header" );
+                for (String col : cols) {
+                    assertEquals(expected[i++], col.trim(), "Wrong column header");
                 }
-            }
-            else if ( line.startsWith( "|" ) )
-            {
-                String[] cols = line.split( "\\|" );
+            } else if (line.startsWith("|")) {
+                String[] cols = line.split("\\|");
 
-                String type = trimApt( cols[1] );
-                String classifier = trimApt( cols[2] );
-                String extension = trimApt( cols[3], type );
-                String packaging = trimApt( cols[4], type );
-                String language = trimApt( cols[5] );
-                String addedToClasspath = trimApt( cols[6] );
-                String includesDependencies = trimApt( cols[7] );
+                String type = trimApt(cols[1]);
+                String classifier = trimApt(cols[2]);
+                String extension = trimApt(cols[3], type);
+                String packaging = trimApt(cols[4], type);
+                String language = trimApt(cols[5]);
+                String addedToClasspath = trimApt(cols[6]);
+                String includesDependencies = trimApt(cols[7]);
 
-                ArtifactHandler handler = container.lookup( ArtifactHandler.class, type );
-                assertEquals( handler.getExtension(), extension, type + " extension" );
-                assertEquals( handler.getPackaging(), packaging, type + " packaging" );
-                assertEquals( handler.getClassifier(), classifier, type + " classifier" );
-                assertEquals( handler.getLanguage(), language, type + " language" );
-                assertEquals( handler.isAddedToClasspath() ? "true" : null, addedToClasspath, type + " addedToClasspath" );
-                assertEquals( handler.isIncludesDependencies() ? "true" : null, includesDependencies, type + " includesDependencies" );
+                ArtifactHandler handler =
+                        container.lookup(ArtifactHandlerManager.class).getArtifactHandler(type);
+                assertEquals(handler.getExtension(), extension, type + " extension");
+                // Packaging/Directory is Maven1 remnant!!!
+                // assertEquals(handler.getPackaging(), packaging, type + " packaging");
+                assertEquals(handler.getClassifier(), classifier, type + " classifier");
+                // Language is unused
+                // assertEquals(handler.getLanguage(), language, type + " language");
+                assertEquals(
+                        handler.isAddedToClasspath() ? "true" : null, addedToClasspath, type + " addedToClasspath");
+                assertEquals(
+                        handler.isIncludesDependencies() ? "true" : null,
+                        includesDependencies,
+                        type + " includesDependencies");
             }
         }
     }
 
-    private String trimApt( String content, String type )
-    {
-        String value = trimApt( content );
-        return "= type".equals( value ) ? type : value;
+    private String trimApt(String content, String type) {
+        String value = trimApt(content);
+        return "= type".equals(value) ? type : value;
     }
 
-    private String trimApt( String content )
-    {
-        content = content.replace( '<', ' ' ).replace( '>', ' ' ).trim();
+    private String trimApt(String content) {
+        content = content.replace('<', ' ').replace('>', ' ').trim();
 
-        return ( content.length() == 0 ) ? null : content;
+        return (content.length() == 0) ? null : content;
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java b/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java
index 76b1654..4347e1a 100644
--- a/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java
+++ b/maven-core/src/test/java/org/apache/maven/artifact/resolver/filter/ExclusionArtifactFilterTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.resolver.filter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,139 +16,155 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.model.Exclusion;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.BeforeEach;
+package org.apache.maven.artifact.resolver.filter;
 
 import java.util.Arrays;
 import java.util.Collections;
 
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.model.Exclusion;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-public class ExclusionArtifactFilterTest
-{
+class ExclusionArtifactFilterTest {
     private Artifact artifact;
+    private Artifact artifact2;
 
     @BeforeEach
-    public void setup()
-    {
-        artifact = mock( Artifact.class );
-        when( artifact.getGroupId() ).thenReturn( "org.apache.maven" );
-        when( artifact.getArtifactId() ).thenReturn( "maven-core" );
+    void setup() {
+        artifact = mock(Artifact.class);
+        when(artifact.getGroupId()).thenReturn("org.apache.maven");
+        when(artifact.getArtifactId()).thenReturn("maven-core");
+
+        artifact2 = mock(Artifact.class);
+        when(artifact2.getGroupId()).thenReturn("org.junit.jupiter");
+        when(artifact2.getArtifactId()).thenReturn("junit-jupiter-engine");
     }
 
     @Test
-    public void testExcludeExact()
-    {
+    void testExcludeExact() {
         Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "org.apache.maven" );
-        exclusion.setArtifactId( "maven-core" );
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Collections.singletonList( exclusion ) );
+        exclusion.setGroupId("org.apache.maven");
+        exclusion.setArtifactId("maven-core");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
 
-        assertThat( filter.include( artifact ), is( false ) );
+        assertThat(filter.include(artifact), is(false));
     }
 
     @Test
-    public void testExcludeNoMatch()
-    {
+    void testExcludeNoMatch() {
         Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "org.apache.maven" );
-        exclusion.setArtifactId( "maven-model" );
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Collections.singletonList( exclusion ) );
+        exclusion.setGroupId("org.apache.maven");
+        exclusion.setArtifactId("maven-model");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
 
-        assertThat( filter.include( artifact ), is( true ) );
+        assertThat(filter.include(artifact), is(true));
     }
 
     @Test
-    public void testExcludeGroupIdWildcard()
-    {
+    void testExcludeGroupIdWildcard() {
         Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "*" );
-        exclusion.setArtifactId( "maven-core" );
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Collections.singletonList( exclusion ) );
+        exclusion.setGroupId("*");
+        exclusion.setArtifactId("maven-core");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
 
-        assertThat( filter.include( artifact ), is( false ) );
+        assertThat(filter.include(artifact), is(false));
     }
 
-
     @Test
-    public void testExcludeGroupIdWildcardNoMatch()
-    {
+    void testExcludeGroupIdWildcardNoMatch() {
         Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "*" );
-        exclusion.setArtifactId( "maven-compat" );
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Collections.singletonList( exclusion ) );
+        exclusion.setGroupId("*");
+        exclusion.setArtifactId("maven-compat");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
 
-        assertThat( filter.include( artifact ), is( true ) );
+        assertThat(filter.include(artifact), is(true));
     }
 
     @Test
-    public void testExcludeArtifactIdWildcard()
-    {
+    void testExcludeArtifactIdWildcard() {
         Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "org.apache.maven" );
-        exclusion.setArtifactId( "*" );
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Collections.singletonList( exclusion ) );
+        exclusion.setGroupId("org.apache.maven");
+        exclusion.setArtifactId("*");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
 
-        assertThat( filter.include( artifact ), is( false ) );
+        assertThat(filter.include(artifact), is(false));
     }
 
     @Test
-    public void testExcludeArtifactIdWildcardNoMatch()
-    {
+    void testExcludeArtifactIdWildcardNoMatch() {
         Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "org.apache.groovy" );
-        exclusion.setArtifactId( "*" );
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Collections.singletonList( exclusion ) );
+        exclusion.setGroupId("org.apache.groovy");
+        exclusion.setArtifactId("*");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
 
-        assertThat( filter.include( artifact ), is( true ) );
+        assertThat(filter.include(artifact), is(true));
     }
 
     @Test
-    public void testExcludeAllWildcard()
-    {
+    void testExcludeAllWildcard() {
         Exclusion exclusion = new Exclusion();
-        exclusion.setGroupId( "*" );
-        exclusion.setArtifactId( "*" );
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Collections.singletonList( exclusion ) );
+        exclusion.setGroupId("*");
+        exclusion.setArtifactId("*");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
 
-        assertThat( filter.include( artifact ), is( false ) );
+        assertThat(filter.include(artifact), is(false));
     }
 
     @Test
-    public void testMultipleExclusionsExcludeArtifactIdWildcard()
-    {
+    void testMultipleExclusionsExcludeArtifactIdWildcard() {
         Exclusion exclusion1 = new Exclusion();
-        exclusion1.setGroupId( "org.apache.groovy" );
-        exclusion1.setArtifactId( "*" );
+        exclusion1.setGroupId("org.apache.groovy");
+        exclusion1.setArtifactId("*");
 
         Exclusion exclusion2 = new Exclusion();
-        exclusion2.setGroupId( "org.apache.maven" );
-        exclusion2.setArtifactId( "maven-core" );
+        exclusion2.setGroupId("org.apache.maven");
+        exclusion2.setArtifactId("maven-core");
 
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Arrays.asList( exclusion1, exclusion2 ) );
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Arrays.asList(exclusion1, exclusion2));
 
-        assertThat( filter.include( artifact ), is( false ) );
+        assertThat(filter.include(artifact), is(false));
     }
 
     @Test
-    public void testMultipleExclusionsExcludeGroupIdWildcard()
-    {
+    void testMultipleExclusionsExcludeGroupIdWildcard() {
         Exclusion exclusion1 = new Exclusion();
-        exclusion1.setGroupId( "*" );
-        exclusion1.setArtifactId( "maven-model" );
+        exclusion1.setGroupId("*");
+        exclusion1.setArtifactId("maven-model");
 
         Exclusion exclusion2 = new Exclusion();
-        exclusion2.setGroupId( "org.apache.maven" );
-        exclusion2.setArtifactId( "maven-core" );
+        exclusion2.setGroupId("org.apache.maven");
+        exclusion2.setArtifactId("maven-core");
 
-        ExclusionArtifactFilter filter = new ExclusionArtifactFilter( Arrays.asList( exclusion1, exclusion2 ) );
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Arrays.asList(exclusion1, exclusion2));
 
-        assertThat( filter.include( artifact ), is( false ) );
+        assertThat(filter.include(artifact), is(false));
     }
-}
\ No newline at end of file
+
+    @Test
+    void testExcludeWithGlob() {
+        Exclusion exclusion = new Exclusion();
+        exclusion.setGroupId("*");
+        exclusion.setArtifactId("maven-*");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
+
+        assertThat(filter.include(artifact), is(false));
+        assertThat(filter.include(artifact2), is(true));
+    }
+
+    @Test
+    void testExcludeWithGlobStar() {
+        Exclusion exclusion = new Exclusion();
+        exclusion.setGroupId("**");
+        exclusion.setArtifactId("maven-**");
+        ExclusionArtifactFilter filter = new ExclusionArtifactFilter(Collections.singletonList(exclusion));
+
+        assertThat(filter.include(artifact), is(false));
+        assertThat(filter.include(artifact2), is(true));
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/classrealm/DefaultClassRealmManagerTest.java b/maven-core/src/test/java/org/apache/maven/classrealm/DefaultClassRealmManagerTest.java
new file mode 100644
index 0000000..f1908ad
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/classrealm/DefaultClassRealmManagerTest.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.classrealm;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import org.apache.maven.extension.internal.CoreExports;
+import org.apache.maven.model.Model;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.PlexusContainerException;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.eclipse.aether.artifact.Artifact;
+import org.junit.jupiter.api.Test;
+import org.mockito.InOrder;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.endsWith;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.calls;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author Sebastien Doyon
+ */
+class DefaultClassRealmManagerTest {
+
+    private DefaultClassRealmManager newDefaultClassRealmManager(PlexusContainer container) {
+        HashSet<String> exportedPackages = new HashSet<String>();
+        exportedPackages.add("group1:artifact1");
+
+        return new DefaultClassRealmManager(
+                container,
+                new ArrayList<ClassRealmManagerDelegate>(),
+                new CoreExports(new ClassRealm(null, "test", null), new HashSet<String>(), exportedPackages));
+    }
+
+    private List<Artifact> newTestArtifactList() {
+        List<Artifact> artifacts = new ArrayList<Artifact>();
+
+        Artifact artifact = mock(Artifact.class);
+        when(artifact.getFile()).thenReturn(new File(new File("local/repository"), "some/path"));
+        when(artifact.getGroupId()).thenReturn("group1");
+        when(artifact.getArtifactId()).thenReturn("artifact1");
+        when(artifact.getExtension()).thenReturn("ext");
+        when(artifact.getClassifier()).thenReturn("classifier1");
+        when(artifact.getVersion()).thenReturn("1");
+        artifacts.add(artifact);
+
+        Artifact artifact2 = mock(Artifact.class);
+        when(artifact2.getFile()).thenReturn(null);
+        when(artifact2.getGroupId()).thenReturn("group1");
+        when(artifact2.getArtifactId()).thenReturn("artifact2");
+        when(artifact2.getExtension()).thenReturn("ext");
+        when(artifact2.getClassifier()).thenReturn("classifier1");
+        when(artifact2.getVersion()).thenReturn("1");
+        artifacts.add(artifact2);
+
+        return artifacts;
+    }
+
+    private Model newTestModel() {
+        Model model = new Model();
+        model.setGroupId("modelGroup1");
+        model.setArtifactId("modelArtifact1");
+        model.setVersion("modelVersion1");
+
+        return model;
+    }
+
+    @Test
+    void testDebugEnabled() throws PlexusContainerException {
+        Logger logger = mock(Logger.class);
+        when(logger.isDebugEnabled()).thenReturn(true);
+
+        DefaultClassRealmManager classRealmManager;
+        ClassRealm classRealm;
+
+        InOrder verifier = inOrder(logger);
+
+        PlexusContainer container = new DefaultPlexusContainer();
+
+        try (MockedStatic<LoggerFactory> mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) {
+            mockedLoggerFactory
+                    .when(() -> LoggerFactory.getLogger(DefaultClassRealmManager.class))
+                    .thenReturn(logger);
+
+            classRealmManager = newDefaultClassRealmManager(container);
+            classRealm = classRealmManager.createProjectRealm(newTestModel(), newTestArtifactList());
+        }
+
+        assertEquals(classRealmManager.getMavenApiRealm(), classRealm.getParentClassLoader());
+        assertEquals("project>modelGroup1:modelArtifact1:modelVersion1", classRealm.getId());
+        assertEquals(1, classRealm.getURLs().length);
+        assertThat(classRealm.getURLs()[0].getPath(), endsWith("local/repository/some/path"));
+
+        verifier.verify(logger, calls(1)).debug("Importing foreign packages into class realm {}", "maven.api");
+        verifier.verify(logger, calls(1)).debug("  Imported: {} < {}", "group1:artifact1", "test");
+        verifier.verify(logger, calls(1)).debug("  Excluded: {}", "group1:artifact2:ext:classifier1:null");
+        verifier.verify(logger, calls(1))
+                .debug("Populating class realm {}", "project>modelGroup1:modelArtifact1:modelVersion1");
+        verifier.verify(logger, calls(1)).debug("  Included: {}", "group1:artifact1:ext:classifier1:null");
+    }
+
+    @Test
+    void testDebugDisabled() throws PlexusContainerException {
+        Logger logger = mock(Logger.class);
+        when(logger.isDebugEnabled()).thenReturn(false);
+
+        DefaultClassRealmManager classRealmManager;
+        ClassRealm classRealm;
+
+        InOrder verifier = inOrder(logger);
+
+        PlexusContainer container = new DefaultPlexusContainer();
+
+        try (MockedStatic<LoggerFactory> mockedLoggerFactory = Mockito.mockStatic(LoggerFactory.class)) {
+            mockedLoggerFactory
+                    .when(() -> LoggerFactory.getLogger(DefaultClassRealmManager.class))
+                    .thenReturn(logger);
+
+            classRealmManager = newDefaultClassRealmManager(container);
+            classRealm = classRealmManager.createProjectRealm(newTestModel(), newTestArtifactList());
+        }
+
+        assertEquals(classRealmManager.getMavenApiRealm(), classRealm.getParentClassLoader());
+        assertEquals("project>modelGroup1:modelArtifact1:modelVersion1", classRealm.getId());
+        assertEquals(1, classRealm.getURLs().length);
+        assertThat(classRealm.getURLs()[0].getPath(), endsWith("local/repository/some/path"));
+
+        verifier.verify(logger, calls(1)).debug("Importing foreign packages into class realm {}", "maven.api");
+        verifier.verify(logger, calls(1)).debug("  Imported: {} < {}", "group1:artifact1", "test");
+        verifier.verify(logger, calls(1))
+                .debug("Populating class realm {}", "project>modelGroup1:modelArtifact1:modelVersion1");
+        verifier.verify(logger, never()).debug("  Included: {}", "group1:artifact1:ext:classifier1:null");
+        verifier.verify(logger, never()).debug("  Excluded: {}", "group1:artifact2:ext:classifier1:null");
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorPathTest.java b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorPathTest.java
new file mode 100644
index 0000000..165473f
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorPathTest.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.configuration;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.File;
+import java.io.StringReader;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.maven.configuration.internal.DefaultBeanConfigurator;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ */
+class DefaultBeanConfiguratorPathTest {
+
+    private BeanConfigurator configurator;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        configurator = new DefaultBeanConfigurator();
+    }
+
+    @AfterEach
+    void tearDown() throws Exception {
+        configurator = null;
+    }
+
+    private Xpp3Dom toConfig(String xml) {
+        try {
+            return new Xpp3Dom(XmlNodeBuilder.build(
+                    new StringReader("<configuration>" + xml + "</configuration>"),
+                    (XmlNodeBuilder.InputLocationBuilderStax) null));
+        } catch (XMLStreamException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    @Test
+    void testMinimal() throws BeanConfigurationException {
+        SomeBean bean = new SomeBean();
+
+        Xpp3Dom config = toConfig("<file>test</file>");
+
+        DefaultBeanConfigurationRequest request = new DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+
+        configurator.configureBean(request);
+
+        assertEquals(Paths.get("test"), bean.file);
+    }
+
+    @Test
+    void testPreAndPostProcessing() throws BeanConfigurationException {
+        SomeBean bean = new SomeBean();
+
+        Xpp3Dom config = toConfig("<file>${test}</file>");
+
+        BeanConfigurationValuePreprocessor preprocessor = (value, type) -> {
+            if (value != null && value.startsWith("${") && value.endsWith("}")) {
+                return value.substring(2, value.length() - 1);
+            }
+            return value;
+        };
+
+        BeanConfigurationPathTranslator translator = path -> new File("base", path.getPath()).getAbsoluteFile();
+
+        DefaultBeanConfigurationRequest request = new DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config);
+        request.setValuePreprocessor(preprocessor).setPathTranslator(translator);
+
+        configurator.configureBean(request);
+
+        assertEquals(Paths.get("base/test").toAbsolutePath(), bean.file);
+    }
+
+    @Test
+    void testChildConfigurationElement() throws BeanConfigurationException {
+        SomeBean bean = new SomeBean();
+
+        Xpp3Dom config = toConfig("<wrapper><file>test</file></wrapper>");
+
+        DefaultBeanConfigurationRequest request = new DefaultBeanConfigurationRequest();
+        request.setBean(bean).setConfiguration(config, "wrapper");
+
+        configurator.configureBean(request);
+
+        assertEquals(Paths.get("test"), bean.file);
+    }
+
+    static class SomeBean {
+
+        Path file;
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java
index 3dd3eff..ea9b8a8 100644
--- a/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/configuration/DefaultBeanConfiguratorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.configuration;
+
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
-import java.io.IOException;
 import java.io.StringReader;
 
 import org.apache.maven.configuration.internal.DefaultBeanConfigurator;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
-import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -34,104 +33,85 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
- * @author Benjamin Bentmann
  */
-public class DefaultBeanConfiguratorTest
-{
+class DefaultBeanConfiguratorTest {
 
     private BeanConfigurator configurator;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
+    void setUp() throws Exception {
         configurator = new DefaultBeanConfigurator();
     }
 
     @AfterEach
-    public void tearDown()
-        throws Exception
-    {
+    void tearDown() throws Exception {
         configurator = null;
     }
 
-    private Xpp3Dom toConfig( String xml )
-    {
-        try
-        {
-            return Xpp3DomBuilder.build( new StringReader( "<configuration>" + xml + "</configuration>" ) );
-        }
-        catch ( XmlPullParserException | IOException e )
-        {
-            throw new IllegalArgumentException( e );
+    private Xpp3Dom toConfig(String xml) {
+        try {
+            return new Xpp3Dom(XmlNodeBuilder.build(
+                    new StringReader("<configuration>" + xml + "</configuration>"),
+                    (XmlNodeBuilder.InputLocationBuilderStax) null));
+        } catch (XMLStreamException e) {
+            throw new IllegalArgumentException(e);
         }
     }
 
     @Test
-    public void testMinimal()
-        throws BeanConfigurationException
-    {
+    void testMinimal() throws BeanConfigurationException {
         SomeBean bean = new SomeBean();
 
-        Xpp3Dom config = toConfig( "<file>test</file>" );
+        Xpp3Dom config = toConfig("<file>test</file>");
 
         DefaultBeanConfigurationRequest request = new DefaultBeanConfigurationRequest();
-        request.setBean( bean ).setConfiguration( config );
+        request.setBean(bean).setConfiguration(config);
 
-        configurator.configureBean( request );
+        configurator.configureBean(request);
 
-        assertEquals( new File( "test" ), bean.file );
+        assertEquals(new File("test"), bean.file);
     }
 
     @Test
-    public void testPreAndPostProcessing()
-        throws BeanConfigurationException
-    {
+    void testPreAndPostProcessing() throws BeanConfigurationException {
         SomeBean bean = new SomeBean();
 
-        Xpp3Dom config = toConfig( "<file>${test}</file>" );
+        Xpp3Dom config = toConfig("<file>${test}</file>");
 
-        BeanConfigurationValuePreprocessor preprocessor = ( value, type ) ->
-        {
-            if ( value != null && value.startsWith( "${" ) && value.endsWith( "}" ) )
-            {
-                return value.substring( 2, value.length() - 1 );
+        BeanConfigurationValuePreprocessor preprocessor = (value, type) -> {
+            if (value != null && value.startsWith("${") && value.endsWith("}")) {
+                return value.substring(2, value.length() - 1);
             }
             return value;
         };
 
-        BeanConfigurationPathTranslator translator = path -> new File( "base", path.getPath() ).getAbsoluteFile();
+        BeanConfigurationPathTranslator translator = path -> new File("base", path.getPath()).getAbsoluteFile();
 
         DefaultBeanConfigurationRequest request = new DefaultBeanConfigurationRequest();
-        request.setBean( bean ).setConfiguration( config );
-        request.setValuePreprocessor( preprocessor ).setPathTranslator( translator );
+        request.setBean(bean).setConfiguration(config);
+        request.setValuePreprocessor(preprocessor).setPathTranslator(translator);
 
-        configurator.configureBean( request );
+        configurator.configureBean(request);
 
-        assertEquals( new File( "base/test" ).getAbsoluteFile(), bean.file );
+        assertEquals(new File("base/test").getAbsoluteFile(), bean.file);
     }
 
     @Test
-    public void testChildConfigurationElement()
-        throws BeanConfigurationException
-    {
+    void testChildConfigurationElement() throws BeanConfigurationException {
         SomeBean bean = new SomeBean();
 
-        Xpp3Dom config = toConfig( "<wrapper><file>test</file></wrapper>" );
+        Xpp3Dom config = toConfig("<wrapper><file>test</file></wrapper>");
 
         DefaultBeanConfigurationRequest request = new DefaultBeanConfigurationRequest();
-        request.setBean( bean ).setConfiguration( config, "wrapper" );
+        request.setBean(bean).setConfiguration(config, "wrapper");
 
-        configurator.configureBean( request );
+        configurator.configureBean(request);
 
-        assertEquals( new File( "test" ), bean.file );
+        assertEquals(new File("test"), bean.file);
     }
 
-    static class SomeBean
-    {
+    static class SomeBean {
 
         File file;
-
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java b/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java
index 48cdb2f..f3f6075 100644
--- a/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.exception;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.exception;
 
 import java.io.IOException;
 import java.net.ConnectException;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.MojoExecutionException;
-
 import org.apache.maven.plugin.PluginContainerException;
 import org.apache.maven.plugin.PluginExecutionException;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
@@ -35,10 +34,8 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
- * @author <a href="mailto:baerrach@apache.org">Barrie Treloar</a>
  */
-public class DefaultExceptionHandlerTest
-{
+class DefaultExceptionHandlerTest {
     /**
      * Running Maven under JDK7 may cause connection issues because IPv6 is used by default.
      * <p>
@@ -50,56 +47,80 @@
      * </p>
      */
     @Test
-    public void testJdk7ipv6()
-    {
-        ConnectException connEx = new ConnectException( "Connection refused: connect" );
-        IOException ioEx = new IOException( "Unable to establish loopback connection", connEx );
+    void testJdk7ipv6() {
+        ConnectException connEx = new ConnectException("Connection refused: connect");
+        IOException ioEx = new IOException("Unable to establish loopback connection", connEx);
         MojoExecutionException mojoEx =
-            new MojoExecutionException( "Error executing Jetty: Unable to establish loopback connection", ioEx );
+                new MojoExecutionException("Error executing Jetty: Unable to establish loopback connection", ioEx);
 
         ExceptionHandler exceptionHandler = new DefaultExceptionHandler();
-        ExceptionSummary exceptionSummary = exceptionHandler.handleException( mojoEx );
+        ExceptionSummary exceptionSummary = exceptionHandler.handleException(mojoEx);
 
         String expectedReference = "http://cwiki.apache.org/confluence/display/MAVEN/ConnectException";
-        assertEquals( expectedReference, exceptionSummary.getReference() );
-
+        assertEquals(expectedReference, exceptionSummary.getReference());
     }
 
     @Test
-    public void testHandleExceptionAetherClassNotFound()
-    {
-        Throwable cause2 = new NoClassDefFoundError( "org/sonatype/aether/RepositorySystem" );
+    void testHandleExceptionAetherClassNotFound() {
+        Throwable cause2 = new NoClassDefFoundError("org/sonatype/aether/RepositorySystem");
         Plugin plugin = new Plugin();
-        Exception cause = new PluginContainerException( plugin, null, null, cause2 );
+        Exception cause = new PluginContainerException(plugin, null, null, cause2);
         PluginDescriptor pluginDescriptor = new PluginDescriptor();
         MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setPluginDescriptor( pluginDescriptor );
+        mojoDescriptor.setPluginDescriptor(pluginDescriptor);
         MojoExecution mojoExecution = new MojoExecution(mojoDescriptor);
-        Throwable exception = new PluginExecutionException( mojoExecution, null, cause );
+        Throwable exception = new PluginExecutionException(mojoExecution, null, cause);
 
         DefaultExceptionHandler handler = new DefaultExceptionHandler();
-        ExceptionSummary summary = handler.handleException( exception );
+        ExceptionSummary summary = handler.handleException(exception);
 
         String expectedReference = "http://cwiki.apache.org/confluence/display/MAVEN/AetherClassNotFound";
-        assertEquals( expectedReference, summary.getReference() );
+        assertEquals(expectedReference, summary.getReference());
     }
 
     @Test
-    public void testHandleExceptionNoClassDefFoundErrorNull()
-    {
+    void testHandleExceptionNoClassDefFoundErrorNull() {
         Throwable cause2 = new NoClassDefFoundError();
         Plugin plugin = new Plugin();
-        Exception cause = new PluginContainerException( plugin, null, null, cause2 );
+        Exception cause = new PluginContainerException(plugin, null, null, cause2);
         PluginDescriptor pluginDescriptor = new PluginDescriptor();
         MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setPluginDescriptor( pluginDescriptor );
+        mojoDescriptor.setPluginDescriptor(pluginDescriptor);
         MojoExecution mojoExecution = new MojoExecution(mojoDescriptor);
-        Throwable exception = new PluginExecutionException( mojoExecution, null, cause );
+        Throwable exception = new PluginExecutionException(mojoExecution, null, cause);
 
         DefaultExceptionHandler handler = new DefaultExceptionHandler();
-        ExceptionSummary summary = handler.handleException( exception );
+        ExceptionSummary summary = handler.handleException(exception);
 
         String expectedReference = "http://cwiki.apache.org/confluence/display/MAVEN/PluginContainerException";
-        assertEquals( expectedReference, summary.getReference() );
+        assertEquals(expectedReference, summary.getReference());
+    }
+
+    @Test
+    void testHandleExceptionLoopInCause() {
+        // Some broken exception that does return "this" as getCause
+        AtomicReference<Throwable> causeRef = new AtomicReference<>(null);
+        Exception cause2 = new RuntimeException("loop") {
+            @Override
+            public synchronized Throwable getCause() {
+                return causeRef.get();
+            }
+        };
+        causeRef.set(cause2);
+
+        Plugin plugin = new Plugin();
+        Exception cause = new PluginContainerException(plugin, null, null, cause2);
+        cause2.initCause(cause);
+        PluginDescriptor pluginDescriptor = new PluginDescriptor();
+        MojoDescriptor mojoDescriptor = new MojoDescriptor();
+        mojoDescriptor.setPluginDescriptor(pluginDescriptor);
+        MojoExecution mojoExecution = new MojoExecution(mojoDescriptor);
+        Throwable exception = new PluginExecutionException(mojoExecution, null, cause);
+
+        DefaultExceptionHandler handler = new DefaultExceptionHandler();
+        ExceptionSummary summary = handler.handleException(exception);
+
+        String expectedReference = "http://cwiki.apache.org/confluence/display/MAVEN/PluginContainerException";
+        assertEquals(expectedReference, summary.getReference());
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzerTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzerTest.java
index eba0e4d..6ed0ecf 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionAnalyzerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.execution;
+
+import java.util.Optional;
 
 import org.apache.maven.lifecycle.LifecycleExecutionException;
 import org.apache.maven.model.Dependency;
@@ -25,127 +26,114 @@
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import java.util.Optional;
-
 import static java.util.Arrays.asList;
 import static java.util.Collections.singletonList;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 
-public class DefaultBuildResumptionAnalyzerTest
-{
+class DefaultBuildResumptionAnalyzerTest {
     private final DefaultBuildResumptionAnalyzer analyzer = new DefaultBuildResumptionAnalyzer();
 
     private MavenExecutionResult executionResult;
 
     @BeforeEach
-    public void before() {
+    void before() {
         executionResult = new DefaultMavenExecutionResult();
     }
 
     @Test
-    public void resumeFromGetsDetermined()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        executionResult.setTopologicallySortedProjects( asList( projectA, projectB ) );
+    void resumeFromGetsDetermined() {
+        MavenProject projectA = createSucceededMavenProject("A");
+        MavenProject projectB = createFailedMavenProject("B");
+        executionResult.setTopologicallySortedProjects(asList(projectA, projectB));
 
-        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData(executionResult);
 
-        assertThat( result.isPresent(), is( true ) );
-        assertThat( result.get().getRemainingProjects(), is( asList ( "test:B" ) ) );
+        assertThat(result.isPresent(), is(true));
+        assertThat(result.get().getRemainingProjects(), is(asList("test:B")));
     }
 
     @Test
-    public void resumeFromIsIgnoredWhenFirstProjectFails()
-    {
-        MavenProject projectA = createFailedMavenProject( "A" );
-        MavenProject projectB = createMavenProject( "B" );
-        executionResult.setTopologicallySortedProjects( asList( projectA, projectB ) );
+    void resumeFromIsIgnoredWhenFirstProjectFails() {
+        MavenProject projectA = createFailedMavenProject("A");
+        MavenProject projectB = createMavenProject("B");
+        executionResult.setTopologicallySortedProjects(asList(projectA, projectB));
 
-        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData(executionResult);
 
-        assertThat( result.isPresent(), is( false ) );
+        assertThat(result.isPresent(), is(false));
     }
 
     @Test
-    public void projectsSucceedingAfterFailedProjectsAreExcluded()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        MavenProject projectC = createSucceededMavenProject( "C" );
-        executionResult.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
+    void projectsSucceedingAfterFailedProjectsAreExcluded() {
+        MavenProject projectA = createSucceededMavenProject("A");
+        MavenProject projectB = createFailedMavenProject("B");
+        MavenProject projectC = createSucceededMavenProject("C");
+        executionResult.setTopologicallySortedProjects(asList(projectA, projectB, projectC));
 
-        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData(executionResult);
 
-        assertThat( result.isPresent(), is( true ) );
-        assertThat( result.get().getRemainingProjects(), is( asList( "test:B" ) ) );
+        assertThat(result.isPresent(), is(true));
+        assertThat(result.get().getRemainingProjects(), is(asList("test:B")));
     }
 
     @Test
-    public void projectsDependingOnFailedProjectsAreNotExcluded()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        MavenProject projectC = createSkippedMavenProject( "C" );
-        projectC.setDependencies( singletonList( toDependency( projectB ) ) );
-        executionResult.setTopologicallySortedProjects( asList( projectA, projectB, projectC ) );
+    void projectsDependingOnFailedProjectsAreNotExcluded() {
+        MavenProject projectA = createSucceededMavenProject("A");
+        MavenProject projectB = createFailedMavenProject("B");
+        MavenProject projectC = createSkippedMavenProject("C");
+        projectC.setDependencies(singletonList(toDependency(projectB)));
+        executionResult.setTopologicallySortedProjects(asList(projectA, projectB, projectC));
 
-        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData(executionResult);
 
-        assertThat( result.isPresent(), is( true ) );
-        assertThat( result.get().getRemainingProjects(), is( asList( "test:B", "test:C" ) ) );
+        assertThat(result.isPresent(), is(true));
+        assertThat(result.get().getRemainingProjects(), is(asList("test:B", "test:C")));
     }
 
     @Test
-    public void projectsFailingAfterAnotherFailedProjectAreNotExcluded()
-    {
-        MavenProject projectA = createSucceededMavenProject( "A" );
-        MavenProject projectB = createFailedMavenProject( "B" );
-        MavenProject projectC = createSucceededMavenProject( "C" );
-        MavenProject projectD = createFailedMavenProject( "D" );
-        executionResult.setTopologicallySortedProjects( asList( projectA, projectB, projectC, projectD ) );
+    void projectsFailingAfterAnotherFailedProjectAreNotExcluded() {
+        MavenProject projectA = createSucceededMavenProject("A");
+        MavenProject projectB = createFailedMavenProject("B");
+        MavenProject projectC = createSucceededMavenProject("C");
+        MavenProject projectD = createFailedMavenProject("D");
+        executionResult.setTopologicallySortedProjects(asList(projectA, projectB, projectC, projectD));
 
-        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData( executionResult );
+        Optional<BuildResumptionData> result = analyzer.determineBuildResumptionData(executionResult);
 
-        assertThat( result.isPresent(), is( true ) );
-        assertThat( result.get().getRemainingProjects(), is( asList ( "test:B", "test:D" ) ) );
+        assertThat(result.isPresent(), is(true));
+        assertThat(result.get().getRemainingProjects(), is(asList("test:B", "test:D")));
     }
 
-    private MavenProject createMavenProject( String artifactId )
-    {
+    private MavenProject createMavenProject(String artifactId) {
         MavenProject project = new MavenProject();
-        project.setGroupId( "test" );
-        project.setArtifactId( artifactId );
+        project.setGroupId("test");
+        project.setArtifactId(artifactId);
         return project;
     }
 
-    private Dependency toDependency(MavenProject mavenProject )
-    {
+    private Dependency toDependency(MavenProject mavenProject) {
         Dependency dependency = new Dependency();
-        dependency.setGroupId( mavenProject.getGroupId() );
-        dependency.setArtifactId( mavenProject.getArtifactId() );
-        dependency.setVersion( mavenProject.getVersion() );
+        dependency.setGroupId(mavenProject.getGroupId());
+        dependency.setArtifactId(mavenProject.getArtifactId());
+        dependency.setVersion(mavenProject.getVersion());
         return dependency;
     }
 
-    private MavenProject createSkippedMavenProject( String artifactId )
-    {
-        return createMavenProject( artifactId );
+    private MavenProject createSkippedMavenProject(String artifactId) {
+        return createMavenProject(artifactId);
     }
 
-    private MavenProject createSucceededMavenProject( String artifactId )
-    {
-        MavenProject project = createMavenProject( artifactId );
-        executionResult.addBuildSummary( new BuildSuccess( project, 0 ) );
+    private MavenProject createSucceededMavenProject(String artifactId) {
+        MavenProject project = createMavenProject(artifactId);
+        executionResult.addBuildSummary(new BuildSuccess(project, 0));
         return project;
     }
 
-    private MavenProject createFailedMavenProject( String artifactId )
-    {
-        MavenProject project = createMavenProject( artifactId );
-        executionResult.addBuildSummary( new BuildFailure( project, 0, new Exception() ) );
-        executionResult.addException( new LifecycleExecutionException( "", project ) );
+    private MavenProject createFailedMavenProject(String artifactId) {
+        MavenProject project = createMavenProject(artifactId);
+        executionResult.addBuildSummary(new BuildFailure(project, 0, new Exception()));
+        executionResult.addException(new LifecycleExecutionException("", project));
         return project;
     }
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
index ce7ab6a..dc7be6b 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultBuildResumptionDataRepositoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,88 +16,87 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.model.Build;
-import org.apache.maven.project.MavenProject;
-import org.junit.jupiter.api.Test;
+package org.apache.maven.execution;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
 
+import org.apache.maven.model.Build;
+import org.apache.maven.project.MavenProject;
+import org.junit.jupiter.api.Test;
+
 import static java.util.Collections.singleton;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.is;
 
-public class DefaultBuildResumptionDataRepositoryTest
-{
+class DefaultBuildResumptionDataRepositoryTest {
     private final DefaultBuildResumptionDataRepository repository = new DefaultBuildResumptionDataRepository();
 
     @Test
-    public void resumeFromPropertyGetsApplied()
-    {
+    void resumeFromPropertyGetsApplied() {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
         Properties properties = new Properties();
-        properties.setProperty( "remainingProjects", ":module-a" );
+        properties.setProperty("remainingProjects", ":module-a");
 
-        repository.applyResumptionProperties( request, properties );
+        repository.applyResumptionProperties(request, properties);
 
-        assertThat( request.getProjectActivation().getOptionalActiveProjectSelectors(), is( singleton( ":module-a" ) ) );
+        assertThat(request.getProjectActivation().getOptionalActiveProjectSelectors(), is(singleton(":module-a")));
     }
 
     @Test
-    public void resumeFromPropertyDoesNotOverrideExistingRequestParameters()
-    {
+    void resumeFromPropertyDoesNotOverrideExistingRequestParameters() {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
-        request.setResumeFrom( ":module-b" );
+        request.setResumeFrom(":module-b");
         Properties properties = new Properties();
-        properties.setProperty( "remainingProjects", ":module-a" );
+        properties.setProperty("remainingProjects", ":module-a");
 
-        repository.applyResumptionProperties( request, properties );
+        repository.applyResumptionProperties(request, properties);
 
-        assertThat( request.getResumeFrom(), is( ":module-b" ) );
+        assertThat(request.getResumeFrom(), is(":module-b"));
     }
 
     @Test
-    public void projectsFromPropertyGetsAddedToExistingRequestParameters()
-    {
+    void projectsFromPropertyGetsAddedToExistingRequestParameters() {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
         List<String> selectedProjects = new ArrayList<>();
-        selectedProjects.add( ":module-a" );
-        request.setSelectedProjects( selectedProjects );
+        selectedProjects.add(":module-a");
+        request.setSelectedProjects(selectedProjects);
         Properties properties = new Properties();
-        properties.setProperty( "remainingProjects", ":module-b, :module-c" );
+        properties.setProperty("remainingProjects", ":module-b, :module-c");
 
-        repository.applyResumptionProperties( request, properties );
+        repository.applyResumptionProperties(request, properties);
 
-        assertThat( request.getProjectActivation().getOptionalActiveProjectSelectors(), containsInAnyOrder( ":module-a", ":module-b", ":module-c" ) );
+        assertThat(
+                request.getProjectActivation().getOptionalActiveProjectSelectors(),
+                containsInAnyOrder(":module-a", ":module-b", ":module-c"));
     }
 
     @Test
-    public void selectedProjectsAreNotAddedWhenPropertyValueIsEmpty()
-    {
+    void selectedProjectsAreNotAddedWhenPropertyValueIsEmpty() {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
         Properties properties = new Properties();
-        properties.setProperty( "remainingProjects", "" );
+        properties.setProperty("remainingProjects", "");
 
-        repository.applyResumptionProperties( request, properties );
+        repository.applyResumptionProperties(request, properties);
 
-        assertThat( request.getProjectActivation().getOptionalActiveProjectSelectors(), is( empty() ) );
+        assertThat(request.getProjectActivation().getOptionalActiveProjectSelectors(), is(empty()));
     }
 
     @Test
-    public void applyResumptionData_shouldLoadData()
-    {
+    void applyResumptionData_shouldLoadData() {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
         Build build = new Build();
-        build.setDirectory( "src/test/resources/org/apache/maven/execution/" );
+        build.setDirectory("src/test/resources/org/apache/maven/execution/");
         MavenProject rootProject = new MavenProject();
-        rootProject.setBuild( build );
+        rootProject.setBuild(build);
 
-        repository.applyResumptionData( request,  rootProject );
+        repository.applyResumptionData(request, rootProject);
 
-        assertThat( request.getProjectActivation().getOptionalActiveProjectSelectors(), containsInAnyOrder( "example:module-c" ) );
+        assertThat(
+                request.getProjectActivation().getOptionalActiveProjectSelectors(),
+                containsInAnyOrder("example:module-c"));
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulatorTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulatorTest.java
index 02be60e..3340299 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulatorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionRequestPopulatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,11 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.List;
+package org.apache.maven.execution;
 
 import javax.inject.Inject;
 
+import java.util.List;
+
 import org.apache.maven.artifact.repository.ArtifactRepository;
 import org.apache.maven.settings.Profile;
 import org.apache.maven.settings.Repository;
@@ -33,34 +32,31 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 @PlexusTest
-public class DefaultMavenExecutionRequestPopulatorTest
-{
+class DefaultMavenExecutionRequestPopulatorTest {
     @Inject
     MavenExecutionRequestPopulator testee;
 
     @Test
-    public void testPluginRepositoryInjection()
-        throws Exception
-    {
+    void testPluginRepositoryInjection() throws Exception {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest();
 
         Repository r = new Repository();
-        r.setId( "test" );
-        r.setUrl( "file:///test" );
+        r.setId("test");
+        r.setUrl("file:///test");
 
         Profile p = new Profile();
-        p.setId( "test" );
-        p.addPluginRepository( r );
+        p.setId("test");
+        p.addPluginRepository(r);
 
         Settings settings = new Settings();
-        settings.addProfile( p );
-        settings.addActiveProfile( p.getId() );
+        settings.addProfile(p);
+        settings.addActiveProfile(p.getId());
 
-        testee.populateFromSettings( request, settings );
+        testee.populateFromSettings(request, settings);
 
         List<ArtifactRepository> repositories = request.getPluginArtifactRepositories();
-        assertEquals( 1, repositories.size() );
-        assertEquals( r.getId(), repositories.get( 0 ).getId() );
-        assertEquals( r.getUrl(), repositories.get( 0 ).getUrl() );
+        assertEquals(1, repositories.size());
+        assertEquals(r.getId(), repositories.get(0).getId());
+        assertEquals(r.getUrl(), repositories.get(0).getUrl());
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionTest.java b/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionTest.java
index f8f5e0a..605137a 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/DefaultMavenExecutionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.execution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,40 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import static org.hamcrest.Matchers.empty;
-import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNotSame;
-import static org.hamcrest.MatcherAssert.assertThat;
+package org.apache.maven.execution;
 
 import java.util.List;
 
 import org.apache.maven.project.MavenProject;
 import org.junit.jupiter.api.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+
 /**
- * @author Benjamin Bentmann
  */
-public class DefaultMavenExecutionTest
-{
+class DefaultMavenExecutionTest {
     @Test
-    public void testCopyDefault()
-    {
+    void testCopyDefault() {
         MavenExecutionRequest original = new DefaultMavenExecutionRequest();
-        MavenExecutionRequest copy = DefaultMavenExecutionRequest.copy( original );
-        assertNotNull( copy );
-        assertNotSame( copy, original );
+        MavenExecutionRequest copy = DefaultMavenExecutionRequest.copy(original);
+        assertNotNull(copy);
+        assertNotSame(copy, original);
     }
 
     @Test
-    public void testResultWithNullTopologicallySortedProjectsIsEmptyList()
-    {
+    void testResultWithNullTopologicallySortedProjectsIsEmptyList() {
         MavenExecutionResult result = new DefaultMavenExecutionResult();
-        result.setTopologicallySortedProjects( null );
+        result.setTopologicallySortedProjects(null);
         List<MavenProject> projects = result.getTopologicallySortedProjects();
-        assertNotNull( projects );
-        assertThat( projects, is( empty() ) );
+        assertNotNull(projects);
+        assertThat(projects, is(empty()));
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java b/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java
index 0dda050..5e53789 100644
--- a/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java
+++ b/maven-core/src/test/java/org/apache/maven/execution/scope/internal/MojoExecutionScopeTest.java
@@ -1,16 +1,20 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 package org.apache.maven.execution.scope.internal;
 
@@ -26,76 +30,68 @@
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-public class MojoExecutionScopeTest
-{
+class MojoExecutionScopeTest {
     @Test
-    public void testNestedEnter()
-        throws Exception
-    {
+    void testNestedEnter() throws Exception {
         MojoExecutionScope scope = new MojoExecutionScope();
 
         scope.enter();
 
         Object o1 = new Object();
-        scope.seed( Object.class, o1 );
-        assertSame( o1, scope.scope( Key.get( Object.class ), null ).get() );
+        scope.seed(Object.class, o1);
+        assertSame(o1, scope.scope(Key.get(Object.class), null).get());
 
         scope.enter();
         Object o2 = new Object();
-        scope.seed( Object.class, o2 );
-        assertSame( o2, scope.scope( Key.get( Object.class ), null ).get() );
+        scope.seed(Object.class, o2);
+        assertSame(o2, scope.scope(Key.get(Object.class), null).get());
 
         scope.exit();
-        assertSame( o1, scope.scope( Key.get( Object.class ), null ).get() );
+        assertSame(o1, scope.scope(Key.get(Object.class), null).get());
 
         scope.exit();
 
-        assertThrows( IllegalStateException.class, () -> scope.exit() );
+        assertThrows(IllegalStateException.class, () -> scope.exit());
     }
 
     @Test
-    public void testMultiKeyInstance()
-        throws Exception
-    {
+    void testMultiKeyInstance() throws Exception {
         MojoExecutionScope scope = new MojoExecutionScope();
         scope.enter();
 
         final AtomicInteger beforeExecution = new AtomicInteger();
         final AtomicInteger afterExecutionSuccess = new AtomicInteger();
         final AtomicInteger afterExecutionFailure = new AtomicInteger();
-        final WeakMojoExecutionListener instance = new WeakMojoExecutionListener()
-        {
+        final WeakMojoExecutionListener instance = new WeakMojoExecutionListener() {
             @Override
-            public void beforeMojoExecution( MojoExecutionEvent event )
-                throws MojoExecutionException
-            {
+            public void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException {
                 beforeExecution.incrementAndGet();
             }
 
             @Override
-            public void afterMojoExecutionSuccess( MojoExecutionEvent event )
-                throws MojoExecutionException
-            {
+            public void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException {
                 afterExecutionSuccess.incrementAndGet();
             }
 
             @Override
-            public void afterExecutionFailure( MojoExecutionEvent event )
-            {
+            public void afterExecutionFailure(MojoExecutionEvent event) {
                 afterExecutionFailure.incrementAndGet();
             }
         };
-        assertSame( instance, scope.scope( Key.get( Object.class ), () -> instance ).get() );
-        assertSame( instance, scope.scope( Key.get( WeakMojoExecutionListener.class ), () -> instance ).get() );
+        assertSame(instance, scope.scope(Key.get(Object.class), () -> instance).get());
+        assertSame(
+                instance,
+                scope.scope(Key.get(WeakMojoExecutionListener.class), () -> instance)
+                        .get());
 
-        final MojoExecutionEvent event = new MojoExecutionEvent( null, null, null, null );
-        scope.beforeMojoExecution( event );
-        scope.afterMojoExecutionSuccess( event );
-        scope.afterExecutionFailure( event );
+        final MojoExecutionEvent event = new MojoExecutionEvent(null, null, null, null);
+        scope.beforeMojoExecution(event);
+        scope.afterMojoExecutionSuccess(event);
+        scope.afterExecutionFailure(event);
 
-        assertEquals( 1, beforeExecution.get() );
-        assertEquals( 1, afterExecutionSuccess.get() );
-        assertEquals( 1, afterExecutionFailure.get() );
+        assertEquals(1, beforeExecution.get());
+        assertEquals(1, afterExecutionSuccess.get());
+        assertEquals(1, afterExecutionFailure.get());
 
         scope.exit();
     }
diff --git a/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java b/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
index 8ff4711..4bc76e4 100644
--- a/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/graph/DefaultGraphBuilderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.graph;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.graph;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.execution.BuildResumptionDataRepository;
@@ -32,6 +40,7 @@
 import org.apache.maven.model.locator.ModelLocator;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingException;
 import org.apache.maven.project.ProjectBuildingRequest;
 import org.apache.maven.project.ProjectBuildingResult;
 import org.apache.maven.project.collector.DefaultProjectsSelector;
@@ -39,21 +48,12 @@
 import org.apache.maven.project.collector.PomlessCollectionStrategy;
 import org.apache.maven.project.collector.ProjectsSelector;
 import org.apache.maven.project.collector.RequestPomCollectionStrategy;
-import org.codehaus.plexus.util.StringUtils;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
 import static java.util.Arrays.asList;
 import static java.util.Collections.emptyList;
 import static java.util.Collections.singletonList;
@@ -70,8 +70,7 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-class DefaultGraphBuilderTest
-{
+class DefaultGraphBuilderTest {
     /*
     The multi-module structure in this project is displayed as follows:
 
@@ -82,6 +81,7 @@
          module-c
          └─── module-c-1
               module-c-2        (depends on module-b)
+         module-d               (packaging is bom)
      */
     private static final String GROUP_ID = "unittest";
     private static final String PARENT_MODULE = "module-parent";
@@ -89,172 +89,190 @@
     private static final String MODULE_A = "module-a";
     private static final String MODULE_B = "module-b";
     private static final String MODULE_C = "module-c";
+    private static final String MODULE_D = "module-d";
     private static final String MODULE_C_1 = "module-c-1";
     private static final String MODULE_C_2 = "module-c-2";
 
     private DefaultGraphBuilder graphBuilder;
 
-    private final ProjectBuilder projectBuilder = mock( ProjectBuilder.class );
-    private final MavenSession session = mock( MavenSession.class );
-    private final MavenExecutionRequest mavenExecutionRequest = mock( MavenExecutionRequest.class );
+    private final ProjectBuilder projectBuilder = mock(ProjectBuilder.class);
+    private final MavenSession session = mock(MavenSession.class);
+    private final MavenExecutionRequest mavenExecutionRequest = mock(MavenExecutionRequest.class);
 
-    private final ProjectsSelector projectsSelector = new DefaultProjectsSelector( projectBuilder );
+    private final ProjectsSelector projectsSelector = new DefaultProjectsSelector(projectBuilder);
 
     // Not using mocks for these strategies - a mock would just copy the actual implementation.
 
     private final ModelLocator modelLocator = new DefaultModelLocator();
-    private final PomlessCollectionStrategy pomlessCollectionStrategy = new PomlessCollectionStrategy( projectBuilder );
-    private final MultiModuleCollectionStrategy multiModuleCollectionStrategy = new MultiModuleCollectionStrategy( modelLocator, projectsSelector );
-    private final RequestPomCollectionStrategy requestPomCollectionStrategy = new RequestPomCollectionStrategy( projectsSelector );
+    private final PomlessCollectionStrategy pomlessCollectionStrategy = new PomlessCollectionStrategy(projectBuilder);
+    private final MultiModuleCollectionStrategy multiModuleCollectionStrategy =
+            new MultiModuleCollectionStrategy(modelLocator, projectsSelector);
+    private final RequestPomCollectionStrategy requestPomCollectionStrategy =
+            new RequestPomCollectionStrategy(projectsSelector);
 
     private Map<String, MavenProject> artifactIdProjectMap;
 
-    public static Stream<Arguments> parameters()
-    {
+    public static Stream<Arguments> parameters() {
         return Stream.of(
-                scenario( "Full reactor in order" )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_B, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Selected project" )
-                        .activeRequiredProjects( MODULE_B )
-                        .expectResult( MODULE_B ),
-                scenario( "Selected aggregator project (including child modules)" )
-                        .activeRequiredProjects( MODULE_C )
-                        .expectResult( MODULE_C, MODULE_C_1, MODULE_C_2 ),
-                scenario( "Selected aggregator project with non-recursive" )
-                        .activeRequiredProjects( MODULE_C )
+                scenario("Full reactor in order")
+                        .expectResult(
+                                PARENT_MODULE,
+                                MODULE_C,
+                                MODULE_C_1,
+                                MODULE_A,
+                                MODULE_B,
+                                MODULE_C_2,
+                                INDEPENDENT_MODULE),
+                scenario("Selected project").activeRequiredProjects(MODULE_B).expectResult(MODULE_B),
+                scenario("Selected aggregator project (including child modules)")
+                        .activeRequiredProjects(MODULE_C)
+                        .expectResult(MODULE_C, MODULE_C_1, MODULE_C_2),
+                scenario("Selected aggregator project with non-recursive")
+                        .activeRequiredProjects(MODULE_C)
                         .nonRecursive()
-                        .expectResult( MODULE_C ),
-                scenario( "Selected optional project" )
-                        .activeOptionalProjects( MODULE_B )
-                        .expectResult( MODULE_B ),
-                scenario( "Selected missing optional project" )
-                        .activeOptionalProjects( "non-existing-module" )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_B, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Selected missing optional and required project" )
-                        .activeOptionalProjects( "non-existing-module" )
-                        .activeRequiredProjects( MODULE_B )
-                        .expectResult( MODULE_B ),
-                scenario( "Excluded project" )
-                        .inactiveRequiredProjects( MODULE_B )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Excluded optional project" )
-                        .inactiveOptionalProjects( MODULE_B )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Excluded missing optional project" )
-                        .inactiveOptionalProjects( "non-existing-module" )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_B, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Excluded missing optional and required project" )
-                        .inactiveOptionalProjects( "non-existing-module" )
-                        .inactiveRequiredProjects( MODULE_B )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Excluded aggregator project with non-recursive" )
-                        .inactiveRequiredProjects( MODULE_C )
+                        .expectResult(MODULE_C),
+                scenario("Selected optional project")
+                        .activeOptionalProjects(MODULE_B)
+                        .expectResult(MODULE_B),
+                scenario("Selected missing optional project")
+                        .activeOptionalProjects("non-existing-module")
+                        .expectResult(
+                                PARENT_MODULE,
+                                MODULE_C,
+                                MODULE_C_1,
+                                MODULE_A,
+                                MODULE_B,
+                                MODULE_C_2,
+                                INDEPENDENT_MODULE),
+                scenario("Selected missing optional and required project")
+                        .activeOptionalProjects("non-existing-module")
+                        .activeRequiredProjects(MODULE_B)
+                        .expectResult(MODULE_B),
+                scenario("Excluded project")
+                        .inactiveRequiredProjects(MODULE_B)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Excluded optional project")
+                        .inactiveOptionalProjects(MODULE_B)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Excluded missing optional project")
+                        .inactiveOptionalProjects("non-existing-module")
+                        .expectResult(
+                                PARENT_MODULE,
+                                MODULE_C,
+                                MODULE_C_1,
+                                MODULE_A,
+                                MODULE_B,
+                                MODULE_C_2,
+                                INDEPENDENT_MODULE),
+                scenario("Excluded missing optional and required project")
+                        .inactiveOptionalProjects("non-existing-module")
+                        .inactiveRequiredProjects(MODULE_B)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Excluded aggregator project with non-recursive")
+                        .inactiveRequiredProjects(MODULE_C)
                         .nonRecursive()
-                        .expectResult( PARENT_MODULE, MODULE_C_1, MODULE_A, MODULE_B, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Selected and excluded same project" )
-                        .activeRequiredProjects( MODULE_A )
-                        .inactiveRequiredProjects( MODULE_A )
-                        .expectResult( MavenExecutionException.class, "empty reactor" ),
-                scenario( "Excluded aggregator, but selected child" )
-                        .activeRequiredProjects( MODULE_C_1 )
-                        .inactiveRequiredProjects( MODULE_C )
-                        .expectResult( MavenExecutionException.class, "empty reactor" ),
-                scenario( "Project selected with different selector resolves to same project" )
-                        .activeRequiredProjects( GROUP_ID + ":" + MODULE_A )
-                        .inactiveRequiredProjects( MODULE_A )
-                        .expectResult( MavenExecutionException.class, "empty reactor" ),
-                scenario( "Selected and excluded same project, but also selected another project" )
-                        .activeRequiredProjects( MODULE_A, MODULE_B )
-                        .inactiveRequiredProjects( MODULE_A )
-                        .expectResult( MODULE_B ),
-                scenario( "Selected missing project as required and as optional" )
-                        .activeRequiredProjects( "non-existing-module" )
-                        .activeOptionalProjects( "non-existing-module" )
-                        .expectResult( MavenExecutionException.class, "not find the selected project" ),
-                scenario( "Resuming from project" )
-                        .resumeFrom( MODULE_B )
-                        .expectResult( MODULE_B, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Selected project with also make dependencies" )
-                        .activeRequiredProjects( MODULE_C_2 )
-                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_A, MODULE_B, MODULE_C_2 ),
-                scenario( "Selected project with also make dependents" )
-                        .activeRequiredProjects( MODULE_B )
-                        .makeBehavior( REACTOR_MAKE_DOWNSTREAM )
-                        .expectResult( MODULE_B, MODULE_C_2 ),
-                scenario( "Resuming from project with also make dependencies" )
-                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
-                        .resumeFrom( MODULE_C_2 )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_A, MODULE_B, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Selected project with resume from and also make dependency (MNG-4960 IT#1)" )
-                        .activeRequiredProjects( MODULE_C_2 )
-                        .resumeFrom( MODULE_B )
-                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_A, MODULE_B, MODULE_C_2 ),
-                scenario( "Selected project with resume from and also make dependent (MNG-4960 IT#2)" )
-                        .activeRequiredProjects( MODULE_B )
-                        .resumeFrom( MODULE_C_2 )
-                        .makeBehavior( REACTOR_MAKE_DOWNSTREAM )
-                        .expectResult( MODULE_C_2 ),
-                scenario( "Excluding an also make dependency from selectedProject does take its transitive dependency" )
-                        .activeRequiredProjects( MODULE_C_2 )
-                        .inactiveRequiredProjects( MODULE_B )
-                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_A, MODULE_C_2 ),
-                scenario( "Excluding a project also excludes its children" )
-                        .inactiveRequiredProjects( MODULE_C )
-                        .expectResult( PARENT_MODULE, MODULE_A, MODULE_B, INDEPENDENT_MODULE ),
-                scenario( "Excluding an also make dependency from resumeFrom does take its transitive dependency" )
-                        .resumeFrom( MODULE_C_2 )
-                        .inactiveRequiredProjects( MODULE_B )
-                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Resume from exclude project downstream" )
-                        .resumeFrom( MODULE_A )
-                        .inactiveRequiredProjects( MODULE_B )
-                        .expectResult( MODULE_A, MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Exclude the project we are resuming from (as proposed in MNG-6676)" )
-                        .resumeFrom( MODULE_B )
-                        .inactiveRequiredProjects( MODULE_B )
-                        .expectResult( MODULE_C_2, INDEPENDENT_MODULE ),
-                scenario( "Selected projects in wrong order are resumed correctly in order" )
-                        .activeRequiredProjects( MODULE_C_2, MODULE_B, MODULE_A )
-                        .resumeFrom( MODULE_B )
-                        .expectResult( MODULE_B, MODULE_C_2 ),
-                scenario( "Duplicate projects are filtered out" )
-                        .activeRequiredProjects( MODULE_A, MODULE_A )
-                        .expectResult( MODULE_A ),
-                scenario( "Select reactor by specific pom" )
-                        .requestedPom( MODULE_C )
-                        .expectResult( MODULE_C, MODULE_C_1, MODULE_C_2 ),
-                scenario( "Select reactor by specific pom with also make dependencies" )
-                        .requestedPom( MODULE_C )
-                        .makeBehavior( REACTOR_MAKE_UPSTREAM )
-                        .expectResult( PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_B, MODULE_C_2 ),
-                scenario( "Select reactor by specific pom with also make dependents" )
-                        .requestedPom( MODULE_B )
-                        .makeBehavior( REACTOR_MAKE_DOWNSTREAM )
-                        .expectResult( MODULE_B, MODULE_C_2 )
-        );
+                        .expectResult(PARENT_MODULE, MODULE_C_1, MODULE_A, MODULE_B, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Selected and excluded same project")
+                        .activeRequiredProjects(MODULE_A)
+                        .inactiveRequiredProjects(MODULE_A)
+                        .expectResult(MavenExecutionException.class, "empty reactor"),
+                scenario("Excluded aggregator, but selected child")
+                        .activeRequiredProjects(MODULE_C_1)
+                        .inactiveRequiredProjects(MODULE_C)
+                        .expectResult(MavenExecutionException.class, "empty reactor"),
+                scenario("Project selected with different selector resolves to same project")
+                        .activeRequiredProjects(GROUP_ID + ":" + MODULE_A)
+                        .inactiveRequiredProjects(MODULE_A)
+                        .expectResult(MavenExecutionException.class, "empty reactor"),
+                scenario("Selected and excluded same project, but also selected another project")
+                        .activeRequiredProjects(MODULE_A, MODULE_B)
+                        .inactiveRequiredProjects(MODULE_A)
+                        .expectResult(MODULE_B),
+                scenario("Selected missing project as required and as optional")
+                        .activeRequiredProjects("non-existing-module")
+                        .activeOptionalProjects("non-existing-module")
+                        .expectResult(MavenExecutionException.class, "not find the selected project"),
+                scenario("Resuming from project")
+                        .resumeFrom(MODULE_B)
+                        .expectResult(MODULE_B, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Selected project with also make dependencies")
+                        .activeRequiredProjects(MODULE_C_2)
+                        .makeBehavior(REACTOR_MAKE_UPSTREAM)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_A, MODULE_B, MODULE_C_2),
+                scenario("Selected project with also make dependents")
+                        .activeRequiredProjects(MODULE_B)
+                        .makeBehavior(REACTOR_MAKE_DOWNSTREAM)
+                        .expectResult(MODULE_B, MODULE_C_2),
+                scenario("Resuming from project with also make dependencies")
+                        .makeBehavior(REACTOR_MAKE_UPSTREAM)
+                        .resumeFrom(MODULE_C_2)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_A, MODULE_B, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Selected project with resume from and also make dependency (MNG-4960 IT#1)")
+                        .activeRequiredProjects(MODULE_C_2)
+                        .resumeFrom(MODULE_B)
+                        .makeBehavior(REACTOR_MAKE_UPSTREAM)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_A, MODULE_B, MODULE_C_2),
+                scenario("Selected project with resume from and also make dependent (MNG-4960 IT#2)")
+                        .activeRequiredProjects(MODULE_B)
+                        .resumeFrom(MODULE_C_2)
+                        .makeBehavior(REACTOR_MAKE_DOWNSTREAM)
+                        .expectResult(MODULE_C_2),
+                scenario("Excluding an also make dependency from selectedProject does take its transitive dependency")
+                        .activeRequiredProjects(MODULE_C_2)
+                        .inactiveRequiredProjects(MODULE_B)
+                        .makeBehavior(REACTOR_MAKE_UPSTREAM)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_A, MODULE_C_2),
+                scenario("Excluding a project also excludes its children")
+                        .inactiveRequiredProjects(MODULE_C)
+                        .expectResult(PARENT_MODULE, MODULE_A, MODULE_B, INDEPENDENT_MODULE),
+                scenario("Excluding an also make dependency from resumeFrom does take its transitive dependency")
+                        .resumeFrom(MODULE_C_2)
+                        .inactiveRequiredProjects(MODULE_B)
+                        .makeBehavior(REACTOR_MAKE_UPSTREAM)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_A, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Resume from exclude project downstream")
+                        .resumeFrom(MODULE_A)
+                        .inactiveRequiredProjects(MODULE_B)
+                        .expectResult(MODULE_A, MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Exclude the project we are resuming from (as proposed in MNG-6676)")
+                        .resumeFrom(MODULE_B)
+                        .inactiveRequiredProjects(MODULE_B)
+                        .expectResult(MODULE_C_2, INDEPENDENT_MODULE),
+                scenario("Selected projects in wrong order are resumed correctly in order")
+                        .activeRequiredProjects(MODULE_C_2, MODULE_B, MODULE_A)
+                        .resumeFrom(MODULE_B)
+                        .expectResult(MODULE_B, MODULE_C_2),
+                scenario("Duplicate projects are filtered out")
+                        .activeRequiredProjects(MODULE_A, MODULE_A)
+                        .expectResult(MODULE_A),
+                scenario("Select reactor by specific pom")
+                        .requestedPom(MODULE_C)
+                        .expectResult(MODULE_C, MODULE_C_1, MODULE_C_2),
+                scenario("Select reactor by specific pom with also make dependencies")
+                        .requestedPom(MODULE_C)
+                        .makeBehavior(REACTOR_MAKE_UPSTREAM)
+                        .expectResult(PARENT_MODULE, MODULE_C, MODULE_C_1, MODULE_A, MODULE_B, MODULE_C_2),
+                scenario("Select reactor by specific pom with also make dependents")
+                        .requestedPom(MODULE_B)
+                        .makeBehavior(REACTOR_MAKE_DOWNSTREAM)
+                        .expectResult(MODULE_B, MODULE_C_2));
     }
 
-    interface ExpectedResult {
+    interface ExpectedResult {}
 
-    }
     static class SelectedProjectsResult implements ExpectedResult {
         final List<String> projectNames;
 
-        public SelectedProjectsResult( List<String> projectSelectors )
-        {
+        public SelectedProjectsResult(List<String> projectSelectors) {
             this.projectNames = projectSelectors;
         }
     }
+
     static class ExceptionThrown implements ExpectedResult {
         final Class<? extends Throwable> expected;
         final String partOfMessage;
 
-        public ExceptionThrown( final Class<? extends Throwable> expected, final String partOfMessage )
-        {
+        public ExceptionThrown(final Class<? extends Throwable> expected, final String partOfMessage) {
             this.expected = expected;
             this.partOfMessage = partOfMessage;
         }
@@ -272,130 +290,186 @@
             String parameterMakeBehavior,
             ExpectedResult parameterExpectedResult,
             File parameterRequestedPom,
-            boolean parameterRecursive )
-    {
+            boolean parameterRecursive) {
         // Given
         ProjectActivation projectActivation = new ProjectActivation();
-        parameterActiveRequiredProjects.forEach( projectActivation::activateRequiredProject );
-        parameterActiveOptionalProjects.forEach( projectActivation::activateOptionalProject );
-        parameterInactiveRequiredProjects.forEach( projectActivation::deactivateRequiredProject );
-        parameterInactiveOptionalProjects.forEach( projectActivation::deactivateOptionalProject );
+        parameterActiveRequiredProjects.forEach(projectActivation::activateRequiredProject);
+        parameterActiveOptionalProjects.forEach(projectActivation::activateOptionalProject);
+        parameterInactiveRequiredProjects.forEach(projectActivation::deactivateRequiredProject);
+        parameterInactiveOptionalProjects.forEach(projectActivation::deactivateOptionalProject);
 
-        when( mavenExecutionRequest.getProjectActivation() ).thenReturn( projectActivation );
-        when( mavenExecutionRequest.getMakeBehavior() ).thenReturn( parameterMakeBehavior );
-        when( mavenExecutionRequest.getPom() ).thenReturn( parameterRequestedPom );
-        when( mavenExecutionRequest.isRecursive() ).thenReturn( parameterRecursive );
-        if ( StringUtils.isNotEmpty( parameterResumeFrom ) )
-        {
-            when( mavenExecutionRequest.getResumeFrom() ).thenReturn( ":" + parameterResumeFrom );
+        when(mavenExecutionRequest.getProjectActivation()).thenReturn(projectActivation);
+        when(mavenExecutionRequest.getMakeBehavior()).thenReturn(parameterMakeBehavior);
+        when(mavenExecutionRequest.getPom()).thenReturn(parameterRequestedPom);
+        when(mavenExecutionRequest.isRecursive()).thenReturn(parameterRecursive);
+        if (parameterResumeFrom != null && !parameterResumeFrom.isEmpty()) {
+            when(mavenExecutionRequest.getResumeFrom()).thenReturn(":" + parameterResumeFrom);
         }
 
         // When
-        Result<ProjectDependencyGraph> result = graphBuilder.build( session );
+        Result<ProjectDependencyGraph> result = graphBuilder.build(session);
 
         // Then
-        if ( parameterExpectedResult instanceof SelectedProjectsResult )
-        {
-            assertThat( result.hasErrors() ).withFailMessage( "Expected result not to have errors" ).isFalse();
+        if (parameterExpectedResult instanceof SelectedProjectsResult) {
+            assertThat(result.hasErrors())
+                    .withFailMessage("Expected result not to have errors")
+                    .isFalse();
             List<String> expectedProjectNames = ((SelectedProjectsResult) parameterExpectedResult).projectNames;
             List<MavenProject> actualReactorProjects = result.get().getSortedProjects();
-            List<MavenProject> expectedReactorProjects = expectedProjectNames.stream()
-                    .map( artifactIdProjectMap::get )
-                    .collect( toList() );
-            assertEquals( expectedReactorProjects, actualReactorProjects, parameterDescription );
-        }
-        else
-        {
-            assertThat( result.hasErrors() ).withFailMessage( "Expected result to have errors" ).isTrue();
+            List<MavenProject> expectedReactorProjects =
+                    expectedProjectNames.stream().map(artifactIdProjectMap::get).collect(toList());
+            assertEquals(expectedReactorProjects, actualReactorProjects, parameterDescription);
+        } else {
+            assertThat(result.hasErrors())
+                    .withFailMessage("Expected result to have errors")
+                    .isTrue();
             Class<? extends Throwable> expectedException = ((ExceptionThrown) parameterExpectedResult).expected;
             String partOfMessage = ((ExceptionThrown) parameterExpectedResult).partOfMessage;
 
-            assertThat( result.getProblems() ).hasSize( 1 );
-            result.getProblems().forEach( p ->
-                assertThat( p.getException() ).isInstanceOf( expectedException ).hasMessageContaining( partOfMessage )
-            );
+            assertThat(result.getProblems()).hasSize(1);
+            result.getProblems().forEach(p -> assertThat(p.getException())
+                    .isInstanceOf(expectedException)
+                    .hasMessageContaining(partOfMessage));
         }
     }
 
-    @BeforeEach
-    public void before() throws Exception
-    {
+    @Test
+    void testProcessPackagingAttribute() throws ProjectBuildingException {
         graphBuilder = new DefaultGraphBuilder(
-                mock( BuildResumptionDataRepository.class ),
+                mock(BuildResumptionDataRepository.class),
                 pomlessCollectionStrategy,
                 multiModuleCollectionStrategy,
-                requestPomCollectionStrategy
-        );
+                requestPomCollectionStrategy);
 
         // Create projects
-        MavenProject projectParent = getMavenProject( PARENT_MODULE );
-        MavenProject projectIndependentModule = getMavenProject( INDEPENDENT_MODULE );
-        MavenProject projectModuleA = getMavenProject( MODULE_A, projectParent );
-        MavenProject projectModuleB = getMavenProject( MODULE_B, projectParent );
-        MavenProject projectModuleC = getMavenProject( MODULE_C, projectParent );
-        MavenProject projectModuleC1 = getMavenProject( MODULE_C_1, projectModuleC );
-        MavenProject projectModuleC2 = getMavenProject( MODULE_C_2, projectModuleC );
+        MavenProject projectParent = getMavenProject(PARENT_MODULE);
+        MavenProject projectModuleD = getMavenProject(MODULE_D, projectParent, "bom");
 
-        artifactIdProjectMap = Stream.of( projectParent, projectIndependentModule, projectModuleA, projectModuleB, projectModuleC, projectModuleC1, projectModuleC2 )
-                .collect( Collectors.toMap( MavenProject::getArtifactId, identity() ) );
-
-        // Set dependencies and modules
-        projectModuleB.setDependencies( singletonList( toDependency( projectModuleA ) ) );
-        projectModuleC2.setDependencies( singletonList( toDependency( projectModuleB ) ) );
-        projectParent.setCollectedProjects( asList( projectIndependentModule, projectModuleA, projectModuleB, projectModuleC, projectModuleC1, projectModuleC2 ) );
-        projectModuleC.setCollectedProjects( asList( projectModuleC1, projectModuleC2 ) );
+        projectParent.setCollectedProjects(singletonList(projectModuleD));
 
         // Set up needed mocks
-        when( session.getRequest() ).thenReturn( mavenExecutionRequest );
-        when( session.getProjects() ).thenReturn( null ); // needed, otherwise it will be an empty list by default
-        when( mavenExecutionRequest.getProjectBuildingRequest() ).thenReturn( mock( ProjectBuildingRequest.class ) );
-        List<ProjectBuildingResult> projectBuildingResults = createProjectBuildingResultMocks( artifactIdProjectMap.values() );
-        when( projectBuilder.build( anyList(), anyBoolean(), any( ProjectBuildingRequest.class ) ) ).thenReturn( projectBuildingResults );
+        when(session.getRequest()).thenReturn(mavenExecutionRequest);
+        when(session.getProjects()).thenReturn(null); // needed, otherwise it will be an empty list by default
+        when(mavenExecutionRequest.getProjectBuildingRequest()).thenReturn(mock(ProjectBuildingRequest.class));
+        List<ProjectBuildingResult> projectBuildingResults =
+                createProjectBuildingResultMocks(Stream.of(projectParent, projectModuleD)
+                        .collect(Collectors.toMap(MavenProject::getArtifactId, identity()))
+                        .values());
+        when(projectBuilder.build(anyList(), anyBoolean(), any(ProjectBuildingRequest.class)))
+                .thenReturn(projectBuildingResults);
+
+        ProjectActivation projectActivation = new ProjectActivation();
+
+        when(mavenExecutionRequest.getProjectActivation()).thenReturn(projectActivation);
+        when(mavenExecutionRequest.getPom()).thenReturn(new File(PARENT_MODULE, "pom.xml"));
+
+        Result<ProjectDependencyGraph> result = graphBuilder.build(session);
+
+        assertThat(result.hasErrors())
+                .withFailMessage("Expected result not to have errors")
+                .isFalse();
+        List<MavenProject> actualReactorProjects = result.get().getSortedProjects();
+        assertEquals(2, actualReactorProjects.size());
+        assertEquals("pom", actualReactorProjects.get(1).getPackaging());
     }
 
-    private MavenProject getMavenProject( String artifactId, MavenProject parentProject )
-    {
-        MavenProject project = getMavenProject( artifactId );
+    @BeforeEach
+    void before() throws Exception {
+        graphBuilder = new DefaultGraphBuilder(
+                mock(BuildResumptionDataRepository.class),
+                pomlessCollectionStrategy,
+                multiModuleCollectionStrategy,
+                requestPomCollectionStrategy);
+
+        // Create projects
+        MavenProject projectParent = getMavenProject(PARENT_MODULE);
+        MavenProject projectIndependentModule = getMavenProject(INDEPENDENT_MODULE);
+        MavenProject projectModuleA = getMavenProject(MODULE_A, projectParent);
+        MavenProject projectModuleB = getMavenProject(MODULE_B, projectParent);
+        MavenProject projectModuleC = getMavenProject(MODULE_C, projectParent);
+        MavenProject projectModuleC1 = getMavenProject(MODULE_C_1, projectModuleC);
+        MavenProject projectModuleC2 = getMavenProject(MODULE_C_2, projectModuleC);
+
+        artifactIdProjectMap = Stream.of(
+                        projectParent,
+                        projectIndependentModule,
+                        projectModuleA,
+                        projectModuleB,
+                        projectModuleC,
+                        projectModuleC1,
+                        projectModuleC2)
+                .collect(Collectors.toMap(MavenProject::getArtifactId, identity()));
+
+        // Set dependencies and modules
+        projectModuleB.setDependencies(singletonList(toDependency(projectModuleA)));
+        projectModuleC2.setDependencies(singletonList(toDependency(projectModuleB)));
+        projectParent.setCollectedProjects(asList(
+                projectIndependentModule,
+                projectModuleA,
+                projectModuleB,
+                projectModuleC,
+                projectModuleC1,
+                projectModuleC2));
+        projectModuleC.setCollectedProjects(asList(projectModuleC1, projectModuleC2));
+
+        // Set up needed mocks
+        when(session.getRequest()).thenReturn(mavenExecutionRequest);
+        when(session.getProjects()).thenReturn(null); // needed, otherwise it will be an empty list by default
+        when(mavenExecutionRequest.getProjectBuildingRequest()).thenReturn(mock(ProjectBuildingRequest.class));
+        List<ProjectBuildingResult> projectBuildingResults =
+                createProjectBuildingResultMocks(artifactIdProjectMap.values());
+        when(projectBuilder.build(anyList(), anyBoolean(), any(ProjectBuildingRequest.class)))
+                .thenReturn(projectBuildingResults);
+    }
+
+    private MavenProject getMavenProject(String artifactId, MavenProject parentProject) {
+        MavenProject project = getMavenProject(artifactId);
         Parent parent = new Parent();
-        parent.setGroupId( parentProject.getGroupId() );
-        parent.setArtifactId( parentProject.getArtifactId() );
-        project.getModel().setParent( parent );
+        parent.setGroupId(parentProject.getGroupId());
+        parent.setArtifactId(parentProject.getArtifactId());
+        project.getModel().setParent(parent);
         return project;
     }
 
-    private MavenProject getMavenProject( String artifactId )
-    {
+    private MavenProject getMavenProject(String artifactId) {
         MavenProject mavenProject = new MavenProject();
-        mavenProject.setGroupId( GROUP_ID );
-        mavenProject.setArtifactId( artifactId );
-        mavenProject.setVersion( "1.0" );
-        mavenProject.setPomFile( new File ( artifactId, "pom.xml" ) );
-        mavenProject.setCollectedProjects( new ArrayList<>() );
+        mavenProject.setGroupId(GROUP_ID);
+        mavenProject.setArtifactId(artifactId);
+        mavenProject.setVersion("1.0");
+        mavenProject.setPomFile(new File(artifactId, "pom.xml"));
+        mavenProject.setCollectedProjects(new ArrayList<>());
         return mavenProject;
     }
 
-    private Dependency toDependency( MavenProject mavenProject )
-    {
+    private MavenProject getMavenProject(String artifactId, MavenProject parentProject, String packaging) {
+        MavenProject project = getMavenProject(artifactId);
+        Parent parent = new Parent();
+        parent.setGroupId(parentProject.getGroupId());
+        parent.setArtifactId(parentProject.getArtifactId());
+        project.getModel().setParent(parent);
+        project.setPackaging(packaging);
+        return project;
+    }
+
+    private Dependency toDependency(MavenProject mavenProject) {
         Dependency dependency = new Dependency();
-        dependency.setGroupId( mavenProject.getGroupId() );
-        dependency.setArtifactId( mavenProject.getArtifactId() );
-        dependency.setVersion( mavenProject.getVersion() );
+        dependency.setGroupId(mavenProject.getGroupId());
+        dependency.setArtifactId(mavenProject.getArtifactId());
+        dependency.setVersion(mavenProject.getVersion());
         return dependency;
     }
 
-    private List<ProjectBuildingResult> createProjectBuildingResultMocks( Collection<MavenProject> projects )
-    {
+    private List<ProjectBuildingResult> createProjectBuildingResultMocks(Collection<MavenProject> projects) {
         return projects.stream()
-                .map( project -> {
-                    ProjectBuildingResult result = mock( ProjectBuildingResult.class );
-                    when( result.getProject() ).thenReturn( project );
+                .map(project -> {
+                    ProjectBuildingResult result = mock(ProjectBuildingResult.class);
+                    when(result.getProject()).thenReturn(project);
                     return result;
-                } )
-                .collect( toList() );
+                })
+                .collect(toList());
     }
 
-    static class ScenarioBuilder
-    {
+    static class ScenarioBuilder {
         private String description;
         private List<String> activeRequiredProjects = emptyList();
         private List<String> activeOptionalProjects = emptyList();
@@ -403,94 +477,87 @@
         private List<String> inactiveOptionalProjects = emptyList();
         private String resumeFrom = "";
         private String makeBehavior = "";
-        private File requestedPom = new File( PARENT_MODULE, "pom.xml" );
+        private File requestedPom = new File(PARENT_MODULE, "pom.xml");
         private boolean recursive = true;
 
-        private ScenarioBuilder() { }
+        private ScenarioBuilder() {}
 
-        public static ScenarioBuilder scenario( String description )
-        {
+        public static ScenarioBuilder scenario(String description) {
             ScenarioBuilder scenarioBuilder = new ScenarioBuilder();
             scenarioBuilder.description = description;
             return scenarioBuilder;
         }
 
-        public ScenarioBuilder activeRequiredProjects( String... activeRequiredProjects )
-        {
-            this.activeRequiredProjects = prependWithColonIfNeeded( activeRequiredProjects );
+        public ScenarioBuilder activeRequiredProjects(String... activeRequiredProjects) {
+            this.activeRequiredProjects = prependWithColonIfNeeded(activeRequiredProjects);
             return this;
         }
 
-        public ScenarioBuilder activeOptionalProjects( String... activeOptionalProjects )
-        {
-            this.activeOptionalProjects = prependWithColonIfNeeded( activeOptionalProjects );
+        public ScenarioBuilder activeOptionalProjects(String... activeOptionalProjects) {
+            this.activeOptionalProjects = prependWithColonIfNeeded(activeOptionalProjects);
             return this;
         }
 
-        public ScenarioBuilder inactiveRequiredProjects( String... inactiveRequiredProjects )
-        {
-            this.inactiveRequiredProjects = prependWithColonIfNeeded( inactiveRequiredProjects );
+        public ScenarioBuilder inactiveRequiredProjects(String... inactiveRequiredProjects) {
+            this.inactiveRequiredProjects = prependWithColonIfNeeded(inactiveRequiredProjects);
             return this;
         }
 
-        public ScenarioBuilder inactiveOptionalProjects( String... inactiveOptionalProjects )
-        {
-            this.inactiveOptionalProjects = prependWithColonIfNeeded( inactiveOptionalProjects );
+        public ScenarioBuilder inactiveOptionalProjects(String... inactiveOptionalProjects) {
+            this.inactiveOptionalProjects = prependWithColonIfNeeded(inactiveOptionalProjects);
             return this;
         }
 
-        public ScenarioBuilder resumeFrom( String resumeFrom )
-        {
+        public ScenarioBuilder resumeFrom(String resumeFrom) {
             this.resumeFrom = resumeFrom;
             return this;
         }
 
-        public ScenarioBuilder makeBehavior( String makeBehavior )
-        {
+        public ScenarioBuilder makeBehavior(String makeBehavior) {
             this.makeBehavior = makeBehavior;
             return this;
         }
 
-        public ScenarioBuilder requestedPom( String requestedPom )
-        {
-            this.requestedPom = new File( requestedPom, "pom.xml" );
+        public ScenarioBuilder requestedPom(String requestedPom) {
+            this.requestedPom = new File(requestedPom, "pom.xml");
             return this;
         }
 
-        public ScenarioBuilder nonRecursive()
-        {
+        public ScenarioBuilder nonRecursive() {
             this.recursive = false;
             return this;
         }
 
-        public Arguments expectResult( String... expectedReactorProjects )
-        {
-            ExpectedResult expectedResult = new SelectedProjectsResult( asList( expectedReactorProjects ) );
-            return createTestArguments( expectedResult );
+        public Arguments expectResult(String... expectedReactorProjects) {
+            ExpectedResult expectedResult = new SelectedProjectsResult(asList(expectedReactorProjects));
+            return createTestArguments(expectedResult);
         }
 
-        public Arguments expectResult( Class<? extends Exception> expected, final String partOfMessage )
-        {
-            ExpectedResult expectedResult = new ExceptionThrown( expected, partOfMessage );
-            return createTestArguments( expectedResult );
+        public Arguments expectResult(Class<? extends Exception> expected, final String partOfMessage) {
+            ExpectedResult expectedResult = new ExceptionThrown(expected, partOfMessage);
+            return createTestArguments(expectedResult);
         }
 
-        private Arguments createTestArguments( ExpectedResult expectedResult )
-        {
-            return Arguments.arguments( description, activeRequiredProjects, activeOptionalProjects,
-                    inactiveRequiredProjects, inactiveOptionalProjects, resumeFrom, makeBehavior, expectedResult,
-                    requestedPom, recursive );
+        private Arguments createTestArguments(ExpectedResult expectedResult) {
+            return Arguments.arguments(
+                    description,
+                    activeRequiredProjects,
+                    activeOptionalProjects,
+                    inactiveRequiredProjects,
+                    inactiveOptionalProjects,
+                    resumeFrom,
+                    makeBehavior,
+                    expectedResult,
+                    requestedPom,
+                    recursive);
         }
 
-        private List<String> prependWithColonIfNeeded( String[] selectors )
-        {
-            return Arrays.stream( selectors )
-                    .map( this::prependWithColonIfNeeded )
-                    .collect( toList() );
+        private List<String> prependWithColonIfNeeded(String[] selectors) {
+            return Arrays.stream(selectors).map(this::prependWithColonIfNeeded).collect(toList());
         }
 
-        private String prependWithColonIfNeeded( String selector ) {
-            return selector.indexOf( ':' ) == -1 ? ":" + selector : selector;
+        private String prependWithColonIfNeeded(String selector) {
+            return selector.indexOf(':') == -1 ? ":" + selector : selector;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
index 94737fb..9d68de0 100644
--- a/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
+++ b/maven-core/src/test/java/org/apache/maven/graph/DefaultProjectDependencyGraphTest.java
@@ -1,16 +1,20 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
 package org.apache.maven.graph;
 
@@ -19,163 +23,139 @@
 
 import org.apache.maven.execution.ProjectDependencyGraph;
 import org.apache.maven.model.Dependency;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
- * @author Kristian Rosenvold
  */
-public class DefaultProjectDependencyGraphTest
-{
+class DefaultProjectDependencyGraphTest {
 
     private final MavenProject aProject = createA();
 
-    private final MavenProject depender1 = createProject( Arrays.asList( toDependency( aProject ) ), "depender1" );
+    private final MavenProject depender1 = createProject(Arrays.asList(toDependency(aProject)), "depender1");
 
-    private final MavenProject depender2 = createProject( Arrays.asList( toDependency( aProject ) ), "depender2" );
+    private final MavenProject depender2 = createProject(Arrays.asList(toDependency(aProject)), "depender2");
 
-    private final MavenProject depender3 = createProject( Arrays.asList( toDependency( aProject ) ), "depender3" );
+    private final MavenProject depender3 = createProject(Arrays.asList(toDependency(aProject)), "depender3");
 
     private final MavenProject depender4 =
-        createProject( Arrays.asList( toDependency( aProject ), toDependency( depender3 ) ), "depender4" );
+            createProject(Arrays.asList(toDependency(aProject), toDependency(depender3)), "depender4");
 
-    private final MavenProject transitiveOnly =
-        createProject( Arrays.asList( toDependency( depender3 ) ), "depender5" );
+    private final MavenProject transitiveOnly = createProject(Arrays.asList(toDependency(depender3)), "depender5");
 
     @Test
-    public void testGetSortedProjects()
-        throws DuplicateProjectException, CycleDetectedException
-    {
-        ProjectDependencyGraph graph = new DefaultProjectDependencyGraph( Arrays.asList( depender1, aProject ) );
+    void testGetSortedProjects() throws DuplicateProjectException, CycleDetectedException {
+        ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(Arrays.asList(depender1, aProject));
         final List<MavenProject> sortedProjects = graph.getSortedProjects();
-        assertEquals( aProject, sortedProjects.get( 0 ) );
-        assertEquals( depender1, sortedProjects.get( 1 ) );
+        assertEquals(aProject, sortedProjects.get(0));
+        assertEquals(depender1, sortedProjects.get(1));
     }
 
     @Test
-    public void testVerifyExpectedParentStructure()
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    void testVerifyExpectedParentStructure() throws CycleDetectedException, DuplicateProjectException {
         // This test verifies the baseline structure used in subsequent tests. If this fails, the rest will fail.
         ProjectDependencyGraph graph = threeProjectsDependingOnASingle();
         final List<MavenProject> sortedProjects = graph.getSortedProjects();
-        assertEquals( aProject, sortedProjects.get( 0 ) );
-        assertEquals( depender1, sortedProjects.get( 1 ) );
-        assertEquals( depender2, sortedProjects.get( 2 ) );
-        assertEquals( depender3, sortedProjects.get( 3 ) );
+        assertEquals(aProject, sortedProjects.get(0));
+        assertEquals(depender1, sortedProjects.get(1));
+        assertEquals(depender2, sortedProjects.get(2));
+        assertEquals(depender3, sortedProjects.get(3));
     }
 
     @Test
-    public void testVerifyThatDownstreamProjectsComeInSortedOrder()
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    void testVerifyThatDownstreamProjectsComeInSortedOrder() throws CycleDetectedException, DuplicateProjectException {
         final List<MavenProject> downstreamProjects =
-            threeProjectsDependingOnASingle().getDownstreamProjects( aProject, true );
-        assertEquals( depender1, downstreamProjects.get( 0 ) );
-        assertEquals( depender2, downstreamProjects.get( 1 ) );
-        assertEquals( depender3, downstreamProjects.get( 2 ) );
+                threeProjectsDependingOnASingle().getDownstreamProjects(aProject, true);
+        assertEquals(depender1, downstreamProjects.get(0));
+        assertEquals(depender2, downstreamProjects.get(1));
+        assertEquals(depender3, downstreamProjects.get(2));
     }
 
     @Test
-    public void testTransitivesInOrder()
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    void testTransitivesInOrder() throws CycleDetectedException, DuplicateProjectException {
         final ProjectDependencyGraph graph =
-            new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) );
+                new DefaultProjectDependencyGraph(Arrays.asList(depender1, depender4, depender2, depender3, aProject));
 
-        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true );
-        assertEquals( depender1, downstreamProjects.get( 0 ) );
-        assertEquals( depender3, downstreamProjects.get( 1 ) );
-        assertEquals( depender4, downstreamProjects.get( 2 ) );
-        assertEquals( depender2, downstreamProjects.get( 3 ) );
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects(aProject, true);
+        assertEquals(depender1, downstreamProjects.get(0));
+        assertEquals(depender3, downstreamProjects.get(1));
+        assertEquals(depender4, downstreamProjects.get(2));
+        assertEquals(depender2, downstreamProjects.get(3));
     }
 
     @Test
-    public void testNonTransitivesInOrder()
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    void testNonTransitivesInOrder() throws CycleDetectedException, DuplicateProjectException {
         final ProjectDependencyGraph graph =
-            new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender4, depender2, depender3, aProject ) );
+                new DefaultProjectDependencyGraph(Arrays.asList(depender1, depender4, depender2, depender3, aProject));
 
-        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false );
-        assertEquals( depender1, downstreamProjects.get( 0 ) );
-        assertEquals( depender3, downstreamProjects.get( 1 ) );
-        assertEquals( depender4, downstreamProjects.get( 2 ) );
-        assertEquals( depender2, downstreamProjects.get( 3 ) );
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects(aProject, false);
+        assertEquals(depender1, downstreamProjects.get(0));
+        assertEquals(depender3, downstreamProjects.get(1));
+        assertEquals(depender4, downstreamProjects.get(2));
+        assertEquals(depender2, downstreamProjects.get(3));
     }
 
     @Test
-    public void testWithTransitiveOnly()
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    void testWithTransitiveOnly() throws CycleDetectedException, DuplicateProjectException {
         final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(
-            Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) );
+                Arrays.asList(depender1, transitiveOnly, depender2, depender3, aProject));
 
-        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, true );
-        assertEquals( depender1, downstreamProjects.get( 0 ) );
-        assertEquals( depender3, downstreamProjects.get( 1 ) );
-        assertEquals( transitiveOnly, downstreamProjects.get( 2 ) );
-        assertEquals( depender2, downstreamProjects.get( 3 ) );
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects(aProject, true);
+        assertEquals(depender1, downstreamProjects.get(0));
+        assertEquals(depender3, downstreamProjects.get(1));
+        assertEquals(transitiveOnly, downstreamProjects.get(2));
+        assertEquals(depender2, downstreamProjects.get(3));
     }
 
     @Test
-    public void testWithMissingTransitiveOnly()
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    void testWithMissingTransitiveOnly() throws CycleDetectedException, DuplicateProjectException {
         final ProjectDependencyGraph graph = new DefaultProjectDependencyGraph(
-            Arrays.asList( depender1, transitiveOnly, depender2, depender3, aProject ) );
+                Arrays.asList(depender1, transitiveOnly, depender2, depender3, aProject));
 
-        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects( aProject, false );
-        assertEquals( depender1, downstreamProjects.get( 0 ) );
-        assertEquals( depender3, downstreamProjects.get( 1 ) );
-        assertEquals( depender2, downstreamProjects.get( 2 ) );
+        final List<MavenProject> downstreamProjects = graph.getDownstreamProjects(aProject, false);
+        assertEquals(depender1, downstreamProjects.get(0));
+        assertEquals(depender3, downstreamProjects.get(1));
+        assertEquals(depender2, downstreamProjects.get(2));
     }
 
     @Test
-    public void testGetUpstreamProjects()
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    void testGetUpstreamProjects() throws CycleDetectedException, DuplicateProjectException {
         ProjectDependencyGraph graph = threeProjectsDependingOnASingle();
-        final List<MavenProject> downstreamProjects = graph.getUpstreamProjects( depender1, true );
-        assertEquals( aProject, downstreamProjects.get( 0 ) );
+        final List<MavenProject> downstreamProjects = graph.getUpstreamProjects(depender1, true);
+        assertEquals(aProject, downstreamProjects.get(0));
     }
 
     private ProjectDependencyGraph threeProjectsDependingOnASingle()
-        throws CycleDetectedException, DuplicateProjectException
-    {
-        return new DefaultProjectDependencyGraph( Arrays.asList( depender1, depender2, depender3, aProject ) );
+            throws CycleDetectedException, DuplicateProjectException {
+        return new DefaultProjectDependencyGraph(Arrays.asList(depender1, depender2, depender3, aProject));
     }
 
-    private static MavenProject createA()
-    {
+    private static MavenProject createA() {
         MavenProject result = new MavenProject();
-        result.setGroupId( "org.apache" );
-        result.setArtifactId( "A" );
-        result.setVersion( "1.2" );
+        result.setGroupId("org.apache");
+        result.setArtifactId("A");
+        result.setVersion("1.2");
         return result;
     }
 
-    static Dependency toDependency( MavenProject mavenProject )
-    {
+    static Dependency toDependency(MavenProject mavenProject) {
         final Dependency dependency = new Dependency();
-        dependency.setArtifactId( mavenProject.getArtifactId() );
-        dependency.setGroupId( mavenProject.getGroupId() );
-        dependency.setVersion( mavenProject.getVersion() );
+        dependency.setArtifactId(mavenProject.getArtifactId());
+        dependency.setGroupId(mavenProject.getGroupId());
+        dependency.setVersion(mavenProject.getVersion());
         return dependency;
     }
 
-    private static MavenProject createProject( List<Dependency> dependencies, String artifactId )
-    {
+    private static MavenProject createProject(List<Dependency> dependencies, String artifactId) {
         MavenProject result = new MavenProject();
-        result.setGroupId( "org.apache" );
-        result.setArtifactId( artifactId );
-        result.setVersion( "1.2" );
-        result.setDependencies( dependencies );
+        result.setGroupId("org.apache");
+        result.setArtifactId(artifactId);
+        result.setVersion("1.2");
+        result.setDependencies(dependencies);
         return result;
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/test/java/org/apache/maven/graph/ProjectSelectorTest.java b/maven-core/src/test/java/org/apache/maven/graph/ProjectSelectorTest.java
index 34bb445..2cdeac3 100644
--- a/maven-core/src/test/java/org/apache/maven/graph/ProjectSelectorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/graph/ProjectSelectorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.graph;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.graph;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 import org.apache.maven.MavenExecutionException;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -28,14 +35,6 @@
 import org.junit.jupiter.params.provider.EmptySource;
 import org.junit.jupiter.params.provider.ValueSource;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsString;
@@ -46,176 +45,163 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-class ProjectSelectorTest
-{
+class ProjectSelectorTest {
     private final ProjectSelector sut = new ProjectSelector();
-    private final MavenExecutionRequest mavenExecutionRequest = mock( MavenExecutionRequest.class );
+    private final MavenExecutionRequest mavenExecutionRequest = mock(MavenExecutionRequest.class);
 
     @Test
-    void getBaseDirectoryFromRequestWhenDirectoryIsNullReturnNull()
-    {
-        when( mavenExecutionRequest.getBaseDirectory() ).thenReturn( null );
+    void getBaseDirectoryFromRequestWhenDirectoryIsNullReturnNull() {
+        when(mavenExecutionRequest.getBaseDirectory()).thenReturn(null);
 
-        final File baseDirectoryFromRequest = sut.getBaseDirectoryFromRequest( mavenExecutionRequest );
+        final File baseDirectoryFromRequest = sut.getBaseDirectoryFromRequest(mavenExecutionRequest);
 
-        assertThat( baseDirectoryFromRequest, nullValue() );
+        assertThat(baseDirectoryFromRequest, nullValue());
     }
 
     @Test
-    void getBaseDirectoryFromRequestWhenDirectoryIsValidReturnFile()
-    {
-        when( mavenExecutionRequest.getBaseDirectory() ).thenReturn( "path/to/file" );
+    void getBaseDirectoryFromRequestWhenDirectoryIsValidReturnFile() {
+        when(mavenExecutionRequest.getBaseDirectory()).thenReturn("path/to/file");
 
-        final File baseDirectoryFromRequest = sut.getBaseDirectoryFromRequest( mavenExecutionRequest );
+        final File baseDirectoryFromRequest = sut.getBaseDirectoryFromRequest(mavenExecutionRequest);
 
-        assertThat( baseDirectoryFromRequest, notNullValue() );
-        assertThat( baseDirectoryFromRequest.getPath(), is( new File( "path/to/file" ).getPath() ) );
+        assertThat(baseDirectoryFromRequest, notNullValue());
+        assertThat(baseDirectoryFromRequest.getPath(), is(new File("path/to/file").getPath()));
     }
 
     @ParameterizedTest
-    @ValueSource( strings = {":wrong-selector", "wrong-selector"} )
+    @ValueSource(strings = {":wrong-selector", "wrong-selector"})
     @EmptySource
-    void isMatchingProjectNoMatchOnSelectorReturnsFalse( String selector )
-    {
-        final boolean result = sut.isMatchingProject( createMavenProject("maven-core" ), selector, null );
-        assertThat( result, is( false ) );
+    void isMatchingProjectNoMatchOnSelectorReturnsFalse(String selector) {
+        final boolean result = sut.isMatchingProject(createMavenProject("maven-core"), selector, null);
+        assertThat(result, is(false));
     }
 
     @ParameterizedTest
-    @ValueSource( strings = {":maven-core", "org.apache.maven:maven-core"} )
-    void isMatchingProjectMatchOnSelectorReturnsTrue( String selector )
-    {
-        final boolean result = sut.isMatchingProject( createMavenProject("maven-core" ), selector, null );
-        assertThat( result, is( true ) );
+    @ValueSource(strings = {":maven-core", "org.apache.maven:maven-core"})
+    void isMatchingProjectMatchOnSelectorReturnsTrue(String selector) {
+        final boolean result = sut.isMatchingProject(createMavenProject("maven-core"), selector, null);
+        assertThat(result, is(true));
     }
 
     @Test
-    void isMatchingProjectMatchOnFileReturnsTrue() throws IOException
-    {
-        final File tempFile = File.createTempFile( "maven-core-unit-test-pom", ".xml" );
+    void isMatchingProjectMatchOnFileReturnsTrue() throws IOException {
+        final File tempFile = File.createTempFile("maven-core-unit-test-pom", ".xml");
         final String selector = tempFile.getName();
-        final MavenProject mavenProject = createMavenProject("maven-core" );
-        mavenProject.setFile( tempFile );
+        final MavenProject mavenProject = createMavenProject("maven-core");
+        mavenProject.setFile(tempFile);
 
-        final boolean result = sut.isMatchingProject( mavenProject, selector, tempFile.getParentFile() );
+        final boolean result = sut.isMatchingProject(mavenProject, selector, tempFile.getParentFile());
 
         tempFile.delete();
-        assertThat( result, is( true ) );
+        assertThat(result, is(true));
     }
 
     @Test
-    void isMatchingProjectMatchOnDirectoryReturnsTrue(@TempDir File tempDir)
-    {
+    void isMatchingProjectMatchOnDirectoryReturnsTrue(@TempDir File tempDir) {
         String selector = "maven-core";
-        final File tempProjectDir = new File( tempDir, "maven-core" );
+        final File tempProjectDir = new File(tempDir, "maven-core");
         tempProjectDir.mkdir();
-        final MavenProject mavenProject = createMavenProject("maven-core" );
-        mavenProject.setFile( new File( tempProjectDir, "some-file.xml" ) );
+        final MavenProject mavenProject = createMavenProject("maven-core");
+        mavenProject.setFile(new File(tempProjectDir, "some-file.xml"));
 
-        final boolean result = sut.isMatchingProject( mavenProject, selector, tempDir );
+        final boolean result = sut.isMatchingProject(mavenProject, selector, tempDir);
 
         tempProjectDir.delete();
-        assertThat( result, is( true ) );
+        assertThat(result, is(true));
     }
 
     @Test
-    void getOptionalProjectsBySelectorsReturnsMatches()
-    {
+    void getOptionalProjectsBySelectorsReturnsMatches() {
         final HashSet<String> selectors = new HashSet<>();
-        selectors.add( ":maven-core" );
-        selectors.add( ":optional" );
+        selectors.add(":maven-core");
+        selectors.add(":optional");
 
-        final MavenProject mavenProject = createMavenProject("maven-core" );
-        final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+        final MavenProject mavenProject = createMavenProject("maven-core");
+        final List<MavenProject> listOfProjects = Collections.singletonList(mavenProject);
 
         final Set<MavenProject> optionalProjectsBySelectors =
-                sut.getOptionalProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+                sut.getOptionalProjectsBySelectors(mavenExecutionRequest, listOfProjects, selectors);
 
-        assertThat( optionalProjectsBySelectors.size(), is( 1 ) );
-        assertThat( optionalProjectsBySelectors, contains( mavenProject ) );
+        assertThat(optionalProjectsBySelectors.size(), is(1));
+        assertThat(optionalProjectsBySelectors, contains(mavenProject));
     }
 
     @Test
-    void getRequiredProjectsBySelectorsThrowsMavenExecutionException()
-    {
+    void getRequiredProjectsBySelectorsThrowsMavenExecutionException() {
         final HashSet<String> selectors = new HashSet<>();
-        selectors.add( ":maven-core" );
-        selectors.add( ":required" );
+        selectors.add(":maven-core");
+        selectors.add(":required");
 
-        final MavenProject mavenProject = createMavenProject("maven-core" );
-        final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+        final MavenProject mavenProject = createMavenProject("maven-core");
+        final List<MavenProject> listOfProjects = Collections.singletonList(mavenProject);
 
-        final MavenExecutionException exception = assertThrows( MavenExecutionException.class,
-                () -> sut.getRequiredProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors ) );
-        assertThat( exception.getMessage(), containsString( "Could not find" ) );
-        assertThat( exception.getMessage(), containsString( ":required" ) );
+        final MavenExecutionException exception = assertThrows(
+                MavenExecutionException.class,
+                () -> sut.getRequiredProjectsBySelectors(mavenExecutionRequest, listOfProjects, selectors));
+        assertThat(exception.getMessage(), containsString("Could not find"));
+        assertThat(exception.getMessage(), containsString(":required"));
     }
 
     @Test
-    void getRequiredProjectsBySelectorsReturnsProject() throws MavenExecutionException
-    {
+    void getRequiredProjectsBySelectorsReturnsProject() throws MavenExecutionException {
         final HashSet<String> selectors = new HashSet<>();
-        selectors.add( ":maven-core" );
+        selectors.add(":maven-core");
 
-        final MavenProject mavenProject = createMavenProject("maven-core" );
-        final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+        final MavenProject mavenProject = createMavenProject("maven-core");
+        final List<MavenProject> listOfProjects = Collections.singletonList(mavenProject);
 
         final Set<MavenProject> requiredProjectsBySelectors =
-                sut.getRequiredProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+                sut.getRequiredProjectsBySelectors(mavenExecutionRequest, listOfProjects, selectors);
 
-        assertThat( requiredProjectsBySelectors.size(), is( 1 ) );
-        assertThat( requiredProjectsBySelectors, contains( mavenProject ) );
+        assertThat(requiredProjectsBySelectors.size(), is(1));
+        assertThat(requiredProjectsBySelectors, contains(mavenProject));
     }
 
     @Test
-    void getRequiredProjectsBySelectorsReturnsProjectWithChildProjects() throws MavenExecutionException
-    {
-        when( mavenExecutionRequest.isRecursive() ).thenReturn( true );
+    void getRequiredProjectsBySelectorsReturnsProjectWithChildProjects() throws MavenExecutionException {
+        when(mavenExecutionRequest.isRecursive()).thenReturn(true);
 
         final HashSet<String> selectors = new HashSet<>();
-        selectors.add( ":maven-core" );
+        selectors.add(":maven-core");
 
-        final MavenProject mavenProject = createMavenProject("maven-core" );
-        final MavenProject child = createMavenProject("maven-core-child" );
-        mavenProject.setCollectedProjects( Collections.singletonList( child ) );
-        final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+        final MavenProject mavenProject = createMavenProject("maven-core");
+        final MavenProject child = createMavenProject("maven-core-child");
+        mavenProject.setCollectedProjects(Collections.singletonList(child));
+        final List<MavenProject> listOfProjects = Collections.singletonList(mavenProject);
 
         final Set<MavenProject> requiredProjectsBySelectors =
-                sut.getRequiredProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+                sut.getRequiredProjectsBySelectors(mavenExecutionRequest, listOfProjects, selectors);
 
-        assertThat( requiredProjectsBySelectors.size(), is( 2 ) );
-        assertThat( requiredProjectsBySelectors, contains( mavenProject, child ) );
+        assertThat(requiredProjectsBySelectors.size(), is(2));
+        assertThat(requiredProjectsBySelectors, contains(mavenProject, child));
     }
 
     @Test
-    void getOptionalProjectsBySelectorsReturnsProjectWithChildProjects()
-    {
-        when( mavenExecutionRequest.isRecursive() ).thenReturn( true );
+    void getOptionalProjectsBySelectorsReturnsProjectWithChildProjects() {
+        when(mavenExecutionRequest.isRecursive()).thenReturn(true);
 
         final HashSet<String> selectors = new HashSet<>();
-        selectors.add( ":maven-core" );
+        selectors.add(":maven-core");
 
-        final MavenProject mavenProject = createMavenProject("maven-core" );
-        final MavenProject child = createMavenProject("maven-core-child" );
-        mavenProject.setCollectedProjects( Collections.singletonList( child ) );
-        final List<MavenProject> listOfProjects = Collections.singletonList( mavenProject );
+        final MavenProject mavenProject = createMavenProject("maven-core");
+        final MavenProject child = createMavenProject("maven-core-child");
+        mavenProject.setCollectedProjects(Collections.singletonList(child));
+        final List<MavenProject> listOfProjects = Collections.singletonList(mavenProject);
 
         final Set<MavenProject> optionalProjectsBySelectors =
-                sut.getOptionalProjectsBySelectors( mavenExecutionRequest, listOfProjects, selectors );
+                sut.getOptionalProjectsBySelectors(mavenExecutionRequest, listOfProjects, selectors);
 
-        assertThat( optionalProjectsBySelectors.size(), is( 2 ) );
-        assertThat( optionalProjectsBySelectors, contains( mavenProject, child ) );
+        assertThat(optionalProjectsBySelectors.size(), is(2));
+        assertThat(optionalProjectsBySelectors, contains(mavenProject, child));
     }
 
-    private MavenProject createMavenProject(String artifactId )
-    {
+    private MavenProject createMavenProject(String artifactId) {
         MavenProject mavenProject = new MavenProject();
-        mavenProject.setGroupId( "org.apache.maven" );
-        mavenProject.setArtifactId( artifactId );
-        mavenProject.setVersion( "1.0" );
-        mavenProject.setFile( new File( artifactId, "some-dir" ) );
-        mavenProject.setCollectedProjects( new ArrayList<>() );
+        mavenProject.setGroupId("org.apache.maven");
+        mavenProject.setArtifactId(artifactId);
+        mavenProject.setVersion("1.0");
+        mavenProject.setFile(new File(artifactId, "some-dir"));
+        mavenProject.setCollectedProjects(new ArrayList<>());
         return mavenProject;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/internal/MultilineMessageHelperTest.java b/maven-core/src/test/java/org/apache/maven/internal/MultilineMessageHelperTest.java
index 904b39c..819b9e8 100644
--- a/maven-core/src/test/java/org/apache/maven/internal/MultilineMessageHelperTest.java
+++ b/maven-core/src/test/java/org/apache/maven/internal/MultilineMessageHelperTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.internal;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -26,46 +25,46 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class MultilineMessageHelperTest
-{
+class MultilineMessageHelperTest {
 
     @Test
-    public void testBuilderCommon()
-    {
+    void testBuilderCommon() {
         List<String> msgs = new ArrayList<>();
-        msgs.add( "*****************************************************************" );
-        msgs.add( "* Your build is requesting parallel execution, but project      *" );
-        msgs.add( "* contains the following plugin(s) that have goals not marked   *" );
-        msgs.add( "* as @threadSafe to support parallel building.                  *" );
-        msgs.add( "* While this /may/ work fine, please look for plugin updates    *" );
-        msgs.add( "* and/or request plugins be made thread-safe.                   *" );
-        msgs.add( "* If reporting an issue, report it against the plugin in        *" );
-        msgs.add( "* question, not against maven-core                              *" );
-        msgs.add( "*****************************************************************" );
+        msgs.add("*****************************************************************");
+        msgs.add("* Your build is requesting parallel execution, but project      *");
+        msgs.add("* contains the following plugin(s) that have goals not marked   *");
+        msgs.add("* as @threadSafe to support parallel building.                  *");
+        msgs.add("* While this /may/ work fine, please look for plugin updates    *");
+        msgs.add("* and/or request plugins be made thread-safe.                   *");
+        msgs.add("* If reporting an issue, report it against the plugin in        *");
+        msgs.add("* question, not against maven-core                              *");
+        msgs.add("*****************************************************************");
 
-        assertEquals( msgs, MultilineMessageHelper.format(
-                "Your build is requesting parallel execution, but project contains the following "
-                        + "plugin(s) that have goals not marked as @threadSafe to support parallel building.",
-                "While this /may/ work fine, please look for plugin updates and/or "
-                        + "request plugins be made thread-safe.",
-                "If reporting an issue, report it against the plugin in question, not against maven-core"
-        ) );
+        assertEquals(
+                msgs,
+                MultilineMessageHelper.format(
+                        "Your build is requesting parallel execution, but project contains the following "
+                                + "plugin(s) that have goals not marked as @threadSafe to support parallel building.",
+                        "While this /may/ work fine, please look for plugin updates and/or "
+                                + "request plugins be made thread-safe.",
+                        "If reporting an issue, report it against the plugin in question, not against maven-core"));
     }
 
     @Test
-    public void testMojoExecutor()
-    {
+    void testMojoExecutor() {
         List<String> msgs = new ArrayList<>();
-        msgs.add( "*****************************************************************" );
-        msgs.add( "* An aggregator Mojo is already executing in parallel build,    *" );
-        msgs.add( "* but aggregator Mojos require exclusive access to reactor to   *" );
-        msgs.add( "* prevent race conditions. This mojo execution will be blocked  *" );
-        msgs.add( "* until the aggregator work is done.                            *" );
-        msgs.add( "*****************************************************************" );
+        msgs.add("*****************************************************************");
+        msgs.add("* An aggregator Mojo is already executing in parallel build,    *");
+        msgs.add("* but aggregator Mojos require exclusive access to reactor to   *");
+        msgs.add("* prevent race conditions. This mojo execution will be blocked  *");
+        msgs.add("* until the aggregator work is done.                            *");
+        msgs.add("*****************************************************************");
 
-        assertEquals( msgs, MultilineMessageHelper.format(
-                "An aggregator Mojo is already executing in parallel build, but aggregator "
-                        + "Mojos require exclusive access to reactor to prevent race conditions. This "
-                        + "mojo execution will be blocked until the aggregator work is done." ) );
+        assertEquals(
+                msgs,
+                MultilineMessageHelper.format(
+                        "An aggregator Mojo is already executing in parallel build, but aggregator "
+                                + "Mojos require exclusive access to reactor to prevent race conditions. This "
+                                + "mojo execution will be blocked until the aggregator work is done."));
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformerTest.java b/maven-core/src/test/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformerTest.java
deleted file mode 100644
index 5050623..0000000
--- a/maven-core/src/test/java/org/apache/maven/internal/aether/ConsumerModelSourceTransformerTest.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package org.apache.maven.internal.aether;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.InputStream;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-import org.apache.maven.model.Model;
-import org.apache.maven.model.building.TransformerContext;
-import org.junit.jupiter.api.Test;
-import org.xmlunit.assertj.XmlAssert;
-
-public class ConsumerModelSourceTransformerTest
-{
-    private ConsumerModelSourceTransformer transformer = new ConsumerModelSourceTransformer();
-
-    @Test
-    public void transform() throws Exception
-    {
-        Path beforePomFile = Paths.get( "src/test/resources/projects/transform/before.pom").toAbsolutePath();
-        Path afterPomFile = Paths.get( "src/test/resources/projects/transform/after.pom").toAbsolutePath();
-
-        try( InputStream expected = Files.newInputStream( afterPomFile );
-             InputStream result = transformer.transform( beforePomFile, new NoTransformerContext() ) )
-        {
-            XmlAssert.assertThat( result ).and( expected ).areIdentical();
-        }
-    }
-
-    private static class NoTransformerContext implements TransformerContext
-    {
-        @Override
-        public String getUserProperty( String key )
-        {
-            return null;
-        }
-
-        @Override
-        public Model getRawModel( String groupId, String artifactId )
-            throws IllegalStateException
-        {
-            return null;
-        }
-
-        @Override
-        public Model getRawModel( Path p )
-        {
-            return null;
-        }
-    }
-}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactoryTest.java b/maven-core/src/test/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactoryTest.java
new file mode 100644
index 0000000..16b90aa
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/aether/DefaultRepositorySystemSessionFactoryTest.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.aether;
+
+import javax.inject.Inject;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.maven.artifact.InvalidRepositoryException;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.eventspy.internal.EventSpyDispatcher;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.internal.impl.DefaultTypeRegistry;
+import org.apache.maven.rtinfo.RuntimeInformation;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.crypto.SettingsDecrypter;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.eclipse.aether.ConfigurationProperties;
+import org.eclipse.aether.repository.RepositoryPolicy;
+import org.junit.jupiter.api.Test;
+
+import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
+
+/**
+ * UT for {@link DefaultRepositorySystemSessionFactory}.
+ */
+@PlexusTest
+public class DefaultRepositorySystemSessionFactoryTest {
+    @Inject
+    protected MavenRepositorySystem mavenRepositorySystem;
+
+    @Inject
+    protected EventSpyDispatcher eventSpyDispatcher;
+
+    @Inject
+    protected SettingsDecrypter settingsDecrypter;
+
+    @Inject
+    protected org.eclipse.aether.RepositorySystem aetherRepositorySystem;
+
+    @Inject
+    protected ArtifactHandlerManager artifactHandlerManager;
+
+    @Inject
+    protected RuntimeInformation information;
+
+    @Inject
+    protected DefaultTypeRegistry defaultTypeRegistry;
+
+    @Test
+    void isNoSnapshotUpdatesTest() throws InvalidRepositoryException {
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        assertNull(systemSessionFactory.newRepositorySession(request).getUpdatePolicy());
+
+        request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        request.setNoSnapshotUpdates(true);
+        assertEquals(
+                RepositoryPolicy.UPDATE_POLICY_NEVER,
+                systemSessionFactory.newRepositorySession(request).getUpdatePolicy());
+    }
+
+    @Test
+    void isSnapshotUpdatesTest() throws InvalidRepositoryException {
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        request.setUpdateSnapshots(true);
+        assertEquals(
+                RepositoryPolicy.UPDATE_POLICY_ALWAYS,
+                systemSessionFactory.newRepositorySession(request).getUpdatePolicy());
+    }
+
+    @Test
+    void wagonProviderConfigurationTest() throws InvalidRepositoryException {
+        Server server = new Server();
+        server.setId("repository");
+        server.setUsername("jason");
+        server.setPassword("abc123");
+        Xpp3Dom configuration = new Xpp3Dom("configuration");
+        Xpp3Dom wagonProvider = new Xpp3Dom("wagonProvider");
+        wagonProvider.setValue("httpclient");
+        configuration.addChild(wagonProvider);
+        server.setConfiguration(configuration);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        List<Server> servers = new ArrayList<>();
+        servers.add(server);
+        request.setServers(servers);
+
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        PlexusConfiguration plexusConfiguration = (PlexusConfiguration) systemSessionFactory
+                .newRepositorySession(request)
+                .getConfigProperties()
+                .get("aether.connector.wagon.config.repository");
+        assertNotNull(plexusConfiguration);
+        assertEquals(0, plexusConfiguration.getChildCount());
+    }
+
+    @Test
+    void httpConfigurationWithHttpHeadersTest() throws InvalidRepositoryException {
+        Server server = new Server();
+        server.setId("repository");
+        server.setUsername("jason");
+        server.setPassword("abc123");
+        Xpp3Dom httpConfiguration = new Xpp3Dom("httpConfiguration");
+        Xpp3Dom httpHeaders = new Xpp3Dom("httpHeaders");
+        Xpp3Dom property = new Xpp3Dom("property");
+        Xpp3Dom headerName = new Xpp3Dom("name");
+        headerName.setValue("header");
+        Xpp3Dom headerValue = new Xpp3Dom("value");
+        headerValue.setValue("value");
+        property.addChild(headerName);
+        property.addChild(headerValue);
+        httpHeaders.addChild(property);
+        httpConfiguration.addChild(httpHeaders);
+
+        server.setConfiguration(httpConfiguration);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        List<Server> servers = new ArrayList<>();
+        servers.add(server);
+        request.setServers(servers);
+
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        Map<String, String> headers = (Map<String, String>) systemSessionFactory
+                .newRepositorySession(request)
+                .getConfigProperties()
+                .get(ConfigurationProperties.HTTP_HEADERS + "." + server.getId());
+        assertNotNull(headers);
+        assertEquals(1, headers.size());
+        assertEquals("value", headers.get("header"));
+    }
+
+    @Test
+    void connectTimeoutConfigurationTest() throws InvalidRepositoryException {
+        Server server = new Server();
+        server.setId("repository");
+        server.setUsername("jason");
+        server.setPassword("abc123");
+        Xpp3Dom configuration = new Xpp3Dom("configuration");
+        Xpp3Dom connectTimeoutConfiguration = new Xpp3Dom("connectTimeout");
+        connectTimeoutConfiguration.setValue("3000");
+        configuration.addChild(connectTimeoutConfiguration);
+
+        server.setConfiguration(configuration);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        List<Server> servers = new ArrayList<>();
+        servers.add(server);
+        request.setServers(servers);
+
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        int connectionTimeout = (Integer) systemSessionFactory
+                .newRepositorySession(request)
+                .getConfigProperties()
+                .get(ConfigurationProperties.CONNECT_TIMEOUT + "." + server.getId());
+        assertEquals(3000, connectionTimeout);
+    }
+
+    @Test
+    void connectionTimeoutFromHttpConfigurationTest() throws InvalidRepositoryException {
+        Server server = new Server();
+        server.setId("repository");
+        server.setUsername("jason");
+        server.setPassword("abc123");
+
+        Xpp3Dom configuration = new Xpp3Dom("configuration");
+        Xpp3Dom httpConfiguration = new Xpp3Dom("httpConfiguration");
+        Xpp3Dom all = new Xpp3Dom("all");
+        Xpp3Dom connectTimeoutConfiguration = new Xpp3Dom("connectionTimeout");
+        connectTimeoutConfiguration.setValue("3000");
+
+        all.addChild(connectTimeoutConfiguration);
+        httpConfiguration.addChild(all);
+        configuration.addChild(httpConfiguration);
+
+        server.setConfiguration(configuration);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        List<Server> servers = new ArrayList<>();
+        servers.add(server);
+        request.setServers(servers);
+
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        int connectionTimeout = (Integer) systemSessionFactory
+                .newRepositorySession(request)
+                .getConfigProperties()
+                .get(ConfigurationProperties.CONNECT_TIMEOUT + "." + server.getId());
+        assertEquals(3000, connectionTimeout);
+    }
+
+    @Test
+    void requestTimeoutConfigurationTest() throws InvalidRepositoryException {
+        Server server = new Server();
+        server.setId("repository");
+        server.setUsername("jason");
+        server.setPassword("abc123");
+        Xpp3Dom configuration = new Xpp3Dom("configuration");
+        Xpp3Dom requestTimeoutConfiguration = new Xpp3Dom("requestTimeout");
+        requestTimeoutConfiguration.setValue("3000");
+        configuration.addChild(requestTimeoutConfiguration);
+
+        server.setConfiguration(configuration);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        List<Server> servers = new ArrayList<>();
+        servers.add(server);
+        request.setServers(servers);
+
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        int requestTimeout = (Integer) systemSessionFactory
+                .newRepositorySession(request)
+                .getConfigProperties()
+                .get(ConfigurationProperties.REQUEST_TIMEOUT + "." + server.getId());
+        assertEquals(3000, requestTimeout);
+    }
+
+    @Test
+    void readTimeoutFromHttpConfigurationTest() throws InvalidRepositoryException {
+        Server server = new Server();
+        server.setId("repository");
+        server.setUsername("jason");
+        server.setPassword("abc123");
+
+        Xpp3Dom configuration = new Xpp3Dom("configuration");
+        Xpp3Dom httpConfiguration = new Xpp3Dom("httpConfiguration");
+        Xpp3Dom all = new Xpp3Dom("all");
+        Xpp3Dom readTimeoutConfiguration = new Xpp3Dom("readTimeout");
+        readTimeoutConfiguration.setValue("3000");
+
+        all.addChild(readTimeoutConfiguration);
+        httpConfiguration.addChild(all);
+        configuration.addChild(httpConfiguration);
+
+        server.setConfiguration(configuration);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+        List<Server> servers = new ArrayList<>();
+        servers.add(server);
+        request.setServers(servers);
+
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        int requestTimeout = (Integer) systemSessionFactory
+                .newRepositorySession(request)
+                .getConfigProperties()
+                .get(ConfigurationProperties.REQUEST_TIMEOUT + "." + server.getId());
+        assertEquals(3000, requestTimeout);
+    }
+
+    @Test
+    void transportConfigurationTest() throws InvalidRepositoryException {
+        DefaultRepositorySystemSessionFactory systemSessionFactory = new DefaultRepositorySystemSessionFactory(
+                artifactHandlerManager,
+                aetherRepositorySystem,
+                null,
+                settingsDecrypter,
+                eventSpyDispatcher,
+                information,
+                defaultTypeRegistry);
+
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest();
+        request.setLocalRepository(getLocalRepository());
+
+        // native
+        Properties properties = new Properties();
+        properties.setProperty("maven.resolver.transport", "apache");
+        request.setSystemProperties(properties);
+        Map<String, Object> configProperties =
+                systemSessionFactory.newRepositorySession(request).getConfigProperties();
+        assertEquals(String.valueOf(Float.MAX_VALUE), configProperties.get("aether.priority.FileTransporterFactory"));
+        assertEquals(String.valueOf(Float.MAX_VALUE), configProperties.get("aether.priority.HttpTransporterFactory"));
+        properties.remove("maven.resolver.transport");
+
+        // wagon
+        properties.setProperty("maven.resolver.transport", "wagon");
+        request.setSystemProperties(properties);
+        assertEquals(
+                String.valueOf(Float.MAX_VALUE),
+                systemSessionFactory
+                        .newRepositorySession(request)
+                        .getConfigProperties()
+                        .get("aether.priority.WagonTransporterFactory"));
+        properties.remove("maven.resolver.transport");
+
+        // illegal
+        properties.setProperty("maven.resolver.transport", "illegal");
+        request.setSystemProperties(properties);
+        IllegalArgumentException exception = assertThrowsExactly(
+                IllegalArgumentException.class, () -> systemSessionFactory.newRepositorySession(request));
+        assertEquals(
+                "Unknown resolver transport 'illegal'. Supported transports are: wagon, apache, jdk, auto",
+                exception.getMessage());
+        properties.remove("maven.resolver.transport");
+    }
+
+    protected ArtifactRepository getLocalRepository() throws InvalidRepositoryException {
+        File repoDir = new File(getBasedir(), "target/local-repo").getAbsoluteFile();
+
+        return mavenRepositorySystem.createLocalRepository(repoDir);
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListenerTest.java b/maven-core/src/test/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListenerTest.java
new file mode 100644
index 0000000..8e7210b
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/aether/ReverseTreeRepositoryListenerTest.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.aether;
+
+import java.io.File;
+
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RequestTrace;
+import org.eclipse.aether.artifact.Artifact;
+import org.eclipse.aether.collection.CollectStepData;
+import org.eclipse.aether.repository.LocalRepository;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * UT for {@link ReverseTreeRepositoryListener}.
+ */
+class ReverseTreeRepositoryListenerTest {
+    @Test
+    void isLocalRepositoryArtifactTest() {
+        File baseDir = new File("local/repository");
+        LocalRepository localRepository = new LocalRepository(baseDir);
+        RepositorySystemSession session = mock(RepositorySystemSession.class);
+        when(session.getLocalRepository()).thenReturn(localRepository);
+
+        Artifact localRepositoryArtifact = mock(Artifact.class);
+        when(localRepositoryArtifact.getFile()).thenReturn(new File(baseDir, "some/path/within"));
+
+        Artifact nonLocalReposioryArtifact = mock(Artifact.class);
+        when(nonLocalReposioryArtifact.getFile()).thenReturn(new File("something/completely/different"));
+
+        assertThat(
+                ReverseTreeRepositoryListener.isLocalRepositoryArtifactOrMissing(session, localRepositoryArtifact),
+                equalTo(true));
+        assertThat(
+                ReverseTreeRepositoryListener.isLocalRepositoryArtifactOrMissing(session, nonLocalReposioryArtifact),
+                equalTo(false));
+    }
+
+    @Test
+    void isMissingArtifactTest() {
+        File baseDir = new File("local/repository");
+        LocalRepository localRepository = new LocalRepository(baseDir);
+        RepositorySystemSession session = mock(RepositorySystemSession.class);
+        when(session.getLocalRepository()).thenReturn(localRepository);
+
+        Artifact localRepositoryArtifact = mock(Artifact.class);
+        when(localRepositoryArtifact.getFile()).thenReturn(null);
+
+        assertThat(
+                ReverseTreeRepositoryListener.isLocalRepositoryArtifactOrMissing(session, localRepositoryArtifact),
+                equalTo(true));
+    }
+
+    @Test
+    void lookupCollectStepDataTest() {
+        RequestTrace doesNotHaveIt =
+                RequestTrace.newChild(null, "foo").newChild("bar").newChild("baz");
+        assertThat(ReverseTreeRepositoryListener.lookupCollectStepData(doesNotHaveIt), nullValue());
+
+        final CollectStepData data = mock(CollectStepData.class);
+
+        RequestTrace haveItFirst = RequestTrace.newChild(null, data)
+                .newChild("foo")
+                .newChild("bar")
+                .newChild("baz");
+        assertThat(ReverseTreeRepositoryListener.lookupCollectStepData(haveItFirst), sameInstance(data));
+
+        RequestTrace haveItLast = RequestTrace.newChild(null, "foo")
+                .newChild("bar")
+                .newChild("baz")
+                .newChild(data);
+        assertThat(ReverseTreeRepositoryListener.lookupCollectStepData(haveItLast), sameInstance(data));
+
+        RequestTrace haveIt = RequestTrace.newChild(null, "foo")
+                .newChild("bar")
+                .newChild(data)
+                .newChild("baz");
+        assertThat(ReverseTreeRepositoryListener.lookupCollectStepData(haveIt), sameInstance(data));
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/DefaultSessionTest.java b/maven-core/src/test/java/org/apache/maven/internal/impl/DefaultSessionTest.java
new file mode 100644
index 0000000..e8ff9c0
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/impl/DefaultSessionTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.root.RootLocator;
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+
+public class DefaultSessionTest {
+
+    @Test
+    void testRootDirectoryWithNull() {
+        RepositorySystemSession rss = MavenRepositorySystemUtils.newSession();
+        DefaultMavenExecutionRequest mer = new DefaultMavenExecutionRequest();
+        MavenSession ms = new MavenSession(null, rss, mer, null);
+        DefaultSession session =
+                new DefaultSession(ms, mock(RepositorySystem.class), Collections.emptyList(), null, null, null);
+
+        assertEquals(
+                RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE,
+                assertThrows(IllegalStateException.class, session::getRootDirectory)
+                        .getMessage());
+    }
+
+    @Test
+    void testRootDirectory() {
+        RepositorySystemSession rss = MavenRepositorySystemUtils.newSession();
+        DefaultMavenExecutionRequest mer = new DefaultMavenExecutionRequest();
+        MavenSession ms = new MavenSession(null, rss, mer, null);
+        ms.getRequest().setRootDirectory(Paths.get("myRootDirectory"));
+        DefaultSession session =
+                new DefaultSession(ms, mock(RepositorySystem.class), Collections.emptyList(), null, null, null);
+
+        assertEquals(Paths.get("myRootDirectory"), session.getRootDirectory());
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/PropertiesAsMapTest.java b/maven-core/src/test/java/org/apache/maven/internal/impl/PropertiesAsMapTest.java
new file mode 100644
index 0000000..1d7036f
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/impl/PropertiesAsMapTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import java.util.Iterator;
+import java.util.Map.Entry;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.Set;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class PropertiesAsMapTest {
+
+    @Test
+    void testPropertiesAsMap() {
+        Properties props = new Properties();
+        props.setProperty("foo1", "bar1");
+        props.setProperty("foo2", "bar2");
+        PropertiesAsMap pam = new PropertiesAsMap(props);
+        assertEquals(2, pam.size());
+        Set<Entry<String, String>> set = pam.entrySet();
+        assertNotNull(set);
+        assertEquals(2, set.size());
+        Iterator<Entry<String, String>> iterator = set.iterator();
+        assertNotNull(iterator);
+        assertTrue(iterator.hasNext());
+        assertTrue(iterator.hasNext());
+        Entry<String, String> entry = iterator.next();
+        assertNotNull(entry);
+        entry = iterator.next();
+        assertNotNull(entry);
+        assertThrows(NoSuchElementException.class, () -> iterator.next());
+        assertFalse(iterator.hasNext());
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java
new file mode 100644
index 0000000..bac881a
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestApi.java
@@ -0,0 +1,146 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import javax.inject.Inject;
+
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.Optional;
+
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.ArtifactCoordinate;
+import org.apache.maven.api.Node;
+import org.apache.maven.api.Project;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.services.ProjectBuilder;
+import org.apache.maven.api.services.ProjectBuilderRequest;
+import org.apache.maven.api.services.SettingsBuilder;
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.execution.scope.internal.MojoExecutionScope;
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.apache.maven.rtinfo.RuntimeInformation;
+import org.apache.maven.session.scope.internal.SessionScope;
+import org.apache.maven.toolchain.DefaultToolchainManagerPrivate;
+import org.apache.maven.toolchain.building.ToolchainsBuilder;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@PlexusTest
+class TestApi {
+
+    Session session;
+
+    @Inject
+    RepositorySystem repositorySystem;
+
+    @Inject
+    org.apache.maven.project.ProjectBuilder projectBuilder;
+
+    @Inject
+    MavenRepositorySystem mavenRepositorySystem;
+
+    @Inject
+    DefaultToolchainManagerPrivate toolchainManagerPrivate;
+
+    @Inject
+    PlexusContainer plexusContainer;
+
+    @Inject
+    MojoExecutionScope mojoExecutionScope;
+
+    @Inject
+    RuntimeInformation runtimeInformation;
+
+    @Inject
+    ArtifactHandlerManager artifactHandlerManager;
+
+    @Inject
+    SessionScope sessionScope;
+
+    @Inject
+    SettingsBuilder settingsBuilder;
+
+    @Inject
+    ToolchainsBuilder toolchainsBuilder;
+
+    @BeforeEach
+    void setup() {
+        RepositorySystemSession rss = MavenRepositorySystemUtils.newSession();
+        DefaultMavenExecutionRequest mer = new DefaultMavenExecutionRequest();
+        DefaultMavenExecutionResult meres = new DefaultMavenExecutionResult();
+        MavenSession ms = new MavenSession(rss, mer, meres);
+        DefaultSession session = new DefaultSession(
+                ms,
+                repositorySystem,
+                Collections.emptyList(),
+                mavenRepositorySystem,
+                plexusContainer,
+                runtimeInformation);
+        DefaultLocalRepository localRepository =
+                new DefaultLocalRepository(new LocalRepository("target/test-classes/apiv4-repo"));
+        org.apache.maven.api.RemoteRepository remoteRepository = session.getRemoteRepository(
+                new RemoteRepository.Builder("mirror", "default", "file:target/test-classes/repo").build());
+        this.session = session.withLocalRepository(localRepository)
+                .withRemoteRepositories(Collections.singletonList(remoteRepository));
+
+        sessionScope.enter();
+        sessionScope.seed(InternalSession.class, InternalSession.from(this.session));
+    }
+
+    @Test
+    void testCreateAndResolveArtifact() throws Exception {
+        ArtifactCoordinate coord =
+                session.createArtifactCoordinate("org.codehaus.plexus", "plexus-utils", "1.4.5", "pom");
+
+        Artifact resolved = session.resolveArtifact(coord);
+        Optional<Path> op = session.getArtifactPath(resolved);
+        assertTrue(op.isPresent());
+        assertNotNull(op.get());
+
+        Project project = session.getService(ProjectBuilder.class)
+                .build(ProjectBuilderRequest.builder()
+                        .session(session)
+                        .path(op.get())
+                        .processPlugins(false)
+                        .resolveDependencies(false)
+                        .build())
+                .getProject()
+                .get();
+        assertNotNull(project);
+
+        Artifact artifact =
+                session.createArtifact("org.codehaus.plexus", "plexus-container-default", "1.0-alpha-32", "jar");
+        Node root = session.collectDependencies(artifact);
+        assertNotNull(root);
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java
new file mode 100644
index 0000000..cb86c6e
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/impl/TestArtifactHandler.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.impl;
+
+import org.apache.maven.artifact.handler.ArtifactHandler;
+
+/**
+ * Assists unit testing.
+ *
+ */
+class TestArtifactHandler implements ArtifactHandler {
+
+    private String type;
+
+    private String extension;
+
+    public TestArtifactHandler(String type) {
+        this(type, type);
+    }
+
+    public TestArtifactHandler(String type, String extension) {
+        this.type = type;
+        this.extension = extension;
+    }
+
+    public String getClassifier() {
+        return null;
+    }
+
+    public String getDirectory() {
+        return getPackaging() + "s";
+    }
+
+    public String getExtension() {
+        return extension;
+    }
+
+    public String getLanguage() {
+        return "java";
+    }
+
+    public String getPackaging() {
+        return type;
+    }
+
+    public boolean isAddedToClasspath() {
+        return true;
+    }
+
+    public boolean isIncludesDependencies() {
+        return false;
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/AbstractRepositoryTestCase.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/AbstractRepositoryTestCase.java
new file mode 100644
index 0000000..728e749
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/AbstractRepositoryTestCase.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation;
+
+import javax.inject.Inject;
+
+import java.net.MalformedURLException;
+
+import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositoryListener;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.RemoteRepository;
+import org.eclipse.aether.transfer.TransferListener;
+import org.junit.jupiter.api.BeforeEach;
+import org.mockito.Mockito;
+
+import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
+
+@PlexusTest
+public abstract class AbstractRepositoryTestCase {
+    @Inject
+    protected RepositorySystem system;
+
+    @Inject
+    protected PlexusContainer container;
+
+    protected RepositorySystemSession session;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        session = newMavenRepositorySystemSession(system);
+    }
+
+    protected PlexusContainer getContainer() {
+        return container;
+    }
+
+    public static RepositorySystemSession newMavenRepositorySystemSession(RepositorySystem system) {
+        DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
+
+        LocalRepository localRepo = new LocalRepository("target/local-repo");
+        session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
+
+        session.setTransferListener(Mockito.mock(TransferListener.class));
+        session.setRepositoryListener(Mockito.mock(RepositoryListener.class));
+
+        return session;
+    }
+
+    public static RemoteRepository newTestRepository() throws MalformedURLException {
+        return new RemoteRepository.Builder(
+                        "repo",
+                        "default",
+                        getTestFile("target/test-classes/repo").toURI().toURL().toString())
+                .build();
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformerTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformerTest.java
new file mode 100644
index 0000000..970881a
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomArtifactTransformerTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.TransformerContext;
+import org.apache.maven.model.v4.MavenStaxReader;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.SessionData;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.xmlunit.assertj.XmlAssert;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+class ConsumerPomArtifactTransformerTest {
+
+    @Test
+    void transform() throws Exception {
+        RepositorySystemSession systemSessionMock = Mockito.mock(RepositorySystemSession.class);
+        SessionData sessionDataMock = Mockito.mock(SessionData.class);
+        when(systemSessionMock.getData()).thenReturn(sessionDataMock);
+        when(sessionDataMock.get(any())).thenReturn(new NoTransformerContext());
+
+        Path beforePomFile =
+                Paths.get("src/test/resources/projects/transform/before.pom").toAbsolutePath();
+        Path afterPomFile =
+                Paths.get("src/test/resources/projects/transform/after.pom").toAbsolutePath();
+        Path tempFile = Files.createTempFile("", ".pom");
+        Files.delete(tempFile);
+        try (InputStream expected = Files.newInputStream(beforePomFile)) {
+            Model model = new Model(new MavenStaxReader().read(expected));
+            MavenProject project = new MavenProject(model);
+            project.setOriginalModel(model);
+            DefaultConsumerPomArtifactTransformer t = new DefaultConsumerPomArtifactTransformer((s, p, f) -> {
+                try (InputStream is = Files.newInputStream(f)) {
+                    return DefaultConsumerPomBuilder.transform(new MavenStaxReader().read(is), project);
+                }
+            });
+
+            t.transform(project, systemSessionMock, beforePomFile, tempFile);
+        }
+        XmlAssert.assertThat(afterPomFile.toFile()).and(tempFile.toFile()).areIdentical();
+    }
+
+    @Test
+    void injectTransformedArtifactsWithoutPomShouldNotInjectAnyArtifacts() throws IOException {
+        MavenProject emptyProject = new MavenProject();
+
+        RepositorySystemSession systemSessionMock = Mockito.mock(RepositorySystemSession.class);
+        SessionData sessionDataMock = Mockito.mock(SessionData.class);
+        when(systemSessionMock.getData()).thenReturn(sessionDataMock);
+        when(sessionDataMock.get(any())).thenReturn(new NoTransformerContext());
+
+        new DefaultConsumerPomArtifactTransformer((session, project, src) -> null)
+                .injectTransformedArtifacts(systemSessionMock, emptyProject);
+
+        assertThat(emptyProject.getAttachedArtifacts()).isEmpty();
+    }
+
+    private static class NoTransformerContext implements TransformerContext {
+        @Override
+        public String getUserProperty(String key) {
+            return null;
+        }
+
+        @Override
+        public Model getRawModel(Path from, String groupId, String artifactId) throws IllegalStateException {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Model getRawModel(Path from, Path p) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public Path locate(Path path) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
new file mode 100644
index 0000000..9cf8c93
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.transformation.impl;
+
+import javax.inject.Inject;
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.internal.transformation.AbstractRepositoryTestCase;
+import org.apache.maven.model.v4.MavenStaxReader;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ConsumerPomBuilderTest extends AbstractRepositoryTestCase {
+
+    @Inject
+    ConsumerPomBuilder builder;
+
+    @Test
+    void testTrivialConsumer() throws Exception {
+        MavenProject project;
+        Path file = Paths.get("src/test/resources/consumer/trivial/child/pom.xml");
+        try (InputStream inputStream = Files.newInputStream(file)) {
+            org.apache.maven.model.Model model =
+                    new org.apache.maven.model.Model(new MavenStaxReader().read(inputStream));
+            project = new MavenProject(model);
+            project.setRootDirectory(Paths.get("src/test/resources/consumer/trivial"));
+            project.setOriginalModel(model);
+            project.setRemoteArtifactRepositories(Collections.singletonList(new MavenArtifactRepository(
+                    "central", "http://repo.maven.apache.org/", new DefaultRepositoryLayout(), null, null)));
+        }
+        Model model = builder.build(session, project, file);
+
+        assertNotNull(model);
+    }
+
+    @Test
+    void testSimpleConsumer() throws Exception {
+        MavenProject project;
+        Path file = Paths.get("src/test/resources/consumer/simple/simple-parent/simple-weather/pom.xml");
+        ((DefaultRepositorySystemSession) session).setUserProperty("changelist", "MNG6957");
+        try (InputStream inputStream = Files.newInputStream(file)) {
+            org.apache.maven.model.Model model =
+                    new org.apache.maven.model.Model(new MavenStaxReader().read(inputStream));
+            project = new MavenProject(model);
+            project.setRootDirectory(Paths.get("src/test/resources/consumer/simple"));
+            project.setRemoteArtifactRepositories(Collections.singletonList(new MavenArtifactRepository(
+                    "central", "http://repo.maven.apache.org/", new DefaultRepositoryLayout(), null, null)));
+            project.setOriginalModel(model);
+        }
+        Model model = builder.build(session, project, file);
+
+        assertNotNull(model);
+        assertTrue(model.getProfiles().isEmpty());
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java
index 046227a..584c258 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/DefaultLifecyclesTest.java
@@ -1,28 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.lifecycle;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
-import javax.inject.Inject;
-
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.codehaus.plexus.testing.PlexusTest;
 import org.junit.jupiter.api.Test;
 
@@ -30,81 +36,76 @@
 import static org.hamcrest.Matchers.arrayWithSize;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 /**
- * @author Kristian Rosenvold
  */
 @PlexusTest
-public class DefaultLifecyclesTest
-{
+class DefaultLifecyclesTest {
     @Inject
     private DefaultLifecycles defaultLifeCycles;
 
     @Test
-    public void testDefaultLifecycles()
-    {
+    void testDefaultLifecycles() {
         final List<Lifecycle> lifecycles = defaultLifeCycles.getLifeCycles();
-        assertThat( lifecycles, hasSize( 4 ) );
-        assertThat( DefaultLifecycles.STANDARD_LIFECYCLES,  arrayWithSize( 4 ) );
+        assertThat(lifecycles, hasSize(4));
+        assertThat(DefaultLifecycles.STANDARD_LIFECYCLES, arrayWithSize(4));
     }
 
     @Test
-    public void testDefaultLifecycle()
-    {
-        final Lifecycle lifecycle = getLifeCycleById( "default" );
-        assertThat( lifecycle.getId(), is( "default" )  );
-        assertThat( lifecycle.getPhases(), hasSize( 23 ) );
+    void testDefaultLifecycle() {
+        final Lifecycle lifecycle = getLifeCycleById("default");
+        assertThat(lifecycle.getId(), is("default"));
+        assertThat(lifecycle.getPhases(), hasSize(23));
     }
 
     @Test
-    public void testCleanLifecycle()
-    {
-        final Lifecycle lifecycle = getLifeCycleById( "clean" );
-        assertThat( lifecycle.getId(), is( "clean" )  );
-        assertThat( lifecycle.getPhases(), hasSize( 3 ) );
+    void testCleanLifecycle() {
+        final Lifecycle lifecycle = getLifeCycleById("clean");
+        assertThat(lifecycle.getId(), is("clean"));
+        assertThat(lifecycle.getPhases(), hasSize(3));
     }
 
     @Test
-    public void testSiteLifecycle()
-    {
-        final Lifecycle lifecycle = getLifeCycleById( "site" );
-        assertThat( lifecycle.getId(), is( "site" )  );
-        assertThat( lifecycle.getPhases(), hasSize( 4 ) );
+    void testSiteLifecycle() {
+        final Lifecycle lifecycle = getLifeCycleById("site");
+        assertThat(lifecycle.getId(), is("site"));
+        assertThat(lifecycle.getPhases(), hasSize(4));
     }
 
     @Test
-    public void testWrapperLifecycle()
-    {
-        final Lifecycle lifecycle = getLifeCycleById( "wrapper" );
-        assertThat( lifecycle.getId(), is( "wrapper" )  );
-        assertThat( lifecycle.getPhases(), hasSize( 1 ) );
+    void testWrapperLifecycle() {
+        final Lifecycle lifecycle = getLifeCycleById("wrapper");
+        assertThat(lifecycle.getId(), is("wrapper"));
+        assertThat(lifecycle.getPhases(), hasSize(1));
     }
 
     @Test
-    public void testCustomLifecycle()
-    {
+    void testCustomLifecycle() throws ComponentLookupException {
         List<Lifecycle> myLifecycles = new ArrayList<>();
-        Lifecycle myLifecycle = new Lifecycle( "etl",
-                                               Arrays.asList( "extract", "transform", "load" ),
-                                               Collections.emptyMap() );
-        myLifecycles.add( myLifecycle );
-        myLifecycles.addAll( defaultLifeCycles.getLifeCycles() );
+        Lifecycle myLifecycle =
+                new Lifecycle("etl", Arrays.asList("extract", "transform", "load"), Collections.emptyMap());
+        myLifecycles.add(myLifecycle);
+        myLifecycles.addAll(defaultLifeCycles.getLifeCycles());
 
-        DefaultLifecycles dl = new DefaultLifecycles( myLifecycles.stream()
-                                                            .collect( Collectors.toMap( l -> l.getId(), l -> l ) ) );
+        Map<String, Lifecycle> lifeCycles = myLifecycles.stream().collect(Collectors.toMap(Lifecycle::getId, l -> l));
+        PlexusContainer mockedPlexusContainer = mock(PlexusContainer.class);
+        when(mockedPlexusContainer.lookupMap(Lifecycle.class)).thenReturn(lifeCycles);
 
-        assertThat( dl.getLifeCycles().get( 0 ).getId(), is( "clean" ) );
-        assertThat( dl.getLifeCycles().get( 1 ).getId(), is( "default" ) );
-        assertThat( dl.getLifeCycles().get( 2 ).getId(), is( "site" ) );
-        assertThat( dl.getLifeCycles().get( 3 ).getId(), is( "wrapper" ) );
-        assertThat( dl.getLifeCycles().get( 4 ).getId(), is( "etl" ) );
+        DefaultLifecycles dl = new DefaultLifecycles(mockedPlexusContainer);
+
+        assertThat(dl.getLifeCycles().get(0).getId(), is("clean"));
+        assertThat(dl.getLifeCycles().get(1).getId(), is("default"));
+        assertThat(dl.getLifeCycles().get(2).getId(), is("site"));
+        assertThat(dl.getLifeCycles().get(3).getId(), is("wrapper"));
+        assertThat(dl.getLifeCycles().get(4).getId(), is("etl"));
     }
 
-    private Lifecycle getLifeCycleById( String id )
-    {
+    private Lifecycle getLifeCycleById(String id) {
         return defaultLifeCycles.getLifeCycles().stream()
-                        .filter( l -> id.equals( l.getId() ) )
-                        .findFirst()
-                        .orElseThrow( IllegalArgumentException::new );
+                .filter(l -> id.equals(l.getId()))
+                .findFirst()
+                .orElseThrow(IllegalArgumentException::new);
     }
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java
index b111969..843938f 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingMojoExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,58 +16,46 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
+package org.apache.maven.lifecycle;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
 import org.apache.maven.execution.MojoExecutionEvent;
 import org.apache.maven.execution.MojoExecutionListener;
 import org.apache.maven.plugin.MojoExecutionException;
 
 @Named
 @Singleton
-public class DelegatingMojoExecutionListener
-    implements MojoExecutionListener
-{
+public class DelegatingMojoExecutionListener implements MojoExecutionListener {
     private final List<MojoExecutionListener> listeners = new CopyOnWriteArrayList<>();
 
-    public void beforeMojoExecution( MojoExecutionEvent event )
-        throws MojoExecutionException
-    {
-        for ( MojoExecutionListener listener : listeners )
-        {
-            listener.beforeMojoExecution( event );
+    public void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException {
+        for (MojoExecutionListener listener : listeners) {
+            listener.beforeMojoExecution(event);
         }
     }
 
-    public void afterMojoExecutionSuccess( MojoExecutionEvent event )
-        throws MojoExecutionException
-    {
-        for ( MojoExecutionListener listener : listeners )
-        {
-            listener.afterMojoExecutionSuccess( event );
+    public void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException {
+        for (MojoExecutionListener listener : listeners) {
+            listener.afterMojoExecutionSuccess(event);
         }
     }
 
-    public void afterExecutionFailure( MojoExecutionEvent event )
-    {
-        for ( MojoExecutionListener listener : listeners )
-        {
-            listener.afterExecutionFailure( event );
+    public void afterExecutionFailure(MojoExecutionEvent event) {
+        for (MojoExecutionListener listener : listeners) {
+            listener.afterExecutionFailure(event);
         }
     }
 
-    public void addMojoExecutionListener( MojoExecutionListener listener )
-    {
-        this.listeners.add( listener );
+    public void addMojoExecutionListener(MojoExecutionListener listener) {
+        this.listeners.add(listener);
     }
 
-    public void removeMojoExecutionListener( MojoExecutionListener listener )
-    {
-        this.listeners.remove( listener );
+    public void removeMojoExecutionListener(MojoExecutionListener listener) {
+        this.listeners.remove(listener);
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java
index 4266c15..d90c373 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/DelegatingProjectExecutionListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,65 +16,51 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
+package org.apache.maven.lifecycle;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
 import org.apache.maven.execution.ProjectExecutionEvent;
 import org.apache.maven.execution.ProjectExecutionListener;
 
 @Named
 @Singleton
-public class DelegatingProjectExecutionListener
-    implements ProjectExecutionListener
-{
+public class DelegatingProjectExecutionListener implements ProjectExecutionListener {
     private final List<ProjectExecutionListener> listeners = new CopyOnWriteArrayList<>();
 
-    public void beforeProjectExecution( ProjectExecutionEvent event )
-        throws LifecycleExecutionException
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.beforeProjectExecution( event );
+    public void beforeProjectExecution(ProjectExecutionEvent event) throws LifecycleExecutionException {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.beforeProjectExecution(event);
         }
     }
 
-    public void beforeProjectLifecycleExecution( ProjectExecutionEvent event )
-        throws LifecycleExecutionException
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.beforeProjectLifecycleExecution( event );
+    public void beforeProjectLifecycleExecution(ProjectExecutionEvent event) throws LifecycleExecutionException {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.beforeProjectLifecycleExecution(event);
         }
     }
 
-    public void afterProjectExecutionSuccess( ProjectExecutionEvent event )
-        throws LifecycleExecutionException
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.afterProjectExecutionSuccess( event );
+    public void afterProjectExecutionSuccess(ProjectExecutionEvent event) throws LifecycleExecutionException {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.afterProjectExecutionSuccess(event);
         }
     }
 
-    public void afterProjectExecutionFailure( ProjectExecutionEvent event )
-    {
-        for ( ProjectExecutionListener listener : listeners )
-        {
-            listener.afterProjectExecutionFailure( event );
+    public void afterProjectExecutionFailure(ProjectExecutionEvent event) {
+        for (ProjectExecutionListener listener : listeners) {
+            listener.afterProjectExecutionFailure(event);
         }
     }
 
-    public void addProjectExecutionListener( ProjectExecutionListener listener )
-    {
-        this.listeners.add( listener );
+    public void addProjectExecutionListener(ProjectExecutionListener listener) {
+        this.listeners.add(listener);
     }
 
-    public void removeProjectExecutionListener( ProjectExecutionListener listener )
-    {
-        this.listeners.remove( listener );
+    public void removeProjectExecutionListener(ProjectExecutionListener listener) {
+        this.listeners.remove(listener);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java b/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java
index a812c26..a73adac 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/EmptyLifecyclePluginAnalyzer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -27,51 +26,41 @@
 import org.apache.maven.model.PluginExecution;
 
 /**
- * @author Benjamin Bentmann
  */
-public class EmptyLifecyclePluginAnalyzer
-    implements LifeCyclePluginAnalyzer
-{
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
+public class EmptyLifecyclePluginAnalyzer implements LifeCyclePluginAnalyzer {
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
         Set<Plugin> plugins;
 
         // NOTE: The upper-case packaging name is intentional, that's a special hinting mode used for certain tests
-        if ( "JAR".equals( packaging ) )
-        {
+        if ("JAR".equals(packaging)) {
             plugins = new LinkedHashSet<>();
 
-            plugins.add( newPlugin( "maven-compiler-plugin", "compile", "testCompile" ) );
-            plugins.add( newPlugin( "maven-resources-plugin", "resources", "testResources" ) );
-            plugins.add( newPlugin( "maven-surefire-plugin", "test" ) );
-            plugins.add( newPlugin( "maven-jar-plugin", "jar" ) );
-            plugins.add( newPlugin( "maven-install-plugin", "install" ) );
-            plugins.add( newPlugin( "maven-deploy-plugin", "deploy" ) );
-        }
-        else
-        {
+            plugins.add(newPlugin("maven-compiler-plugin", "compile", "testCompile"));
+            plugins.add(newPlugin("maven-resources-plugin", "resources", "testResources"));
+            plugins.add(newPlugin("maven-surefire-plugin", "test"));
+            plugins.add(newPlugin("maven-jar-plugin", "jar"));
+            plugins.add(newPlugin("maven-install-plugin", "install"));
+            plugins.add(newPlugin("maven-deploy-plugin", "deploy"));
+        } else {
             plugins = Collections.emptySet();
         }
 
         return plugins;
     }
 
-    private Plugin newPlugin( String artifactId, String... goals )
-    {
+    private Plugin newPlugin(String artifactId, String... goals) {
         Plugin plugin = new Plugin();
 
-        plugin.setGroupId( "org.apache.maven.plugins" );
-        plugin.setArtifactId( artifactId );
+        plugin.setGroupId("org.apache.maven.plugins");
+        plugin.setArtifactId(artifactId);
 
-        for ( String goal : goals )
-        {
+        for (String goal : goals) {
             PluginExecution pluginExecution = new PluginExecution();
-            pluginExecution.setId( "default-" + goal );
-            pluginExecution.addGoal( goal );
-            plugin.addExecution( pluginExecution );
+            pluginExecution.setId("default-" + goal);
+            pluginExecution.addGoal(goal);
+            plugin.addExecution(pluginExecution);
         }
 
         return plugin;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorSubModulesTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorSubModulesTest.java
index cc2961f..98c5c33 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorSubModulesTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorSubModulesTest.java
@@ -1,21 +1,25 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
-
 package org.apache.maven.lifecycle;
 
+import javax.inject.Inject;
+
 import org.apache.maven.AbstractCoreMavenComponentTestCase;
 import org.apache.maven.exception.ExceptionHandler;
 import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver;
@@ -23,9 +27,6 @@
 import org.apache.maven.lifecycle.internal.LifecycleModuleBuilder;
 import org.apache.maven.lifecycle.internal.LifecycleTaskSegmentCalculator;
 import org.apache.maven.lifecycle.internal.MojoExecutor;
-
-import javax.inject.Inject;
-
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -33,12 +34,8 @@
 /**
  * Just asserts that it's able to create those components. Handy when CDI container gets a nervous breakdown.
  *
- * @author Kristian Rosenvold
  */
-
-public class LifecycleExecutorSubModulesTest
-    extends AbstractCoreMavenComponentTestCase
-{
+class LifecycleExecutorSubModulesTest extends AbstractCoreMavenComponentTestCase {
     @Inject
     private DefaultLifecycles defaultLifeCycles;
 
@@ -63,23 +60,19 @@
     @Inject
     private ExceptionHandler exceptionHandler;
 
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/lifecycle-executor";
     }
 
     @Test
-    public void testCreation()
-        throws Exception
-    {
-        assertNotNull( defaultLifeCycles );
-        assertNotNull( mojoExecutor );
-        assertNotNull( lifeCycleBuilder );
-        assertNotNull( lifeCycleDependencyResolver );
-        assertNotNull( lifeCycleExecutionPlanCalculator );
-        assertNotNull( lifeCyclePluginAnalyzer );
-        assertNotNull( lifeCycleTaskSegmentCalculator );
-        assertNotNull( exceptionHandler );
+    void testCreation() throws Exception {
+        assertNotNull(defaultLifeCycles);
+        assertNotNull(mojoExecutor);
+        assertNotNull(lifeCycleBuilder);
+        assertNotNull(lifeCycleDependencyResolver);
+        assertNotNull(lifeCycleExecutionPlanCalculator);
+        assertNotNull(lifeCyclePluginAnalyzer);
+        assertNotNull(lifeCycleTaskSegmentCalculator);
+        assertNotNull(exceptionHandler);
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
index 4daf735..2c742b4 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/LifecycleExecutorTest.java
@@ -1,19 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.lifecycle;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -23,6 +28,7 @@
 import java.util.List;
 
 import org.apache.maven.AbstractCoreMavenComponentTestCase;
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.MojoExecutionEvent;
 import org.apache.maven.execution.MojoExecutionListener;
@@ -41,7 +47,6 @@
 import org.apache.maven.plugin.MojoNotFoundException;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.junit.jupiter.api.Test;
 
 import static org.hamcrest.MatcherAssert.assertThat;
@@ -51,11 +56,7 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-import javax.inject.Inject;
-
-public class LifecycleExecutorTest
-    extends AbstractCoreMavenComponentTestCase
-{
+class LifecycleExecutorTest extends AbstractCoreMavenComponentTestCase {
     @Inject
     private DefaultLifecycleExecutor lifecycleExecutor;
 
@@ -68,8 +69,7 @@
     @Inject
     private MojoDescriptorCreator mojoDescriptorCreator;
 
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/lifecycle-executor";
     }
 
@@ -78,470 +78,453 @@
     // -----------------------------------------------------------------------------------------------
 
     @Test
-    public void testCalculationOfBuildPlanWithIndividualTaskWherePluginIsSpecifiedInThePom()
-        throws Exception
-    {
+    void testCalculationOfBuildPlanWithIndividualTaskWherePluginIsSpecifiedInThePom() throws Exception {
         // We are doing something like "mvn resources:resources" where no version is specified but this
         // project we are working on has the version specified in the POM so the version should come from there.
-        File pom = getProject( "project-basic" );
-        MavenSession session = createMavenSession( pom );
-        assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
-        assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = getExecutions( calculateExecutionPlan( session, "resources:resources" ) );
-        assertEquals( 1, executionPlan.size() );
-        MojoExecution mojoExecution = executionPlan.get( 0 );
-        assertNotNull( mojoExecution );
-        assertEquals( "org.apache.maven.plugins",
-                      mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId() );
-        assertEquals( "maven-resources-plugin",
-                      mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId() );
-        assertEquals( "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion() );
+        File pom = getProject("project-basic");
+        MavenSession session = createMavenSession(pom);
+        assertEquals("project-basic", session.getCurrentProject().getArtifactId());
+        assertEquals("1.0", session.getCurrentProject().getVersion());
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan(session, "resources:resources"));
+        assertEquals(1, executionPlan.size());
+        MojoExecution mojoExecution = executionPlan.get(0);
+        assertNotNull(mojoExecution);
+        assertEquals(
+                "org.apache.maven.plugins",
+                mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId());
+        assertEquals(
+                "maven-resources-plugin",
+                mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId());
+        assertEquals(
+                "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion());
     }
 
     @Test
-    public void testCalculationOfBuildPlanWithIndividualTaskOfTheCleanLifecycle()
-        throws Exception
-    {
+    void testCalculationOfBuildPlanWithIndividualTaskOfTheCleanLifecycle() throws Exception {
         // We are doing something like "mvn clean:clean" where no version is specified but this
         // project we are working on has the version specified in the POM so the version should come from there.
-        File pom = getProject( "project-basic" );
-        MavenSession session = createMavenSession( pom );
-        assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
-        assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = getExecutions( calculateExecutionPlan( session, "clean" ) );
-        assertEquals( 1, executionPlan.size() );
-        MojoExecution mojoExecution = executionPlan.get( 0 );
-        assertNotNull( mojoExecution );
-        assertEquals( "org.apache.maven.plugins",
-                      mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId() );
-        assertEquals( "maven-clean-plugin", mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId() );
-        assertEquals( "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion() );
+        File pom = getProject("project-basic");
+        MavenSession session = createMavenSession(pom);
+        assertEquals("project-basic", session.getCurrentProject().getArtifactId());
+        assertEquals("1.0", session.getCurrentProject().getVersion());
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan(session, "clean"));
+        assertEquals(1, executionPlan.size());
+        MojoExecution mojoExecution = executionPlan.get(0);
+        assertNotNull(mojoExecution);
+        assertEquals(
+                "org.apache.maven.plugins",
+                mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId());
+        assertEquals(
+                "maven-clean-plugin",
+                mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId());
+        assertEquals(
+                "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion());
     }
 
     @Test
-    public void testCalculationOfBuildPlanWithIndividualTaskOfTheCleanCleanGoal()
-        throws Exception
-    {
+    void testCalculationOfBuildPlanWithIndividualTaskOfTheCleanCleanGoal() throws Exception {
         // We are doing something like "mvn clean:clean" where no version is specified but this
         // project we are working on has the version specified in the POM so the version should come from there.
-        File pom = getProject( "project-basic" );
-        MavenSession session = createMavenSession( pom );
-        assertEquals( "project-basic", session.getCurrentProject().getArtifactId() );
-        assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = getExecutions( calculateExecutionPlan( session, "clean:clean" ) );
-        assertEquals( 1, executionPlan.size() );
-        MojoExecution mojoExecution = executionPlan.get( 0 );
-        assertNotNull( mojoExecution );
-        assertEquals( "org.apache.maven.plugins",
-                      mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId() );
-        assertEquals( "maven-clean-plugin", mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId() );
-        assertEquals( "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion() );
+        File pom = getProject("project-basic");
+        MavenSession session = createMavenSession(pom);
+        assertEquals("project-basic", session.getCurrentProject().getArtifactId());
+        assertEquals("1.0", session.getCurrentProject().getVersion());
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan(session, "clean:clean"));
+        assertEquals(1, executionPlan.size());
+        MojoExecution mojoExecution = executionPlan.get(0);
+        assertNotNull(mojoExecution);
+        assertEquals(
+                "org.apache.maven.plugins",
+                mojoExecution.getMojoDescriptor().getPluginDescriptor().getGroupId());
+        assertEquals(
+                "maven-clean-plugin",
+                mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId());
+        assertEquals(
+                "0.1", mojoExecution.getMojoDescriptor().getPluginDescriptor().getVersion());
     }
 
-    List<MojoExecution> getExecutions( MavenExecutionPlan mavenExecutionPlan )
-    {
+    List<MojoExecution> getExecutions(MavenExecutionPlan mavenExecutionPlan) {
         List<MojoExecution> result = new ArrayList<>();
-        for ( ExecutionPlanItem executionPlanItem : mavenExecutionPlan )
-        {
-            result.add( executionPlanItem.getMojoExecution() );
+        for (ExecutionPlanItem executionPlanItem : mavenExecutionPlan) {
+            result.add(executionPlanItem.getMojoExecution());
         }
         return result;
     }
 
     // We need to take in multiple lifecycles
-    public void testCalculationOfBuildPlanTasksOfTheCleanLifecycleAndTheInstallLifecycle()
-        throws Exception
-    {
-        File pom = getProject( "project-with-additional-lifecycle-elements" );
-        MavenSession session = createMavenSession( pom );
-        assertEquals( "project-with-additional-lifecycle-elements", session.getCurrentProject().getArtifactId() );
-        assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = getExecutions( calculateExecutionPlan( session, "clean", "install" ) );
+    public void testCalculationOfBuildPlanTasksOfTheCleanLifecycleAndTheInstallLifecycle() throws Exception {
+        File pom = getProject("project-with-additional-lifecycle-elements");
+        MavenSession session = createMavenSession(pom);
+        assertEquals(
+                "project-with-additional-lifecycle-elements",
+                session.getCurrentProject().getArtifactId());
+        assertEquals("1.0", session.getCurrentProject().getVersion());
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan(session, "clean", "install"));
 
-        //[01] clean:clean
-        //[02] resources:resources
-        //[03] compiler:compile
-        //[04] it:generate-metadata
-        //[05] resources:testResources
-        //[06] compiler:testCompile
-        //[07] it:generate-test-metadata
-        //[08] surefire:test
-        //[09] jar:jar
-        //[10] install:install
+        // [01] clean:clean
+        // [02] resources:resources
+        // [03] compiler:compile
+        // [04] it:generate-metadata
+        // [05] resources:testResources
+        // [06] compiler:testCompile
+        // [07] it:generate-test-metadata
+        // [08] surefire:test
+        // [09] jar:jar
+        // [10] install:install
         //
-        assertEquals( 10, executionPlan.size() );
+        assertEquals(10, executionPlan.size());
 
-        assertEquals( "clean:clean", executionPlan.get( 0 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "resources:resources", executionPlan.get( 1 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "compiler:compile", executionPlan.get( 2 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:generate-metadata", executionPlan.get( 3 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "resources:testResources", executionPlan.get( 4 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "compiler:testCompile", executionPlan.get( 5 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:generate-test-metadata", executionPlan.get( 6 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "surefire:test", executionPlan.get( 7 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "jar:jar", executionPlan.get( 8 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "install:install", executionPlan.get( 9 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals("clean:clean", executionPlan.get(0).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "resources:resources", executionPlan.get(1).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "compiler:compile", executionPlan.get(2).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "it:generate-metadata", executionPlan.get(3).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "resources:testResources",
+                executionPlan.get(4).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "compiler:testCompile", executionPlan.get(5).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "it:generate-test-metadata",
+                executionPlan.get(6).getMojoDescriptor().getFullGoalName());
+        assertEquals("surefire:test", executionPlan.get(7).getMojoDescriptor().getFullGoalName());
+        assertEquals("jar:jar", executionPlan.get(8).getMojoDescriptor().getFullGoalName());
+        assertEquals("install:install", executionPlan.get(9).getMojoDescriptor().getFullGoalName());
     }
 
     // We need to take in multiple lifecycles
-    public void testCalculationOfBuildPlanWithMultipleExecutionsOfModello()
-        throws Exception
-    {
-        File pom = getProject( "project-with-multiple-executions" );
-        MavenSession session = createMavenSession( pom );
-        assertEquals( "project-with-multiple-executions", session.getCurrentProject().getArtifactId() );
-        assertEquals( "1.0.1", session.getCurrentProject().getVersion() );
+    public void testCalculationOfBuildPlanWithMultipleExecutionsOfModello() throws Exception {
+        File pom = getProject("project-with-multiple-executions");
+        MavenSession session = createMavenSession(pom);
+        assertEquals(
+                "project-with-multiple-executions", session.getCurrentProject().getArtifactId());
+        assertEquals("1.0.1", session.getCurrentProject().getVersion());
 
-        MavenExecutionPlan plan = calculateExecutionPlan( session, "clean", "install" );
+        MavenExecutionPlan plan = calculateExecutionPlan(session, "clean", "install");
 
-        List<MojoExecution> executions = getExecutions( plan );
+        List<MojoExecution> executions = getExecutions(plan);
 
-        //[01] clean:clean
-        //[02] modello:xpp3-writer
-        //[03] modello:java
-        //[04] modello:xpp3-reader
-        //[05] modello:xpp3-writer
-        //[06] modello:java
-        //[07] modello:xpp3-reader
-        //[08] plugin:descriptor
-        //[09] resources:resources
-        //[10] compiler:compile
-        //[11] resources:testResources
-        //[12] compiler:testCompile
-        //[13] surefire:test
-        //[14] jar:jar
-        //[15] plugin:addPluginArtifactMetadata
-        //[16] install:install
+        // [01] clean:clean
+        // [02] modello:xpp3-writer
+        // [03] modello:java
+        // [04] modello:xpp3-reader
+        // [05] modello:xpp3-writer
+        // [06] modello:java
+        // [07] modello:xpp3-reader
+        // [08] plugin:descriptor
+        // [09] resources:resources
+        // [10] compiler:compile
+        // [11] resources:testResources
+        // [12] compiler:testCompile
+        // [13] surefire:test
+        // [14] jar:jar
+        // [15] plugin:addPluginArtifactMetadata
+        // [16] install:install
         //
 
-        assertEquals( 16, executions.size() );
+        assertEquals(16, executions.size());
 
-        assertEquals( "clean:clean", executions.get( 0 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:xpp3-writer", executions.get( 1 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:java", executions.get( 2 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:xpp3-reader", executions.get( 3 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:xpp3-writer", executions.get( 4 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:java", executions.get( 5 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:xpp3-reader", executions.get( 6 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "resources:resources", executions.get( 7 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "compiler:compile", executions.get( 8 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "plugin:descriptor", executions.get( 9 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "resources:testResources", executions.get( 10 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "compiler:testCompile", executions.get( 11 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "surefire:test", executions.get( 12 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "jar:jar", executions.get( 13 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "plugin:addPluginArtifactMetadata", executions.get( 14 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "install:install", executions.get( 15 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals("clean:clean", executions.get(0).getMojoDescriptor().getFullGoalName());
+        assertEquals("it:xpp3-writer", executions.get(1).getMojoDescriptor().getFullGoalName());
+        assertEquals("it:java", executions.get(2).getMojoDescriptor().getFullGoalName());
+        assertEquals("it:xpp3-reader", executions.get(3).getMojoDescriptor().getFullGoalName());
+        assertEquals("it:xpp3-writer", executions.get(4).getMojoDescriptor().getFullGoalName());
+        assertEquals("it:java", executions.get(5).getMojoDescriptor().getFullGoalName());
+        assertEquals("it:xpp3-reader", executions.get(6).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "resources:resources", executions.get(7).getMojoDescriptor().getFullGoalName());
+        assertEquals("compiler:compile", executions.get(8).getMojoDescriptor().getFullGoalName());
+        assertEquals("plugin:descriptor", executions.get(9).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "resources:testResources",
+                executions.get(10).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "compiler:testCompile", executions.get(11).getMojoDescriptor().getFullGoalName());
+        assertEquals("surefire:test", executions.get(12).getMojoDescriptor().getFullGoalName());
+        assertEquals("jar:jar", executions.get(13).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "plugin:addPluginArtifactMetadata",
+                executions.get(14).getMojoDescriptor().getFullGoalName());
+        assertEquals("install:install", executions.get(15).getMojoDescriptor().getFullGoalName());
 
-        assertEquals( "src/main/mdo/remote-resources.mdo",
-                      new MojoExecutionXPathContainer( executions.get( 1 ) ).getValue(
-                          "configuration/models[1]/model" ) );
-        assertEquals( "src/main/mdo/supplemental-model.mdo",
-                      new MojoExecutionXPathContainer( executions.get( 4 ) ).getValue(
-                          "configuration/models[1]/model" ) );
+        assertEquals(
+                "src/main/mdo/remote-resources.mdo",
+                new MojoExecutionXPathContainer(executions.get(1)).getValue("configuration/models[1]/model"));
+        assertEquals(
+                "src/main/mdo/supplemental-model.mdo",
+                new MojoExecutionXPathContainer(executions.get(4)).getValue("configuration/models[1]/model"));
     }
 
     @Test
-    public void testLifecycleQueryingUsingADefaultLifecyclePhase()
-        throws Exception
-    {
-        File pom = getProject( "project-with-additional-lifecycle-elements" );
-        MavenSession session = createMavenSession( pom );
-        assertEquals( "project-with-additional-lifecycle-elements", session.getCurrentProject().getArtifactId() );
-        assertEquals( "1.0", session.getCurrentProject().getVersion() );
-        List<MojoExecution> executionPlan = getExecutions( calculateExecutionPlan( session, "package" ) );
+    void testLifecycleQueryingUsingADefaultLifecyclePhase() throws Exception {
+        File pom = getProject("project-with-additional-lifecycle-elements");
+        MavenSession session = createMavenSession(pom);
+        assertEquals(
+                "project-with-additional-lifecycle-elements",
+                session.getCurrentProject().getArtifactId());
+        assertEquals("1.0", session.getCurrentProject().getVersion());
+        List<MojoExecution> executionPlan = getExecutions(calculateExecutionPlan(session, "package"));
 
-        //[01] resources:resources
-        //[02] compiler:compile
-        //[03] it:generate-metadata
-        //[04] resources:testResources
-        //[05] compiler:testCompile
-        //[06] plexus-component-metadata:generate-test-metadata
-        //[07] surefire:test
-        //[08] jar:jar
+        // [01] resources:resources
+        // [02] compiler:compile
+        // [03] it:generate-metadata
+        // [04] resources:testResources
+        // [05] compiler:testCompile
+        // [06] plexus-component-metadata:generate-test-metadata
+        // [07] surefire:test
+        // [08] jar:jar
         //
-        assertEquals( 8, executionPlan.size() );
+        assertEquals(8, executionPlan.size());
 
-        assertEquals( "resources:resources", executionPlan.get( 0 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "compiler:compile", executionPlan.get( 1 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:generate-metadata", executionPlan.get( 2 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "resources:testResources", executionPlan.get( 3 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "compiler:testCompile", executionPlan.get( 4 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "it:generate-test-metadata", executionPlan.get( 5 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "surefire:test", executionPlan.get( 6 ).getMojoDescriptor().getFullGoalName() );
-        assertEquals( "jar:jar", executionPlan.get( 7 ).getMojoDescriptor().getFullGoalName() );
+        assertEquals(
+                "resources:resources", executionPlan.get(0).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "compiler:compile", executionPlan.get(1).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "it:generate-metadata", executionPlan.get(2).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "resources:testResources",
+                executionPlan.get(3).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "compiler:testCompile", executionPlan.get(4).getMojoDescriptor().getFullGoalName());
+        assertEquals(
+                "it:generate-test-metadata",
+                executionPlan.get(5).getMojoDescriptor().getFullGoalName());
+        assertEquals("surefire:test", executionPlan.get(6).getMojoDescriptor().getFullGoalName());
+        assertEquals("jar:jar", executionPlan.get(7).getMojoDescriptor().getFullGoalName());
     }
 
     @Test
-    public void testLifecyclePluginsRetrievalForDefaultLifecycle()
-        throws Exception
-    {
-        List<Plugin> plugins =
-            new ArrayList<>( lifecycleExecutor.getPluginsBoundByDefaultToAllLifecycles( "jar" ) );
+    void testLifecyclePluginsRetrievalForDefaultLifecycle() throws Exception {
+        List<Plugin> plugins = new ArrayList<>(lifecycleExecutor.getPluginsBoundByDefaultToAllLifecycles("jar"));
 
-        assertThat( plugins.toString(), plugins, hasSize( 9 ) );
+        assertThat(plugins.toString(), plugins, hasSize(9));
     }
 
     @Test
-    public void testPluginConfigurationCreation()
-        throws Exception
-    {
-        File pom = getProject( "project-with-additional-lifecycle-elements" );
-        MavenSession session = createMavenSession( pom );
-        MojoDescriptor mojoDescriptor =
-            mojoDescriptorCreator.getMojoDescriptor( "org.apache.maven.its.plugins:maven-it-plugin:0.1:java", session,
-                                                     session.getCurrentProject() );
-        Xpp3Dom dom = MojoDescriptorCreator.convert( mojoDescriptor );
-        System.out.println( dom );
+    void testPluginConfigurationCreation() throws Exception {
+        File pom = getProject("project-with-additional-lifecycle-elements");
+        MavenSession session = createMavenSession(pom);
+        MojoDescriptor mojoDescriptor = mojoDescriptorCreator.getMojoDescriptor(
+                "org.apache.maven.its.plugins:maven-it-plugin:0.1:java", session, session.getCurrentProject());
+        XmlNode dom = MojoDescriptorCreator.convert(mojoDescriptor).getDom();
+        System.out.println(dom);
     }
 
-    MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
-        throws Exception
-    {
+    MavenExecutionPlan calculateExecutionPlan(MavenSession session, String... tasks) throws Exception {
         List<TaskSegment> taskSegments =
-            lifeCycleTaskSegmentCalculator.calculateTaskSegments( session, Arrays.asList( tasks ) );
+                lifeCycleTaskSegmentCalculator.calculateTaskSegments(session, Arrays.asList(tasks));
 
-        TaskSegment mergedSegment = new TaskSegment( false );
+        TaskSegment mergedSegment = new TaskSegment(false);
 
-        for ( TaskSegment taskSegment : taskSegments )
-        {
-            mergedSegment.getTasks().addAll( taskSegment.getTasks() );
+        for (TaskSegment taskSegment : taskSegments) {
+            mergedSegment.getTasks().addAll(taskSegment.getTasks());
         }
 
-        return lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, session.getCurrentProject(),
-                                                                        mergedSegment.getTasks() );
+        return lifeCycleExecutionPlanCalculator.calculateExecutionPlan(
+                session, session.getCurrentProject(), mergedSegment.getTasks());
     }
 
     @Test
-    public void testInvalidGoalName()
-        throws Exception
-    {
-        File pom = getProject( "project-basic" );
-        MavenSession session = createMavenSession( pom );
+    void testInvalidGoalName() throws Exception {
+        File pom = getProject("project-basic");
+        MavenSession session = createMavenSession(pom);
         MojoNotFoundException e = assertThrows(
                 MojoNotFoundException.class,
-                () -> getExecutions( calculateExecutionPlan( session, "resources:" ) ),
-                "expected a MojoNotFoundException" );
-        assertEquals( "", e.getGoal() );
+                () -> getExecutions(calculateExecutionPlan(session, "resources:")),
+                "expected a MojoNotFoundException");
+        assertEquals("", e.getGoal());
 
         e = assertThrows(
                 MojoNotFoundException.class,
-                () -> getExecutions( calculateExecutionPlan( session, "org.apache.maven.plugins:maven-resources-plugin:0.1:resources:toomany" ) ),
-                "expected a MojoNotFoundException" );
-        assertEquals( "resources:toomany", e.getGoal() );
+                () -> getExecutions(calculateExecutionPlan(
+                        session, "org.apache.maven.plugins:maven-resources-plugin:0.1:resources:toomany")),
+                "expected a MojoNotFoundException");
+        assertEquals("resources:toomany", e.getGoal());
     }
 
-
     @Test
-    public void testPluginPrefixRetrieval()
-        throws Exception
-    {
-        File pom = getProject( "project-basic" );
-        MavenSession session = createMavenSession( pom );
-        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix( "resources", session );
-        assertEquals( "org.apache.maven.plugins", plugin.getGroupId() );
-        assertEquals( "maven-resources-plugin", plugin.getArtifactId() );
+    void testPluginPrefixRetrieval() throws Exception {
+        File pom = getProject("project-basic");
+        MavenSession session = createMavenSession(pom);
+        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix("resources", session);
+        assertEquals("org.apache.maven.plugins", plugin.getGroupId());
+        assertEquals("maven-resources-plugin", plugin.getArtifactId());
     }
 
     // Prefixes
 
     @Test
-    public void testFindingPluginPrefixForCleanClean()
-        throws Exception
-    {
-        File pom = getProject( "project-basic" );
-        MavenSession session = createMavenSession( pom );
-        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix( "clean", session );
-        assertNotNull( plugin );
+    void testFindingPluginPrefixForCleanClean() throws Exception {
+        File pom = getProject("project-basic");
+        MavenSession session = createMavenSession(pom);
+        Plugin plugin = mojoDescriptorCreator.findPluginForPrefix("clean", session);
+        assertNotNull(plugin);
     }
 
     @Test
-    public void testSetupMojoExecution()
-        throws Exception
-    {
-        File pom = getProject( "mojo-configuration" );
+    void testSetupMojoExecution() throws Exception {
+        File pom = getProject("mojo-configuration");
 
-        MavenSession session = createMavenSession( pom );
+        MavenSession session = createMavenSession(pom);
 
-        LifecycleTask task = new LifecycleTask( "generate-sources" );
-        MavenExecutionPlan executionPlan =
-            lifeCycleExecutionPlanCalculator.calculateExecutionPlan( session, session.getCurrentProject(),
-                                                                     Arrays.asList( (Object) task ), false );
+        LifecycleTask task = new LifecycleTask("generate-sources");
+        MavenExecutionPlan executionPlan = lifeCycleExecutionPlanCalculator.calculateExecutionPlan(
+                session, session.getCurrentProject(), Arrays.asList((Object) task), false);
 
         MojoExecution execution = executionPlan.getMojoExecutions().get(0);
-        assertEquals( "maven-it-plugin", execution.getArtifactId(), execution.toString() );
+        assertEquals("maven-it-plugin", execution.getArtifactId(), execution.toString());
         assertNull(execution.getConfiguration());
 
-        lifeCycleExecutionPlanCalculator.setupMojoExecution( session, session.getCurrentProject(), execution,
-                new HashSet<>() );
+        lifeCycleExecutionPlanCalculator.setupMojoExecution(
+                session, session.getCurrentProject(), execution, new HashSet<>());
         assertNotNull(execution.getConfiguration());
-        assertEquals("1.0", execution.getConfiguration().getChild( "version" ).getAttribute( "default-value" ));
+        assertEquals("1.0", execution.getConfiguration().getChild("version").getAttribute("default-value"));
     }
 
     @Test
-    public void testExecutionListeners()
-        throws Exception
-    {
-        final File pom = getProject( "project-basic" );
-        final MavenSession session = createMavenSession( pom );
-        session.setProjectDependencyGraph( new ProjectDependencyGraph()
-        {
+    void testExecutionListeners() throws Exception {
+        final File pom = getProject("project-basic");
+        final MavenSession session = createMavenSession(pom);
+        session.setProjectDependencyGraph(new ProjectDependencyGraph() {
             @Override
-            public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive )
-            {
+            public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
                 return Collections.emptyList();
             }
 
             @Override
-            public List<MavenProject> getAllProjects()
-            {
+            public List<MavenProject> getAllProjects() {
                 return session.getAllProjects();
             }
 
             @Override
-            public List<MavenProject> getSortedProjects()
-            {
-                return Collections.singletonList( session.getCurrentProject() );
+            public List<MavenProject> getSortedProjects() {
+                return Collections.singletonList(session.getCurrentProject());
             }
 
             @Override
-            public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive )
-            {
+            public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
                 return Collections.emptyList();
             }
-        } );
+        });
 
         final List<String> log = new ArrayList<>();
 
-        MojoExecutionListener mojoListener = new MojoExecutionListener()
-        {
-            public void beforeMojoExecution( MojoExecutionEvent event )
-                throws MojoExecutionException
-            {
-                assertNotNull( event.getSession() );
-                assertNotNull( event.getProject() );
-                assertNotNull( event.getExecution() );
-                assertNotNull( event.getMojo() );
-                assertNull( event.getCause() );
+        MojoExecutionListener mojoListener = new MojoExecutionListener() {
+            public void beforeMojoExecution(MojoExecutionEvent event) throws MojoExecutionException {
+                assertNotNull(event.getSession());
+                assertNotNull(event.getProject());
+                assertNotNull(event.getExecution());
+                assertNotNull(event.getMojo());
+                assertNull(event.getCause());
 
-                log.add( "beforeMojoExecution " + event.getProject().getArtifactId() + ":"
-                    + event.getExecution().getExecutionId() );
+                log.add("beforeMojoExecution " + event.getProject().getArtifactId() + ":"
+                        + event.getExecution().getExecutionId());
             }
 
-            public void afterMojoExecutionSuccess( MojoExecutionEvent event )
-                throws MojoExecutionException
-            {
-                assertNotNull( event.getSession() );
-                assertNotNull( event.getProject() );
-                assertNotNull( event.getExecution() );
-                assertNotNull( event.getMojo() );
-                assertNull( event.getCause() );
+            public void afterMojoExecutionSuccess(MojoExecutionEvent event) throws MojoExecutionException {
+                assertNotNull(event.getSession());
+                assertNotNull(event.getProject());
+                assertNotNull(event.getExecution());
+                assertNotNull(event.getMojo());
+                assertNull(event.getCause());
 
-                log.add( "afterMojoExecutionSuccess " + event.getProject().getArtifactId() + ":"
-                    + event.getExecution().getExecutionId() );
+                log.add("afterMojoExecutionSuccess " + event.getProject().getArtifactId() + ":"
+                        + event.getExecution().getExecutionId());
             }
 
-            public void afterExecutionFailure( MojoExecutionEvent event )
-            {
-                assertNotNull( event.getSession() );
-                assertNotNull( event.getProject() );
-                assertNotNull( event.getExecution() );
-                assertNotNull( event.getMojo() );
-                assertNotNull( event.getCause() );
+            public void afterExecutionFailure(MojoExecutionEvent event) {
+                assertNotNull(event.getSession());
+                assertNotNull(event.getProject());
+                assertNotNull(event.getExecution());
+                assertNotNull(event.getMojo());
+                assertNotNull(event.getCause());
 
-                log.add( "afterExecutionFailure " + event.getProject().getArtifactId() + ":"
-                    + event.getExecution().getExecutionId() );
+                log.add("afterExecutionFailure " + event.getProject().getArtifactId() + ":"
+                        + event.getExecution().getExecutionId());
             }
         };
-        ProjectExecutionListener projectListener = new ProjectExecutionListener()
-        {
-            public void beforeProjectExecution( ProjectExecutionEvent event )
-                throws LifecycleExecutionException
-            {
-                assertNotNull( event.getSession() );
-                assertNotNull( event.getProject() );
-                assertNull( event.getExecutionPlan() );
-                assertNull( event.getCause() );
+        ProjectExecutionListener projectListener = new ProjectExecutionListener() {
+            public void beforeProjectExecution(ProjectExecutionEvent event) throws LifecycleExecutionException {
+                assertNotNull(event.getSession());
+                assertNotNull(event.getProject());
+                assertNull(event.getExecutionPlan());
+                assertNull(event.getCause());
 
-                log.add( "beforeProjectExecution " + event.getProject().getArtifactId() );
+                log.add("beforeProjectExecution " + event.getProject().getArtifactId());
             }
 
-            public void beforeProjectLifecycleExecution( ProjectExecutionEvent event )
-                throws LifecycleExecutionException
-            {
-                assertNotNull( event.getSession() );
-                assertNotNull( event.getProject() );
-                assertNotNull( event.getExecutionPlan() );
-                assertNull( event.getCause() );
+            public void beforeProjectLifecycleExecution(ProjectExecutionEvent event)
+                    throws LifecycleExecutionException {
+                assertNotNull(event.getSession());
+                assertNotNull(event.getProject());
+                assertNotNull(event.getExecutionPlan());
+                assertNull(event.getCause());
 
-                log.add( "beforeProjectLifecycleExecution " + event.getProject().getArtifactId() );
+                log.add("beforeProjectLifecycleExecution " + event.getProject().getArtifactId());
             }
 
-            public void afterProjectExecutionSuccess( ProjectExecutionEvent event )
-                throws LifecycleExecutionException
-            {
-                assertNotNull( event.getSession() );
-                assertNotNull( event.getProject() );
-                assertNotNull( event.getExecutionPlan() );
-                assertNull( event.getCause() );
+            public void afterProjectExecutionSuccess(ProjectExecutionEvent event) throws LifecycleExecutionException {
+                assertNotNull(event.getSession());
+                assertNotNull(event.getProject());
+                assertNotNull(event.getExecutionPlan());
+                assertNull(event.getCause());
 
-                log.add( "afterProjectExecutionSuccess " + event.getProject().getArtifactId() );
+                log.add("afterProjectExecutionSuccess " + event.getProject().getArtifactId());
             }
 
-            public void afterProjectExecutionFailure( ProjectExecutionEvent event )
-            {
-                assertNotNull( event.getSession() );
-                assertNotNull( event.getProject() );
-                assertNull( event.getExecutionPlan() );
-                assertNotNull( event.getCause() );
+            public void afterProjectExecutionFailure(ProjectExecutionEvent event) {
+                assertNotNull(event.getSession());
+                assertNotNull(event.getProject());
+                assertNull(event.getExecutionPlan());
+                assertNotNull(event.getCause());
 
-                log.add( "afterProjectExecutionFailure " + event.getProject().getArtifactId() );
+                log.add("afterProjectExecutionFailure " + event.getProject().getArtifactId());
             }
         };
-        getContainer().lookup( DelegatingProjectExecutionListener.class ).addProjectExecutionListener( projectListener );
-        getContainer().lookup( DelegatingMojoExecutionListener.class ).addMojoExecutionListener( mojoListener );
+        getContainer().lookup(DelegatingProjectExecutionListener.class).addProjectExecutionListener(projectListener);
+        getContainer().lookup(DelegatingMojoExecutionListener.class).addMojoExecutionListener(mojoListener);
 
-        try
-        {
-            lifecycleExecutor.execute( session );
-        }
-        finally
-        {
-            getContainer().lookup( DelegatingProjectExecutionListener.class ).removeProjectExecutionListener( projectListener );
-            getContainer().lookup( DelegatingMojoExecutionListener.class ).removeMojoExecutionListener( mojoListener );
+        try {
+            lifecycleExecutor.execute(session);
+        } finally {
+            getContainer()
+                    .lookup(DelegatingProjectExecutionListener.class)
+                    .removeProjectExecutionListener(projectListener);
+            getContainer().lookup(DelegatingMojoExecutionListener.class).removeMojoExecutionListener(mojoListener);
         }
 
-        List<String> expectedLog = Arrays.asList( "beforeProjectExecution project-basic", //
-                                                  "beforeProjectLifecycleExecution project-basic", //
-                                                  "beforeMojoExecution project-basic:default-resources", //
-                                                  "afterMojoExecutionSuccess project-basic:default-resources", //
-                                                  "beforeMojoExecution project-basic:default-compile", //
-                                                  "afterMojoExecutionSuccess project-basic:default-compile", //
-                                                  "beforeMojoExecution project-basic:default-testResources", //
-                                                  "afterMojoExecutionSuccess project-basic:default-testResources", //
-                                                  "beforeMojoExecution project-basic:default-testCompile", //
-                                                  "afterMojoExecutionSuccess project-basic:default-testCompile", //
-                                                  "beforeMojoExecution project-basic:default-test", //
-                                                  "afterMojoExecutionSuccess project-basic:default-test", //
-                                                  "beforeMojoExecution project-basic:default-jar", //
-                                                  "afterMojoExecutionSuccess project-basic:default-jar", //
-                                                  "afterProjectExecutionSuccess project-basic" //
-        );
+        List<String> expectedLog = Arrays.asList(
+                "beforeProjectExecution project-basic", //
+                "beforeProjectLifecycleExecution project-basic", //
+                "beforeMojoExecution project-basic:default-resources", //
+                "afterMojoExecutionSuccess project-basic:default-resources", //
+                "beforeMojoExecution project-basic:default-compile", //
+                "afterMojoExecutionSuccess project-basic:default-compile", //
+                "beforeMojoExecution project-basic:default-testResources", //
+                "afterMojoExecutionSuccess project-basic:default-testResources", //
+                "beforeMojoExecution project-basic:default-testCompile", //
+                "afterMojoExecutionSuccess project-basic:default-testCompile", //
+                "beforeMojoExecution project-basic:default-test", //
+                "afterMojoExecutionSuccess project-basic:default-test", //
+                "beforeMojoExecution project-basic:default-jar", //
+                "afterMojoExecutionSuccess project-basic:default-jar", //
+                "afterProjectExecutionSuccess project-basic" //
+                );
 
-        assertEventLog( expectedLog, log );
+        assertEventLog(expectedLog, log);
     }
 
-    private static void assertEventLog( List<String> expectedList, List<String> actualList )
-    {
-        assertEquals( toString( expectedList ), toString( actualList ) );
+    private static void assertEventLog(List<String> expectedList, List<String> actualList) {
+        assertEquals(toString(expectedList), toString(actualList));
     }
 
-    private static String toString( List<String> lines )
-    {
+    private static String toString(List<String> lines) {
         StringBuilder sb = new StringBuilder();
-        for ( String line : lines )
-        {
-            sb.append( line ).append( '\n' );
+        for (String line : lines) {
+            sb.append(line).append('\n');
         }
         return sb.toString();
     }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/MavenExecutionPlanTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/MavenExecutionPlanTest.java
index 179dfe0..c24ec44 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/MavenExecutionPlanTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/MavenExecutionPlanTest.java
@@ -1,18 +1,21 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle;
 
 import java.util.Set;
@@ -27,54 +30,42 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 
 /**
- * @author Kristian Rosenvold
  */
-public class MavenExecutionPlanTest
-{
+class MavenExecutionPlanTest {
 
     @Test
-    public void testFindLastInPhase()
-        throws Exception
-    {
+    void testFindLastInPhase() throws Exception {
         MavenExecutionPlan plan = LifecycleExecutionPlanCalculatorStub.getProjectAExecutionPlan();
 
-        ExecutionPlanItem expected = plan.findLastInPhase( "package" );
-        ExecutionPlanItem beerPhase = plan.findLastInPhase( "BEER" );  // Beer comes straight after package in stub
-        assertEquals( expected, beerPhase );
-        assertNotNull( expected );
+        ExecutionPlanItem expected = plan.findLastInPhase("package");
+        ExecutionPlanItem beerPhase = plan.findLastInPhase("BEER"); // Beer comes straight after package in stub
+        assertEquals(expected, beerPhase);
+        assertNotNull(expected);
     }
 
     @Test
-    public void testThreadSafeMojos()
-        throws Exception
-    {
+    void testThreadSafeMojos() throws Exception {
         MavenExecutionPlan plan = LifecycleExecutionPlanCalculatorStub.getProjectAExecutionPlan();
         final Set<Plugin> unSafePlugins = plan.getNonThreadSafePlugins();
         // There is only a single threadsafe plugin here...
-        assertEquals( plan.size() - 1, unSafePlugins.size() );
-
+        assertEquals(plan.size() - 1, unSafePlugins.size());
     }
 
-
     @Test
-    public void testFindLastWhenFirst()
-        throws Exception
-    {
+    void testFindLastWhenFirst() throws Exception {
         MavenExecutionPlan plan = LifecycleExecutionPlanCalculatorStub.getProjectAExecutionPlan();
 
         ExecutionPlanItem beerPhase = plan.findLastInPhase(
-            LifecycleExecutionPlanCalculatorStub.VALIDATE.getPhase() );  // Beer comes straight after package in stub
-        assertNull( beerPhase );
+                LifecycleExecutionPlanCalculatorStub.VALIDATE.getPhase()); // Beer comes straight after package in stub
+        assertNull(beerPhase);
     }
 
     @Test
-    public void testFindLastInPhaseMisc()
-        throws Exception
-    {
+    void testFindLastInPhaseMisc() throws Exception {
         MavenExecutionPlan plan = LifecycleExecutionPlanCalculatorStub.getProjectAExecutionPlan();
 
-        assertNull( plan.findLastInPhase( "pacXkage" ) );
+        assertNull(plan.findLastInPhase("pacXkage"));
         // Beer comes straight after package in stub, much like real life.
-        assertNotNull( plan.findLastInPhase( LifecycleExecutionPlanCalculatorStub.INITIALIZE.getPhase() ) );
+        assertNotNull(plan.findLastInPhase(LifecycleExecutionPlanCalculatorStub.INITIALIZE.getPhase()));
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/MojoExecutionXPathContainer.java b/maven-core/src/test/java/org/apache/maven/lifecycle/MojoExecutionXPathContainer.java
index ce81c85..73d53be 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/MojoExecutionXPathContainer.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/MojoExecutionXPathContainer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle;
 
 import java.io.IOException;
 import java.util.Iterator;
@@ -28,45 +27,35 @@
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.project.harness.Xpp3DomPointerFactory;
 
-public class MojoExecutionXPathContainer
-{
+public class MojoExecutionXPathContainer {
     private JXPathContext context;
 
-    static
-    {
-        JXPathContextReferenceImpl.addNodePointerFactory( new Xpp3DomPointerFactory() );
+    static {
+        JXPathContextReferenceImpl.addNodePointerFactory(new Xpp3DomPointerFactory());
     }
 
-    public MojoExecutionXPathContainer( MojoExecution mojoExecution )
-        throws IOException
-    {
-        context = JXPathContext.newContext( mojoExecution );
+    public MojoExecutionXPathContainer(MojoExecution mojoExecution) throws IOException {
+        context = JXPathContext.newContext(mojoExecution);
     }
 
-    public Iterator<?> getIteratorForXPathExpression( String expression )
-    {
-        return context.iterate( expression );
+    public Iterator<?> getIteratorForXPathExpression(String expression) {
+        return context.iterate(expression);
     }
 
-    public boolean containsXPathExpression( String expression )
-    {
-        return context.getValue( expression ) != null;
+    public boolean containsXPathExpression(String expression) {
+        return context.getValue(expression) != null;
     }
 
-    public Object getValue( String expression )
-    {
-        try
-        {
-            return context.getValue( expression );
-        }
-        catch ( JXPathNotFoundException e )
-        {
+    public Object getValue(String expression) {
+        try {
+            return context.getValue(expression);
+        } catch (JXPathNotFoundException e) {
             return null;
         }
     }
 
-    public boolean xPathExpressionEqualsValue( String expression, String value )
-    {
-        return context.getValue( expression ) != null && context.getValue( expression ).equals( value );
+    public boolean xPathExpressionEqualsValue(String expression, String value) {
+        return context.getValue(expression) != null
+                && context.getValue(expression).equals(value);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuildListCalculatorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuildListCalculatorTest.java
index 4f0b059..8f45138 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuildListCalculatorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/BuildListCalculatorTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.List;
 
@@ -26,33 +29,27 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
 
-public class BuildListCalculatorTest
-{
+class BuildListCalculatorTest {
 
     @Test
-    public void testCalculateProjectBuilds()
-        throws Exception
-    {
+    void testCalculateProjectBuilds() throws Exception {
         LifecycleTaskSegmentCalculator lifecycleTaskSegmentCalculator = getTaskSegmentCalculator();
         BuildListCalculator buildListCalculator = new BuildListCalculator();
         final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
-        List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments( session );
-        final ProjectBuildList buildList = buildListCalculator.calculateProjectBuilds( session, taskSegments );
-        final ProjectBuildList segments = buildList.getByTaskSegment( taskSegments.get( 0 ) );
-        assertEquals( 3, taskSegments.size(), "Stub data contains 3 segments" );
-        assertEquals( 6, segments.size(), "Stub data contains 6 items" );
-        final ProjectSegment build = segments.get( 0 );
-        assertNotNull( build );
+        List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments(session);
+        final ProjectBuildList buildList = buildListCalculator.calculateProjectBuilds(session, taskSegments);
+        final ProjectBuildList segments = buildList.getByTaskSegment(taskSegments.get(0));
+        assertEquals(3, taskSegments.size(), "Stub data contains 3 segments");
+        assertEquals(6, segments.size(), "Stub data contains 6 items");
+        final ProjectSegment build = segments.get(0);
+        assertNotNull(build);
 
-        for ( ProjectSegment segment : segments )
-        {
-            assertSame( session, segment.getSession() );
+        for (ProjectSegment segment : segments) {
+            assertSame(session, segment.getSession());
         }
     }
 
-    private static LifecycleTaskSegmentCalculator getTaskSegmentCalculator()
-    {
+    private static LifecycleTaskSegmentCalculator getTaskSegmentCalculator() {
         return new LifecycleTaskSegmentCalculatorStub();
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrencyDependencyGraphTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrencyDependencyGraphTest.java
index c2971f1..27afe65 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrencyDependencyGraphTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ConcurrencyDependencyGraphTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.List;
 
@@ -43,61 +46,56 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
- * @author Kristian Rosenvold
  */
-public class ConcurrencyDependencyGraphTest
-{
+class ConcurrencyDependencyGraphTest {
     @Test
-    public void testConcurrencyGraphPrimaryVersion()
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+    void testConcurrencyGraphPrimaryVersion()
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
         ProjectDependencyGraph dependencyGraph = new ProjectDependencyGraphStub();
         final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
 
         ConcurrencyDependencyGraph graph =
-            new ConcurrencyDependencyGraph( getProjectBuildList( session ), dependencyGraph );
+                new ConcurrencyDependencyGraph(getProjectBuildList(session), dependencyGraph);
 
         final List<MavenProject> projectBuilds = graph.getRootSchedulableBuilds();
-        assertEquals( 1, projectBuilds.size() );
-        assertEquals( A, projectBuilds.iterator().next() );
+        assertEquals(1, projectBuilds.size());
+        assertEquals(A, projectBuilds.iterator().next());
 
-        final List<MavenProject> subsequent = graph.markAsFinished( A );
-        assertEquals( 2, subsequent.size() );
-        assertEquals( ProjectDependencyGraphStub.B, subsequent.get( 0 ) );
-        assertEquals( C, subsequent.get( 1 ) );
+        final List<MavenProject> subsequent = graph.markAsFinished(A);
+        assertEquals(2, subsequent.size());
+        assertEquals(ProjectDependencyGraphStub.B, subsequent.get(0));
+        assertEquals(C, subsequent.get(1));
 
-        final List<MavenProject> bDescendants = graph.markAsFinished( B );
-        assertEquals( 1, bDescendants.size() );
-        assertEquals( Y, bDescendants.get( 0 ) );
+        final List<MavenProject> bDescendants = graph.markAsFinished(B);
+        assertEquals(1, bDescendants.size());
+        assertEquals(Y, bDescendants.get(0));
 
-        final List<MavenProject> cDescendants = graph.markAsFinished( C );
-        assertEquals( 2, cDescendants.size() );
-        assertEquals( X, cDescendants.get( 0 ) );
-        assertEquals( Z, cDescendants.get( 1 ) );
+        final List<MavenProject> cDescendants = graph.markAsFinished(C);
+        assertEquals(2, cDescendants.size());
+        assertEquals(X, cDescendants.get(0));
+        assertEquals(Z, cDescendants.get(1));
     }
 
     @Test
-    public void testConcurrencyGraphDifferentCompletionOrder()
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+    void testConcurrencyGraphDifferentCompletionOrder()
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
         ProjectDependencyGraph dependencyGraph = new ProjectDependencyGraphStub();
         final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
         ConcurrencyDependencyGraph graph =
-            new ConcurrencyDependencyGraph( getProjectBuildList( session ), dependencyGraph );
+                new ConcurrencyDependencyGraph(getProjectBuildList(session), dependencyGraph);
 
-        graph.markAsFinished( A );
-        final List<MavenProject> cDescendants = graph.markAsFinished( C );
-        assertEquals( 1, cDescendants.size() );
-        assertEquals( Z, cDescendants.get( 0 ) );
+        graph.markAsFinished(A);
+        final List<MavenProject> cDescendants = graph.markAsFinished(C);
+        assertEquals(1, cDescendants.size());
+        assertEquals(Z, cDescendants.get(0));
 
-        final List<MavenProject> bDescendants = graph.markAsFinished( B );
-        assertEquals( 2, bDescendants.size() );
-        assertEquals( X, bDescendants.get( 0 ) );
-        assertEquals( Y, bDescendants.get( 1 ) );
+        final List<MavenProject> bDescendants = graph.markAsFinished(B);
+        assertEquals(2, bDescendants.size());
+        assertEquals(X, bDescendants.get(0));
+        assertEquals(Y, bDescendants.get(1));
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolverTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolverTest.java
index 9413111..3ff43bc 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolverTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
+
+import javax.inject.Inject;
 
 import java.io.File;
 import java.util.Collection;
@@ -30,50 +31,52 @@
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.project.MavenProject;
-
-import javax.inject.Inject;
-
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
-public class LifecycleDependencyResolverTest extends AbstractCoreMavenComponentTestCase
-{
+class LifecycleDependencyResolverTest extends AbstractCoreMavenComponentTestCase {
     @Inject
     private LifecycleDependencyResolver resolver;
 
     @Override
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return null;
     }
 
     @Test
-    public void testCachedReactorProjectDependencies() throws Exception
-    {
-        MavenSession session = createMavenSession( new File( "src/test/projects/lifecycle-dependency-resolver/pom.xml" ), new Properties(), true );
+    void testCachedReactorProjectDependencies() throws Exception {
+        MavenSession session = createMavenSession(
+                new File("src/test/projects/lifecycle-dependency-resolver/pom.xml"), new Properties(), true);
         Collection<String> scopesToCollect = null;
-        Collection<String> scopesToResolve = Collections.singletonList( "compile" );
+        Collection<String> scopesToResolve = Collections.singletonList("compile");
         boolean aggregating = false;
 
-        Set<Artifact> reactorArtifacts = new HashSet<>( 3 );
-        for ( MavenProject reactorProject : session.getProjects() )
-        {
-            reactorProject.setArtifactFilter( artifact -> true );
-            resolver.resolveProjectDependencies( reactorProject, scopesToCollect, scopesToResolve, session, aggregating, reactorArtifacts );
-            reactorArtifacts.add( reactorProject.getArtifact() );
+        Set<Artifact> reactorArtifacts = new HashSet<>(3);
+        for (MavenProject reactorProject : session.getProjects()) {
+            reactorProject.setArtifactFilter(artifact -> true);
+            resolver.resolveProjectDependencies(
+                    reactorProject, scopesToCollect, scopesToResolve, session, aggregating, reactorArtifacts);
+            reactorArtifacts.add(reactorProject.getArtifact());
         }
 
-        MavenProject lib = session.getProjects().get( 1 );
-        MavenProject war = session.getProjects().get( 2 );
+        MavenProject lib = session.getProjects().get(1);
+        MavenProject war = session.getProjects().get(2);
 
-        assertNull( war.getArtifactMap().get( "org.apache.maven.its.mng6300:mng6300-lib" ).getFile() );
+        assertNull(war.getArtifactMap()
+                .get("org.apache.maven.its.mng6300:mng6300-lib")
+                .getFile());
 
-        lib.getArtifact().setFile( new File( "lib.jar" ) );
+        lib.getArtifact().setFile(new File("lib.jar"));
 
-        resolver.resolveProjectDependencies( war, scopesToCollect, scopesToResolve, session, aggregating, reactorArtifacts );
+        resolver.resolveProjectDependencies(
+                war, scopesToCollect, scopesToResolve, session, aggregating, reactorArtifacts);
 
-        assertEquals( new File( "lib.jar" ) , war.getArtifactMap().get("org.apache.maven.its.mng6300:mng6300-lib").getFile() );
+        assertEquals(
+                new File("lib.jar"),
+                war.getArtifactMap()
+                        .get("org.apache.maven.its.mng6300:mng6300-lib")
+                        .getFile());
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorTest.java
index 28d552a..de70d73 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleExecutionPlanCalculatorTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import org.apache.maven.AbstractCoreMavenComponentTestCase;
 import org.apache.maven.execution.MavenSession;
@@ -23,64 +26,59 @@
 import org.apache.maven.lifecycle.internal.stub.PluginPrefixResolverStub;
 import org.apache.maven.lifecycle.internal.stub.PluginVersionResolverStub;
 import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
- * @author Kristian Rosenvold
  */
-public class LifecycleExecutionPlanCalculatorTest
-    extends AbstractCoreMavenComponentTestCase
-{
+class LifecycleExecutionPlanCalculatorTest extends AbstractCoreMavenComponentTestCase {
 
     @Test
-    public void testCalculateExecutionPlanWithGoalTasks()
-        throws Exception
-    {
+    void testCalculateExecutionPlanWithGoalTasks() throws Exception {
         MojoDescriptorCreator mojoDescriptorCreator = createMojoDescriptorCreator();
         LifecycleExecutionPlanCalculator lifecycleExecutionPlanCalculator =
-            createExecutionPlaceCalculator( mojoDescriptorCreator );
+                createExecutionPlaceCalculator(mojoDescriptorCreator);
 
-        final GoalTask goalTask1 = new GoalTask( "compiler:compile" );
-        final GoalTask goalTask2 = new GoalTask( "surefire:test" );
-        final TaskSegment taskSegment1 = new TaskSegment( false, goalTask1, goalTask2 );
-        final MavenSession session1 = ProjectDependencyGraphStub.getMavenSession( ProjectDependencyGraphStub.A );
+        final GoalTask goalTask1 = new GoalTask("compiler:compile");
+        final GoalTask goalTask2 = new GoalTask("surefire:test");
+        final TaskSegment taskSegment1 = new TaskSegment(false, goalTask1, goalTask2);
+        final MavenSession session1 = ProjectDependencyGraphStub.getMavenSession(ProjectDependencyGraphStub.A);
 
-        MavenExecutionPlan executionPlan =
-            lifecycleExecutionPlanCalculator.calculateExecutionPlan( session1, ProjectDependencyGraphStub.A,
-                                                                     taskSegment1.getTasks() );
-        assertEquals( 2, executionPlan.size() );
+        MavenExecutionPlan executionPlan = lifecycleExecutionPlanCalculator.calculateExecutionPlan(
+                session1, ProjectDependencyGraphStub.A, taskSegment1.getTasks());
+        assertEquals(2, executionPlan.size());
 
-        final GoalTask goalTask3 = new GoalTask( "surefire:test" );
-        final TaskSegment taskSegment2 = new TaskSegment( false, goalTask1, goalTask2, goalTask3 );
-        MavenExecutionPlan executionPlan2 =
-            lifecycleExecutionPlanCalculator.calculateExecutionPlan( session1, ProjectDependencyGraphStub.A,
-                                                                     taskSegment2.getTasks() );
-        assertEquals( 3, executionPlan2.size() );
+        final GoalTask goalTask3 = new GoalTask("surefire:test");
+        final TaskSegment taskSegment2 = new TaskSegment(false, goalTask1, goalTask2, goalTask3);
+        MavenExecutionPlan executionPlan2 = lifecycleExecutionPlanCalculator.calculateExecutionPlan(
+                session1, ProjectDependencyGraphStub.A, taskSegment2.getTasks());
+        assertEquals(3, executionPlan2.size());
     }
 
     // Maybe also make one with LifeCycleTasks
 
-    public static LifecycleExecutionPlanCalculator createExecutionPlaceCalculator( MojoDescriptorCreator mojoDescriptorCreator )
-    {
-        LifecyclePluginResolver lifecyclePluginResolver = new LifecyclePluginResolver( new PluginVersionResolverStub() );
-        return new DefaultLifecycleExecutionPlanCalculator( new BuildPluginManagerStub(),
-                                                            DefaultLifecyclesStub.createDefaultLifecycles(),
-                                                            mojoDescriptorCreator, lifecyclePluginResolver );
+    public static LifecycleExecutionPlanCalculator createExecutionPlaceCalculator(
+            MojoDescriptorCreator mojoDescriptorCreator) throws ComponentLookupException {
+        LifecyclePluginResolver lifecyclePluginResolver = new LifecyclePluginResolver(new PluginVersionResolverStub());
+        return new DefaultLifecycleExecutionPlanCalculator(
+                new BuildPluginManagerStub(),
+                DefaultLifecyclesStub.createDefaultLifecycles(),
+                mojoDescriptorCreator,
+                lifecyclePluginResolver);
     }
 
-    public static MojoDescriptorCreator createMojoDescriptorCreator()
-    {
-        return new MojoDescriptorCreator( new PluginVersionResolverStub(), new BuildPluginManagerStub(),
-                                          new PluginPrefixResolverStub(),
-                                          new LifecyclePluginResolver( new PluginVersionResolverStub() ) );
+    public static MojoDescriptorCreator createMojoDescriptorCreator() {
+        return new MojoDescriptorCreator(
+                new PluginVersionResolverStub(),
+                new BuildPluginManagerStub(),
+                new PluginPrefixResolverStub(),
+                new LifecyclePluginResolver(new PluginVersionResolverStub()));
     }
 
     @Override
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/lifecycle-executor";
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilderTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilderTest.java
index 2e0eaa7..8d018ac 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleModuleBuilderTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import javax.inject.Inject;
 
@@ -34,57 +37,60 @@
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.testing.PlexusTest;
+import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
 @PlexusTest
-public class LifecycleModuleBuilderTest
-{
+class LifecycleModuleBuilderTest {
     @Inject
     PlexusContainer container;
 
     @Test
-    public void testCurrentProject() throws Exception
-    {
+    void testCurrentProject() throws Exception {
         List<MavenProject> currentProjects = new ArrayList<>();
-        MojoExecutorStub mojoExecutor = new MojoExecutorStub()
-        {
+        MojoExecutorStub mojoExecutor = new MojoExecutorStub() {
             @Override
-            public void execute( MavenSession session, List<MojoExecution> mojoExecutions, ProjectIndex projectIndex )
-                    throws LifecycleExecutionException
-            {
-                super.execute( session, mojoExecutions, projectIndex );
-                currentProjects.add( session.getCurrentProject() );
+            public void execute(MavenSession session, List<MojoExecution> mojoExecutions, ProjectIndex projectIndex)
+                    throws LifecycleExecutionException {
+                super.execute(session, mojoExecutions, projectIndex);
+                currentProjects.add(session.getCurrentProject());
             }
         };
 
         final DefaultMavenExecutionResult defaultMavenExecutionResult = new DefaultMavenExecutionResult();
         MavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest();
-        mavenExecutionRequest.setExecutionListener( new AbstractExecutionListener() );
-        mavenExecutionRequest.setGoals( Arrays.asList( "clean" ) );
-        final MavenSession session = new MavenSession( null, null, mavenExecutionRequest, defaultMavenExecutionResult );
+        mavenExecutionRequest.setExecutionListener(new AbstractExecutionListener());
+        mavenExecutionRequest.setGoals(Arrays.asList("clean"));
+        final MavenSession session = new MavenSession(
+                null, new DefaultRepositorySystemSession(), mavenExecutionRequest, defaultMavenExecutionResult);
         final ProjectDependencyGraphStub dependencyGraphStub = new ProjectDependencyGraphStub();
-        session.setProjectDependencyGraph( dependencyGraphStub );
-        session.setProjects( dependencyGraphStub.getSortedProjects() );
+        session.setProjectDependencyGraph(dependencyGraphStub);
+        session.setProjects(dependencyGraphStub.getSortedProjects());
 
-        LifecycleModuleBuilder moduleBuilder = container.lookup( LifecycleModuleBuilder.class );
-        set( moduleBuilder, "mojoExecutor", mojoExecutor );
+        LifecycleModuleBuilder moduleBuilder = container.lookup(LifecycleModuleBuilder.class);
+        set(moduleBuilder, "mojoExecutor", mojoExecutor);
 
-        LifecycleStarter ls = container.lookup( LifecycleStarter.class );
-        ls.execute( session );
+        LifecycleStarter ls = container.lookup(LifecycleStarter.class);
+        ls.execute(session);
 
-        assertNull( session.getCurrentProject() );
-        assertEquals( Arrays.asList( ProjectDependencyGraphStub.A, ProjectDependencyGraphStub.B, ProjectDependencyGraphStub.C,
-                ProjectDependencyGraphStub.X, ProjectDependencyGraphStub.Y, ProjectDependencyGraphStub.Z ), currentProjects );
+        assertNull(session.getCurrentProject());
+        assertEquals(
+                Arrays.asList(
+                        ProjectDependencyGraphStub.A,
+                        ProjectDependencyGraphStub.B,
+                        ProjectDependencyGraphStub.C,
+                        ProjectDependencyGraphStub.X,
+                        ProjectDependencyGraphStub.Y,
+                        ProjectDependencyGraphStub.Z),
+                currentProjects);
     }
 
-    static void set( Object obj, String field, Object v ) throws NoSuchFieldException, IllegalAccessException
-    {
-        Field f = obj.getClass().getDeclaredField( field );
-        f.setAccessible( true );
-        f.set( obj, v );
+    static void set(Object obj, String field, Object v) throws NoSuchFieldException, IllegalAccessException {
+        Field f = obj.getClass().getDeclaredField(field);
+        f.setAccessible(true);
+        f.set(obj, v);
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorImplTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorImplTest.java
index e5a44d6..a6bc0d2 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorImplTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/LifecycleTaskSegmentCalculatorImplTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.List;
 
@@ -30,31 +29,24 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
- * @author Kristian Rosenvold
  */
-public class LifecycleTaskSegmentCalculatorImplTest
-{
+class LifecycleTaskSegmentCalculatorImplTest {
     @Test
-    public void testCalculateProjectBuilds()
-        throws Exception
-    {
+    void testCalculateProjectBuilds() throws Exception {
         LifecycleTaskSegmentCalculator lifecycleTaskSegmentCalculator = getTaskSegmentCalculator();
         BuildListCalculator buildListCalculator = new BuildListCalculator();
         final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
-        List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments( session );
+        List<TaskSegment> taskSegments = lifecycleTaskSegmentCalculator.calculateTaskSegments(session);
 
-        final ProjectBuildList buildList = buildListCalculator.calculateProjectBuilds( session, taskSegments );
-        final ProjectBuildList segments = buildList.getByTaskSegment( taskSegments.get( 0 ) );
-        assertEquals( 3, taskSegments.size(), "Stub data contains 3 segments" );
-        assertEquals( 6, segments.size(), "Stub data contains 6 items" );
-        final ProjectSegment build = segments.get( 0 );
-        assertNotNull( build );
+        final ProjectBuildList buildList = buildListCalculator.calculateProjectBuilds(session, taskSegments);
+        final ProjectBuildList segments = buildList.getByTaskSegment(taskSegments.get(0));
+        assertEquals(3, taskSegments.size(), "Stub data contains 3 segments");
+        assertEquals(6, segments.size(), "Stub data contains 6 items");
+        final ProjectSegment build = segments.get(0);
+        assertNotNull(build);
     }
 
-    private static LifecycleTaskSegmentCalculator getTaskSegmentCalculator()
-    {
+    private static LifecycleTaskSegmentCalculator getTaskSegmentCalculator() {
         return new LifecycleTaskSegmentCalculatorStub();
     }
-
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/PhaseRecorderTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/PhaseRecorderTest.java
index f995d56..48e0b5d 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/PhaseRecorderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/PhaseRecorderTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal;
 
 import java.util.List;
 
@@ -27,26 +30,22 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author Kristian Rosenvold
  */
-public class PhaseRecorderTest
-{
+class PhaseRecorderTest {
     @Test
-    public void testObserveExecution() throws Exception {
-        PhaseRecorder phaseRecorder = new PhaseRecorder( ProjectDependencyGraphStub.A);
+    void testObserveExecution() throws Exception {
+        PhaseRecorder phaseRecorder = new PhaseRecorder(ProjectDependencyGraphStub.A);
         MavenExecutionPlan plan = LifecycleExecutionPlanCalculatorStub.getProjectAExecutionPlan();
         final List<MojoExecution> executions = plan.getMojoExecutions();
 
-        final MojoExecution mojoExecution1 = executions.get( 0 );
-        final MojoExecution mojoExecution2 = executions.get( 1 );
-        phaseRecorder.observeExecution( mojoExecution1 );
+        final MojoExecution mojoExecution1 = executions.get(0);
+        final MojoExecution mojoExecution2 = executions.get(1);
+        phaseRecorder.observeExecution(mojoExecution1);
 
-        assertTrue( ProjectDependencyGraphStub.A.hasLifecyclePhase( mojoExecution1.getLifecyclePhase() ));
-        assertFalse( ProjectDependencyGraphStub.A.hasLifecyclePhase( mojoExecution2.getLifecyclePhase() ));
+        assertTrue(ProjectDependencyGraphStub.A.hasLifecyclePhase(mojoExecution1.getLifecyclePhase()));
+        assertFalse(ProjectDependencyGraphStub.A.hasLifecyclePhase(mojoExecution2.getLifecyclePhase()));
 
-        assertFalse( phaseRecorder.isDifferentPhase( mojoExecution1));
-        assertTrue( phaseRecorder.isDifferentPhase( mojoExecution2));
-
+        assertFalse(phaseRecorder.isDifferentPhase(mojoExecution1));
+        assertTrue(phaseRecorder.isDifferentPhase(mojoExecution2));
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ProjectBuildListTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ProjectBuildListTest.java
index 106c311..761ac82 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ProjectBuildListTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/ProjectBuildListTest.java
@@ -1,47 +1,46 @@
-package org.apache.maven.lifecycle.internal;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.hamcrest.MatcherAssert.assertThat;
+package org.apache.maven.lifecycle.internal;
 
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.internal.stub.ProjectDependencyGraphStub;
 import org.junit.jupiter.api.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThanOrEqualTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 /**
- * @author Kristian Rosenvold
  */
-public class ProjectBuildListTest
-{
+class ProjectBuildListTest {
     @Test
-    public void testGetByTaskSegment()
-        throws Exception
-    {
+    void testGetByTaskSegment() throws Exception {
         final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
-        ProjectBuildList projectBuildList = ProjectDependencyGraphStub.getProjectBuildList( session );
-        TaskSegment taskSegment = projectBuildList.get( 0 ).getTaskSegment();
-        assertThat( "This test assumes there are at least 6 elements in projectBuilds",
-                    projectBuildList.size(), is( greaterThanOrEqualTo( 6 ) ) );
+        ProjectBuildList projectBuildList = ProjectDependencyGraphStub.getProjectBuildList(session);
+        TaskSegment taskSegment = projectBuildList.get(0).getTaskSegment();
+        assertThat(
+                "This test assumes there are at least 6 elements in projectBuilds",
+                projectBuildList.size(),
+                is(greaterThanOrEqualTo(6)));
 
-        final ProjectBuildList byTaskSegment = projectBuildList.getByTaskSegment( taskSegment );
-        assertEquals( projectBuildList.size(),
-                      byTaskSegment.size() ); // TODO Make multiple segments on projectBuildList
+        final ProjectBuildList byTaskSegment = projectBuildList.getByTaskSegment(taskSegment);
+        assertEquals(projectBuildList.size(), byTaskSegment.size()); // TODO Make multiple segments on projectBuildList
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/BuilderCommonTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/BuilderCommonTest.java
index edb0892..c2ab010 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/BuilderCommonTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/BuilderCommonTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal.builder;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal.builder;
 
 import java.util.HashSet;
 
@@ -32,76 +35,61 @@
 import static org.mockito.Mockito.verify;
 
 /**
- * @author Kristian Rosenvold
  */
-public class BuilderCommonTest
-{
-    private Logger logger = mock( Logger.class );
+class BuilderCommonTest {
+    private Logger logger = mock(Logger.class);
 
     @Test
-    public void testResolveBuildPlan()
-        throws Exception
-    {
+    void testResolveBuildPlan() throws Exception {
         MavenSession original = ProjectDependencyGraphStub.getMavenSession();
 
-        final TaskSegment taskSegment1 = new TaskSegment( false );
+        final TaskSegment taskSegment1 = new TaskSegment(false);
         final MavenSession session1 = original.clone();
-        session1.setCurrentProject( ProjectDependencyGraphStub.A );
+        session1.setCurrentProject(ProjectDependencyGraphStub.A);
 
-        final BuilderCommon builderCommon = getBuilderCommon( logger );
+        final BuilderCommon builderCommon = getBuilderCommon(logger);
         final MavenExecutionPlan plan =
-            builderCommon.resolveBuildPlan( session1, ProjectDependencyGraphStub.A, taskSegment1,
-                    new HashSet<>() );
-        assertEquals( LifecycleExecutionPlanCalculatorStub.getProjectAExecutionPlan().size(), plan.size() );
+                builderCommon.resolveBuildPlan(session1, ProjectDependencyGraphStub.A, taskSegment1, new HashSet<>());
+        assertEquals(
+                LifecycleExecutionPlanCalculatorStub.getProjectAExecutionPlan().size(), plan.size());
     }
 
     @Test
-    public void testDefaultBindingPluginsWarning()
-        throws Exception
-    {
+    void testDefaultBindingPluginsWarning() throws Exception {
         MavenSession original = ProjectDependencyGraphStub.getMavenSession();
 
-        final TaskSegment taskSegment1 = new TaskSegment( false );
+        final TaskSegment taskSegment1 = new TaskSegment(false);
         final MavenSession session1 = original.clone();
-        session1.setCurrentProject( ProjectDependencyGraphStub.A );
+        session1.setCurrentProject(ProjectDependencyGraphStub.A);
 
-        getBuilderCommon( logger ).resolveBuildPlan( session1, ProjectDependencyGraphStub.A, taskSegment1, new HashSet<>() );
+        getBuilderCommon(logger)
+                .resolveBuildPlan(session1, ProjectDependencyGraphStub.A, taskSegment1, new HashSet<>());
 
-        verify( logger ).warn("Version not locked for default bindings plugins ["
-            + "stub-plugin-initialize, "
-            + "stub-plugin-process-resources, "
-            + "stub-plugin-compile, "
-            + "stub-plugin-process-test-resources, "
-            + "stub-plugin-test-compile, "
-            + "stub-plugin-test, "
-            + "stub-plugin-package, "
-            + "stub-plugin-install], "
-            + "you should define versions in pluginManagement section of your pom.xml or parent");
+        verify(logger)
+                .warn("Version not locked for default bindings plugins ["
+                        + "stub-plugin-initialize, "
+                        + "stub-plugin-process-resources, "
+                        + "stub-plugin-compile, "
+                        + "stub-plugin-process-test-resources, "
+                        + "stub-plugin-test-compile, "
+                        + "stub-plugin-test, "
+                        + "stub-plugin-package, "
+                        + "stub-plugin-install], "
+                        + "you should define versions in pluginManagement section of your pom.xml or parent");
     }
 
     @Test
-    public void testHandleBuildError()
-        throws Exception
-    {
-    }
+    void testHandleBuildError() throws Exception {}
 
     @Test
-    public void testAttachToThread()
-        throws Exception
-    {
-    }
+    void testAttachToThread() throws Exception {}
 
     @Test
-    public void testGetKey()
-        throws Exception
-    {
-    }
+    void testGetKey() throws Exception {}
 
-    public BuilderCommon getBuilderCommon( Logger logger )
-    {
+    public BuilderCommon getBuilderCommon(Logger logger) {
         final LifecycleDebugLogger debugLogger = new LifecycleDebugLogger();
-        return new BuilderCommon( debugLogger, new LifecycleExecutionPlanCalculatorStub(), mock(
-                ExecutionEventCatapult.class ),  logger );
+        return new BuilderCommon(
+                debugLogger, new LifecycleExecutionPlanCalculatorStub(), mock(ExecutionEventCatapult.class), logger);
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraphTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraphTest.java
index 674435c..6cfc7fb 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraphTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ConcurrencyDependencyGraphTest.java
@@ -1,18 +1,22 @@
-package org.apache.maven.lifecycle.internal.builder.multithreaded;
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal.builder.multithreaded;
 
 import java.util.List;
 import java.util.Set;
@@ -25,62 +29,63 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class ConcurrencyDependencyGraphTest {
+class ConcurrencyDependencyGraphTest {
 
     @Test
-    public void testGraph() throws Exception {
+    void testGraph() throws Exception {
 
-        ProjectBuildList projectBuildList = ProjectDependencyGraphStub.getProjectBuildList(
-                ProjectDependencyGraphStub.getMavenSession() );
+        ProjectBuildList projectBuildList =
+                ProjectDependencyGraphStub.getProjectBuildList(ProjectDependencyGraphStub.getMavenSession());
 
         ProjectDependencyGraph projectDependencyGraph = new ProjectDependencyGraphStub();
 
-        ConcurrencyDependencyGraph graph = new ConcurrencyDependencyGraph( projectBuildList, projectDependencyGraph );
+        ConcurrencyDependencyGraph graph = new ConcurrencyDependencyGraph(projectBuildList, projectDependencyGraph);
 
         // start
-        assertEquals( 0, graph.getFinishedProjects().size() );
-        assertEquals( 6, graph.getNumberOfBuilds() );
+        assertEquals(0, graph.getFinishedProjects().size());
+        assertEquals(6, graph.getNumberOfBuilds());
 
         List<MavenProject> rootSchedulableBuilds = graph.getRootSchedulableBuilds();
         // only Project.A has no dependencies
-        assertEquals( 1, rootSchedulableBuilds.size() );
-        assertEquals( ProjectDependencyGraphStub.A, rootSchedulableBuilds.iterator().next() );
+        assertEquals(1, rootSchedulableBuilds.size());
+        assertEquals(
+                ProjectDependencyGraphStub.A, rootSchedulableBuilds.iterator().next());
         // double check A deps
-        List<MavenProject> dependenciesA = graph.getDependencies( ProjectDependencyGraphStub.A );
-        assertEquals( 0, dependenciesA.size() );
+        List<MavenProject> dependenciesA = graph.getDependencies(ProjectDependencyGraphStub.A);
+        assertEquals(0, dependenciesA.size());
 
-        assertEquals( 6, graph.getUnfinishedProjects().size() );
+        assertEquals(6, graph.getUnfinishedProjects().size());
 
-        List<MavenProject> schedulableNewProcesses = graph.markAsFinished( ProjectDependencyGraphStub.A );
+        List<MavenProject> schedulableNewProcesses = graph.markAsFinished(ProjectDependencyGraphStub.A);
         // expect Project B, C
-        assertEquals( 2, schedulableNewProcesses.size() );
-        assertEquals( 1, graph.getFinishedProjects().size() );
+        assertEquals(2, schedulableNewProcesses.size());
+        assertEquals(1, graph.getFinishedProjects().size());
 
-        graph.markAsFinished( ProjectDependencyGraphStub.A );
+        graph.markAsFinished(ProjectDependencyGraphStub.A);
         // still only  A
-        assertEquals( 1, graph.getFinishedProjects().size() );
+        assertEquals(1, graph.getFinishedProjects().size());
 
         Set<MavenProject> unfinishedProjects = graph.getUnfinishedProjects();
-        assertEquals( 5, unfinishedProjects.size() );
+        assertEquals(5, unfinishedProjects.size());
 
-        graph.markAsFinished( schedulableNewProcesses.get( 0 ) );
-        assertEquals( 2, graph.getFinishedProjects().size() );
-        assertEquals( 4, graph.getUnfinishedProjects().size() );
+        graph.markAsFinished(schedulableNewProcesses.get(0));
+        assertEquals(2, graph.getFinishedProjects().size());
+        assertEquals(4, graph.getUnfinishedProjects().size());
 
-        List<MavenProject> dependenciesC = graph.getDependencies( ProjectDependencyGraphStub.C );
+        List<MavenProject> dependenciesC = graph.getDependencies(ProjectDependencyGraphStub.C);
         // C depends only on A
-        assertEquals( 1, dependenciesC.size() );
+        assertEquals(1, dependenciesC.size());
 
-        List<MavenProject> dependenciesX = graph.getDependencies( ProjectDependencyGraphStub.X );
+        List<MavenProject> dependenciesX = graph.getDependencies(ProjectDependencyGraphStub.X);
         // X depends only on B and C
-        assertEquals( 2, dependenciesX.size() );
+        assertEquals(2, dependenciesX.size());
 
-        List<MavenProject> activeDependenciesC = graph.getActiveDependencies( ProjectDependencyGraphStub.C );
+        List<MavenProject> activeDependenciesC = graph.getActiveDependencies(ProjectDependencyGraphStub.C);
         // A already finished
-        assertEquals( 0, activeDependenciesC.size() );
+        assertEquals(0, activeDependenciesC.size());
 
-        List<MavenProject> activeDependenciesX = graph.getActiveDependencies( ProjectDependencyGraphStub.X );
+        List<MavenProject> activeDependenciesX = graph.getActiveDependencies(ProjectDependencyGraphStub.X);
         // waiting for C
-        assertEquals( 1, activeDependenciesX.size() );
+        assertEquals(1, activeDependenciesX.size());
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxerTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxerTest.java
index 549e90b..69eda5f 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/builder/multithreaded/ThreadOutputMuxerTest.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal.builder.multithreaded;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal.builder.multithreaded;
 
 import java.io.ByteArrayOutputStream;
 import java.io.PrintStream;
@@ -46,10 +49,8 @@
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 /**
- * @author Kristian Rosenvold
  */
-public class ThreadOutputMuxerTest
-{
+class ThreadOutputMuxerTest {
 
     final String paid = "Paid";
 
@@ -58,111 +59,94 @@
     final String full = "Full";
 
     @Test
-    public void testSingleThreaded()
-        throws Exception
-    {
+    void testSingleThreaded() throws Exception {
         ProjectBuildList src = getProjectBuildList();
-        ProjectBuildList projectBuildList =
-            new ProjectBuildList( Arrays.asList( src.get( 0 ), src.get( 1 ), src.get( 2 ) ) );
+        ProjectBuildList projectBuildList = new ProjectBuildList(Arrays.asList(src.get(0), src.get(1), src.get(2)));
 
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        PrintStream systemOut = new PrintStream( byteArrayOutputStream );
-        ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut );
+        PrintStream systemOut = new PrintStream(byteArrayOutputStream);
+        ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer(projectBuildList, systemOut);
 
-        threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 0 ) );
-        System.out.print( paid );  // No, this does not print to system.out. It's part of the test
-        assertEquals( paid.length(), byteArrayOutputStream.size() );
-        threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 1 ) );
-        System.out.print( in );  // No, this does not print to system.out. It's part of the test
-        assertEquals( paid.length(), byteArrayOutputStream.size() );
-        threadOutputMuxer.associateThreadWithProjectSegment( projectBuildList.get( 2 ) );
-        System.out.print( full ); // No, this does not print to system.out. It's part of the test
-        assertEquals( paid.length(), byteArrayOutputStream.size() );
+        threadOutputMuxer.associateThreadWithProjectSegment(projectBuildList.get(0));
+        System.out.print(paid); // No, this does not print to system.out. It's part of the test
+        assertEquals(paid.length(), byteArrayOutputStream.size());
+        threadOutputMuxer.associateThreadWithProjectSegment(projectBuildList.get(1));
+        System.out.print(in); // No, this does not print to system.out. It's part of the test
+        assertEquals(paid.length(), byteArrayOutputStream.size());
+        threadOutputMuxer.associateThreadWithProjectSegment(projectBuildList.get(2));
+        System.out.print(full); // No, this does not print to system.out. It's part of the test
+        assertEquals(paid.length(), byteArrayOutputStream.size());
 
-        threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 0 ) );
-        threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 1 ) );
-        threadOutputMuxer.setThisModuleComplete( projectBuildList.get( 2 ) );
+        threadOutputMuxer.setThisModuleComplete(projectBuildList.get(0));
+        threadOutputMuxer.setThisModuleComplete(projectBuildList.get(1));
+        threadOutputMuxer.setThisModuleComplete(projectBuildList.get(2));
         threadOutputMuxer.close();
-        assertEquals( ( paid + in + full ).length(), byteArrayOutputStream.size() );
+        assertEquals((paid + in + full).length(), byteArrayOutputStream.size());
     }
 
     @Test
-    public void testMultiThreaded()
-        throws Exception
-    {
+    void testMultiThreaded() throws Exception {
         ProjectBuildList projectBuildList = getProjectBuildList();
 
         ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
-        PrintStream systemOut = new PrintStream( byteArrayOutputStream );
-        final ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer( projectBuildList, systemOut );
+        PrintStream systemOut = new PrintStream(byteArrayOutputStream);
+        final ThreadOutputMuxer threadOutputMuxer = new ThreadOutputMuxer(projectBuildList, systemOut);
 
-        final List<String> stringList =
-            Arrays.asList( "Thinkin", "of", "a", "master", "plan", "Cuz", "ain’t", "nuthin", "but", "sweat", "inside",
-                           "my", "hand" );
+        final List<String> stringList = Arrays.asList(
+                "Thinkin", "of", "a", "master", "plan", "Cuz", "ain’t", "nuthin", "but", "sweat", "inside", "my",
+                "hand");
         Iterator<String> lyrics = stringList.iterator();
 
-        ExecutorService executor = Executors.newFixedThreadPool( 10 );
-        CompletionService<ProjectSegment> service = new ExecutorCompletionService<>( executor );
+        ExecutorService executor = Executors.newFixedThreadPool(10);
+        CompletionService<ProjectSegment> service = new ExecutorCompletionService<>(executor);
 
         List<Future<ProjectSegment>> futures = new ArrayList<>();
-        for ( ProjectSegment projectBuild : projectBuildList )
-        {
+        for (ProjectSegment projectBuild : projectBuildList) {
             final Future<ProjectSegment> buildFuture =
-                service.submit( new Outputter( threadOutputMuxer, projectBuild, lyrics.next() ) );
-            futures.add( buildFuture );
+                    service.submit(new Outputter(threadOutputMuxer, projectBuild, lyrics.next()));
+            futures.add(buildFuture);
         }
 
-        for ( Future<ProjectSegment> future : futures )
-        {
+        for (Future<ProjectSegment> future : futures) {
             future.get();
         }
         int expectedLength = 0;
-        for ( int i = 0; i < projectBuildList.size(); i++ )
-        {
-            expectedLength += stringList.get( i ).length();
+        for (int i = 0; i < projectBuildList.size(); i++) {
+            expectedLength += stringList.get(i).length();
         }
 
         threadOutputMuxer.close();
         final byte[] bytes = byteArrayOutputStream.toByteArray();
-        String result = new String( bytes );
-        assertEquals( expectedLength, bytes.length, result );
-
-
+        String result = new String(bytes);
+        assertEquals(expectedLength, bytes.length, result);
     }
 
-    class Outputter
-        implements Callable<ProjectSegment>
-    {
+    class Outputter implements Callable<ProjectSegment> {
         private final ThreadOutputMuxer threadOutputMuxer;
 
         private final ProjectSegment item;
 
         private final String response;
 
-        Outputter( ThreadOutputMuxer threadOutputMuxer, ProjectSegment item, String response )
-        {
+        Outputter(ThreadOutputMuxer threadOutputMuxer, ProjectSegment item, String response) {
             this.threadOutputMuxer = threadOutputMuxer;
             this.item = item;
             this.response = response;
         }
 
-        public ProjectSegment call()
-            throws Exception
-        {
-            threadOutputMuxer.associateThreadWithProjectSegment( item );
-            System.out.print( response );
-            threadOutputMuxer.setThisModuleComplete( item );
+        public ProjectSegment call() throws Exception {
+            threadOutputMuxer.associateThreadWithProjectSegment(item);
+            System.out.print(response);
+            threadOutputMuxer.setThisModuleComplete(item);
             return item;
         }
     }
 
-
     private ProjectBuildList getProjectBuildList()
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
         final MavenSession session = ProjectDependencyGraphStub.getMavenSession();
-        return ProjectDependencyGraphStub.getProjectBuildList( session );
+        return ProjectDependencyGraphStub.getProjectBuildList(session);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java
index cdb00fc..cbed25b 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/BuildPluginManagerStub.java
@@ -1,19 +1,22 @@
-package org.apache.maven.lifecycle.internal.stub;
-
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
+package org.apache.maven.lifecycle.internal.stub;
 
 import java.util.List;
 
@@ -28,29 +31,22 @@
 import org.eclipse.aether.repository.RemoteRepository;
 
 /**
- * @author Kristian Rosenvold
  */
-public class BuildPluginManagerStub
-    implements BuildPluginManager
-{
+public class BuildPluginManagerStub implements BuildPluginManager {
 
-    public PluginDescriptor loadPlugin( Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session )
-    {
+    public PluginDescriptor loadPlugin(
+            Plugin plugin, List<RemoteRepository> repositories, RepositorySystemSession session) {
         return null;
     }
 
-    public MojoDescriptor getMojoDescriptor( Plugin plugin, String goal, List<RemoteRepository> repositories,
-                                             RepositorySystemSession session )
-    {
-        return MojoExecutorStub.createMojoDescriptor( plugin );
+    public MojoDescriptor getMojoDescriptor(
+            Plugin plugin, String goal, List<RemoteRepository> repositories, RepositorySystemSession session) {
+        return MojoExecutorStub.createMojoDescriptor(plugin);
     }
 
-    public ClassRealm getPluginRealm( MavenSession session, PluginDescriptor pluginDescriptor )
-    {
+    public ClassRealm getPluginRealm(MavenSession session, PluginDescriptor pluginDescriptor) {
         return null;
     }
 
-    public void executeMojo( MavenSession session, MojoExecution execution )
-    {
-    }
+    public void executeMojo(MavenSession session, MojoExecution execution) {}
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/CompletionServiceStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/CompletionServiceStub.java
index 6c7acea..cdfe05b 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/CompletionServiceStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/CompletionServiceStub.java
@@ -1,22 +1,23 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
-import org.apache.maven.lifecycle.internal.ProjectSegment;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -26,64 +27,50 @@
 import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.maven.lifecycle.internal.ProjectSegment;
+
 /**
- * @author Kristian Rosenvold
  */
-public class CompletionServiceStub
-    implements CompletionService<ProjectSegment>
-{
-    List<FutureTask<ProjectSegment>> projectBuildFutureTasks =
-        Collections.synchronizedList(new ArrayList<>() );
+public class CompletionServiceStub implements CompletionService<ProjectSegment> {
+    List<FutureTask<ProjectSegment>> projectBuildFutureTasks = Collections.synchronizedList(new ArrayList<>());
 
     final boolean finishImmediately;
 
-
-    public int size()
-    {
+    public int size() {
         return projectBuildFutureTasks.size();
     }
 
-    public CompletionServiceStub( boolean finishImmediately )
-    {
+    public CompletionServiceStub(boolean finishImmediately) {
         this.finishImmediately = finishImmediately;
     }
 
-    public Future<ProjectSegment> submit( Callable<ProjectSegment> task )
-    {
-        FutureTask<ProjectSegment> projectBuildFutureTask = new FutureTask<>( task );
-        projectBuildFutureTasks.add( projectBuildFutureTask );
-        if ( finishImmediately )
-        {
+    public Future<ProjectSegment> submit(Callable<ProjectSegment> task) {
+        FutureTask<ProjectSegment> projectBuildFutureTask = new FutureTask<>(task);
+        projectBuildFutureTasks.add(projectBuildFutureTask);
+        if (finishImmediately) {
             projectBuildFutureTask.run();
         }
         return projectBuildFutureTask;
     }
 
-    public Future<ProjectSegment> submit( Runnable task, ProjectSegment result )
-    {
-        FutureTask<ProjectSegment> projectBuildFutureTask = new FutureTask<>( task, result );
-        projectBuildFutureTasks.add( projectBuildFutureTask );
-        if ( finishImmediately )
-        {
+    public Future<ProjectSegment> submit(Runnable task, ProjectSegment result) {
+        FutureTask<ProjectSegment> projectBuildFutureTask = new FutureTask<>(task, result);
+        projectBuildFutureTasks.add(projectBuildFutureTask);
+        if (finishImmediately) {
             projectBuildFutureTask.run();
         }
         return projectBuildFutureTask;
     }
 
-    public Future<ProjectSegment> take()
-        throws InterruptedException
-    {
+    public Future<ProjectSegment> take() throws InterruptedException {
         return null;
     }
 
-    public Future<ProjectSegment> poll()
-    {
+    public Future<ProjectSegment> poll() {
         return null;
     }
 
-    public Future<ProjectSegment> poll( long timeout, TimeUnit unit )
-        throws InterruptedException
-    {
+    public Future<ProjectSegment> poll(long timeout, TimeUnit unit) throws InterruptedException {
         return null;
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java
index 1d3f8fd..9854800 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/DefaultLifecyclesStub.java
@@ -1,64 +1,75 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
-import org.apache.maven.lifecycle.DefaultLifecycles;
-import org.apache.maven.lifecycle.Lifecycle;
-
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.maven.lifecycle.DefaultLifecycles;
+import org.apache.maven.lifecycle.Lifecycle;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+
 import static org.apache.maven.lifecycle.internal.stub.LifecycleExecutionPlanCalculatorStub.*;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 /**
- * @author Kristian Rosenvold
  */
+public class DefaultLifecyclesStub {
+    public static DefaultLifecycles createDefaultLifecycles() throws ComponentLookupException {
 
-public class DefaultLifecyclesStub
-{
-    public static DefaultLifecycles createDefaultLifecycles()
-    {
-
-        List<String> stubDefaultCycle =
-            Arrays.asList( VALIDATE.getPhase(), INITIALIZE.getPhase(), PROCESS_RESOURCES.getPhase(), COMPILE.getPhase(),
-                           TEST.getPhase(), PROCESS_TEST_RESOURCES.getPhase(), PACKAGE.getPhase(), "BEER",
-                           INSTALL.getPhase() );
+        List<String> stubDefaultCycle = Arrays.asList(
+                VALIDATE.getPhase(),
+                INITIALIZE.getPhase(),
+                PROCESS_RESOURCES.getPhase(),
+                COMPILE.getPhase(),
+                TEST.getPhase(),
+                PROCESS_TEST_RESOURCES.getPhase(),
+                PACKAGE.getPhase(),
+                "BEER",
+                INSTALL.getPhase());
 
         // The two phases below are really for future expansion, some would say they lack a drink
         // The point being that they do not really have to match the "real" stuff,
-        List<String> stubCleanCycle = Arrays.asList( PRE_CLEAN.getPhase(), CLEAN.getPhase(), POST_CLEAN.getPhase() );
+        List<String> stubCleanCycle = Arrays.asList(PRE_CLEAN.getPhase(), CLEAN.getPhase(), POST_CLEAN.getPhase());
 
         List<String> stubSiteCycle =
-            Arrays.asList( PRE_SITE.getPhase(), SITE.getPhase(), POST_SITE.getPhase(), SITE_DEPLOY.getPhase() );
+                Arrays.asList(PRE_SITE.getPhase(), SITE.getPhase(), POST_SITE.getPhase(), SITE_DEPLOY.getPhase());
 
-        List<String> stubWrapperCycle = Arrays.asList( WRAPPER.getPhase() );
+        List<String> stubWrapperCycle = Arrays.asList(WRAPPER.getPhase());
 
-        Iterator<List<String>> lcs = Arrays.asList( stubDefaultCycle, stubCleanCycle, stubSiteCycle, stubWrapperCycle ).iterator();
+        Iterator<List<String>> lcs = Arrays.asList(stubDefaultCycle, stubCleanCycle, stubSiteCycle, stubWrapperCycle)
+                .iterator();
 
         Map<String, Lifecycle> lifeCycles = new HashMap<>();
-        for ( String s : DefaultLifecycles.STANDARD_LIFECYCLES )
-        {
-            final Lifecycle lifecycle = new Lifecycle( s, lcs.next(), null );
-            lifeCycles.put( s, lifecycle );
-
+        for (String s : DefaultLifecycles.STANDARD_LIFECYCLES) {
+            final Lifecycle lifecycle = new Lifecycle(s, lcs.next(), null);
+            lifeCycles.put(s, lifecycle);
         }
-        return new DefaultLifecycles( lifeCycles );
-    }
 
-}
\ No newline at end of file
+        PlexusContainer mockedContainer = mock(PlexusContainer.class);
+        when(mockedContainer.lookupMap(Lifecycle.class)).thenReturn(lifeCycles);
+
+        return new DefaultLifecycles(mockedContainer);
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ExecutionEventCatapultStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ExecutionEventCatapultStub.java
index e47ec61..a5e3bbe 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ExecutionEventCatapultStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ExecutionEventCatapultStub.java
@@ -1,5 +1,3 @@
-package org.apache.maven.lifecycle.internal.stub;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,25 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.lifecycle.internal.stub;
 
-import org.apache.maven.execution.MavenSession;
 import org.apache.maven.execution.ExecutionEvent.Type;
+import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
 import org.apache.maven.plugin.MojoExecution;
 
 /**
- * @author Benjamin Bentmann
  */
-public class ExecutionEventCatapultStub
-    implements ExecutionEventCatapult
-{
+public class ExecutionEventCatapultStub implements ExecutionEventCatapult {
 
-    public void fire( Type eventType, MavenSession session, MojoExecution mojoExecution )
-    {
-    }
+    public void fire(Type eventType, MavenSession session, MojoExecution mojoExecution) {}
 
-    public void fire( Type eventType, MavenSession session, MojoExecution mojoExecution, Exception exception )
-    {
-    }
-
+    public void fire(Type eventType, MavenSession session, MojoExecution mojoExecution, Exception exception) {}
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java
index b067e24..4d60570 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifeCyclePluginAnalyzerStub.java
@@ -1,74 +1,67 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
-import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginExecution;
-
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Set;
 
+import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.model.PluginExecution;
+
 /**
- * @author Kristian Rosenvold
  */
-public class LifeCyclePluginAnalyzerStub
-    implements LifeCyclePluginAnalyzer
-{
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
+public class LifeCyclePluginAnalyzerStub implements LifeCyclePluginAnalyzer {
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
         Set<Plugin> plugins;
 
         // NOTE: The upper-case packaging name is intentional, that's a special hinting mode used for certain tests
-        if ( "JAR".equals( packaging ) )
-        {
+        if ("JAR".equals(packaging)) {
             plugins = new LinkedHashSet<>();
 
-            plugins.add( newPlugin( "maven-compiler-plugin", "compile", "testCompile" ) );
-            plugins.add( newPlugin( "maven-resources-plugin", "resources", "testResources" ) );
-            plugins.add( newPlugin( "maven-surefire-plugin", "test" ) );
-            plugins.add( newPlugin( "maven-jar-plugin", "jar" ) );
-            plugins.add( newPlugin( "maven-install-plugin", "install" ) );
-            plugins.add( newPlugin( "maven-deploy-plugin", "deploy" ) );
-        }
-        else
-        {
+            plugins.add(newPlugin("maven-compiler-plugin", "compile", "testCompile"));
+            plugins.add(newPlugin("maven-resources-plugin", "resources", "testResources"));
+            plugins.add(newPlugin("maven-surefire-plugin", "test"));
+            plugins.add(newPlugin("maven-jar-plugin", "jar"));
+            plugins.add(newPlugin("maven-install-plugin", "install"));
+            plugins.add(newPlugin("maven-deploy-plugin", "deploy"));
+        } else {
             plugins = Collections.emptySet();
         }
 
         return plugins;
     }
 
-    private Plugin newPlugin( String artifactId, String... goals )
-    {
+    private Plugin newPlugin(String artifactId, String... goals) {
         Plugin plugin = new Plugin();
 
-        plugin.setGroupId( "org.apache.maven.plugins" );
-        plugin.setArtifactId( artifactId );
+        plugin.setGroupId("org.apache.maven.plugins");
+        plugin.setArtifactId(artifactId);
 
-        for ( String goal : goals )
-        {
+        for (String goal : goals) {
             PluginExecution pluginExecution = new PluginExecution();
-            pluginExecution.setId( "default-" + goal );
-            pluginExecution.addGoal( goal );
-            plugin.addExecution( pluginExecution );
+            pluginExecution.setId("default-" + goal);
+            pluginExecution.addGoal(goal);
+            plugin.addExecution(pluginExecution);
         }
 
         return plugin;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleExecutionPlanCalculatorStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleExecutionPlanCalculatorStub.java
index f7514b7..15cb77f 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleExecutionPlanCalculatorStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleExecutionPlanCalculatorStub.java
@@ -1,21 +1,32 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.xml.XmlNodeImpl;
+import org.apache.maven.lifecycle.DefaultLifecycles;
 import org.apache.maven.lifecycle.LifecycleNotFoundException;
 import org.apache.maven.lifecycle.LifecyclePhaseNotFoundException;
 import org.apache.maven.lifecycle.MavenExecutionPlan;
@@ -38,216 +49,201 @@
 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
 
 /**
- * @author Kristian Rosenvold
  */
-public class LifecycleExecutionPlanCalculatorStub
-    implements LifecycleExecutionPlanCalculator
-{
+public class LifecycleExecutionPlanCalculatorStub implements LifecycleExecutionPlanCalculator {
     // clean
 
-    public final static MojoDescriptor PRE_CLEAN = createMojoDescriptor( "pre-clean" );
+    public static final MojoDescriptor PRE_CLEAN = createMojoDescriptor("pre-clean");
 
-    public final static MojoDescriptor CLEAN = createMojoDescriptor( "clean" );
+    public static final MojoDescriptor CLEAN = createMojoDescriptor("clean");
 
-    public final static MojoDescriptor POST_CLEAN = createMojoDescriptor( "post-clean" );
+    public static final MojoDescriptor POST_CLEAN = createMojoDescriptor("post-clean");
 
     // default (or at least some of them)
 
-    public final static MojoDescriptor VALIDATE = createMojoDescriptor( "validate" );
+    public static final MojoDescriptor VALIDATE = createMojoDescriptor("validate");
 
-    public final static MojoDescriptor INITIALIZE = createMojoDescriptor( "initialize" );
+    public static final MojoDescriptor INITIALIZE = createMojoDescriptor("initialize");
 
-    public final static MojoDescriptor TEST_COMPILE = createMojoDescriptor( "test-compile" );
+    public static final MojoDescriptor TEST_COMPILE = createMojoDescriptor("test-compile");
 
-    public final static MojoDescriptor PROCESS_TEST_RESOURCES = createMojoDescriptor( "process-test-resources" );
+    public static final MojoDescriptor PROCESS_TEST_RESOURCES = createMojoDescriptor("process-test-resources");
 
-    public final static MojoDescriptor PROCESS_RESOURCES = createMojoDescriptor( "process-resources" );
+    public static final MojoDescriptor PROCESS_RESOURCES = createMojoDescriptor("process-resources");
 
-    public final static MojoDescriptor COMPILE = createMojoDescriptor( "compile", true );
+    public static final MojoDescriptor COMPILE = createMojoDescriptor("compile", true);
 
-    public final static MojoDescriptor TEST = createMojoDescriptor( "test" );
+    public static final MojoDescriptor TEST = createMojoDescriptor("test");
 
-    public final static MojoDescriptor PACKAGE = createMojoDescriptor( "package" );
+    public static final MojoDescriptor PACKAGE = createMojoDescriptor("package");
 
-    public final static MojoDescriptor INSTALL = createMojoDescriptor( "install" );
+    public static final MojoDescriptor INSTALL = createMojoDescriptor("install");
 
     // site
 
-    public final static MojoDescriptor PRE_SITE = createMojoDescriptor( "pre-site" );
+    public static final MojoDescriptor PRE_SITE = createMojoDescriptor("pre-site");
 
-    public final static MojoDescriptor SITE = createMojoDescriptor( "site" );
+    public static final MojoDescriptor SITE = createMojoDescriptor("site");
 
-    public final static MojoDescriptor POST_SITE = createMojoDescriptor( "post-site" );
+    public static final MojoDescriptor POST_SITE = createMojoDescriptor("post-site");
 
-    public final static MojoDescriptor SITE_DEPLOY = createMojoDescriptor( "site-deploy" );
+    public static final MojoDescriptor SITE_DEPLOY = createMojoDescriptor("site-deploy");
 
     // wrapper
 
-    public final static MojoDescriptor WRAPPER = createMojoDescriptor( "wrapper" );
+    public static final MojoDescriptor WRAPPER = createMojoDescriptor("wrapper");
 
     /**
      * @deprecated instead use {@link #getNumberOfExecutions(ProjectBuildList)}
      */
     @Deprecated
-    public int getNumberOfExceutions( ProjectBuildList projectBuildList )
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+    public int getNumberOfExceutions(ProjectBuildList projectBuildList)
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
         int result = 0;
-        for ( ProjectSegment projectBuild : projectBuildList )
-        {
-            MavenExecutionPlan plan = calculateExecutionPlan( projectBuild.getSession(), projectBuild.getProject(),
-                                                              projectBuild.getTaskSegment().getTasks() );
+        for (ProjectSegment projectBuild : projectBuildList) {
+            MavenExecutionPlan plan = calculateExecutionPlan(
+                    projectBuild.getSession(),
+                    projectBuild.getProject(),
+                    projectBuild.getTaskSegment().getTasks());
             result += plan.size();
         }
         return result;
     }
 
-    public int getNumberOfExecutions( ProjectBuildList projectBuildList )
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
-        return getNumberOfExceutions( projectBuildList );
+    public int getNumberOfExecutions(ProjectBuildList projectBuildList)
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        return getNumberOfExceutions(projectBuildList);
     }
 
-    public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-        throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
+    public void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session)
+            throws MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
+                    PluginDescriptorParsingException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {
         // Maybe do something ?
     }
 
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks,
-                                                      boolean setup )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        if ( project.equals( ProjectDependencyGraphStub.A ) )
-        {
+    public MavenExecutionPlan calculateExecutionPlan(
+            MavenSession session, MavenProject project, List<Object> tasks, boolean setup)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        if (project.equals(ProjectDependencyGraphStub.A)) {
             return getProjectAExecutionPlan();
         }
-        if ( project.equals( ProjectDependencyGraphStub.B ) )
-        {
+        if (project.equals(ProjectDependencyGraphStub.B)) {
             return getProjectBExecutionPlan();
         }
         // The remaining are basically "for future expansion"
         List<MojoExecution> me = new ArrayList<>();
-        me.add( createMojoExecution( "resources", "default-resources", PROCESS_RESOURCES ) );
-        me.add( createMojoExecution( "compile", "default-compile", COMPILE ) );
-        return createExecutionPlan( project, me );
+        me.add(createMojoExecution("resources", "default-resources", PROCESS_RESOURCES));
+        me.add(createMojoExecution("compile", "default-compile", COMPILE));
+        return createExecutionPlan(project, me);
     }
 
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, MavenProject project, List<Object> tasks )
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-        return calculateExecutionPlan( session, project, tasks, true );
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, MavenProject project, List<Object> tasks)
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
+        return calculateExecutionPlan(session, project, tasks, true);
     }
 
-    public void setupMojoExecution( MavenSession session, MavenProject project, MojoExecution mojoExecution, Set<MojoDescriptor> alreadyForkedExecutions )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
-    }
+    public void setupMojoExecution(
+            MavenSession session,
+            MavenProject project,
+            MojoExecution mojoExecution,
+            Set<MojoDescriptor> alreadyForkedExecutions)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, InvalidPluginDescriptorException, NoPluginFoundForPrefixException,
+                    LifecyclePhaseNotFoundException, LifecycleNotFoundException, PluginVersionResolutionException {}
 
     public static MavenExecutionPlan getProjectAExecutionPlan()
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
         List<MojoExecution> me = new ArrayList<>();
-        me.add( createMojoExecution( "initialize", "default-initialize", INITIALIZE ) );
-        me.add( createMojoExecution( "resources", "default-resources", PROCESS_RESOURCES ) );
-        me.add( createMojoExecution( "compile", "default-compile", COMPILE ) );
-        me.add( createMojoExecution( "testResources", "default-testResources", PROCESS_TEST_RESOURCES ) );
-        me.add( createMojoExecution( "testCompile", "default-testCompile", TEST_COMPILE ) );
-        me.add( createMojoExecution( "test", "default-test", TEST ) );
-        me.add( createMojoExecution( "war", "default-war", PACKAGE ) );
-        me.add( createMojoExecution( "install", "default-install", INSTALL ) );
-        return createExecutionPlan( ProjectDependencyGraphStub.A.getExecutionProject(), me );
+        me.add(createMojoExecution("initialize", "default-initialize", INITIALIZE));
+        me.add(createMojoExecution("resources", "default-resources", PROCESS_RESOURCES));
+        me.add(createMojoExecution("compile", "default-compile", COMPILE));
+        me.add(createMojoExecution("testResources", "default-testResources", PROCESS_TEST_RESOURCES));
+        me.add(createMojoExecution("testCompile", "default-testCompile", TEST_COMPILE));
+        me.add(createMojoExecution("test", "default-test", TEST));
+        me.add(createMojoExecution("war", "default-war", PACKAGE));
+        me.add(createMojoExecution("install", "default-install", INSTALL));
+        return createExecutionPlan(ProjectDependencyGraphStub.A.getExecutionProject(), me);
     }
 
     public static MavenExecutionPlan getProjectBExecutionPlan()
-        throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
-        PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
-        NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException
-    {
+            throws PluginNotFoundException, PluginResolutionException, LifecyclePhaseNotFoundException,
+                    PluginDescriptorParsingException, MojoNotFoundException, InvalidPluginDescriptorException,
+                    NoPluginFoundForPrefixException, LifecycleNotFoundException, PluginVersionResolutionException {
         List<MojoExecution> me = new ArrayList<>();
-        me.add( createMojoExecution( "enforce", "enforce-versions", VALIDATE ) );
-        me.add( createMojoExecution( "resources", "default-resources", PROCESS_RESOURCES ) );
-        me.add( createMojoExecution( "compile", "default-compile", COMPILE ) );
-        me.add( createMojoExecution( "testResources", "default-testResources", PROCESS_TEST_RESOURCES ) );
-        me.add( createMojoExecution( "testCompile", "default-testCompile", TEST_COMPILE ) );
-        me.add( createMojoExecution( "test", "default-test", TEST ) );
-        return createExecutionPlan( ProjectDependencyGraphStub.B.getExecutionProject(), me );
+        me.add(createMojoExecution("enforce", "enforce-versions", VALIDATE));
+        me.add(createMojoExecution("resources", "default-resources", PROCESS_RESOURCES));
+        me.add(createMojoExecution("compile", "default-compile", COMPILE));
+        me.add(createMojoExecution("testResources", "default-testResources", PROCESS_TEST_RESOURCES));
+        me.add(createMojoExecution("testCompile", "default-testCompile", TEST_COMPILE));
+        me.add(createMojoExecution("test", "default-test", TEST));
+        return createExecutionPlan(ProjectDependencyGraphStub.B.getExecutionProject(), me);
     }
 
-
-    private static MavenExecutionPlan createExecutionPlan( MavenProject project, List<MojoExecution> mojoExecutions )
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+    private static MavenExecutionPlan createExecutionPlan(MavenProject project, List<MojoExecution> mojoExecutions)
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
         final List<ExecutionPlanItem> planItemList =
-            ExecutionPlanItem.createExecutionPlanItems( project, mojoExecutions );
-        return new MavenExecutionPlan( planItemList, DefaultLifecyclesStub.createDefaultLifecycles() );
+                ExecutionPlanItem.createExecutionPlanItems(project, mojoExecutions);
+        return new MavenExecutionPlan(planItemList, getDefaultLifecycles());
     }
 
-    private static MojoExecution createMojoExecution( String goal, String executionId, MojoDescriptor mojoDescriptor )
-    {
+    private static DefaultLifecycles getDefaultLifecycles() {
+        try {
+            return DefaultLifecyclesStub.createDefaultLifecycles();
+        } catch (ComponentLookupException e) {
+            // ignore
+            return null;
+        }
+    }
+
+    private static MojoExecution createMojoExecution(String goal, String executionId, MojoDescriptor mojoDescriptor) {
         InputSource defaultBindings = new InputSource();
-        defaultBindings.setModelId( DefaultLifecyclePluginAnalyzer.DEFAULTLIFECYCLEBINDINGS_MODELID );
+        defaultBindings.setModelId(DefaultLifecyclePluginAnalyzer.DEFAULTLIFECYCLEBINDINGS_MODELID);
 
         final Plugin plugin = mojoDescriptor.getPluginDescriptor().getPlugin();
-        plugin.setLocation( "version", new InputLocation( 12, 34, defaultBindings ) );
-        MojoExecution result = new MojoExecution( plugin, goal, executionId );
-        result.setConfiguration( new Xpp3Dom( executionId + "-" + goal ) );
-        result.setMojoDescriptor( mojoDescriptor );
-        result.setLifecyclePhase( mojoDescriptor.getPhase() );
+        plugin.setLocation("version", new InputLocation(12, 34, defaultBindings));
+        MojoExecution result = new MojoExecution(plugin, goal, executionId);
+        result.setConfiguration(new XmlNodeImpl(executionId + "-" + goal));
+        result.setMojoDescriptor(mojoDescriptor);
+        result.setLifecyclePhase(mojoDescriptor.getPhase());
 
         return result;
-
     }
 
-    public static MojoDescriptor createMojoDescriptor( String phaseName )
-    {
-        return createMojoDescriptor( phaseName, false );
+    public static MojoDescriptor createMojoDescriptor(String phaseName) {
+        return createMojoDescriptor(phaseName, false);
     }
 
-    public static MojoDescriptor createMojoDescriptor( String phaseName, boolean threadSafe )
-    {
+    public static MojoDescriptor createMojoDescriptor(String phaseName, boolean threadSafe) {
         final MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setPhase( phaseName );
+        mojoDescriptor.setPhase(phaseName);
         final PluginDescriptor descriptor = new PluginDescriptor();
         Plugin plugin = new Plugin();
-        plugin.setGroupId( "org.apache.maven.test.MavenExecutionPlan" );
-        plugin.setArtifactId( "stub-plugin-" + phaseName );
-        descriptor.setPlugin( plugin );
-        descriptor.setArtifactId( "artifact." + phaseName );
-        mojoDescriptor.setPluginDescriptor( descriptor );
-        mojoDescriptor.setThreadSafe( threadSafe );
+        plugin.setGroupId("org.apache.maven.test.MavenExecutionPlan");
+        plugin.setArtifactId("stub-plugin-" + phaseName);
+        descriptor.setPlugin(plugin);
+        descriptor.setArtifactId("artifact." + phaseName);
+        mojoDescriptor.setPluginDescriptor(descriptor);
+        mojoDescriptor.setThreadSafe(threadSafe);
         return mojoDescriptor;
     }
 
-
-    public static Set<String> getScopes()
-    {
-        return new HashSet<>( Arrays.asList( "compile" ) );
+    public static Set<String> getScopes() {
+        return new HashSet<>(Arrays.asList("compile"));
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleTaskSegmentCalculatorStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleTaskSegmentCalculatorStub.java
index 6422235..85f30af 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleTaskSegmentCalculatorStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/LifecycleTaskSegmentCalculatorStub.java
@@ -1,24 +1,30 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.lifecycle.internal.DefaultLifecycleTaskSegmentCalculator;
 import org.apache.maven.lifecycle.internal.GoalTask;
 import org.apache.maven.lifecycle.internal.LifecycleTask;
-import org.apache.maven.lifecycle.internal.DefaultLifecycleTaskSegmentCalculator;
 import org.apache.maven.lifecycle.internal.TaskSegment;
 import org.apache.maven.plugin.InvalidPluginDescriptorException;
 import org.apache.maven.plugin.MojoNotFoundException;
@@ -28,66 +34,51 @@
 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
- * @author Kristian Rosenvold
  */
-public class LifecycleTaskSegmentCalculatorStub
-    extends DefaultLifecycleTaskSegmentCalculator
-{
+public class LifecycleTaskSegmentCalculatorStub extends DefaultLifecycleTaskSegmentCalculator {
     public static final String clean = "clean";
 
     public static final String aggr = "aggr";
 
     public static final String install = "install";
 
-    public LifecycleTaskSegmentCalculatorStub()
-    {
-        super( null, null );
+    public LifecycleTaskSegmentCalculatorStub() {
+        super(null, null);
     }
 
-    public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks )
-        throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
-        MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
-        PluginVersionResolutionException
-    {
-        List<TaskSegment> taskSegments = new ArrayList<>( tasks.size() );
+    public List<TaskSegment> calculateTaskSegments(MavenSession session, List<String> tasks)
+            throws PluginNotFoundException, PluginResolutionException, PluginDescriptorParsingException,
+                    MojoNotFoundException, NoPluginFoundForPrefixException, InvalidPluginDescriptorException,
+                    PluginVersionResolutionException {
+        List<TaskSegment> taskSegments = new ArrayList<>(tasks.size());
 
         TaskSegment currentSegment = null;
 
-        for ( String task : tasks )
-        {
-            if ( aggr.equals( task ) )
-            {
+        for (String task : tasks) {
+            if (aggr.equals(task)) {
                 boolean aggregating = true;
 
-                if ( currentSegment == null || currentSegment.isAggregating() != aggregating )
-                {
-                    currentSegment = new TaskSegment( aggregating );
-                    taskSegments.add( currentSegment );
+                if (currentSegment == null || currentSegment.isAggregating() != aggregating) {
+                    currentSegment = new TaskSegment(aggregating);
+                    taskSegments.add(currentSegment);
                 }
 
-                currentSegment.getTasks().add( new GoalTask( task ) );
-            }
-            else
-            {
+                currentSegment.getTasks().add(new GoalTask(task));
+            } else {
                 // lifecycle phase
-                if ( currentSegment == null || currentSegment.isAggregating() )
-                {
-                    currentSegment = new TaskSegment( false );
-                    taskSegments.add( currentSegment );
+                if (currentSegment == null || currentSegment.isAggregating()) {
+                    currentSegment = new TaskSegment(false);
+                    taskSegments.add(currentSegment);
                 }
-                currentSegment.getTasks().add( new LifecycleTask( task ) );
+                currentSegment.getTasks().add(new LifecycleTask(task));
             }
         }
 
         return taskSegments;
     }
 
-    public boolean requiresProject( MavenSession session )
-    {
+    public boolean requiresProject(MavenSession session) {
         return true;
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java
index e716645..94d5095 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/MojoExecutorStub.java
@@ -1,54 +1,53 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
 import javax.inject.Provider;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.maven.api.services.MessageBuilderFactory;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
-import org.apache.maven.lifecycle.internal.DependencyContext;
 import org.apache.maven.lifecycle.internal.ExecutionEventCatapult;
 import org.apache.maven.lifecycle.internal.LifecycleDependencyResolver;
 import org.apache.maven.lifecycle.internal.MojoExecutor;
 import org.apache.maven.lifecycle.internal.ProjectIndex;
+import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.BuildPluginManager;
 import org.apache.maven.plugin.MavenPluginManager;
-import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.MojosExecutionStrategy;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
 import org.apache.maven.project.MavenProject;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
 /**
- * @author Kristian Rosenvold
  */
-public class MojoExecutorStub
-    extends MojoExecutor
-{ // This is being lazy instead of making interface
+public class MojoExecutorStub extends MojoExecutor { // This is being lazy instead of making interface
 
-    public final List<MojoExecution> executions = Collections.synchronizedList(new ArrayList<>() );
+    public final List<MojoExecution> executions = Collections.synchronizedList(new ArrayList<>());
 
-    public MojoExecutorStub()
-    {
-        super( null, null, null, null, null );
+    public MojoExecutorStub() {
+        super(null, null, null, null, null, null);
     }
 
     public MojoExecutorStub(
@@ -56,35 +55,38 @@
             MavenPluginManager mavenPluginManager,
             LifecycleDependencyResolver lifeCycleDependencyResolver,
             ExecutionEventCatapult eventCatapult,
-            Provider<MojosExecutionStrategy> mojosExecutionStrategy )
-    {
-        super( pluginManager, mavenPluginManager, lifeCycleDependencyResolver, eventCatapult, mojosExecutionStrategy );
+            Provider<MojosExecutionStrategy> mojosExecutionStrategy,
+            MessageBuilderFactory messageBuilderFactory) {
+        super(
+                pluginManager,
+                mavenPluginManager,
+                lifeCycleDependencyResolver,
+                eventCatapult,
+                mojosExecutionStrategy,
+                messageBuilderFactory);
     }
 
     @Override
-    public void execute( MavenSession session, List<MojoExecution> mojoExecutions, ProjectIndex projectIndex )
-        throws LifecycleExecutionException
-    {
-        executions.addAll( mojoExecutions );
+    public void execute(MavenSession session, List<MojoExecution> mojoExecutions, ProjectIndex projectIndex)
+            throws LifecycleExecutionException {
+        executions.addAll(mojoExecutions);
     }
 
     @Override
-    public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session, ProjectIndex projectIndex ) throws LifecycleExecutionException
-    {
+    public List<MavenProject> executeForkedExecutions(
+            MojoExecution mojoExecution, MavenSession session, ProjectIndex projectIndex)
+            throws LifecycleExecutionException {
         return null;
     }
 
-
-    public static MojoDescriptor createMojoDescriptor( Plugin plugin )
-    {
+    public static MojoDescriptor createMojoDescriptor(Plugin plugin) {
         final PluginDescriptor descriptor = new PluginDescriptor();
-        descriptor.setGroupId( plugin.getGroupId() );
-        descriptor.setArtifactId( plugin.getArtifactId() );
-        descriptor.setPlugin( plugin );
-        descriptor.setVersion( plugin.getVersion() );
+        descriptor.setGroupId(plugin.getGroupId());
+        descriptor.setArtifactId(plugin.getArtifactId());
+        descriptor.setPlugin(plugin);
+        descriptor.setVersion(plugin.getVersion());
         final MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setPluginDescriptor( descriptor );
+        mojoDescriptor.setPluginDescriptor(descriptor);
         return mojoDescriptor;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginPrefixResolverStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginPrefixResolverStub.java
index a4b54e9..dd759f9 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginPrefixResolverStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginPrefixResolverStub.java
@@ -1,18 +1,21 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
 import org.apache.maven.plugin.prefix.NoPluginFoundForPrefixException;
@@ -22,29 +25,19 @@
 import org.eclipse.aether.repository.ArtifactRepository;
 
 /**
- * @author Kristian Rosenvold
  */
-
-public class PluginPrefixResolverStub
-    implements PluginPrefixResolver
-{
-    public PluginPrefixResult resolve( PluginPrefixRequest request )
-        throws NoPluginFoundForPrefixException
-    {
-        return new PluginPrefixResult()
-        {
-            public String getGroupId()
-            {
+public class PluginPrefixResolverStub implements PluginPrefixResolver {
+    public PluginPrefixResult resolve(PluginPrefixRequest request) throws NoPluginFoundForPrefixException {
+        return new PluginPrefixResult() {
+            public String getGroupId() {
                 return "com.foobar";
             }
 
-            public String getArtifactId()
-            {
+            public String getArtifactId() {
                 return "bazbaz";
             }
 
-            public ArtifactRepository getRepository()
-            {
+            public ArtifactRepository getRepository() {
                 return null;
             }
         };
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginVersionResolverStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginVersionResolverStub.java
index c79658e..6ec4beb 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginVersionResolverStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/PluginVersionResolverStub.java
@@ -1,18 +1,21 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
 import org.apache.maven.plugin.version.PluginVersionRequest;
@@ -22,25 +25,16 @@
 import org.eclipse.aether.repository.ArtifactRepository;
 
 /**
- * @author Kristian Rosenvold
  */
+public class PluginVersionResolverStub implements PluginVersionResolver {
 
-public class PluginVersionResolverStub
-    implements PluginVersionResolver
-{
-
-    public PluginVersionResult resolve( PluginVersionRequest request )
-        throws PluginVersionResolutionException
-    {
-        return new PluginVersionResult()
-        {
-            public String getVersion()
-            {
+    public PluginVersionResult resolve(PluginVersionRequest request) throws PluginVersionResolutionException {
+        return new PluginVersionResult() {
+            public String getVersion() {
                 return "0.42";
             }
 
-            public ArtifactRepository getRepository()
-            {
+            public ArtifactRepository getRepository() {
                 return null;
             }
         };
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependenciesResolverStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependenciesResolverStub.java
deleted file mode 100644
index 8a557d5..0000000
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependenciesResolverStub.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-package org.apache.maven.lifecycle.internal.stub;
-
-import org.apache.maven.ProjectDependenciesResolver;
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
-import org.apache.maven.artifact.resolver.ArtifactResolutionException;
-import org.apache.maven.execution.MavenSession;
-import org.apache.maven.project.DependencyResolutionException;
-import org.apache.maven.project.DependencyResolutionRequest;
-import org.apache.maven.project.DependencyResolutionResult;
-import org.apache.maven.project.MavenProject;
-import org.eclipse.aether.graph.DefaultDependencyNode;
-import org.eclipse.aether.graph.Dependency;
-import org.eclipse.aether.graph.DependencyNode;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * @author Kristian Rosenvold
- */
-public class ProjectDependenciesResolverStub
-    implements ProjectDependenciesResolver, org.apache.maven.project.ProjectDependenciesResolver
-{
-    public Set<Artifact> resolve( MavenProject project, Collection<String> scopesToResolve, MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return new HashSet<>();
-    }
-
-    public Set<Artifact> resolve( MavenProject project, Collection<String> scopesToCollect,
-                                  Collection<String> scopesToResolve, MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return new HashSet<>();
-    }
-
-    public Set<Artifact> resolve( Collection<? extends MavenProject> projects, Collection<String> scopes,
-                                  MavenSession session )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return new HashSet<>();
-    }
-
-    public Set<Artifact> resolve( MavenProject project, Collection<String> scopesToCollect,
-                                  Collection<String> scopesToResolve, MavenSession session,
-                                  Set<Artifact> ignorableArtifacts )
-        throws ArtifactResolutionException, ArtifactNotFoundException
-    {
-        return new HashSet<>();
-    }
-
-    public DependencyResolutionResult resolve( DependencyResolutionRequest request )
-        throws DependencyResolutionException
-    {
-        return new DependencyResolutionResult()
-        {
-
-            public List<Dependency> getUnresolvedDependencies()
-            {
-                return Collections.emptyList();
-            }
-
-            public List<Dependency> getResolvedDependencies()
-            {
-                return Collections.emptyList();
-            }
-
-            public List<Exception> getResolutionErrors( Dependency dependency )
-            {
-                return Collections.emptyList();
-            }
-
-            public DependencyNode getDependencyGraph()
-            {
-                return new DefaultDependencyNode( (Dependency) null );
-            }
-
-            public List<Dependency> getDependencies()
-            {
-                return Collections.emptyList();
-            }
-
-            public List<Exception> getCollectionErrors()
-            {
-                return Collections.emptyList();
-            }
-        };
-    }
-
-}
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStub.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStub.java
index 961dc7c..d8624e2 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStub.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStub.java
@@ -1,20 +1,27 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
 import org.apache.maven.execution.AbstractExecutionListener;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
@@ -36,10 +43,6 @@
 import org.apache.maven.plugin.version.PluginVersionResolutionException;
 import org.apache.maven.project.MavenProject;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
 /**
  * A stub dependency graph that is custom-made for testing concurrent build graph evaluations.
  * <p>
@@ -52,11 +55,8 @@
  * Z depends on C
  * </p>
  *
- * @author Kristian Rosenvold
  */
-public class ProjectDependencyGraphStub
-    implements ProjectDependencyGraph
-{
+public class ProjectDependencyGraphStub implements ProjectDependencyGraph {
     public static final MavenProject A = new MavenProject();
 
     public static final MavenProject B = new MavenProject();
@@ -71,163 +71,139 @@
 
     public static final MavenProject UNKNOWN = new MavenProject();
 
-    static
-    {
-        A.setArtifactId( "A" );
-        B.setArtifactId( "B" );
-        C.setArtifactId( "C" );
-        X.setArtifactId( "X" );
-        Y.setArtifactId( "Y" );
-        Z.setArtifactId( "Z" );
+    static {
+        A.setArtifactId("A");
+        B.setArtifactId("B");
+        C.setArtifactId("C");
+        X.setArtifactId("X");
+        Y.setArtifactId("Y");
+        Z.setArtifactId("Z");
     }
 
     // This should probably be moved to a separate stub
 
-    public static ProjectBuildList getProjectBuildList( MavenSession session )
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
-        final List<ProjectSegment> list = getProjectBuilds( session );
-        return new ProjectBuildList( list );
-
+    public static ProjectBuildList getProjectBuildList(MavenSession session)
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
+        final List<ProjectSegment> list = getProjectBuilds(session);
+        return new ProjectBuildList(list);
     }
 
-    public static List<ProjectSegment> getProjectBuilds( MavenSession session )
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, PluginNotFoundException, MojoNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+    public static List<ProjectSegment> getProjectBuilds(MavenSession session)
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, PluginNotFoundException, MojoNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
         List<ProjectSegment> projectBuilds = new ArrayList<>();
 
         TaskSegment segment = createTaskSegment();
-        projectBuilds.add( createProjectBuild( A, session, segment ) );
-        projectBuilds.add( createProjectBuild( B, session, segment ) );
-        projectBuilds.add( createProjectBuild( C, session, segment ) );
-        projectBuilds.add( createProjectBuild( X, session, segment ) );
-        projectBuilds.add( createProjectBuild( Y, session, segment ) );
-        projectBuilds.add( createProjectBuild( Z, session, segment ) );
+        projectBuilds.add(createProjectBuild(A, session, segment));
+        projectBuilds.add(createProjectBuild(B, session, segment));
+        projectBuilds.add(createProjectBuild(C, session, segment));
+        projectBuilds.add(createProjectBuild(X, session, segment));
+        projectBuilds.add(createProjectBuild(Y, session, segment));
+        projectBuilds.add(createProjectBuild(Z, session, segment));
         return projectBuilds;
     }
 
-    private static ProjectSegment createProjectBuild( MavenProject project, MavenSession session,
-                                                      TaskSegment taskSegment )
-        throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
-        NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException, PluginResolutionException,
-        LifecyclePhaseNotFoundException, LifecycleNotFoundException
-    {
+    private static ProjectSegment createProjectBuild(
+            MavenProject project, MavenSession session, TaskSegment taskSegment)
+            throws InvalidPluginDescriptorException, PluginVersionResolutionException, PluginDescriptorParsingException,
+                    NoPluginFoundForPrefixException, MojoNotFoundException, PluginNotFoundException,
+                    PluginResolutionException, LifecyclePhaseNotFoundException, LifecycleNotFoundException {
         final MavenSession session1 = session.clone();
-        return new ProjectSegment( project, taskSegment, session1 );
+        return new ProjectSegment(project, taskSegment, session1);
     }
 
-
-    private static TaskSegment createTaskSegment()
-    {
-        TaskSegment result = new TaskSegment( false );
-        result.getTasks().add( new GoalTask( "t1" ) );
-        result.getTasks().add( new GoalTask( "t2" ) );
+    private static TaskSegment createTaskSegment() {
+        TaskSegment result = new TaskSegment(false);
+        result.getTasks().add(new GoalTask("t1"));
+        result.getTasks().add(new GoalTask("t2"));
         return result;
     }
 
-    class Dependency
-    {
+    class Dependency {
         MavenProject dependant;
 
         MavenProject dependency;
 
-        Dependency( MavenProject dependant, MavenProject dependency )
-        {
+        Dependency(MavenProject dependant, MavenProject dependency) {
             this.dependant = dependant;
             this.dependency = dependency;
         }
 
-        void addIfDownstream( MavenProject mavenProject, List<MavenProject> result )
-        {
-            if ( dependency == mavenProject )
-            {
-                result.add( dependant );
+        void addIfDownstream(MavenProject mavenProject, List<MavenProject> result) {
+            if (dependency == mavenProject) {
+                result.add(dependant);
             }
         }
 
-        void addIfUpstreamOf( MavenProject mavenProject, List<MavenProject> result )
-        {
-            if ( dependant == mavenProject )
-            {
-                result.add( dependency ); // All projects are the statics from this class
+        void addIfUpstreamOf(MavenProject mavenProject, List<MavenProject> result) {
+            if (dependant == mavenProject) {
+                result.add(dependency); // All projects are the statics from this class
             }
         }
     }
 
-    private List<Dependency> getDependencies()
-    {
+    private List<Dependency> getDependencies() {
         List<Dependency> dependencies = new ArrayList<>();
-        dependencies.add( new Dependency( B, A ) );
-        dependencies.add( new Dependency( C, A ) );
-        dependencies.add( new Dependency( X, B ) );
-        dependencies.add( new Dependency( X, C ) );
-        dependencies.add( new Dependency( Y, B ) );
-        dependencies.add( new Dependency( Z, C ) );
+        dependencies.add(new Dependency(B, A));
+        dependencies.add(new Dependency(C, A));
+        dependencies.add(new Dependency(X, B));
+        dependencies.add(new Dependency(X, C));
+        dependencies.add(new Dependency(Y, B));
+        dependencies.add(new Dependency(Z, C));
         return dependencies;
     }
 
-    public List<MavenProject> getAllProjects()
-    {
-        return Arrays.asList( A, B, C, X, Y, Z, UNKNOWN );
+    public List<MavenProject> getAllProjects() {
+        return Arrays.asList(A, B, C, X, Y, Z, UNKNOWN);
     }
 
-    public List<MavenProject> getSortedProjects()
-    {
-        return Arrays.asList( A, B, C, X, Y, Z ); // I'm not entirely sure about the order but this should do...
+    public List<MavenProject> getSortedProjects() {
+        return Arrays.asList(A, B, C, X, Y, Z); // I'm not entirely sure about the order but this should do...
     }
 
-    public List<MavenProject> getDownstreamProjects( MavenProject project, boolean transitive )
-    {
-        if ( transitive )
-        {
-            throw new RuntimeException( "Not implemented yet" );
+    public List<MavenProject> getDownstreamProjects(MavenProject project, boolean transitive) {
+        if (transitive) {
+            throw new RuntimeException("Not implemented yet");
         }
         List<MavenProject> result = new ArrayList<>();
-        for ( Dependency dependency : getDependencies() )
-        {
-            dependency.addIfDownstream( project, result );
+        for (Dependency dependency : getDependencies()) {
+            dependency.addIfDownstream(project, result);
         }
         return result;
     }
 
-    public List<MavenProject> getUpstreamProjects( MavenProject project, boolean transitive )
-    {
+    public List<MavenProject> getUpstreamProjects(MavenProject project, boolean transitive) {
         /*  if ( transitive )
         {
             throw new RuntimeException( "Not implemented yet" );
         }*/
         List<MavenProject> result = new ArrayList<>();
         final List<Dependency> dependencies = getDependencies();
-        for ( Dependency dependency : dependencies )
-        {
-            dependency.addIfUpstreamOf( project, result );
+        for (Dependency dependency : dependencies) {
+            dependency.addIfUpstreamOf(project, result);
         }
         return result;
     }
 
-    public static MavenSession getMavenSession( MavenProject mavenProject )
-    {
+    public static MavenSession getMavenSession(MavenProject mavenProject) {
         final MavenSession session = getMavenSession();
-        session.setCurrentProject( mavenProject );
+        session.setCurrentProject(mavenProject);
         return session;
     }
 
-    public static MavenSession getMavenSession()
-    {
+    public static MavenSession getMavenSession() {
         final DefaultMavenExecutionResult defaultMavenExecutionResult = new DefaultMavenExecutionResult();
         MavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest();
-        mavenExecutionRequest.setExecutionListener( new AbstractExecutionListener() );
-        mavenExecutionRequest.setGoals( Arrays.asList( "clean", "aggr", "install" ) );
-        mavenExecutionRequest.setDegreeOfConcurrency( 1 );
-        final MavenSession session = new MavenSession( null, null, mavenExecutionRequest, defaultMavenExecutionResult );
+        mavenExecutionRequest.setExecutionListener(new AbstractExecutionListener());
+        mavenExecutionRequest.setGoals(Arrays.asList("clean", "aggr", "install"));
+        mavenExecutionRequest.setDegreeOfConcurrency(1);
+        final MavenSession session = new MavenSession(null, null, mavenExecutionRequest, defaultMavenExecutionResult);
         final ProjectDependencyGraphStub dependencyGraphStub = new ProjectDependencyGraphStub();
-        session.setProjectDependencyGraph( dependencyGraphStub );
-        session.setProjects( dependencyGraphStub.getSortedProjects() );
+        session.setProjectDependencyGraph(dependencyGraphStub);
+        session.setProjects(dependencyGraphStub.getSortedProjects());
         return session;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStubTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStubTest.java
index 56283ad..2a12af0 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStubTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/internal/stub/ProjectDependencyGraphStubTest.java
@@ -1,18 +1,21 @@
 /*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
  *
- * http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
  */
-
 package org.apache.maven.lifecycle.internal.stub;
 
 import java.util.List;
@@ -26,42 +29,35 @@
 /**
  * Tests the stub. Yeah, I know.
  *
- * @author Kristian Rosenvold
  */
-
-public class ProjectDependencyGraphStubTest
-{
+class ProjectDependencyGraphStubTest {
     ProjectDependencyGraphStub stub = new ProjectDependencyGraphStub();
 
     @Test
-    public void testADependencies()
-    {
-        final List<MavenProject> mavenProjects = stub.getUpstreamProjects( ProjectDependencyGraphStub.A, false );
-        assertEquals( 0, mavenProjects.size() );
+    void testADependencies() {
+        final List<MavenProject> mavenProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.A, false);
+        assertEquals(0, mavenProjects.size());
     }
 
     @Test
-    public void testBDependencies()
-    {
-        final List<MavenProject> bProjects = stub.getUpstreamProjects( ProjectDependencyGraphStub.B, false );
-        assertEquals( 1, bProjects.size() );
-        assertTrue( bProjects.contains( ProjectDependencyGraphStub.A ) );
+    void testBDependencies() {
+        final List<MavenProject> bProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.B, false);
+        assertEquals(1, bProjects.size());
+        assertTrue(bProjects.contains(ProjectDependencyGraphStub.A));
     }
 
     @Test
-    public void testCDependencies()
-    {
-        final List<MavenProject> cProjects = stub.getUpstreamProjects( ProjectDependencyGraphStub.C, false );
-        assertEquals( 1, cProjects.size() );
-        assertTrue( cProjects.contains( ProjectDependencyGraphStub.A ) );
+    void testCDependencies() {
+        final List<MavenProject> cProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.C, false);
+        assertEquals(1, cProjects.size());
+        assertTrue(cProjects.contains(ProjectDependencyGraphStub.A));
     }
 
     @Test
-    public void testXDependencies()
-    {
-        final List<MavenProject> cProjects = stub.getUpstreamProjects( ProjectDependencyGraphStub.X, false );
-        assertEquals( 2, cProjects.size() );
-        assertTrue( cProjects.contains( ProjectDependencyGraphStub.C ) );
-        assertTrue( cProjects.contains( ProjectDependencyGraphStub.B ) );
+    void testXDependencies() {
+        final List<MavenProject> cProjects = stub.getUpstreamProjects(ProjectDependencyGraphStub.X, false);
+        assertEquals(2, cProjects.size());
+        assertTrue(cProjects.contains(ProjectDependencyGraphStub.C));
+        assertTrue(cProjects.contains(ProjectDependencyGraphStub.B));
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/lifecycle/mapping/LifecyclePhaseTest.java b/maven-core/src/test/java/org/apache/maven/lifecycle/mapping/LifecyclePhaseTest.java
index 677915f..afa112d 100644
--- a/maven-core/src/test/java/org/apache/maven/lifecycle/mapping/LifecyclePhaseTest.java
+++ b/maven-core/src/test/java/org/apache/maven/lifecycle/mapping/LifecyclePhaseTest.java
@@ -1,73 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.lifecycle.mapping;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
 import java.util.Arrays;
 import java.util.List;
 
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
 /**
- * @author atanasenko
  */
-public class LifecyclePhaseTest
-{
+class LifecyclePhaseTest {
     @Test
-    public void testToString()
-    {
+    void testToString() {
         LifecyclePhase phase = new LifecyclePhase();
-        assertEquals( "", phase.toString() );
+        assertEquals("", phase.toString());
 
         LifecycleMojo mojo1 = new LifecycleMojo();
-        mojo1.setGoal( "jar:jar" );
-        phase.setMojos( Arrays.asList( mojo1 ) );
-        assertEquals( "jar:jar", phase.toString()  );
+        mojo1.setGoal("jar:jar");
+        phase.setMojos(Arrays.asList(mojo1));
+        assertEquals("jar:jar", phase.toString());
 
         LifecycleMojo mojo2 = new LifecycleMojo();
-        mojo2.setGoal( "war:war" );
-        phase.setMojos( Arrays.asList( mojo1, mojo2 ) );
-        assertEquals( "jar:jar,war:war", phase.toString() );
+        mojo2.setGoal("war:war");
+        phase.setMojos(Arrays.asList(mojo1, mojo2));
+        assertEquals("jar:jar,war:war", phase.toString());
     }
 
     @Test
-    public void testSet()
-    {
+    void testSet() {
         LifecyclePhase phase = new LifecyclePhase();
-        assertNull( phase.getMojos() );
+        assertNull(phase.getMojos());
 
-        phase.set( "" );
-        assertNotNull( phase.getMojos() );
-        assertEquals( 0, phase.getMojos().size() );
+        phase.set("");
+        assertNotNull(phase.getMojos());
+        assertEquals(0, phase.getMojos().size());
 
-        phase.set( "jar:jar, war:war" );
+        phase.set("jar:jar, war:war");
 
         List<LifecycleMojo> mojos = phase.getMojos();
-        assertNotNull( mojos );
-        assertEquals( 2, mojos.size() );
+        assertNotNull(mojos);
+        assertEquals(2, mojos.size());
 
         LifecycleMojo mojo1 = mojos.get(0);
-        assertNotNull( mojo1 );
-        assertEquals( "jar:jar", mojo1.getGoal() );
+        assertNotNull(mojo1);
+        assertEquals("jar:jar", mojo1.getGoal());
 
         LifecycleMojo mojo2 = mojos.get(1);
-        assertNotNull( mojo2 );
-        assertEquals( "war:war", mojo2.getGoal() );
+        assertNotNull(mojo2);
+        assertEquals("war:war", mojo2.getGoal());
     }
 }
-
diff --git a/maven-core/src/test/java/org/apache/maven/model/ModelBuilderTest.java b/maven-core/src/test/java/org/apache/maven/model/ModelBuilderTest.java
new file mode 100644
index 0000000..2692899
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/model/ModelBuilderTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model;
+
+import javax.inject.Inject;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
+import org.apache.maven.project.DefaultProjectBuildingRequest;
+import org.apache.maven.project.ProjectBuilder;
+import org.apache.maven.project.ProjectBuildingResult;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+@PlexusTest
+public class ModelBuilderTest {
+
+    @Inject
+    ProjectBuilder projectBuilder;
+
+    @Inject
+    MavenRepositorySystem repositorySystem;
+
+    @Inject
+    DefaultRepositorySystemSessionFactory repositorySessionFactory;
+
+    @Test
+    void testModelBuilder() throws Exception {
+        MavenExecutionRequest mavenRequest = new DefaultMavenExecutionRequest();
+        mavenRequest.setLocalRepository(repositorySystem.createLocalRepository(new File("target/test-repo/")));
+
+        DefaultProjectBuildingRequest request = new DefaultProjectBuildingRequest();
+        request.setRepositorySession(repositorySessionFactory.newRepositorySession(mavenRequest));
+        List<ProjectBuildingResult> results = projectBuilder.build(
+                Collections.singletonList(new File("src/test/resources/projects/tree/pom.xml")), true, request);
+
+        assertEquals(3, results.size());
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginManagerTest.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginManagerTest.java
index a688c76..7020e40 100644
--- a/maven-core/src/test/java/org/apache/maven/plugin/PluginManagerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginManagerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
+
+import javax.inject.Inject;
 
 import java.util.List;
 
@@ -38,65 +39,57 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
-import javax.inject.Inject;
-
-public class PluginManagerTest
-    extends AbstractCoreMavenComponentTestCase
-{
+class PluginManagerTest extends AbstractCoreMavenComponentTestCase {
     @Inject
     private DefaultBuildPluginManager pluginManager;
 
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/plugin-manager";
     }
 
     @Test
-    public void testPluginLoading()
-        throws Exception
-    {
-        MavenSession session = createMavenSession( null );
+    void testPluginLoading() throws Exception {
+        MavenSession session = createMavenSession(null);
         Plugin plugin = new Plugin();
-        plugin.setGroupId( "org.apache.maven.its.plugins" );
-        plugin.setArtifactId( "maven-it-plugin" );
-        plugin.setVersion( "0.1" );
-        PluginDescriptor pluginDescriptor =
-            pluginManager.loadPlugin( plugin, session.getCurrentProject().getRemotePluginRepositories(),
-                                      session.getRepositorySession() );
-        assertNotNull( pluginDescriptor );
+        plugin.setGroupId("org.apache.maven.its.plugins");
+        plugin.setArtifactId("maven-it-plugin");
+        plugin.setVersion("0.1");
+        PluginDescriptor pluginDescriptor = pluginManager.loadPlugin(
+                plugin, session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+        assertNotNull(pluginDescriptor);
     }
 
     @Test
-    public void testMojoDescriptorRetrieval()
-        throws Exception
-    {
-        MavenSession session = createMavenSession( null );
+    void testMojoDescriptorRetrieval() throws Exception {
+        MavenSession session = createMavenSession(null);
         String goal = "it";
         Plugin plugin = new Plugin();
-        plugin.setGroupId( "org.apache.maven.its.plugins" );
-        plugin.setArtifactId( "maven-it-plugin" );
-        plugin.setVersion( "0.1" );
+        plugin.setGroupId("org.apache.maven.its.plugins");
+        plugin.setArtifactId("maven-it-plugin");
+        plugin.setVersion("0.1");
 
-        MojoDescriptor mojoDescriptor =
-            pluginManager.getMojoDescriptor( plugin, goal, session.getCurrentProject().getRemotePluginRepositories(),
-                                             session.getRepositorySession() );
-        assertNotNull( mojoDescriptor );
-        assertEquals( goal, mojoDescriptor.getGoal() );
+        MojoDescriptor mojoDescriptor = pluginManager.getMojoDescriptor(
+                plugin,
+                goal,
+                session.getCurrentProject().getRemotePluginRepositories(),
+                session.getRepositorySession());
+        assertNotNull(mojoDescriptor);
+        assertEquals(goal, mojoDescriptor.getGoal());
         // igorf: plugin realm comes later
         // assertNotNull( mojoDescriptor.getRealm() );
 
         PluginDescriptor pluginDescriptor = mojoDescriptor.getPluginDescriptor();
-        assertNotNull( pluginDescriptor );
-        assertEquals( "org.apache.maven.its.plugins", pluginDescriptor.getGroupId() );
-        assertEquals( "maven-it-plugin", pluginDescriptor.getArtifactId() );
-        assertEquals( "0.1", pluginDescriptor.getVersion() );
+        assertNotNull(pluginDescriptor);
+        assertEquals("org.apache.maven.its.plugins", pluginDescriptor.getGroupId());
+        assertEquals("maven-it-plugin", pluginDescriptor.getArtifactId());
+        assertEquals("0.1", pluginDescriptor.getVersion());
     }
 
     // -----------------------------------------------------------------------------------------------
     // Tests which exercise the lifecycle executor when it is dealing with individual goals.
     // -----------------------------------------------------------------------------------------------
 
-    //TODO These two tests display a lack of symmetry with respect to the input which is a free form string and the
+    // TODO These two tests display a lack of symmetry with respect to the input which is a free form string and the
     //      mojo descriptor which comes back. All the free form parsing needs to be done somewhere else, this is
     //      really the function of the CLI, and then the pre-processing of that output still needs to be fed into
     //      a hinting process which helps flesh out the full specification of the plugin. The plugin manager should
@@ -104,10 +97,8 @@
     //      the plugin manager provides.
 
     @Test
-    public void testRemoteResourcesPlugin()
-        throws Exception
-    {
-        //TODO turn an equivalent back on when the RR plugin is released.
+    void testRemoteResourcesPlugin() throws Exception {
+        // TODO turn an equivalent back on when the RR plugin is released.
 
         /*
 
@@ -132,10 +123,8 @@
         */
     }
 
-    //TODO this will be the basis of the customizable lifecycle execution so need to figure this out quickly.
-    public void testSurefirePlugin()
-        throws Exception
-    {
+    // TODO this will be the basis of the customizable lifecycle execution so need to figure this out quickly.
+    public void testSurefirePlugin() throws Exception {
         /*
         MavenSession session = createMavenSession( getProject( "project-with-inheritance" ) );
         String goal = "test";
@@ -158,10 +147,7 @@
     }
 
     @Test
-    public void testMojoConfigurationIsMergedCorrectly()
-        throws Exception
-    {
-    }
+    void testMojoConfigurationIsMergedCorrectly() throws Exception {}
 
     /**
      * The case where the user wants to specify an alternate version of the underlying tool. Common case
@@ -169,40 +155,28 @@
      * to use a specific version. We need to make sure the version that they specify takes precedence.
      */
     @Test
-    public void testMojoWhereInternallyStatedDependencyIsOverriddenByProject()
-        throws Exception
-    {
-    }
+    void testMojoWhereInternallyStatedDependencyIsOverriddenByProject() throws Exception {}
 
     /**
      * The case where you have a plugin in the current build that you want to be used on projects in
      * the current build.
      */
     @Test
-    public void testMojoThatIsPresentInTheCurrentBuild()
-        throws Exception
-    {
-    }
+    void testMojoThatIsPresentInTheCurrentBuild() throws Exception {}
 
     /**
      * This is the case where the Mojo wants to execute on every project and then do something at the end
      * with the results of each project.
      */
     @Test
-    public void testAggregatorMojo()
-        throws Exception
-    {
-    }
+    void testAggregatorMojo() throws Exception {}
 
     /**
      * This is the case where a Mojo needs the lifecycle run to a certain phase before it can do
      * anything useful.
      */
     @Test
-    public void testMojoThatRequiresExecutionToAGivenPhaseBeforeExecutingItself()
-        throws Exception
-    {
-    }
+    void testMojoThatRequiresExecutionToAGivenPhaseBeforeExecutingItself() throws Exception {}
 
     // test that mojo which does not require dependency resolution trigger no downloading of dependencies
 
@@ -211,111 +185,98 @@
     // test a build where projects use different versions of the same plugin
 
     @Test
-    public void testThatPluginDependencyThatHasSystemScopeIsResolved()
-        throws Exception
-    {
-        MavenSession session = createMavenSession( getProject( "project-contributing-system-scope-plugin-dep" ) );
+    void testThatPluginDependencyThatHasSystemScopeIsResolved() throws Exception {
+        MavenSession session = createMavenSession(getProject("project-contributing-system-scope-plugin-dep"));
         MavenProject project = session.getCurrentProject();
-        Plugin plugin = project.getPlugin( "org.apache.maven.its.plugins:maven-it-plugin" );
+        Plugin plugin = project.getPlugin("org.apache.maven.its.plugins:maven-it-plugin");
 
         RepositoryRequest repositoryRequest = new DefaultRepositoryRequest();
-        repositoryRequest.setLocalRepository( getLocalRepository() );
-        repositoryRequest.setRemoteRepositories( getPluginArtifactRepositories() );
+        repositoryRequest.setLocalRepository(getLocalRepository());
+        repositoryRequest.setRemoteRepositories(getPluginArtifactRepositories());
 
-        PluginDescriptor pluginDescriptor =
-            pluginManager.loadPlugin( plugin, session.getCurrentProject().getRemotePluginRepositories(),
-                                      session.getRepositorySession() );
-        pluginManager.getPluginRealm( session, pluginDescriptor );
+        PluginDescriptor pluginDescriptor = pluginManager.loadPlugin(
+                plugin, session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+        pluginManager.getPluginRealm(session, pluginDescriptor);
         List<Artifact> artifacts = pluginDescriptor.getArtifacts();
 
-        for ( Artifact a : artifacts )
-        {
-            if ( a.getGroupId().equals( "org.apache.maven.its.mng3586" ) && a.getArtifactId().equals( "tools" ) )
-            {
+        for (Artifact a : artifacts) {
+            if (a.getGroupId().equals("org.apache.maven.its.mng3586")
+                    && a.getArtifactId().equals("tools")) {
                 // The system scoped dependencies will be present in the classloader for the plugin
                 return;
             }
         }
 
-        fail( "Can't find the system scoped dependency in the plugin artifacts." );
+        fail("Can't find the system scoped dependency in the plugin artifacts.");
     }
 
     // -----------------------------------------------------------------------------------------------
     // Testing help
     // -----------------------------------------------------------------------------------------------
 
-    protected void assertPluginDescriptor( MojoDescriptor mojoDescriptor, String groupId, String artifactId, String version )
-    {
-        assertNotNull( mojoDescriptor );
+    protected void assertPluginDescriptor(
+            MojoDescriptor mojoDescriptor, String groupId, String artifactId, String version) {
+        assertNotNull(mojoDescriptor);
         PluginDescriptor pd = mojoDescriptor.getPluginDescriptor();
-        assertNotNull( pd );
-        assertEquals( groupId, pd.getGroupId() );
-        assertEquals( artifactId, pd.getArtifactId() );
-        assertEquals( version, pd.getVersion() );
+        assertNotNull(pd);
+        assertEquals(groupId, pd.getGroupId());
+        assertEquals(artifactId, pd.getArtifactId());
+        assertEquals(version, pd.getVersion());
     }
 
     @Test
-    public void testPluginRealmCache()
-        throws Exception
-    {
+    void testPluginRealmCache() throws Exception {
         RepositoryRequest repositoryRequest = new DefaultRepositoryRequest();
-        repositoryRequest.setLocalRepository( getLocalRepository() );
-        repositoryRequest.setRemoteRepositories( getPluginArtifactRepositories() );
+        repositoryRequest.setLocalRepository(getLocalRepository());
+        repositoryRequest.setRemoteRepositories(getPluginArtifactRepositories());
 
         // prime realm cache
-        MavenSession session = createMavenSession( getProject( "project-contributing-system-scope-plugin-dep" ) );
+        MavenSession session = createMavenSession(getProject("project-contributing-system-scope-plugin-dep"));
         MavenProject project = session.getCurrentProject();
-        Plugin plugin = project.getPlugin( "org.apache.maven.its.plugins:maven-it-plugin" );
+        Plugin plugin = project.getPlugin("org.apache.maven.its.plugins:maven-it-plugin");
 
-        PluginDescriptor pluginDescriptor =
-            pluginManager.loadPlugin( plugin, session.getCurrentProject().getRemotePluginRepositories(),
-                                      session.getRepositorySession() );
-        pluginManager.getPluginRealm( session, pluginDescriptor );
+        PluginDescriptor pluginDescriptor = pluginManager.loadPlugin(
+                plugin, session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+        pluginManager.getPluginRealm(session, pluginDescriptor);
 
-        assertEquals( 1, pluginDescriptor.getDependencies().size() );
+        assertEquals(1, pluginDescriptor.getDependencies().size());
 
-        for ( ComponentDescriptor<?> descriptor : pluginDescriptor.getComponents() )
-        {
-            assertNotNull( descriptor.getRealm() );
-            assertNotNull( descriptor.getImplementationClass() );
+        for (ComponentDescriptor<?> descriptor : pluginDescriptor.getComponents()) {
+            assertNotNull(descriptor.getRealm());
+            assertNotNull(descriptor.getImplementationClass());
         }
 
         // reload plugin realm from cache
-        session = createMavenSession( getProject( "project-contributing-system-scope-plugin-dep" ) );
+        session = createMavenSession(getProject("project-contributing-system-scope-plugin-dep"));
         project = session.getCurrentProject();
-        plugin = project.getPlugin( "org.apache.maven.its.plugins:maven-it-plugin" );
+        plugin = project.getPlugin("org.apache.maven.its.plugins:maven-it-plugin");
 
-        pluginDescriptor =
-            pluginManager.loadPlugin( plugin, session.getCurrentProject().getRemotePluginRepositories(),
-                                      session.getRepositorySession() );
-        pluginManager.getPluginRealm( session, pluginDescriptor );
+        pluginDescriptor = pluginManager.loadPlugin(
+                plugin, session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+        pluginManager.getPluginRealm(session, pluginDescriptor);
 
-        assertEquals( 1, pluginDescriptor.getDependencies().size() );
+        assertEquals(1, pluginDescriptor.getDependencies().size());
 
-        for ( ComponentDescriptor<?> descriptor : pluginDescriptor.getComponents() )
-        {
-            assertNotNull( descriptor.getRealm() );
-            assertNotNull( descriptor.getImplementationClass() );
+        for (ComponentDescriptor<?> descriptor : pluginDescriptor.getComponents()) {
+            assertNotNull(descriptor.getRealm());
+            assertNotNull(descriptor.getImplementationClass());
         }
     }
 
     @Test
-    public void testBuildExtensionsPluginLoading()
-        throws Exception
-    {
+    void testBuildExtensionsPluginLoading() throws Exception {
         RepositoryRequest repositoryRequest = new DefaultRepositoryRequest();
-        repositoryRequest.setLocalRepository( getLocalRepository() );
-        repositoryRequest.setRemoteRepositories( getPluginArtifactRepositories() );
+        repositoryRequest.setLocalRepository(getLocalRepository());
+        repositoryRequest.setRemoteRepositories(getPluginArtifactRepositories());
 
         // prime realm cache
-        MavenSession session = createMavenSession( getProject( "project-with-build-extensions-plugin" ) );
+        MavenSession session = createMavenSession(getProject("project-with-build-extensions-plugin"));
         MavenProject project = session.getCurrentProject();
-        Plugin plugin = project.getPlugin( "org.apache.maven.its.plugins:maven-it-plugin" );
+        Plugin plugin = project.getPlugin("org.apache.maven.its.plugins:maven-it-plugin");
 
-        PluginDescriptor pluginDescriptor =
-            pluginManager.loadPlugin( plugin, session.getCurrentProject().getRemotePluginRepositories(),
-                                      session.getRepositorySession() );
-        ClassRealm pluginRealm = pluginManager.getPluginRealm( session, pluginDescriptor );
+        PluginDescriptor pluginDescriptor = pluginManager.loadPlugin(
+                plugin, session.getCurrentProject().getRemotePluginRepositories(), session.getRepositorySession());
+        ClassRealm pluginRealm = pluginManager.getPluginRealm(session, pluginDescriptor);
 
         assertEquals(pluginRealm, pluginDescriptor.getComponents().get(0).getRealm());
     }
diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExceptionTest.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExceptionTest.java
index d270293..50c3051 100644
--- a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExceptionTest.java
+++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExceptionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.Collections;
 
@@ -31,139 +30,140 @@
 /**
  * MNG-3131
  *
- * @author Robert Scholte
  *
  */
-public class PluginParameterExceptionTest
-{
+class PluginParameterExceptionTest {
 
     private final String LS = System.lineSeparator();
 
     @Test
-    public void testMissingRequiredStringArrayTypeParameter()
-    {
+    void testMissingRequiredStringArrayTypeParameter() {
         MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setGoal( "goal" );
+        mojoDescriptor.setGoal("goal");
         PluginDescriptor pluginDescriptor = new PluginDescriptor();
-        pluginDescriptor.setGoalPrefix( "goalPrefix" );
-        pluginDescriptor.setArtifactId( "artifactId" );
-        mojoDescriptor.setPluginDescriptor( pluginDescriptor );
+        pluginDescriptor.setGoalPrefix("goalPrefix");
+        pluginDescriptor.setArtifactId("artifactId");
+        mojoDescriptor.setPluginDescriptor(pluginDescriptor);
 
         Parameter parameter = new Parameter();
-        parameter.setType( "java.lang.String[]" );
-        parameter.setName( "toAddresses" );
+        parameter.setType("java.lang.String[]");
+        parameter.setName("toAddresses");
 
-        parameter.setRequired( true );
+        parameter.setRequired(true);
 
         PluginParameterException exception =
-            new PluginParameterException( mojoDescriptor, Collections.singletonList( parameter ) );
+                new PluginParameterException(mojoDescriptor, Collections.singletonList(parameter));
 
-        assertEquals( "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" +
-                LS + LS +
-                "[0] Inside the definition for plugin 'artifactId', specify the following:" +
-                LS + LS +
-                "<configuration>" + LS +
-                "  ..." + LS +
-                "  <toAddresses>" + LS +
-                "    <item>VALUE</item>" + LS +
-                "  </toAddresses>" + LS +
-                "</configuration>." + LS, exception.buildDiagnosticMessage() );
+        assertEquals(
+                "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" + LS
+                        + LS + "[0] Inside the definition for plugin 'artifactId', specify the following:"
+                        + LS
+                        + LS + "<configuration>"
+                        + LS + "  ..."
+                        + LS + "  <toAddresses>"
+                        + LS + "    <item>VALUE</item>"
+                        + LS + "  </toAddresses>"
+                        + LS + "</configuration>."
+                        + LS,
+                exception.buildDiagnosticMessage());
     }
 
     @Test
-    public void testMissingRequiredCollectionTypeParameter()
-    {
+    void testMissingRequiredCollectionTypeParameter() {
         MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setGoal( "goal" );
+        mojoDescriptor.setGoal("goal");
         PluginDescriptor pluginDescriptor = new PluginDescriptor();
-        pluginDescriptor.setGoalPrefix( "goalPrefix" );
-        pluginDescriptor.setArtifactId( "artifactId" );
-        mojoDescriptor.setPluginDescriptor( pluginDescriptor );
+        pluginDescriptor.setGoalPrefix("goalPrefix");
+        pluginDescriptor.setArtifactId("artifactId");
+        mojoDescriptor.setPluginDescriptor(pluginDescriptor);
 
         Parameter parameter = new Parameter();
-        parameter.setType( "java.util.List" );
-        parameter.setName( "toAddresses" );
+        parameter.setType("java.util.List");
+        parameter.setName("toAddresses");
 
-        parameter.setRequired( true );
+        parameter.setRequired(true);
 
         PluginParameterException exception =
-            new PluginParameterException( mojoDescriptor, Collections.singletonList( parameter ) );
+                new PluginParameterException(mojoDescriptor, Collections.singletonList(parameter));
 
-        assertEquals( "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" +
-                LS + LS +
-                "[0] Inside the definition for plugin 'artifactId', specify the following:" +
-                LS + LS +
-                "<configuration>" + LS +
-                "  ..." + LS +
-                "  <toAddresses>" + LS +
-                "    <item>VALUE</item>" + LS +
-                "  </toAddresses>" + LS +
-                "</configuration>." + LS, exception.buildDiagnosticMessage() );
+        assertEquals(
+                "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" + LS
+                        + LS + "[0] Inside the definition for plugin 'artifactId', specify the following:"
+                        + LS
+                        + LS + "<configuration>"
+                        + LS + "  ..."
+                        + LS + "  <toAddresses>"
+                        + LS + "    <item>VALUE</item>"
+                        + LS + "  </toAddresses>"
+                        + LS + "</configuration>."
+                        + LS,
+                exception.buildDiagnosticMessage());
     }
 
     @Test
-    public void testMissingRequiredMapTypeParameter()
-    {
+    void testMissingRequiredMapTypeParameter() {
         MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setGoal( "goal" );
+        mojoDescriptor.setGoal("goal");
         PluginDescriptor pluginDescriptor = new PluginDescriptor();
-        pluginDescriptor.setGoalPrefix( "goalPrefix" );
-        pluginDescriptor.setArtifactId( "artifactId" );
-        mojoDescriptor.setPluginDescriptor( pluginDescriptor );
+        pluginDescriptor.setGoalPrefix("goalPrefix");
+        pluginDescriptor.setArtifactId("artifactId");
+        mojoDescriptor.setPluginDescriptor(pluginDescriptor);
 
         Parameter parameter = new Parameter();
-        parameter.setType( "java.util.Map" );
-        parameter.setName( "toAddresses" );
+        parameter.setType("java.util.Map");
+        parameter.setName("toAddresses");
 
-        parameter.setRequired( true );
+        parameter.setRequired(true);
 
         PluginParameterException exception =
-            new PluginParameterException( mojoDescriptor, Collections.singletonList( parameter ) );
+                new PluginParameterException(mojoDescriptor, Collections.singletonList(parameter));
 
-        assertEquals( "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" +
-                LS + LS +
-                "[0] Inside the definition for plugin 'artifactId', specify the following:" +
-                LS + LS +
-                "<configuration>" + LS +
-                "  ..." + LS +
-                "  <toAddresses>" + LS +
-                "    <KEY>VALUE</KEY>" + LS +
-                "  </toAddresses>" + LS +
-                "</configuration>." + LS, exception.buildDiagnosticMessage() );
+        assertEquals(
+                "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" + LS
+                        + LS + "[0] Inside the definition for plugin 'artifactId', specify the following:"
+                        + LS
+                        + LS + "<configuration>"
+                        + LS + "  ..."
+                        + LS + "  <toAddresses>"
+                        + LS + "    <KEY>VALUE</KEY>"
+                        + LS + "  </toAddresses>"
+                        + LS + "</configuration>."
+                        + LS,
+                exception.buildDiagnosticMessage());
     }
 
     @Test
-    public void testMissingRequiredPropertiesTypeParameter()
-    {
+    void testMissingRequiredPropertiesTypeParameter() {
         MojoDescriptor mojoDescriptor = new MojoDescriptor();
-        mojoDescriptor.setGoal( "goal" );
+        mojoDescriptor.setGoal("goal");
         PluginDescriptor pluginDescriptor = new PluginDescriptor();
-        pluginDescriptor.setGoalPrefix( "goalPrefix" );
-        pluginDescriptor.setArtifactId( "artifactId" );
-        mojoDescriptor.setPluginDescriptor( pluginDescriptor );
+        pluginDescriptor.setGoalPrefix("goalPrefix");
+        pluginDescriptor.setArtifactId("artifactId");
+        mojoDescriptor.setPluginDescriptor(pluginDescriptor);
 
         Parameter parameter = new Parameter();
-        parameter.setType( "java.util.Properties" );
-        parameter.setName( "toAddresses" );
+        parameter.setType("java.util.Properties");
+        parameter.setName("toAddresses");
 
-        parameter.setRequired( true );
+        parameter.setRequired(true);
 
         PluginParameterException exception =
-            new PluginParameterException( mojoDescriptor, Collections.singletonList( parameter ) );
+                new PluginParameterException(mojoDescriptor, Collections.singletonList(parameter));
 
-        assertEquals( "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" +
-                LS + LS +
-                "[0] Inside the definition for plugin 'artifactId', specify the following:" +
-                LS + LS +
-                "<configuration>" + LS +
-                "  ..." + LS +
-                "  <toAddresses>" + LS +
-                "    <property>" + LS +
-                "      <name>KEY</name>" + LS +
-                "      <value>VALUE</value>" + LS +
-                "    </property>" + LS +
-                "  </toAddresses>" + LS +
-                "</configuration>." + LS, exception.buildDiagnosticMessage() );
+        assertEquals(
+                "One or more required plugin parameters are invalid/missing for 'goalPrefix:goal'" + LS
+                        + LS + "[0] Inside the definition for plugin 'artifactId', specify the following:"
+                        + LS
+                        + LS + "<configuration>"
+                        + LS + "  ..."
+                        + LS + "  <toAddresses>"
+                        + LS + "    <property>"
+                        + LS + "      <name>KEY</name>"
+                        + LS + "      <value>VALUE</value>"
+                        + LS + "    </property>"
+                        + LS + "  </toAddresses>"
+                        + LS + "</configuration>."
+                        + LS,
+                exception.buildDiagnosticMessage());
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
index 16deedd..ce23880 100644
--- a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,18 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
+
+import javax.inject.Inject;
 
 import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 
 import org.apache.maven.AbstractCoreMavenComponentTestCase;
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
 import org.apache.maven.execution.DefaultMavenExecutionRequest;
 import org.apache.maven.execution.DefaultMavenExecutionResult;
 import org.apache.maven.execution.MavenExecutionRequest;
@@ -37,422 +44,474 @@
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Model;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.interpolation.reflection.IntrospectionException;
+import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.CycleDetectedException;
 import org.apache.maven.project.DuplicateProjectException;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.repository.RepositorySystem;
 import org.codehaus.plexus.MutablePlexusContainer;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
-import org.codehaus.plexus.util.dag.CycleDetectedException;
+import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
+import org.codehaus.plexus.util.Os;
 import org.junit.jupiter.api.Test;
 
 import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
 /**
- * @author Jason van Zyl
  */
-public class PluginParameterExpressionEvaluatorTest
-    extends AbstractCoreMavenComponentTestCase
-{
+class PluginParameterExpressionEvaluatorTest extends AbstractCoreMavenComponentTestCase {
     private static final String FS = File.separator;
 
     @Inject
-    private RepositorySystem factory;
+    private MavenRepositorySystem factory;
+
+    private Path rootDirectory;
 
     @Test
-    public void testPluginDescriptorExpressionReference()
-        throws Exception
-    {
+    void testPluginDescriptorExpressionReference() throws Exception {
         MojoExecution exec = newMojoExecution();
 
         MavenSession session = newMavenSession();
 
-        Object result = new PluginParameterExpressionEvaluator( session, exec ).evaluate( "${plugin}" );
+        Object result = new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin}");
 
-        System.out.println( "Result: " + result );
+        System.out.println("Result: " + result);
 
-        assertSame( exec.getMojoDescriptor().getPluginDescriptor(),
-                    result,
-                    "${plugin} expression does not return plugin descriptor." );
+        assertSame(
+                exec.getMojoDescriptor().getPluginDescriptor(),
+                result,
+                "${plugin} expression does not return plugin descriptor.");
     }
 
     @Test
-    public void testPluginArtifactsExpressionReference()
-        throws Exception
-    {
+    void testPluginArtifactsExpressionReference() throws Exception {
         MojoExecution exec = newMojoExecution();
 
-        Artifact depArtifact = createArtifact( "group", "artifact", "1" );
+        Artifact depArtifact = createArtifact("group", "artifact", "1");
 
         List<Artifact> deps = new ArrayList<>();
-        deps.add( depArtifact );
+        deps.add(depArtifact);
 
-        exec.getMojoDescriptor().getPluginDescriptor().setArtifacts( deps );
+        exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
 
         MavenSession session = newMavenSession();
 
-        @SuppressWarnings( "unchecked" )
+        @SuppressWarnings("unchecked")
         List<Artifact> depResults =
-            (List<Artifact>) new PluginParameterExpressionEvaluator( session, exec ).evaluate( "${plugin.artifacts}" );
+                (List<Artifact>) new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin.artifacts}");
 
-        System.out.println( "Result: " + depResults );
+        System.out.println("Result: " + depResults);
 
-        assertNotNull( depResults );
-        assertEquals( 1, depResults.size() );
-        assertSame( depArtifact, depResults.get( 0 ), "dependency artifact is wrong." );
+        assertNotNull(depResults);
+        assertEquals(1, depResults.size());
+        assertSame(depArtifact, depResults.get(0), "dependency artifact is wrong.");
     }
 
     @Test
-    public void testPluginArtifactMapExpressionReference()
-        throws Exception
-    {
+    void testPluginArtifactMapExpressionReference() throws Exception {
         MojoExecution exec = newMojoExecution();
 
-        Artifact depArtifact = createArtifact( "group", "artifact", "1" );
+        Artifact depArtifact = createArtifact("group", "artifact", "1");
 
         List<Artifact> deps = new ArrayList<>();
-        deps.add( depArtifact );
+        deps.add(depArtifact);
 
-        exec.getMojoDescriptor().getPluginDescriptor().setArtifacts( deps );
+        exec.getMojoDescriptor().getPluginDescriptor().setArtifacts(deps);
 
         MavenSession session = newMavenSession();
 
-        @SuppressWarnings( "unchecked" )
-        Map<String, Artifact> depResults =
-            (Map<String, Artifact>) new PluginParameterExpressionEvaluator( session, exec ).evaluate( "${plugin.artifactMap}" );
+        @SuppressWarnings("unchecked")
+        Map<String, Artifact> depResults = (Map<String, Artifact>)
+                new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin.artifactMap}");
 
-        System.out.println( "Result: " + depResults );
+        System.out.println("Result: " + depResults);
 
-        assertNotNull( depResults );
-        assertEquals( 1, depResults.size() );
-        assertSame( depArtifact,
-                    depResults.get( ArtifactUtils.versionlessKey( depArtifact ) ),
-                    "dependency artifact is wrong." );
+        assertNotNull(depResults);
+        assertEquals(1, depResults.size());
+        assertSame(
+                depArtifact,
+                depResults.get(ArtifactUtils.versionlessKey(depArtifact)),
+                "dependency artifact is wrong.");
     }
 
     @Test
-    public void testPluginArtifactIdExpressionReference()
-        throws Exception
-    {
+    void testPluginArtifactIdExpressionReference() throws Exception {
         MojoExecution exec = newMojoExecution();
 
         MavenSession session = newMavenSession();
 
-        Object result = new PluginParameterExpressionEvaluator( session, exec ).evaluate( "${plugin.artifactId}" );
+        Object result = new PluginParameterExpressionEvaluator(session, exec).evaluate("${plugin.artifactId}");
 
-        System.out.println( "Result: " + result );
+        System.out.println("Result: " + result);
 
-        assertSame( exec.getMojoDescriptor().getPluginDescriptor().getArtifactId(),
-                    result,
-                    "${plugin.artifactId} expression does not return plugin descriptor's artifactId." );
+        assertSame(
+                exec.getMojoDescriptor().getPluginDescriptor().getArtifactId(),
+                result,
+                "${plugin.artifactId} expression does not return plugin descriptor's artifactId.");
     }
 
     @Test
-    public void testValueExtractionWithAPomValueContainingAPath()
-        throws Exception
-    {
-        String expected = getTestFile( "target/test-classes/target/classes" ).getCanonicalPath();
+    void testValueExtractionWithAPomValueContainingAPath() throws Exception {
+        String expected = getTestFile("target/test-classes/target/classes").getCanonicalPath();
 
         Build build = new Build();
-        build.setDirectory( expected.substring( 0, expected.length() - "/classes".length() ) );
+        build.setDirectory(expected.substring(0, expected.length() - "/classes".length()));
 
         Model model = new Model();
-        model.setBuild( build );
+        model.setBuild(build);
 
-        MavenProject project = new MavenProject( model );
-        project.setFile( new File( "pom.xml" ).getCanonicalFile() );
+        MavenProject project = new MavenProject(model);
+        project.setFile(new File("pom.xml").getCanonicalFile());
 
-        ExpressionEvaluator expressionEvaluator = createExpressionEvaluator( project, null, new Properties() );
+        ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(project, null, new Properties());
 
-        Object value = expressionEvaluator.evaluate( "${project.build.directory}/classes" );
-        String actual = new File( value.toString() ).getCanonicalPath();
+        Object value = expressionEvaluator.evaluate("${project.build.directory}/classes");
+        String actual = new File(value.toString()).getCanonicalPath();
 
-        assertEquals( expected, actual );
+        assertEquals(expected, actual);
     }
 
     @Test
-    public void testEscapedVariablePassthrough()
-        throws Exception
-    {
+    void testEscapedVariablePassthrough() throws Exception {
         String var = "${var}";
 
         Model model = new Model();
-        model.setVersion( "1" );
+        model.setVersion("1");
 
-        MavenProject project = new MavenProject( model );
+        MavenProject project = new MavenProject(model);
 
-        ExpressionEvaluator ee = createExpressionEvaluator( project, null, new Properties() );
+        ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
 
-        Object value = ee.evaluate( "$" + var );
+        Object value = ee.evaluate("$" + var);
 
-        assertEquals( var, value );
+        assertEquals(var, value);
     }
 
     @Test
-    public void testEscapedVariablePassthroughInLargerExpression()
-        throws Exception
-    {
+    void testEscapedVariablePassthroughInLargerExpression() throws Exception {
         String var = "${var}";
         String key = var + " with version: ${project.version}";
 
         Model model = new Model();
-        model.setVersion( "1" );
+        model.setVersion("1");
 
-        MavenProject project = new MavenProject( model );
+        MavenProject project = new MavenProject(model);
 
-        ExpressionEvaluator ee = createExpressionEvaluator( project, null, new Properties() );
+        ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
 
-        Object value = ee.evaluate( "$" + key );
+        Object value = ee.evaluate("$" + key);
 
-        assertEquals( "${var} with version: 1", value );
+        assertEquals("${var} with version: 1", value);
     }
 
     @Test
-    public void testMultipleSubExpressionsInLargerExpression()
-        throws Exception
-    {
+    void testMultipleSubExpressionsInLargerExpression() throws Exception {
         String key = "${project.artifactId} with version: ${project.version}";
 
         Model model = new Model();
-        model.setArtifactId( "test" );
-        model.setVersion( "1" );
+        model.setArtifactId("test");
+        model.setVersion("1");
 
-        MavenProject project = new MavenProject( model );
+        MavenProject project = new MavenProject(model);
 
-        ExpressionEvaluator ee = createExpressionEvaluator( project, null, new Properties() );
+        ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
 
-        Object value = ee.evaluate( key );
+        Object value = ee.evaluate(key);
 
-        assertEquals( "test with version: 1", value );
+        assertEquals("test with version: 1", value);
     }
 
     @Test
-    public void testMissingPOMPropertyRefInLargerExpression()
-        throws Exception
-    {
+    void testMissingPOMPropertyRefInLargerExpression() throws Exception {
         String expr = "/path/to/someproject-${baseVersion}";
 
-        MavenProject project = new MavenProject( new Model() );
+        MavenProject project = new MavenProject(new Model());
 
-        ExpressionEvaluator ee = createExpressionEvaluator( project, null, new Properties() );
+        ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
 
-        Object value = ee.evaluate( expr );
+        Object value = ee.evaluate(expr);
 
-        assertEquals( expr, value );
+        assertEquals(expr, value);
     }
 
     @Test
-    public void testPOMPropertyExtractionWithMissingProject_WithDotNotation()
-        throws Exception
-    {
+    void testPOMPropertyExtractionWithMissingProject_WithDotNotation() throws Exception {
         String key = "m2.name";
         String checkValue = "value";
 
         Properties properties = new Properties();
-        properties.setProperty( key, checkValue );
+        properties.setProperty(key, checkValue);
 
         Model model = new Model();
-        model.setProperties( properties );
+        model.setProperties(properties);
 
-        MavenProject project = new MavenProject( model );
+        MavenProject project = new MavenProject(model);
 
-        ExpressionEvaluator ee = createExpressionEvaluator( project, null, new Properties() );
+        ExpressionEvaluator ee = createExpressionEvaluator(project, null, new Properties());
 
-        Object value = ee.evaluate( "${" + key + "}" );
+        Object value = ee.evaluate("${" + key + "}");
 
-        assertEquals( checkValue, value );
+        assertEquals(checkValue, value);
     }
 
     @Test
-    public void testBasedirExtractionWithMissingProject()
-        throws Exception
-    {
-        ExpressionEvaluator ee = createExpressionEvaluator( null, null, new Properties() );
+    void testBasedirExtractionWithMissingProject() throws Exception {
+        ExpressionEvaluator ee = createExpressionEvaluator(null, null, new Properties());
 
-        Object value = ee.evaluate( "${basedir}" );
+        Object value = ee.evaluate("${basedir}");
 
-        assertEquals( System.getProperty( "user.dir" ), value );
+        assertEquals(System.getProperty("user.dir"), value);
     }
 
     @Test
-    public void testValueExtractionFromSystemPropertiesWithMissingProject()
-        throws Exception
-    {
+    void testValueExtractionFromSystemPropertiesWithMissingProject() throws Exception {
         String sysprop = "PPEET_sysprop1";
 
         Properties executionProperties = new Properties();
 
-        if ( executionProperties.getProperty( sysprop ) == null )
-        {
-            executionProperties.setProperty( sysprop, "value" );
+        if (executionProperties.getProperty(sysprop) == null) {
+            executionProperties.setProperty(sysprop, "value");
         }
 
-        ExpressionEvaluator ee = createExpressionEvaluator( null, null, executionProperties );
+        ExpressionEvaluator ee = createExpressionEvaluator(null, null, executionProperties);
 
-        Object value = ee.evaluate( "${" + sysprop + "}" );
+        Object value = ee.evaluate("${" + sysprop + "}");
 
-        assertEquals( "value", value );
+        assertEquals("value", value);
     }
 
     @Test
-    public void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation()
-        throws Exception
-    {
+    void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation() throws Exception {
         String sysprop = "PPEET.sysprop2";
 
         Properties executionProperties = new Properties();
 
-        if ( executionProperties.getProperty( sysprop ) == null )
-        {
-            executionProperties.setProperty( sysprop, "value" );
+        if (executionProperties.getProperty(sysprop) == null) {
+            executionProperties.setProperty(sysprop, "value");
         }
 
-        ExpressionEvaluator ee = createExpressionEvaluator( null, null, executionProperties );
+        ExpressionEvaluator ee = createExpressionEvaluator(null, null, executionProperties);
 
-        Object value = ee.evaluate( "${" + sysprop + "}" );
+        Object value = ee.evaluate("${" + sysprop + "}");
 
-        assertEquals( "value", value );
+        assertEquals("value", value);
     }
 
-    @SuppressWarnings( "deprecation" )
-    private static MavenSession createSession( PlexusContainer container, ArtifactRepository repo, Properties properties )
-        throws CycleDetectedException, DuplicateProjectException
-    {
+    @SuppressWarnings("deprecation")
+    private static MavenSession createSession(PlexusContainer container, ArtifactRepository repo, Properties properties)
+            throws CycleDetectedException, DuplicateProjectException {
         MavenExecutionRequest request = new DefaultMavenExecutionRequest()
-            .setSystemProperties( properties )
-            .setGoals( Collections.<String>emptyList() )
-            .setBaseDirectory( new File( "" ) )
-            .setLocalRepository( repo );
+                .setSystemProperties(properties)
+                .setGoals(Collections.<String>emptyList())
+                .setBaseDirectory(new File(""))
+                .setLocalRepository(repo);
 
-        return new MavenSession( container, request, new DefaultMavenExecutionResult(), Collections.<MavenProject>emptyList()  );
+        return new MavenSession(
+                container, request, new DefaultMavenExecutionResult(), Collections.<MavenProject>emptyList());
     }
 
     @Test
-    public void testLocalRepositoryExtraction()
-        throws Exception
-    {
+    void testLocalRepositoryExtraction() throws Exception {
         ExpressionEvaluator expressionEvaluator =
-            createExpressionEvaluator( createDefaultProject(), null, new Properties() );
-        Object value = expressionEvaluator.evaluate( "${localRepository}" );
+                createExpressionEvaluator(createDefaultProject(), null, new Properties());
+        Object value = expressionEvaluator.evaluate("${localRepository}");
 
-        assertEquals( "local", ( (ArtifactRepository) value ).getId() );
+        assertEquals("local", ((ArtifactRepository) value).getId());
     }
 
     @Test
-    public void testTwoExpressions()
-        throws Exception
-    {
+    void testTwoExpressions() throws Exception {
         Build build = new Build();
-        build.setDirectory( "expected-directory" );
-        build.setFinalName( "expected-finalName" );
+        build.setDirectory("expected-directory");
+        build.setFinalName("expected-finalName");
 
         Model model = new Model();
-        model.setBuild( build );
+        model.setBuild(build);
 
         ExpressionEvaluator expressionEvaluator =
-            createExpressionEvaluator( new MavenProject( model ), null, new Properties() );
+                createExpressionEvaluator(new MavenProject(model), null, new Properties());
 
-        Object value = expressionEvaluator.evaluate( "${project.build.directory}" + FS + "${project.build.finalName}" );
+        Object value = expressionEvaluator.evaluate("${project.build.directory}" + FS + "${project.build.finalName}");
 
-        assertEquals( "expected-directory" + File.separatorChar + "expected-finalName", value );
+        assertEquals("expected-directory" + File.separatorChar + "expected-finalName", value);
     }
 
     @Test
-    public void testShouldExtractPluginArtifacts()
-        throws Exception
-    {
+    void testShouldExtractPluginArtifacts() throws Exception {
         PluginDescriptor pd = new PluginDescriptor();
 
-        Artifact artifact = createArtifact( "testGroup", "testArtifact", "1.0" );
+        Artifact artifact = createArtifact("testGroup", "testArtifact", "1.0");
 
-        pd.setArtifacts( Collections.singletonList( artifact ) );
+        pd.setArtifacts(Collections.singletonList(artifact));
 
-        ExpressionEvaluator ee = createExpressionEvaluator( createDefaultProject(), pd, new Properties() );
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), pd, new Properties());
 
-        Object value = ee.evaluate( "${plugin.artifacts}" );
+        Object value = ee.evaluate("${plugin.artifacts}");
 
-        assertTrue( value instanceof List );
+        assertTrue(value instanceof List);
 
-        @SuppressWarnings( "unchecked" )
+        @SuppressWarnings("unchecked")
         List<Artifact> artifacts = (List<Artifact>) value;
 
-        assertEquals( 1, artifacts.size() );
+        assertEquals(1, artifacts.size());
 
-        Artifact result = artifacts.get( 0 );
+        Artifact result = artifacts.get(0);
 
-        assertEquals( "testGroup", result.getGroupId() );
+        assertEquals("testGroup", result.getGroupId());
     }
 
-    private MavenProject createDefaultProject()
-    {
-        return new MavenProject( new Model() );
+    @Test
+    void testRootDirectoryNotPrefixed() throws Exception {
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
+        assertNull(ee.evaluate("${rootDirectory}"));
     }
 
-    private ExpressionEvaluator createExpressionEvaluator( MavenProject project, PluginDescriptor pluginDescriptor, Properties executionProperties )
-        throws Exception
-    {
-        ArtifactRepository repo = factory.createDefaultLocalRepository();
+    @Test
+    void testRootDirectoryWithNull() throws Exception {
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
+        Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
+        e = assertInstanceOf(IntrospectionException.class, e.getCause());
+        e = assertInstanceOf(IllegalStateException.class, e.getCause());
+        assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
+    }
+
+    @Test
+    void testRootDirectory() throws Exception {
+        this.rootDirectory = Paths.get("myRootDirectory");
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), null, new Properties());
+        assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
+    }
+
+    @Test
+    public void testUri() throws Exception {
+        Path path = Paths.get("").toAbsolutePath();
+
+        MavenSession mavenSession = createMavenSession(null);
+        mavenSession.getRequest().setTopDirectory(path);
+        mavenSession.getRequest().setRootDirectory(path);
+
+        Object result = new PluginParameterExpressionEvaluator(mavenSession, new MojoExecution(null))
+                .evaluate("${session.rootDirectory.uri}");
+        assertEquals(path.toUri(), result);
+    }
+
+    @Test
+    public void testPath() throws Exception {
+        Path path = Paths.get("").toAbsolutePath();
+
+        MavenSession mavenSession = createMavenSession(null);
+        mavenSession.getRequest().setTopDirectory(path);
+        mavenSession.getRequest().setRootDirectory(path);
+
+        Object result = new PluginParameterExpressionEvaluator(mavenSession, new MojoExecution(null))
+                .evaluate("${session.rootDirectory/target}");
+        assertEquals(path.resolve("target"), result);
+    }
+
+    @Test
+    public void testPluginInjection() throws Exception {
+        Path path = Paths.get("répâžœα").toAbsolutePath();
+
+        MavenSession mavenSession = createMavenSession(null);
+        mavenSession.getRequest().setTopDirectory(path);
+        mavenSession.getRequest().setRootDirectory(path);
+        DefaultModelBuildingRequest mbr = new DefaultModelBuildingRequest();
+
+        PluginParameterExpressionEvaluator evaluator =
+                new PluginParameterExpressionEvaluator(mavenSession, new MojoExecution(null));
+
+        DefaultPlexusConfiguration configuration = new DefaultPlexusConfiguration("config");
+        configuration.addChild("uri", "${session.rootDirectory.uri}");
+        configuration.addChild("path", "${session.rootDirectory}");
+        configuration.addChild("uriString", "${session.rootDirectory.uri.string}");
+        configuration.addChild("uriAsciiString", "${session.rootDirectory.uri.ASCIIString}");
+        configuration.addChild("pathString", "${session.rootDirectory.string}");
+
+        Mojo mojo = new Mojo();
+        new EnhancedComponentConfigurator().configureComponent(mojo, configuration, evaluator, null);
+
+        assertEquals(
+                Objects.equals(path.toUri().toString(), path.toUri().toASCIIString()), !Os.isFamily(Os.FAMILY_WINDOWS));
+        assertEquals(mojo.uri, path.toUri());
+        assertEquals(mojo.path, path);
+        assertEquals(mojo.uriString, path.toUri().toString());
+        assertEquals(mojo.uriAsciiString, path.toUri().toASCIIString());
+        assertEquals(mojo.pathString, path.toString());
+    }
+
+    private MavenProject createDefaultProject() {
+        return new MavenProject(new Model());
+    }
+
+    private ExpressionEvaluator createExpressionEvaluator(
+            MavenProject project, PluginDescriptor pluginDescriptor, Properties executionProperties) throws Exception {
+        ArtifactRepository repo = getLocalRepository();
 
         MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
-        MavenSession session = createSession( container, repo, executionProperties );
-        session.setCurrentProject( project );
+        MavenSession session = createSession(container, repo, executionProperties);
+        session.setCurrentProject(project);
+        session.getRequest().setRootDirectory(rootDirectory);
 
         MojoDescriptor mojo = new MojoDescriptor();
-        mojo.setPluginDescriptor( pluginDescriptor );
-        mojo.setGoal( "goal" );
+        mojo.setPluginDescriptor(pluginDescriptor);
+        mojo.setGoal("goal");
 
-        MojoExecution mojoExecution = new MojoExecution( mojo );
+        MojoExecution mojoExecution = new MojoExecution(mojo);
 
-        return new PluginParameterExpressionEvaluator( session, mojoExecution );
+        return new PluginParameterExpressionEvaluator(session, mojoExecution);
     }
 
-    protected Artifact createArtifact( String groupId, String artifactId, String version )
-        throws Exception
-    {
+    protected Artifact createArtifact(String groupId, String artifactId, String version) throws Exception {
         Dependency dependency = new Dependency();
-        dependency.setGroupId( groupId );
-        dependency.setArtifactId( artifactId );
-        dependency.setVersion( version );
-        dependency.setType( "jar" );
-        dependency.setScope( "compile" );
+        dependency.setGroupId(groupId);
+        dependency.setArtifactId(artifactId);
+        dependency.setVersion(version);
+        dependency.setType("jar");
+        dependency.setScope("compile");
 
-        return factory.createDependencyArtifact( dependency );
+        return factory.createDependencyArtifact(dependency);
     }
 
-    private MojoExecution newMojoExecution()
-    {
+    private MojoExecution newMojoExecution() {
         PluginDescriptor pd = new PluginDescriptor();
-        pd.setArtifactId( "my-plugin" );
-        pd.setGroupId( "org.myco.plugins" );
-        pd.setVersion( "1" );
+        pd.setArtifactId("my-plugin");
+        pd.setGroupId("org.myco.plugins");
+        pd.setVersion("1");
 
         MojoDescriptor md = new MojoDescriptor();
-        md.setPluginDescriptor( pd );
+        md.setPluginDescriptor(pd);
 
-        pd.addComponentDescriptor( md );
+        pd.addComponentDescriptor(md);
 
-        return new MojoExecution( md );
+        return new MojoExecution(md);
     }
 
-    private MavenSession newMavenSession()
-        throws Exception
-    {
-        return createMavenSession( null );
+    private MavenSession newMavenSession() throws Exception {
+        return createMavenSession(null);
     }
 
     @Override
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         // TODO Auto-generated method stub
         return null;
     }
 
+    public static class Mojo {
+        URI uri;
+        Path path;
+        String uriString;
+        String uriAsciiString;
+        String pathString;
+    }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java
new file mode 100644
index 0000000..eb67659
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/plugin/PluginParameterExpressionEvaluatorV4Test.java
@@ -0,0 +1,516 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin;
+
+import javax.inject.Inject;
+
+import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+
+import org.apache.maven.AbstractCoreMavenComponentTestCase;
+import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.Artifact;
+import org.apache.maven.api.MojoExecution;
+import org.apache.maven.api.Session;
+import org.apache.maven.artifact.DefaultArtifact;
+import org.apache.maven.artifact.handler.DefaultArtifactHandler;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.configuration.internal.EnhancedComponentConfigurator;
+import org.apache.maven.execution.DefaultMavenExecutionRequest;
+import org.apache.maven.execution.DefaultMavenExecutionResult;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.MavenSession;
+import org.apache.maven.internal.impl.AbstractSession;
+import org.apache.maven.internal.impl.DefaultMojoExecution;
+import org.apache.maven.internal.impl.DefaultProject;
+import org.apache.maven.internal.impl.DefaultSession;
+import org.apache.maven.model.Build;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.DefaultModelBuildingRequest;
+import org.apache.maven.model.interpolation.reflection.IntrospectionException;
+import org.apache.maven.model.root.RootLocator;
+import org.apache.maven.plugin.descriptor.MojoDescriptor;
+import org.apache.maven.plugin.descriptor.PluginDescriptor;
+import org.apache.maven.project.CycleDetectedException;
+import org.apache.maven.project.DuplicateProjectException;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.MutablePlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
+import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
+import org.codehaus.plexus.util.Os;
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystem;
+import org.eclipse.aether.graph.DefaultDependencyNode;
+import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
+import org.eclipse.aether.repository.LocalRepository;
+import org.eclipse.aether.repository.NoLocalRepositoryManagerException;
+import org.junit.jupiter.api.Test;
+
+import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+
+/**
+ */
+public class PluginParameterExpressionEvaluatorV4Test extends AbstractCoreMavenComponentTestCase {
+    private static final String FS = File.separator;
+
+    @Inject
+    PlexusContainer container;
+
+    @Inject
+    private MavenRepositorySystem factory;
+
+    private Path rootDirectory;
+
+    @Test
+    public void testPluginDescriptorExpressionReference() throws Exception {
+        Session session = newSession();
+        MojoExecution exec = newMojoExecution(session);
+
+        Object result =
+                new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${mojo.plugin.descriptor}");
+
+        System.out.println("Result: " + result);
+
+        assertSame(
+                exec.getPlugin().getDescriptor(),
+                result,
+                "${mojo.plugin.descriptor} expression does not return plugin descriptor.");
+    }
+
+    @Test
+    public void testPluginArtifactsExpressionReference() throws Exception {
+        Session session = newSession();
+        MojoExecution exec = newMojoExecution(session);
+
+        @SuppressWarnings("unchecked")
+        Collection<Artifact> depResults = (Collection<Artifact>)
+                new PluginParameterExpressionEvaluatorV4(session, null, exec).evaluate("${mojo.plugin.dependencies}");
+
+        System.out.println("Result: " + depResults);
+
+        assertNotNull(depResults);
+        assertEquals(1, depResults.size());
+        assertEquals(
+                exec.getPlugin().getArtifact().key(),
+                depResults.iterator().next().key(),
+                "dependency artifact is wrong.");
+    }
+
+    @Test
+    public void testPluginArtifactMapExpressionReference() throws Exception {
+        Session session = newSession();
+
+        MojoExecution exec = newMojoExecution(session);
+
+        @SuppressWarnings("unchecked")
+        Map<String, org.apache.maven.api.Dependency> depResults = (Map<String, org.apache.maven.api.Dependency>)
+                new PluginParameterExpressionEvaluatorV4(session, null, exec)
+                        .evaluate("${mojo.plugin.dependenciesMap}");
+
+        System.out.println("Result: " + depResults);
+
+        assertNotNull(depResults);
+        assertEquals(1, depResults.size());
+        assertTrue(depResults.containsKey("org.myco.plugins:my-plugin"));
+        assertEquals(
+                exec.getPlugin().getArtifact().key(),
+                depResults.get("org.myco.plugins:my-plugin").key(),
+                "dependency artifact is wrong.");
+    }
+
+    @Test
+    public void testPluginArtifactIdExpressionReference() throws Exception {
+        Session session = newSession();
+
+        MojoExecution exec = newMojoExecution(session);
+
+        Object result = new PluginParameterExpressionEvaluatorV4(session, null, exec)
+                .evaluate("${mojo.plugin.artifact.artifactId}");
+
+        System.out.println("Result: " + result);
+
+        assertSame(
+                exec.getPlugin().getArtifact().getArtifactId(),
+                result,
+                "${plugin.artifactId} expression does not return plugin descriptor's artifactId.");
+    }
+
+    @Test
+    public void testValueExtractionWithAPomValueContainingAPath() throws Exception {
+        String expected = getTestFile("target/test-classes/target/classes").getCanonicalPath();
+
+        Build build = new Build();
+        build.setDirectory(expected.substring(0, expected.length() - "/classes".length()));
+
+        Model model = new Model();
+        model.setBuild(build);
+
+        MavenProject project = new MavenProject(model);
+        project.setFile(new File("pom.xml").getCanonicalFile());
+
+        ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(project, new Properties());
+
+        Object value = expressionEvaluator.evaluate("${project.build.directory}/classes");
+        String actual = new File(value.toString()).getCanonicalPath();
+
+        assertEquals(expected, actual);
+    }
+
+    @Test
+    public void testEscapedVariablePassthrough() throws Exception {
+        String var = "${var}";
+
+        Model model = new Model();
+        model.setVersion("1");
+
+        MavenProject project = new MavenProject(model);
+
+        ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
+
+        Object value = ee.evaluate("$" + var);
+
+        assertEquals(var, value);
+    }
+
+    @Test
+    public void testEscapedVariablePassthroughInLargerExpression() throws Exception {
+        String var = "${var}";
+        String key = var + " with version: ${project.version}";
+
+        Model model = new Model();
+        model.setVersion("1");
+
+        MavenProject project = new MavenProject(model);
+
+        ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
+
+        Object value = ee.evaluate("$" + key);
+
+        assertEquals("${var} with version: 1", value);
+    }
+
+    @Test
+    public void testMultipleSubExpressionsInLargerExpression() throws Exception {
+        String key = "${project.artifactId} with version: ${project.version}";
+
+        Model model = new Model();
+        model.setArtifactId("test");
+        model.setVersion("1");
+
+        MavenProject project = new MavenProject(model);
+
+        ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
+
+        Object value = ee.evaluate(key);
+
+        assertEquals("test with version: 1", value);
+    }
+
+    @Test
+    public void testMissingPOMPropertyRefInLargerExpression() throws Exception {
+        String expr = "/path/to/someproject-${baseVersion}";
+
+        MavenProject project = new MavenProject(new Model());
+
+        ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
+
+        Object value = ee.evaluate(expr);
+
+        assertEquals(expr, value);
+    }
+
+    @Test
+    public void testPOMPropertyExtractionWithMissingProject_WithDotNotation() throws Exception {
+        String key = "m2.name";
+        String checkValue = "value";
+
+        Properties properties = new Properties();
+        properties.setProperty(key, checkValue);
+
+        Model model = new Model();
+        model.setProperties(properties);
+
+        MavenProject project = new MavenProject(model);
+
+        ExpressionEvaluator ee = createExpressionEvaluator(project, new Properties());
+
+        Object value = ee.evaluate("${" + key + "}");
+
+        assertEquals(checkValue, value);
+    }
+
+    @Test
+    public void testValueExtractionFromSystemPropertiesWithMissingProject() throws Exception {
+        String sysprop = "PPEET_sysprop1";
+
+        Properties executionProperties = new Properties();
+
+        if (executionProperties.getProperty(sysprop) == null) {
+            executionProperties.setProperty(sysprop, "value");
+        }
+
+        ExpressionEvaluator ee = createExpressionEvaluator(null, executionProperties);
+
+        Object value = ee.evaluate("${" + sysprop + "}");
+
+        assertEquals("value", value);
+    }
+
+    @Test
+    public void testValueExtractionFromSystemPropertiesWithMissingProject_WithDotNotation() throws Exception {
+        String sysprop = "PPEET.sysprop2";
+
+        Properties executionProperties = new Properties();
+
+        if (executionProperties.getProperty(sysprop) == null) {
+            executionProperties.setProperty(sysprop, "value");
+        }
+
+        ExpressionEvaluator ee = createExpressionEvaluator(null, executionProperties);
+
+        Object value = ee.evaluate("${" + sysprop + "}");
+
+        assertEquals("value", value);
+    }
+
+    @SuppressWarnings("deprecation")
+    private static MavenSession createSession(PlexusContainer container, ArtifactRepository repo, Properties properties)
+            throws CycleDetectedException, DuplicateProjectException, NoLocalRepositoryManagerException {
+        MavenExecutionRequest request = new DefaultMavenExecutionRequest()
+                .setSystemProperties(properties)
+                .setGoals(Collections.<String>emptyList())
+                .setBaseDirectory(new File(""))
+                .setLocalRepository(repo);
+
+        DefaultRepositorySystemSession repositorySession = new DefaultRepositorySystemSession();
+        repositorySession.setLocalRepositoryManager(new SimpleLocalRepositoryManagerFactory()
+                .newInstance(repositorySession, new LocalRepository(repo.getUrl())));
+        MavenSession session =
+                new MavenSession(container, repositorySession, request, new DefaultMavenExecutionResult());
+        session.setProjects(Collections.<MavenProject>emptyList());
+        return session;
+    }
+
+    @Test
+    public void testTwoExpressions() throws Exception {
+        Build build = new Build();
+        build.setDirectory("expected-directory");
+        build.setFinalName("expected-finalName");
+
+        Model model = new Model();
+        model.setBuild(build);
+
+        ExpressionEvaluator expressionEvaluator = createExpressionEvaluator(new MavenProject(model), new Properties());
+
+        Object value = expressionEvaluator.evaluate("${project.build.directory}" + FS + "${project.build.finalName}");
+
+        assertEquals("expected-directory" + File.separatorChar + "expected-finalName", value);
+    }
+
+    @Test
+    public void testShouldExtractPluginArtifacts() throws Exception {
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
+
+        Object value = ee.evaluate("${mojo.plugin.dependencies}");
+
+        assertTrue(value instanceof Collection);
+
+        @SuppressWarnings("unchecked")
+        Collection<Artifact> artifacts = (Collection<Artifact>) value;
+
+        assertEquals(1, artifacts.size());
+
+        Artifact result = artifacts.iterator().next();
+
+        assertEquals("org.myco.plugins", result.getGroupId());
+    }
+
+    @Test
+    void testRootDirectoryNotPrefixed() throws Exception {
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
+        assertNull(ee.evaluate("${rootDirectory}"));
+    }
+
+    @Test
+    void testRootDirectoryWithNull() throws Exception {
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
+        Exception e = assertThrows(Exception.class, () -> ee.evaluate("${session.rootDirectory}"));
+        e = assertInstanceOf(IntrospectionException.class, e.getCause());
+        e = assertInstanceOf(IllegalStateException.class, e.getCause());
+        assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
+    }
+
+    @Test
+    void testRootDirectory() throws Exception {
+        this.rootDirectory = Paths.get("myRootDirectory");
+        ExpressionEvaluator ee = createExpressionEvaluator(createDefaultProject(), new Properties());
+        assertInstanceOf(Path.class, ee.evaluate("${session.rootDirectory}"));
+    }
+
+    private MavenProject createDefaultProject() {
+        return new MavenProject(new Model());
+    }
+
+    private ExpressionEvaluator createExpressionEvaluator(MavenProject project, Properties executionProperties)
+            throws Exception {
+        ArtifactRepository repo = getLocalRepository();
+
+        MutablePlexusContainer container = (MutablePlexusContainer) getContainer();
+        MavenSession mavenSession = createSession(container, repo, executionProperties);
+        mavenSession.setCurrentProject(project);
+        mavenSession.getRequest().setRootDirectory(rootDirectory);
+        mavenSession.getRequest().setTopDirectory(rootDirectory);
+
+        DefaultSession session =
+                new DefaultSession(mavenSession, mock(RepositorySystem.class), null, null, container, null);
+
+        MojoExecution mojoExecution = newMojoExecution(session);
+
+        return new PluginParameterExpressionEvaluatorV4(
+                session, project != null ? new DefaultProject(session, project) : null, mojoExecution);
+    }
+
+    private MojoExecution newMojoExecution(Session session) {
+        PluginDescriptor pd = new PluginDescriptor();
+        pd.setArtifactId("my-plugin");
+        pd.setGroupId("org.myco.plugins");
+        pd.setVersion("1");
+
+        DefaultArtifact artifact = new DefaultArtifact(
+                pd.getGroupId(),
+                pd.getArtifactId(),
+                pd.getVersion(),
+                "compile",
+                "maven-plugin",
+                "",
+                new DefaultArtifactHandler("maven-plugin"));
+        pd.setPluginArtifact(artifact);
+
+        pd.setArtifacts(Collections.singletonList(artifact));
+        DefaultDependencyNode node = new DefaultDependencyNode(
+                new org.eclipse.aether.graph.Dependency(RepositoryUtils.toArtifact(artifact), "compile"));
+        pd.setDependencyNode(node);
+
+        MojoDescriptor md = new MojoDescriptor();
+        md.setGoal("my-goal");
+        md.setPluginDescriptor(pd);
+
+        pd.addComponentDescriptor(md);
+
+        return new DefaultMojoExecution((AbstractSession) session, new org.apache.maven.plugin.MojoExecution(md));
+    }
+
+    private DefaultSession newSession() throws Exception {
+        DefaultSession session =
+                new DefaultSession(newMavenSession(), mock(RepositorySystem.class), null, null, container, null);
+        return session;
+    }
+
+    private MavenSession newMavenSession() throws Exception {
+        return createMavenSession(null);
+    }
+
+    @Test
+    public void testUri() throws Exception {
+        Path path = Paths.get("").toAbsolutePath();
+
+        MavenSession mavenSession = createMavenSession(null);
+        mavenSession.getRequest().setTopDirectory(path);
+        mavenSession.getRequest().setRootDirectory(path);
+
+        Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
+                .evaluate("${session.rootDirectory.uri}");
+        assertEquals(path.toUri(), result);
+    }
+
+    @Test
+    public void testPath() throws Exception {
+        Path path = Paths.get("").toAbsolutePath();
+
+        MavenSession mavenSession = createMavenSession(null);
+        mavenSession.getRequest().setTopDirectory(path);
+        mavenSession.getRequest().setRootDirectory(path);
+
+        Object result = new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null)
+                .evaluate("${session.rootDirectory/target}");
+        assertEquals(path.resolve("target"), result);
+    }
+
+    @Test
+    public void testPluginInjection() throws Exception {
+        Path path = Paths.get("répâžœα").toAbsolutePath();
+
+        MavenSession mavenSession = createMavenSession(null);
+        mavenSession.getRequest().setTopDirectory(path);
+        mavenSession.getRequest().setRootDirectory(path);
+        DefaultModelBuildingRequest mbr = new DefaultModelBuildingRequest();
+
+        PluginParameterExpressionEvaluatorV4 evaluator =
+                new PluginParameterExpressionEvaluatorV4(mavenSession.getSession(), null);
+
+        DefaultPlexusConfiguration configuration = new DefaultPlexusConfiguration("config");
+        configuration.addChild("uri", "${session.rootDirectory.uri}");
+        configuration.addChild("path", "${session.rootDirectory}");
+        configuration.addChild("uriString", "${session.rootDirectory.uri.string}");
+        configuration.addChild("uriAsciiString", "${session.rootDirectory.uri.ASCIIString}");
+        configuration.addChild("pathString", "${session.rootDirectory.string}");
+
+        Mojo mojo = new Mojo();
+        new EnhancedComponentConfigurator().configureComponent(mojo, configuration, evaluator, null);
+
+        assertEquals(
+                Objects.equals(path.toUri().toString(), path.toUri().toASCIIString()), !Os.isFamily(Os.FAMILY_WINDOWS));
+        assertEquals(mojo.uri, path.toUri());
+        assertEquals(mojo.path, path);
+        assertEquals(mojo.uriString, path.toUri().toString());
+        assertEquals(mojo.uriAsciiString, path.toUri().toASCIIString());
+        assertEquals(mojo.pathString, path.toString());
+    }
+
+    @Override
+    protected String getProjectsDirectory() {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public static class Mojo {
+        URI uri;
+        Path path;
+        String uriString;
+        String uriAsciiString;
+        String pathString;
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/plugin/internal/DefaultLegacySupportTest.java b/maven-core/src/test/java/org/apache/maven/plugin/internal/DefaultLegacySupportTest.java
index 4cf01cf..4a64371 100644
--- a/maven-core/src/test/java/org/apache/maven/plugin/internal/DefaultLegacySupportTest.java
+++ b/maven-core/src/test/java/org/apache/maven/plugin/internal/DefaultLegacySupportTest.java
@@ -1,4 +1,3 @@
-package org.apache.maven.plugin.internal;
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -8,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -17,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
 
 import java.util.concurrent.CountDownLatch;
 
@@ -28,14 +28,13 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 
 /**
- * @author Kristian Rosenvold
  */
-public class DefaultLegacySupportTest {
+class DefaultLegacySupportTest {
     final CountDownLatch latch = new CountDownLatch(1);
     final DefaultLegacySupport defaultLegacySupport = new DefaultLegacySupport();
 
     @Test
-    public void testSetSession() throws Exception {
+    void testSetSession() throws Exception {
 
         MavenExecutionRequest mavenExecutionRequest = new DefaultMavenExecutionRequest();
         MavenSession m1 = new MavenSession(null, null, mavenExecutionRequest, null);
@@ -49,21 +48,17 @@
         defaultLegacySupport.setSession(m2);
         latch.countDown();
         thread.join();
-        assertNull( myRunnable.getSession());
+        assertNull(myRunnable.getSession());
     }
 
-
     class MyRunnable implements Runnable {
 
         private volatile MavenSession session;
 
         public void run() {
-            try
-            {
+            try {
                 latch.await();
-            }
-            catch (InterruptedException ignore)
-            {
+            } catch (InterruptedException ignore) {
                 // Test may fail if we get interrupted
             }
             session = defaultLegacySupport.getSession();
@@ -73,5 +68,4 @@
             return session;
         }
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/plugin/internal/MavenPluginJavaPrerequisiteCheckerTest.java b/maven-core/src/test/java/org/apache/maven/plugin/internal/MavenPluginJavaPrerequisiteCheckerTest.java
new file mode 100644
index 0000000..2c68ebb
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/plugin/internal/MavenPluginJavaPrerequisiteCheckerTest.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.plugin.internal;
+
+import org.eclipse.aether.util.version.GenericVersionScheme;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class MavenPluginJavaPrerequisiteCheckerTest {
+
+    @Test
+    void testMatchesVersion() {
+        MavenPluginJavaPrerequisiteChecker checker = new MavenPluginJavaPrerequisiteChecker(new GenericVersionScheme());
+        assertTrue(checker.matchesVersion("1.0", "1.8"));
+        assertTrue(checker.matchesVersion("1.8", "9.0.1+11"));
+        assertFalse(checker.matchesVersion("[1.0,2],[3,4]", "2.1"));
+        assertTrue(checker.matchesVersion("[1.0,2],[3,4]", "3.1"));
+        assertThrows(IllegalArgumentException.class, () -> checker.matchesVersion("(1.0,0)", "11"));
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/plugin/internal/MavenPluginValidatorTest.java b/maven-core/src/test/java/org/apache/maven/plugin/internal/MavenPluginValidatorTest.java
index 8728096..12c0bba 100644
--- a/maven-core/src/test/java/org/apache/maven/plugin/internal/MavenPluginValidatorTest.java
+++ b/maven-core/src/test/java/org/apache/maven/plugin/internal/MavenPluginValidatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.internal;
+
+import javax.inject.Inject;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,79 +28,93 @@
 import org.apache.maven.artifact.DefaultArtifact;
 import org.apache.maven.artifact.handler.DefaultArtifactHandler;
 import org.apache.maven.plugin.descriptor.PluginDescriptor;
-import org.apache.maven.plugin.internal.MavenPluginValidator;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertFalse;
-
-import javax.inject.Inject;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author Michael Simacek
  */
-public class MavenPluginValidatorTest extends AbstractCoreMavenComponentTestCase
-{
+class MavenPluginValidatorTest extends AbstractCoreMavenComponentTestCase {
     @Inject
     private MavenPluginValidator mavenPluginValidator;
 
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/default-maven";
     }
 
     @Test
-    public void testValidate()
-    {
-        Artifact plugin = new DefaultArtifact( "org.apache.maven.its.plugins", "maven-it-plugin", "0.1", "compile",
-                "jar", null, new DefaultArtifactHandler( "ignore" ) );
+    void testValidate() {
+        Artifact plugin = new DefaultArtifact(
+                "org.apache.maven.its.plugins",
+                "maven-it-plugin",
+                "0.1",
+                "compile",
+                "jar",
+                null,
+                new DefaultArtifactHandler("ignore"));
         PluginDescriptor descriptor = new PluginDescriptor();
-        descriptor.setGroupId( "org.apache.maven.its.plugins" );
-        descriptor.setArtifactId( "maven-it-plugin" );
-        descriptor.setVersion( "0.1" );
+        descriptor.setGroupId("org.apache.maven.its.plugins");
+        descriptor.setArtifactId("maven-it-plugin");
+        descriptor.setVersion("0.1");
         List<String> errors = new ArrayList<>();
-        mavenPluginValidator.validate( plugin, descriptor, errors );
-        assertTrue( errors.isEmpty() );
+        mavenPluginValidator.validate(plugin, descriptor, errors);
+        assertTrue(errors.isEmpty());
     }
 
     @Test
-    public void testInvalidGroupId()
-    {
-        Artifact plugin = new DefaultArtifact( "org.apache.maven.its.plugins", "maven-it-plugin", "0.1", "compile",
-                "jar", null, new DefaultArtifactHandler( "ignore" ) );
+    void testInvalidGroupId() {
+        Artifact plugin = new DefaultArtifact(
+                "org.apache.maven.its.plugins",
+                "maven-it-plugin",
+                "0.1",
+                "compile",
+                "jar",
+                null,
+                new DefaultArtifactHandler("ignore"));
         PluginDescriptor descriptor = new PluginDescriptor();
-        descriptor.setGroupId( "org.apache.maven.its.plugins.invalid" );
-        descriptor.setArtifactId( "maven-it-plugin" );
-        descriptor.setVersion( "0.1" );
+        descriptor.setGroupId("org.apache.maven.its.plugins.invalid");
+        descriptor.setArtifactId("maven-it-plugin");
+        descriptor.setVersion("0.1");
         List<String> errors = new ArrayList<>();
-        mavenPluginValidator.validate( plugin, descriptor, errors );
-        assertFalse( errors.isEmpty() );
+        mavenPluginValidator.validate(plugin, descriptor, errors);
+        assertFalse(errors.isEmpty());
     }
 
     @Test
-    public void testInvalidArtifactId()
-    {
-        Artifact plugin = new DefaultArtifact( "org.apache.maven.its.plugins", "maven-it-plugin", "0.1", "compile",
-                "jar", null, new DefaultArtifactHandler( "ignore" ) );
+    void testInvalidArtifactId() {
+        Artifact plugin = new DefaultArtifact(
+                "org.apache.maven.its.plugins",
+                "maven-it-plugin",
+                "0.1",
+                "compile",
+                "jar",
+                null,
+                new DefaultArtifactHandler("ignore"));
         PluginDescriptor descriptor = new PluginDescriptor();
-        descriptor.setGroupId( "org.apache.maven.its.plugins" );
-        descriptor.setArtifactId( "maven-it-plugin.invalid" );
-        descriptor.setVersion( "0.1" );
+        descriptor.setGroupId("org.apache.maven.its.plugins");
+        descriptor.setArtifactId("maven-it-plugin.invalid");
+        descriptor.setVersion("0.1");
         List<String> errors = new ArrayList<>();
-        mavenPluginValidator.validate( plugin, descriptor, errors );
-        assertFalse( errors.isEmpty() );
+        mavenPluginValidator.validate(plugin, descriptor, errors);
+        assertFalse(errors.isEmpty());
     }
 
     @Test
-    public void testInvalidVersion()
-    {
-        Artifact plugin = new DefaultArtifact( "org.apache.maven.its.plugins", "maven-it-plugin", "0.1", "compile",
-                "jar", null, new DefaultArtifactHandler( "ignore" ) );
+    void testInvalidVersion() {
+        Artifact plugin = new DefaultArtifact(
+                "org.apache.maven.its.plugins",
+                "maven-it-plugin",
+                "0.1",
+                "compile",
+                "jar",
+                null,
+                new DefaultArtifactHandler("ignore"));
         PluginDescriptor descriptor = new PluginDescriptor();
-        descriptor.setGroupId( "org.apache.maven.its.plugins" );
-        descriptor.setArtifactId( "maven-it-plugin" );
+        descriptor.setGroupId("org.apache.maven.its.plugins");
+        descriptor.setArtifactId("maven-it-plugin");
         List<String> errors = new ArrayList<>();
-        mavenPluginValidator.validate( plugin, descriptor, errors );
-        assertFalse( errors.isEmpty() );
+        mavenPluginValidator.validate(plugin, descriptor, errors);
+        assertFalse(errors.isEmpty());
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java b/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
index 785958e..cd017cb 100644
--- a/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
+++ b/maven-core/src/test/java/org/apache/maven/project/AbstractMavenProjectTestCase.java
@@ -1,50 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
 package org.apache.maven.project;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
+import javax.inject.Inject;
 
 import java.io.File;
 import java.io.FileNotFoundException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.Arrays;
 
 import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.model.building.ModelBuildingException;
 import org.apache.maven.model.building.ModelProblem;
-import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
-import org.codehaus.plexus.testing.PlexusTest;
 import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.eclipse.aether.DefaultRepositoryCache;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.junit.jupiter.api.BeforeEach;
 
-import javax.inject.Inject;
-
 /**
- * @author Jason van Zyl
  */
 @PlexusTest
-public abstract class AbstractMavenProjectTestCase
-{
+public abstract class AbstractMavenProjectTestCase {
     protected ProjectBuilder projectBuilder;
 
     @Inject
-    protected RepositorySystem repositorySystem;
+    protected MavenRepositorySystem repositorySystem;
 
     @Inject
     protected PlexusContainer container;
@@ -54,22 +54,16 @@
     }
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        if ( getContainer().hasComponent( ProjectBuilder.class, "test" ) )
-        {
-            projectBuilder = getContainer().lookup( ProjectBuilder.class, "test" );
-        }
-        else
-        {
+    public void setUp() throws Exception {
+        if (getContainer().hasComponent(ProjectBuilder.class, "test")) {
+            projectBuilder = getContainer().lookup(ProjectBuilder.class, "test");
+        } else {
             // default over to the main project builder...
-            projectBuilder = getContainer().lookup( ProjectBuilder.class );
+            projectBuilder = getContainer().lookup(ProjectBuilder.class);
         }
     }
 
-    protected ProjectBuilder getProjectBuilder()
-    {
+    protected ProjectBuilder getProjectBuilder() {
         return projectBuilder;
     }
 
@@ -77,103 +71,83 @@
     // Local repository
     // ----------------------------------------------------------------------
 
-    protected File getLocalRepositoryPath()
-        throws FileNotFoundException, URISyntaxException
-    {
-        File markerFile = getFileForClasspathResource( "local-repo/marker.txt" );
+    protected File getLocalRepositoryPath() throws FileNotFoundException, URISyntaxException {
+        File markerFile = getFileForClasspathResource("local-repo/marker.txt");
 
         return markerFile.getAbsoluteFile().getParentFile();
     }
 
-    protected static File getFileForClasspathResource( String resource )
-        throws FileNotFoundException
-    {
+    protected static File getFileForClasspathResource(String resource)
+            throws FileNotFoundException, URISyntaxException {
         ClassLoader cloader = Thread.currentThread().getContextClassLoader();
 
-        URL resourceUrl = cloader.getResource( resource );
+        URL resourceUrl = cloader.getResource(resource);
 
-        if ( resourceUrl == null )
-        {
-            throw new FileNotFoundException( "Unable to find: " + resource );
+        if (resourceUrl == null) {
+            throw new FileNotFoundException("Unable to find: " + resource);
         }
 
-        return new File( URI.create( resourceUrl.toString().replaceAll( " ", "%20" ) ) );
+        return new File(resourceUrl.toURI());
     }
 
-    protected ArtifactRepository getLocalRepository()
-        throws Exception
-    {
-        return repositorySystem.createLocalRepository( getLocalRepositoryPath() );
+    protected ArtifactRepository getLocalRepository() throws Exception {
+        return repositorySystem.createLocalRepository(getLocalRepositoryPath());
     }
 
     // ----------------------------------------------------------------------
     // Project building
     // ----------------------------------------------------------------------
 
-    protected MavenProject getProjectWithDependencies( File pom )
-        throws Exception
-    {
+    protected MavenProject getProjectWithDependencies(File pom) throws Exception {
         ProjectBuildingRequest configuration = newBuildingRequest();
-        configuration.setRemoteRepositories( Arrays.asList( new ArtifactRepository[] {} ) );
-        configuration.setProcessPlugins( false );
-        configuration.setResolveDependencies( true );
+        configuration.setRemoteRepositories(Arrays.asList(new ArtifactRepository[] {}));
+        configuration.setProcessPlugins(false);
+        configuration.setResolveDependencies(true);
 
-        try
-        {
-            return projectBuilder.build( pom, configuration ).getProject();
-        }
-        catch ( Exception e )
-        {
+        try {
+            return projectBuilder.build(pom, configuration).getProject();
+        } catch (Exception e) {
             Throwable cause = e.getCause();
-            if ( cause instanceof ModelBuildingException )
-            {
+            if (cause instanceof ModelBuildingException) {
                 String message = "In: " + pom + "\n\n";
-                for ( ModelProblem problem : ( (ModelBuildingException) cause ).getProblems() )
-                {
+                for (ModelProblem problem : ((ModelBuildingException) cause).getProblems()) {
                     message += problem + "\n";
                 }
-                System.out.println( message );
+                System.out.println(message);
             }
 
             throw e;
         }
     }
 
-    protected MavenProject getProject( File pom )
-        throws Exception
-    {
+    protected MavenProject getProject(File pom) throws Exception {
         ProjectBuildingRequest configuration = newBuildingRequest();
 
-        return projectBuilder.build( pom, configuration ).getProject();
+        return projectBuilder.build(pom, configuration).getProject();
     }
 
-    protected MavenProject getProjectFromRemoteRepository( final File pom )
-        throws Exception
-    {
+    protected MavenProject getProjectFromRemoteRepository(final File pom) throws Exception {
         final ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setLocalRepository( this.getLocalRepository() );
-        configuration.setRemoteRepositories( Arrays.asList( this.repositorySystem.createDefaultRemoteRepository() ) );
-        initRepoSession( configuration );
+        configuration.setLocalRepository(this.getLocalRepository());
+        configuration.setRemoteRepositories(Arrays.asList(this.repositorySystem.createDefaultRemoteRepository()));
+        initRepoSession(configuration);
 
-        return projectBuilder.build( pom, configuration ).getProject();
+        return projectBuilder.build(pom, configuration).getProject();
     }
 
-    protected ProjectBuildingRequest newBuildingRequest()
-        throws Exception
-    {
+    protected ProjectBuildingRequest newBuildingRequest() throws Exception {
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setLocalRepository( getLocalRepository() );
-        initRepoSession( configuration );
+        configuration.setLocalRepository(getLocalRepository());
+        configuration.setRemoteRepositories(Arrays.asList(this.repositorySystem.createDefaultRemoteRepository()));
+        initRepoSession(configuration);
         return configuration;
     }
 
-    protected void initRepoSession( ProjectBuildingRequest request )
-    {
-        File localRepo = new File( request.getLocalRepository().getBasedir() );
+    protected void initRepoSession(ProjectBuildingRequest request) {
+        File localRepo = new File(request.getLocalRepository().getBasedir());
         DefaultRepositorySystemSession repoSession = MavenRepositorySystemUtils.newSession();
-        repoSession.setCache( new DefaultRepositoryCache() );
-        repoSession.setLocalRepositoryManager( new LegacyLocalRepositoryManager( localRepo ) );
-        request.setRepositorySession( repoSession );
+        repoSession.setCache(new DefaultRepositoryCache());
+        repoSession.setLocalRepositoryManager(new LegacyLocalRepositoryManager(localRepo));
+        request.setRepositorySession(repoSession);
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java
index 59cab5d..97152f5 100644
--- a/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/DefaultMavenProjectBuilderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.apache.maven.project.ProjectBuildingResultWithProblemMessageMatcher.projectBuildingResultWithProblemMessage;
-import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.containsString;
-import static org.hamcrest.Matchers.is;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.fail;
+package org.apache.maven.project;
 
 import java.io.File;
 import java.io.InputStream;
@@ -46,9 +32,21 @@
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.io.TempDir;
 
-public class DefaultMavenProjectBuilderTest
-    extends AbstractMavenProjectTestCase
-{
+import static org.apache.maven.project.ProjectBuildingResultWithProblemMessageMatcher.projectBuildingResultWithProblemMessage;
+import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+class DefaultMavenProjectBuilderTest extends AbstractMavenProjectTestCase {
     @TempDir
     File localRepoDir;
 
@@ -58,20 +56,16 @@
 
     @Override
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        projectBuilder = getContainer().lookup( ProjectBuilder.class );
+    public void setUp() throws Exception {
+        projectBuilder = getContainer().lookup(ProjectBuilder.class);
     }
 
-    protected MavenProject getProject( Artifact pom, boolean allowStub )
-        throws Exception
-    {
+    protected MavenProject getProject(Artifact pom, boolean allowStub) throws Exception {
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setLocalRepository( getLocalRepository() );
-        initRepoSession( configuration );
+        configuration.setLocalRepository(getLocalRepository());
+        initRepoSession(configuration);
 
-        return projectBuilder.build( pom, allowStub, configuration ).getProject();
+        return projectBuilder.build(pom, allowStub, configuration).getProject();
     }
 
     /**
@@ -80,122 +74,102 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testBuildFromMiddlePom() throws Exception
-    {
-        File f1 = getTestFile( "src/test/resources/projects/grandchild-check/child/pom.xml");
-        File f2 = getTestFile( "src/test/resources/projects/grandchild-check/child/grandchild/pom.xml");
+    void testBuildFromMiddlePom() throws Exception {
+        File f1 = getTestFile("src/test/resources/projects/grandchild-check/child/pom.xml");
+        File f2 = getTestFile("src/test/resources/projects/grandchild-check/child/grandchild/pom.xml");
 
-        getProject( f1 );
+        getProject(f1);
 
         // it's the building of the grandchild project, having already cached the child project
         // (but not the parent project), which causes the problem.
-        getProject( f2 );
+        getProject(f2);
     }
 
-    @Disabled( "Maven 4 does not allow duplicate plugin declarations" )
+    @Disabled("Maven 4 does not allow duplicate plugin declarations")
     @Test
-    public void testDuplicatePluginDefinitionsMerged()
-        throws Exception
-    {
-        File f1 = getTestFile( "src/test/resources/projects/duplicate-plugins-merged-pom.xml" );
+    void testDuplicatePluginDefinitionsMerged() throws Exception {
+        File f1 = getTestFile("src/test/resources/projects/duplicate-plugins-merged-pom.xml");
 
-        MavenProject project = getProject( f1 );
-        assertEquals( 2, project.getBuildPlugins().get( 0 ).getDependencies().size() );
-        assertEquals( 2, project.getBuildPlugins().get( 0 ).getExecutions().size() );
-        assertEquals( "first", project.getBuildPlugins().get( 0 ).getExecutions().get( 0 ).getId() );
+        MavenProject project = getProject(f1);
+        assertEquals(2, project.getBuildPlugins().get(0).getDependencies().size());
+        assertEquals(2, project.getBuildPlugins().get(0).getExecutions().size());
+        assertEquals(
+                "first", project.getBuildPlugins().get(0).getExecutions().get(0).getId());
     }
 
     @Test
-    public void testFutureModelVersion()
-        throws Exception
-    {
-        File f1 = getTestFile( "src/test/resources/projects/future-model-version-pom.xml" );
+    void testFutureModelVersion() throws Exception {
+        File f1 = getTestFile("src/test/resources/projects/future-model-version-pom.xml");
 
         ProjectBuildingException e = assertThrows(
-                ProjectBuildingException.class,
-                () -> getProject( f1 ),
-                "Expected to fail for future versions" );
-        assertThat(  e.getMessage(), containsString( "Building this project requires a newer version of Maven" ) );
+                ProjectBuildingException.class, () -> getProject(f1), "Expected to fail for future versions");
+        assertThat(e.getMessage(), containsString("Building this project requires a newer version of Maven"));
     }
 
     @Test
-    public void testPastModelVersion()
-        throws Exception
-    {
+    void testPastModelVersion() throws Exception {
         // a Maven 1.x pom will not even
         // update the resource if we stop supporting modelVersion 4.0.0
-        File f1 = getTestFile( "src/test/resources/projects/past-model-version-pom.xml" );
+        File f1 = getTestFile("src/test/resources/projects/past-model-version-pom.xml");
 
         ProjectBuildingException e = assertThrows(
-                ProjectBuildingException.class,
-                () -> getProject( f1 ),
-                "Expected to fail for past versions" );
-        assertThat( e.getMessage(), containsString( "Building this project requires an older version of Maven" ) );
+                ProjectBuildingException.class, () -> getProject(f1), "Expected to fail for past versions");
+        assertThat(e.getMessage(), containsString("Building this project requires an older version of Maven"));
     }
 
     @Test
-    public void testFutureSchemaModelVersion()
-        throws Exception
-    {
-        File f1 = getTestFile( "src/test/resources/projects/future-schema-model-version-pom.xml" );
+    void testFutureSchemaModelVersion() throws Exception {
+        File f1 = getTestFile("src/test/resources/projects/future-schema-model-version-pom.xml");
 
         ProjectBuildingException e = assertThrows(
-                ProjectBuildingException.class,
-                () -> getProject( f1 ),
-                "Expected to fail for future versions" );
-        assertThat( e.getMessage(), containsString( "Building this project requires a newer version of Maven" ) );
+                ProjectBuildingException.class, () -> getProject(f1), "Expected to fail for future versions");
+        assertThat(e.getMessage(), containsString("Building this project requires a newer version of Maven"));
     }
 
     @Test
-    public void testBuildStubModelForMissingRemotePom()
-        throws Exception
-    {
-        Artifact pom = repositorySystem.createProjectArtifact( "org.apache.maven.its", "missing", "0.1" );
-        MavenProject project = getProject( pom, true );
+    void testBuildStubModelForMissingRemotePom() throws Exception {
+        Artifact pom = repositorySystem.createProjectArtifact("org.apache.maven.its", "missing", "0.1");
+        MavenProject project = getProject(pom, true);
 
-        assertNotNull( project.getArtifactId() );
+        assertNotNull(project.getArtifactId());
 
-        assertNotNull( project.getRemoteArtifactRepositories() );
-        assertFalse( project.getRemoteArtifactRepositories().isEmpty() );
+        assertNotNull(project.getRemoteArtifactRepositories());
+        assertTrue(project.getRemoteArtifactRepositories().isEmpty());
 
-        assertNotNull( project.getPluginArtifactRepositories() );
-        assertFalse( project.getPluginArtifactRepositories().isEmpty() );
+        assertNotNull(project.getPluginArtifactRepositories());
+        assertTrue(project.getPluginArtifactRepositories().isEmpty());
 
-        assertNull( project.getParent() );
-        assertNull( project.getParentArtifact() );
+        assertNull(project.getParent());
+        assertNull(project.getParentArtifact());
 
-        assertFalse( project.isExecutionRoot() );
+        assertFalse(project.isExecutionRoot());
     }
 
     @Override
-    protected ArtifactRepository getLocalRepository()
-        throws Exception
-    {
-        return repositorySystem.createLocalRepository( getLocalRepositoryPath() );
+    protected ArtifactRepository getLocalRepository() throws Exception {
+        return repositorySystem.createLocalRepository(getLocalRepositoryPath());
     }
 
     @Test
-    public void testPartialResultUponBadDependencyDeclaration()
-        throws Exception
-    {
-        File pomFile = getTestFile( "src/test/resources/projects/bad-dependency.xml" );
+    void testPartialResultUponBadDependencyDeclaration() throws Exception {
+        File pomFile = getTestFile("src/test/resources/projects/bad-dependency.xml");
 
         ProjectBuildingRequest request = newBuildingRequest();
-        request.setProcessPlugins( false );
-        request.setResolveDependencies( true );
+        request.setProcessPlugins(false);
+        request.setResolveDependencies(true);
         ProjectBuildingException e = assertThrows(
                 ProjectBuildingException.class,
-                () -> projectBuilder.build( pomFile, request ),
-                "Project building did not fail despite invalid POM" );
+                () -> projectBuilder.build(pomFile, request),
+                "Project building did not fail despite invalid POM");
         List<ProjectBuildingResult> results = e.getResults();
-        assertNotNull( results );
-        assertEquals( 1, results.size() );
-        ProjectBuildingResult result = results.get( 0 );
-        assertNotNull( result );
-        assertNotNull( result.getProject() );
-        assertEquals( 1, result.getProblems().size() );
-        assertEquals( 1, result.getProject().getArtifacts().size() );
-        assertNotNull( result.getDependencyResolutionResult() );
+        assertNotNull(results);
+        assertEquals(1, results.size());
+        ProjectBuildingResult result = results.get(0);
+        assertNotNull(result);
+        assertNotNull(result.getProject());
+        assertEquals(1, result.getProblems().size());
+        assertEquals(1, result.getProject().getArtifacts().size());
+        assertNotNull(result.getDependencyResolutionResult());
     }
 
     /**
@@ -204,18 +178,17 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testBuildValidParentVersionRangeLocally() throws Exception
-    {
-        File f1 = getTestFile( "src/test/resources/projects/parent-version-range-local-valid/child/pom.xml" );
+    void testBuildValidParentVersionRangeLocally() throws Exception {
+        File f1 = getTestFile("src/test/resources/projects/parent-version-range-local-valid/child/pom.xml");
 
-        final MavenProject childProject = getProject( f1 );
+        final MavenProject childProject = getProject(f1);
 
-        assertNotNull( childProject.getParentArtifact() );
-        assertEquals( childProject.getParentArtifact().getVersion(), "1" );
-        assertNotNull( childProject.getParent() );
-        assertEquals( childProject.getParent().getVersion(), "1" );
-        assertNotNull( childProject.getModel().getParent() );
-        assertEquals( childProject.getModel().getParent().getVersion(), "[1,10]" );
+        assertNotNull(childProject.getParentArtifact());
+        assertEquals(childProject.getParentArtifact().getVersion(), "1");
+        assertNotNull(childProject.getParent());
+        assertEquals(childProject.getParent().getVersion(), "1");
+        assertNotNull(childProject.getModel().getParent());
+        assertEquals(childProject.getModel().getParent().getVersion(), "[1,10]");
     }
 
     /**
@@ -224,16 +197,15 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testBuildParentVersionRangeLocallyWithoutChildVersion() throws Exception
-    {
-        File f1 =
-            getTestFile( "src/test/resources/projects/parent-version-range-local-child-without-version/child/pom.xml" );
+    void testBuildParentVersionRangeLocallyWithoutChildVersion() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-local-child-without-version/child/pom.xml");
 
         ProjectBuildingException e = assertThrows(
                 ProjectBuildingException.class,
-                () -> getProject( f1 ),
-                "Expected 'ProjectBuildingException' not thrown." );
-        assertThat( e.getResults(), contains( projectBuildingResultWithProblemMessage( "Version must be a constant" ) ) );
+                () -> getProject(f1),
+                "Expected 'ProjectBuildingException' not thrown.");
+        assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
     }
 
     /**
@@ -242,77 +214,47 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testBuildParentVersionRangeLocallyWithChildProjectVersionExpression() throws Exception
-    {
-        File f1 =
-            getTestFile(
-                "src/test/resources/projects/parent-version-range-local-child-project-version-expression/child/pom.xml" );
+    void testBuildParentVersionRangeLocallyWithChildProjectVersionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-local-child-project-version-expression/child/pom.xml");
 
         ProjectBuildingException e = assertThrows(
                 ProjectBuildingException.class,
-                () -> getProject( f1 ),
-                "Expected 'ProjectBuildingException' not thrown." );
-        assertThat( e.getResults(), contains( projectBuildingResultWithProblemMessage( "Version must be a constant" ) ) );
+                () -> getProject(f1),
+                "Expected 'ProjectBuildingException' not thrown.");
+        assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
     }
-    
+
     /**
      * Tests whether local version range parent references are build correctly.
      *
      * @throws Exception
      */
-    public void testBuildParentVersionRangeLocallyWithChildProjectParentVersionExpression() throws Exception
-    {
-        File f1 =
-            getTestFile(
-                "src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml" );
+    public void testBuildParentVersionRangeLocallyWithChildProjectParentVersionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-local-child-project-parent-version-expression/child/pom.xml");
 
-        try
-        {
-            getProject( f1 );
-            fail( "Expected 'ProjectBuildingException' not thrown." );
-        }
-        catch ( final ProjectBuildingException e )
-        {
-            assertNotNull( e.getMessage() );
-            assertThat( e.getMessage(), containsString( "Version must be a constant" ) );
+        try {
+            getProject(f1);
+            fail("Expected 'ProjectBuildingException' not thrown.");
+        } catch (final ProjectBuildingException e) {
+            assertNotNull(e.getMessage());
+            assertThat(e.getMessage(), containsString("Version must be a constant"));
         }
     }
-    
+
     /**
      * Tests whether local version range parent references are build correctly.
      *
      * @throws Exception
      */
-    public void testBuildParentVersionRangeLocallyWithChildRevisionExpression() throws Exception
-    {
-        File f1 =
-            getTestFile(
-                "src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml" );
+    public void testBuildParentVersionRangeLocallyWithChildRevisionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-local-child-revision-expression/child/pom.xml");
 
-        MavenProject mp =  this.getProjectFromRemoteRepository( f1 );
-        
+        MavenProject mp = this.getProjectFromRemoteRepository(f1);
+
         assertEquals("1.0-SNAPSHOT", mp.getVersion());
-      
-    }
-    
-    /**
-     * Tests whether external version range parent references are build correctly.
-     *
-     * @throws Exception in case of issue
-     */
-    @Test
-    public void testBuildParentVersionRangeExternally() throws Exception
-    {
-        File f1 = getTestFile( "src/test/resources/projects/parent-version-range-external-valid/pom.xml" );
-
-        final MavenProject childProject = this.getProjectFromRemoteRepository( f1 );
-
-        assertNotNull( childProject.getParentArtifact() );
-        assertEquals( childProject.getParentArtifact().getVersion(), "1" );
-        assertNotNull( childProject.getParent() );
-        assertEquals( childProject.getParent().getVersion(), "1" );
-        assertNotNull( childProject.getModel().getParent() );
-        assertEquals( childProject.getModel().getParent().getVersion(), "[1,1]" );
     }
 
     /**
@@ -321,17 +263,34 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testBuildParentVersionRangeExternallyWithoutChildVersion() throws Exception
-    {
+    void testBuildParentVersionRangeExternally() throws Exception {
+        File f1 = getTestFile("src/test/resources/projects/parent-version-range-external-valid/pom.xml");
+
+        final MavenProject childProject = this.getProjectFromRemoteRepository(f1);
+
+        assertNotNull(childProject.getParentArtifact());
+        assertEquals(childProject.getParentArtifact().getVersion(), "1");
+        assertNotNull(childProject.getParent());
+        assertEquals(childProject.getParent().getVersion(), "1");
+        assertNotNull(childProject.getModel().getParent());
+        assertEquals(childProject.getModel().getParent().getVersion(), "[1,1]");
+    }
+
+    /**
+     * Tests whether external version range parent references are build correctly.
+     *
+     * @throws Exception in case of issue
+     */
+    @Test
+    void testBuildParentVersionRangeExternallyWithoutChildVersion() throws Exception {
         File f1 =
-            getTestFile(
-                "src/test/resources/projects/parent-version-range-external-child-without-version/pom.xml" );
+                getTestFile("src/test/resources/projects/parent-version-range-external-child-without-version/pom.xml");
 
         ProjectBuildingException e = assertThrows(
                 ProjectBuildingException.class,
-                () -> getProjectFromRemoteRepository( f1 ),
-                "Expected 'ProjectBuildingException' not thrown." );
-        assertThat( e.getResults(), contains( projectBuildingResultWithProblemMessage( "Version must be a constant" ) ) );
+                () -> getProjectFromRemoteRepository(f1),
+                "Expected 'ProjectBuildingException' not thrown.");
+        assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
     }
 
     /**
@@ -340,17 +299,15 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testBuildParentVersionRangeExternallyWithChildProjectVersionExpression() throws Exception
-    {
-        File f1 =
-            getTestFile(
-                "src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml" );
+    void testBuildParentVersionRangeExternallyWithChildProjectVersionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-external-child-project-version-expression/pom.xml");
 
         ProjectBuildingException e = assertThrows(
                 ProjectBuildingException.class,
-                () -> getProjectFromRemoteRepository( f1 ),
-                "Expected 'ProjectBuildingException' not thrown." );
-        assertThat( e.getResults(), contains( projectBuildingResultWithProblemMessage( "Version must be a constant") ) );
+                () -> getProjectFromRemoteRepository(f1),
+                "Expected 'ProjectBuildingException' not thrown.");
+        assertThat(e.getResults(), contains(projectBuildingResultWithProblemMessage("Version must be a constant")));
     }
 
     /**
@@ -359,28 +316,26 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void rereadPom_mng7063() throws Exception
-    {
-        final Path pom = projectRoot.resolve( "pom.xml" );
+    void rereadPom_mng7063() throws Exception {
+        final Path pom = projectRoot.resolve("pom.xml");
         final ProjectBuildingRequest buildingRequest = newBuildingRequest();
 
-        try ( InputStream pomResource =
-            DefaultMavenProjectBuilderTest.class.getResourceAsStream( "/projects/reread/pom1.xml" ) )
-        {
-            Files.copy( pomResource, pom, StandardCopyOption.REPLACE_EXISTING );
+        try (InputStream pomResource =
+                DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom1.xml")) {
+            Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING);
         }
 
-        MavenProject project = projectBuilder.build( pom.toFile(), buildingRequest ).getProject();
-        assertThat( project.getName(), is( "aid" ) ); // inherited from artifactId
+        MavenProject project =
+                projectBuilder.build(pom.toFile(), buildingRequest).getProject();
+        assertThat(project.getName(), is("aid")); // inherited from artifactId
 
-        try ( InputStream pomResource =
-            DefaultMavenProjectBuilderTest.class.getResourceAsStream( "/projects/reread/pom2.xml" ) )
-        {
-            Files.copy( pomResource, pom, StandardCopyOption.REPLACE_EXISTING );
+        try (InputStream pomResource =
+                DefaultMavenProjectBuilderTest.class.getResourceAsStream("/projects/reread/pom2.xml")) {
+            Files.copy(pomResource, pom, StandardCopyOption.REPLACE_EXISTING);
         }
 
-        project = projectBuilder.build( pom.toFile(), buildingRequest ).getProject();
-        assertThat( project.getName(), is( "PROJECT NAME" ) );
+        project = projectBuilder.build(pom.toFile(), buildingRequest).getProject();
+        assertThat(project.getName(), is("PROJECT NAME"));
     }
 
     /**
@@ -388,21 +343,16 @@
      *
      * @throws Exception
      */
-    public void testBuildParentVersionRangeExternallyWithChildPomVersionExpression() throws Exception
-    {
-        File f1 =
-                getTestFile(
-                        "src/test/resources/projects/parent-version-range-external-child-pom-version-expression/pom.xml" );
+    public void testBuildParentVersionRangeExternallyWithChildPomVersionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-external-child-pom-version-expression/pom.xml");
 
-        try
-        {
-            this.getProjectFromRemoteRepository( f1 );
-            fail( "Expected 'ProjectBuildingException' not thrown." );
-        }
-        catch ( final ProjectBuildingException e )
-        {
-            assertNotNull( e.getMessage() );
-            assertThat( e.getMessage(), containsString( "Version must be a constant" ) );
+        try {
+            this.getProjectFromRemoteRepository(f1);
+            fail("Expected 'ProjectBuildingException' not thrown.");
+        } catch (final ProjectBuildingException e) {
+            assertNotNull(e.getMessage());
+            assertThat(e.getMessage(), containsString("Version must be a constant"));
         }
     }
 
@@ -411,21 +361,16 @@
      *
      * @throws Exception
      */
-    public void testBuildParentVersionRangeExternallyWithChildPomParentVersionExpression() throws Exception
-    {
-        File f1 =
-                getTestFile(
-                        "src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml" );
+    public void testBuildParentVersionRangeExternallyWithChildPomParentVersionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-external-child-pom-parent-version-expression/pom.xml");
 
-        try
-        {
-            this.getProjectFromRemoteRepository( f1 );
-            fail( "Expected 'ProjectBuildingException' not thrown." );
-        }
-        catch ( final ProjectBuildingException e )
-        {
-            assertNotNull( e.getMessage() );
-            assertThat( e.getMessage(), containsString( "Version must be a constant" ) );
+        try {
+            this.getProjectFromRemoteRepository(f1);
+            fail("Expected 'ProjectBuildingException' not thrown.");
+        } catch (final ProjectBuildingException e) {
+            assertNotNull(e.getMessage());
+            assertThat(e.getMessage(), containsString("Version must be a constant"));
         }
     }
 
@@ -434,40 +379,30 @@
      *
      * @throws Exception
      */
-    public void testBuildParentVersionRangeExternallyWithChildProjectParentVersionExpression() throws Exception
-    {
-        File f1 =
-            getTestFile(
-                "src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml" );
+    public void testBuildParentVersionRangeExternallyWithChildProjectParentVersionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-external-child-project-parent-version-expression/pom.xml");
 
-        try
-        {
-            this.getProjectFromRemoteRepository( f1 );
-            fail( "Expected 'ProjectBuildingException' not thrown." );
-        }
-        catch ( final ProjectBuildingException e )
-        {
-            assertNotNull( e.getMessage() );
-            assertThat( e.getMessage(), containsString( "Version must be a constant" ) );
+        try {
+            this.getProjectFromRemoteRepository(f1);
+            fail("Expected 'ProjectBuildingException' not thrown.");
+        } catch (final ProjectBuildingException e) {
+            assertNotNull(e.getMessage());
+            assertThat(e.getMessage(), containsString("Version must be a constant"));
         }
     }
-    
+
     /**
      * Tests whether external version range parent references are build correctly.
      *
      * @throws Exception
      */
-    public void testBuildParentVersionRangeExternallyWithChildRevisionExpression() throws Exception
-    {
-        File f1 =
-            getTestFile(
-                "src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml" );
+    public void testBuildParentVersionRangeExternallyWithChildRevisionExpression() throws Exception {
+        File f1 = getTestFile(
+                "src/test/resources/projects/parent-version-range-external-child-revision-expression/pom.xml");
 
-       
-        MavenProject mp =  this.getProjectFromRemoteRepository( f1 );
-          
+        MavenProject mp = this.getProjectFromRemoteRepository(f1);
+
         assertEquals("1.0-SNAPSHOT", mp.getVersion());
-      
-       
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java b/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
index 55b29b6..d455970 100644
--- a/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
+++ b/maven-core/src/test/java/org/apache/maven/project/EmptyLifecycleExecutor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.Collections;
 import java.util.LinkedHashSet;
@@ -35,75 +34,58 @@
  * A stub implementation that assumes an empty lifecycle to bypass interaction with the plugin manager and to avoid
  * plugin artifact resolution from repositories.
  *
- * @author Benjamin Bentmann
  */
-public class EmptyLifecycleExecutor
-    implements LifecycleExecutor
-{
+public class EmptyLifecycleExecutor implements LifecycleExecutor {
 
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, String... tasks )
-    {
-        return new MavenExecutionPlan( null, null );
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, String... tasks) {
+        return new MavenExecutionPlan(null, null);
     }
 
-    public MavenExecutionPlan calculateExecutionPlan( MavenSession session, boolean setup, String... tasks )
-    {
-        return new MavenExecutionPlan( null, null );
+    public MavenExecutionPlan calculateExecutionPlan(MavenSession session, boolean setup, String... tasks) {
+        return new MavenExecutionPlan(null, null);
     }
 
-    public void execute( MavenSession session )
-    {
-    }
+    public void execute(MavenSession session) {}
 
-    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging )
-    {
+    public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles(String packaging) {
         Set<Plugin> plugins;
 
         // NOTE: The upper-case packaging name is intentional, that's a special hinting mode used for certain tests
-        if ( "JAR".equals( packaging ) )
-        {
+        if ("JAR".equals(packaging)) {
             plugins = new LinkedHashSet<>();
 
-            plugins.add( newPlugin( "maven-compiler-plugin", "compile", "testCompile" ) );
-            plugins.add( newPlugin( "maven-resources-plugin", "resources", "testResources" ) );
-            plugins.add( newPlugin( "maven-surefire-plugin", "test" ) );
-            plugins.add( newPlugin( "maven-jar-plugin", "jar" ) );
-            plugins.add( newPlugin( "maven-install-plugin", "install" ) );
-            plugins.add( newPlugin( "maven-deploy-plugin", "deploy" ) );
-        }
-        else
-        {
+            plugins.add(newPlugin("maven-compiler-plugin", "compile", "testCompile"));
+            plugins.add(newPlugin("maven-resources-plugin", "resources", "testResources"));
+            plugins.add(newPlugin("maven-surefire-plugin", "test"));
+            plugins.add(newPlugin("maven-jar-plugin", "jar"));
+            plugins.add(newPlugin("maven-install-plugin", "install"));
+            plugins.add(newPlugin("maven-deploy-plugin", "deploy"));
+        } else {
             plugins = Collections.emptySet();
         }
 
         return plugins;
     }
 
-    private Plugin newPlugin( String artifactId, String... goals )
-    {
+    private Plugin newPlugin(String artifactId, String... goals) {
         Plugin plugin = new Plugin();
 
-        plugin.setGroupId( "org.apache.maven.plugins" );
-        plugin.setArtifactId( artifactId );
+        plugin.setGroupId("org.apache.maven.plugins");
+        plugin.setArtifactId(artifactId);
 
-        for ( String goal : goals )
-        {
+        for (String goal : goals) {
             PluginExecution pluginExecution = new PluginExecution();
-            pluginExecution.setId( "default-" + goal );
-            pluginExecution.addGoal( goal );
-            plugin.addExecution( pluginExecution );
+            pluginExecution.setId("default-" + goal);
+            pluginExecution.setGoals(Collections.singletonList(goal));
+            plugin.addExecution(pluginExecution);
         }
 
         return plugin;
     }
 
-    public void calculateForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-    {
-    }
+    public void calculateForkedExecutions(MojoExecution mojoExecution, MavenSession session) {}
 
-    public List<MavenProject> executeForkedExecutions( MojoExecution mojoExecution, MavenSession session )
-    {
+    public List<MavenProject> executeForkedExecutions(MojoExecution mojoExecution, MavenSession session) {
         return Collections.emptyList();
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/EmptyProjectBuildingHelper.java b/maven-core/src/test/java/org/apache/maven/project/EmptyProjectBuildingHelper.java
index c843ca7..4fc9356 100644
--- a/maven-core/src/test/java/org/apache/maven/project/EmptyProjectBuildingHelper.java
+++ b/maven-core/src/test/java/org/apache/maven/project/EmptyProjectBuildingHelper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -29,34 +28,24 @@
 /**
  * A stub implementation to bypass artifact resolution from repositories.
  *
- * @author Benjamin Bentmann
  */
-public class EmptyProjectBuildingHelper
-    implements ProjectBuildingHelper
-{
+public class EmptyProjectBuildingHelper implements ProjectBuildingHelper {
 
-    public List<ArtifactRepository> createArtifactRepositories( List<Repository> pomRepositories,
-                                                                List<ArtifactRepository> externalRepositories,
-                                                                ProjectBuildingRequest request )
-    {
-        if ( externalRepositories != null )
-        {
+    public List<ArtifactRepository> createArtifactRepositories(
+            List<Repository> pomRepositories,
+            List<ArtifactRepository> externalRepositories,
+            ProjectBuildingRequest request) {
+        if (externalRepositories != null) {
             return externalRepositories;
-        }
-        else
-        {
+        } else {
             return new ArrayList<>();
         }
     }
 
-    public ProjectRealmCache.CacheRecord createProjectRealm( MavenProject project,
-                                                             Model model, ProjectBuildingRequest request )
-    {
-        return new ProjectRealmCache.CacheRecord( null, null );
+    public ProjectRealmCache.CacheRecord createProjectRealm(
+            MavenProject project, Model model, ProjectBuildingRequest request) {
+        return new ProjectRealmCache.CacheRecord(null, null);
     }
 
-    public void selectProjectRealm( MavenProject project )
-    {
-    }
-
+    public void selectProjectRealm(MavenProject project) {}
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java
index 150eb6a..5e73daa 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ExtensionDescriptorBuilderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
@@ -28,72 +27,59 @@
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.is;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.hamcrest.MatcherAssert.assertThat;
 
 /**
  * Tests {@link ExtensionDescriptorBuilder}.
  *
- * @author Benjamin Bentmann
  */
-public class ExtensionDescriptorBuilderTest
-{
+class ExtensionDescriptorBuilderTest {
 
     private ExtensionDescriptorBuilder builder;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
+    void setUp() throws Exception {
         builder = new ExtensionDescriptorBuilder();
     }
 
     @AfterEach
-    public void tearDown()
-        throws Exception
-    {
+    void tearDown() throws Exception {
         builder = null;
     }
 
-    private InputStream toStream( String xml )
-    {
-        return new ByteArrayInputStream( xml.getBytes( StandardCharsets.UTF_8 ) );
+    private InputStream toStream(String xml) {
+        return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
     }
 
     @Test
-    public void testEmptyDescriptor()
-        throws Exception
-    {
+    void testEmptyDescriptor() throws Exception {
         String xml = "<extension></extension>";
 
-        ExtensionDescriptor ed = builder.build( toStream( xml ) );
+        ExtensionDescriptor ed = builder.build(toStream(xml));
 
-        assertNotNull( ed );
-        assertNotNull( ed.getExportedPackages() );
-        assertThat( ed.getExportedPackages(), is( empty() ) );
-        assertNotNull( ed.getExportedArtifacts() );
-        assertThat( ed.getExportedArtifacts(), is( empty() ) );
+        assertNotNull(ed);
+        assertNotNull(ed.getExportedPackages());
+        assertThat(ed.getExportedPackages(), is(empty()));
+        assertNotNull(ed.getExportedArtifacts());
+        assertThat(ed.getExportedArtifacts(), is(empty()));
     }
 
     @Test
-    public void testCompleteDescriptor()
-        throws Exception
-    {
-        String xml =
-            "<?xml version='1.0' encoding='UTF-8'?>" + "<extension>" + "<exportedPackages>"
+    void testCompleteDescriptor() throws Exception {
+        String xml = "<?xml version='1.0' encoding='UTF-8'?>" + "<extension>" + "<exportedPackages>"
                 + "<exportedPackage>a</exportedPackage>" + "<exportedPackage>b</exportedPackage>"
                 + "<exportedPackage>c</exportedPackage>" + "</exportedPackages>" + "<exportedArtifacts>"
                 + "<exportedArtifact>x</exportedArtifact>" + "<exportedArtifact>y</exportedArtifact>"
                 + "<exportedArtifact> z </exportedArtifact>" + "</exportedArtifacts>" + "</extension>";
 
-        ExtensionDescriptor ed = builder.build( toStream( xml ) );
+        ExtensionDescriptor ed = builder.build(toStream(xml));
 
-        assertNotNull( ed );
-        assertEquals( Arrays.asList( "a", "b", "c" ), ed.getExportedPackages() );
-        assertEquals( Arrays.asList( "x", "y", "z" ), ed.getExportedArtifacts() );
+        assertNotNull(ed);
+        assertEquals(Arrays.asList("a", "b", "c"), ed.getExportedPackages());
+        assertEquals(Arrays.asList("x", "y", "z"), ed.getExportedArtifacts());
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/GraphTest.java b/maven-core/src/test/java/org/apache/maven/project/GraphTest.java
new file mode 100644
index 0000000..ef2b832
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/project/GraphTest.java
@@ -0,0 +1,233 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.project;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.maven.project.Graph.Vertex;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class GraphTest {
+
+    @Test
+    public void testGraph() throws CycleDetectedException {
+        Graph graph = new Graph();
+        graph.addVertex("a");
+        assertEquals(1, graph.getVertices().size());
+        assertEquals("a", graph.getVertex("a").getLabel());
+        graph.addVertex("a");
+        assertEquals(1, graph.getVertices().size());
+        assertEquals("a", graph.getVertex("a").getLabel());
+
+        graph.addVertex("b");
+        assertEquals(2, graph.getVertices().size());
+        assertFalse(hasEdge(graph, "a", "b"));
+        assertFalse(hasEdge(graph, "b", "a"));
+
+        Vertex a = graph.getVertex("a");
+        Vertex b = graph.getVertex("b");
+        assertEquals("a", a.getLabel());
+        assertEquals("b", b.getLabel());
+
+        addEdge(graph, "a", "b");
+        assertTrue(a.getChildren().contains(b));
+        assertTrue(b.getParents().contains(a));
+        assertTrue(hasEdge(graph, "a", "b"));
+        assertFalse(hasEdge(graph, "b", "a"));
+
+        addEdge(graph, "c", "d");
+        assertEquals(4, graph.getVertices().size());
+
+        Vertex c = graph.getVertex("c");
+        Vertex d = graph.getVertex("d");
+        assertEquals("a", a.getLabel());
+        assertEquals("b", b.getLabel());
+        assertEquals("c", c.getLabel());
+        assertEquals("d", d.getLabel());
+        assertFalse(hasEdge(graph, "b", "a"));
+        assertFalse(hasEdge(graph, "a", "c"));
+        assertFalse(hasEdge(graph, "a", "d"));
+        assertTrue(hasEdge(graph, "c", "d"));
+        assertFalse(hasEdge(graph, "d", "c"));
+
+        Set<String> labels = graph.getVertices().stream().map(Vertex::getLabel).collect(Collectors.toSet());
+        assertEquals(4, labels.size());
+        assertTrue(labels.contains("a"));
+        assertTrue(labels.contains("b"));
+        assertTrue(labels.contains("c"));
+        assertTrue(labels.contains("d"));
+
+        addEdge(graph, "a", "d");
+        assertEquals(2, a.getChildren().size());
+        assertTrue(a.getChildren().contains(b));
+        assertTrue(a.getChildren().contains(d));
+        assertEquals(2, d.getParents().size());
+        assertTrue(d.getParents().contains(a));
+        assertTrue(d.getParents().contains(c));
+    }
+
+    @Test
+    public void testCycleDetection() throws Exception {
+        Graph graph1 = new Graph();
+        addEdge(graph1, "a", "b");
+        addEdge(graph1, "b", "c");
+
+        Graph graph2 = new Graph();
+        addEdge(graph2, "a", "b");
+        addEdge(graph2, "b", "c");
+        CycleDetectedException cde = assertThrows(CycleDetectedException.class, () -> addEdge(graph2, "c", "a"));
+        List<String> cycle = cde.getCycle();
+        assertNotNull(cycle, "Cycle should be not null");
+        assertTrue(cycle.contains("a"), "Cycle contains 'a'");
+        assertTrue(cycle.contains("b"), "Cycle contains 'b'");
+        assertTrue(cycle.contains("c"), "Cycle contains 'c'");
+
+        Graph graph3 = new Graph();
+        addEdge(graph3, "a", "b");
+        addEdge(graph3, "b", "c");
+        addEdge(graph3, "b", "d");
+        addEdge(graph3, "a", "d");
+
+        Graph graph4 = new Graph();
+        addEdge(graph4, "a", "b");
+        addEdge(graph4, "b", "c");
+        addEdge(graph4, "b", "d");
+        addEdge(graph4, "a", "d");
+        cde = assertThrows(CycleDetectedException.class, () -> addEdge(graph4, "c", "a"));
+        assertEquals(Arrays.asList("a", "b", "c", "a"), cde.getCycle());
+
+        Graph graph5 = new Graph();
+        addEdge(graph5, "a", "b");
+        addEdge(graph5, "b", "c");
+        addEdge(graph5, "b", "f");
+        addEdge(graph5, "f", "g");
+        addEdge(graph5, "g", "h");
+        addEdge(graph5, "c", "d");
+        addEdge(graph5, "d", "e");
+        cde = assertThrows(CycleDetectedException.class, () -> addEdge(graph5, "e", "b"));
+        assertEquals(Arrays.asList("b", "c", "d", "e", "b"), cde.getCycle());
+        assertTrue(hasEdge(graph5, "a", "b"));
+        assertTrue(hasEdge(graph5, "b", "c"));
+        assertTrue(hasEdge(graph5, "b", "f"));
+        assertTrue(hasEdge(graph5, "f", "g"));
+        assertTrue(hasEdge(graph5, "g", "h"));
+        assertTrue(hasEdge(graph5, "c", "d"));
+        assertTrue(hasEdge(graph5, "d", "e"));
+        assertFalse(hasEdge(graph5, "e", "b"));
+    }
+
+    @Test
+    public void testDfs() throws CycleDetectedException {
+        Graph graph1 = new Graph();
+        addEdge(graph1, "a", "b");
+        addEdge(graph1, "b", "c");
+        List<String> expected1 = new ArrayList<>();
+        expected1.add("c");
+        expected1.add("b");
+        expected1.add("a");
+        List<String> actual1 = graph1.visitAll();
+        assertEquals(expected1, actual1);
+
+        Graph graph2 = new Graph();
+        graph2.addVertex("a");
+        graph2.addVertex("b");
+        graph2.addVertex("c");
+        addEdge(graph2, "b", "a");
+        addEdge(graph2, "c", "b");
+        List<String> expected2 = new ArrayList<>();
+        expected2.add("a");
+        expected2.add("b");
+        expected2.add("c");
+        List<String> actual2 = graph2.visitAll();
+        assertEquals(expected2, actual2);
+
+        Graph graph3 = new Graph();
+        graph3.addVertex("a");
+        graph3.addVertex("b");
+        graph3.addVertex("c");
+        graph3.addVertex("d");
+        graph3.addVertex("e");
+        graph3.addVertex("f");
+        addEdge(graph3, "a", "b");
+        addEdge(graph3, "b", "c");
+        addEdge(graph3, "b", "d");
+        addEdge(graph3, "c", "d");
+        addEdge(graph3, "c", "e");
+        addEdge(graph3, "f", "d");
+        addEdge(graph3, "e", "f");
+        addEdge(graph3, "f", "g");
+        List<String> expected3 = new ArrayList<>();
+        expected3.add("d");
+        expected3.add("g");
+        expected3.add("f");
+        expected3.add("e");
+        expected3.add("c");
+        expected3.add("b");
+        expected3.add("a");
+        List<String> actual3 = graph3.visitAll();
+        assertEquals(expected3, actual3);
+
+        Graph graph4 = new Graph();
+        graph4.addVertex("f");
+        graph4.addVertex("e");
+        graph4.addVertex("d");
+        graph4.addVertex("c");
+        graph4.addVertex("a");
+        graph4.addVertex("b");
+        addEdge(graph4, "a", "b");
+        addEdge(graph4, "b", "c");
+        addEdge(graph4, "b", "d");
+        addEdge(graph4, "c", "d");
+        addEdge(graph4, "c", "e");
+        addEdge(graph4, "f", "d");
+        addEdge(graph4, "e", "f");
+
+        List<String> expected4 = new ArrayList<>();
+        expected4.add("d");
+        expected4.add("f");
+        expected4.add("e");
+        expected4.add("c");
+        expected4.add("b");
+        expected4.add("a");
+        List<String> actual4 = graph4.visitAll();
+        assertEquals(expected4, actual4);
+    }
+
+    static void addEdge(Graph graph, String v1, String v2) throws CycleDetectedException {
+        Vertex vx1 = graph.addVertex(v1);
+        Vertex vx2 = graph.addVertex(v2);
+        graph.addEdge(vx1, vx2);
+    }
+
+    static boolean hasEdge(Graph graph, String v1, String v2) {
+        Vertex vx1 = graph.getVertex(v1);
+        Vertex vx2 = graph.getVertex(v2);
+        return vx1 != null && vx2 != null && vx1.children.contains(vx2);
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java b/maven-core/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java
index a685bc1..b49af81 100644
--- a/maven-core/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java
+++ b/maven-core/src/test/java/org/apache/maven/project/LegacyLocalRepositoryManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 
@@ -35,126 +34,103 @@
 import org.eclipse.aether.repository.RemoteRepository;
 
 /**
- * @author Benjamin Bentmann
  */
-public class LegacyLocalRepositoryManager
-    implements LocalRepositoryManager
-{
+public class LegacyLocalRepositoryManager implements LocalRepositoryManager {
 
     private final LocalRepository repository;
 
-    LegacyLocalRepositoryManager( File basedir )
-    {
-        this.repository = new LocalRepository( basedir.getAbsoluteFile(), "legacy" );
+    LegacyLocalRepositoryManager(File basedir) {
+        this.repository = new LocalRepository(basedir.getAbsoluteFile(), "legacy");
     }
 
-    public LocalRepository getRepository()
-    {
+    public LocalRepository getRepository() {
         return repository;
     }
 
-    public String getPathForLocalArtifact( Artifact artifact )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    public String getPathForLocalArtifact(Artifact artifact) {
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( artifact.getGroupId() ).append( '/' );
+        path.append(artifact.getGroupId()).append('/');
 
-        path.append( artifact.getExtension() ).append( "s/" );
+        path.append(artifact.getExtension()).append("s/");
 
-        path.append( artifact.getArtifactId() ).append( '-' ).append( artifact.getVersion() );
+        path.append(artifact.getArtifactId()).append('-').append(artifact.getVersion());
 
-        if ( artifact.getClassifier().length() > 0 )
-        {
-            path.append( '-' ).append( artifact.getClassifier() );
+        if (artifact.getClassifier().length() > 0) {
+            path.append('-').append(artifact.getClassifier());
         }
 
-        path.append( '.' ).append( artifact.getExtension() );
+        path.append('.').append(artifact.getExtension());
 
         return path.toString();
     }
 
-    public String getPathForRemoteArtifact( Artifact artifact, RemoteRepository repository, String context )
-    {
-        return getPathForLocalArtifact( artifact );
+    public String getPathForRemoteArtifact(Artifact artifact, RemoteRepository repository, String context) {
+        return getPathForLocalArtifact(artifact);
     }
 
-    public String getPathForLocalMetadata( Metadata metadata )
-    {
-        return getPath( metadata, "local" );
+    public String getPathForLocalMetadata(Metadata metadata) {
+        return getPath(metadata, "local");
     }
 
-    public String getPathForRemoteMetadata( Metadata metadata, RemoteRepository repository, String context )
-    {
-        return getPath( metadata, getRepositoryKey( repository, context ) );
+    public String getPathForRemoteMetadata(Metadata metadata, RemoteRepository repository, String context) {
+        return getPath(metadata, getRepositoryKey(repository, context));
     }
 
-    String getRepositoryKey( RemoteRepository repository, String context )
-    {
+    String getRepositoryKey(RemoteRepository repository, String context) {
         return repository.getId();
     }
 
-    private String getPath( Metadata metadata, String repositoryKey )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    private String getPath(Metadata metadata, String repositoryKey) {
+        StringBuilder path = new StringBuilder(128);
 
-        if ( metadata.getGroupId().length() > 0 )
-        {
-            path.append( metadata.getGroupId().replace( '.', '/' ) ).append( '/' );
+        if (metadata.getGroupId().length() > 0) {
+            path.append(metadata.getGroupId().replace('.', '/')).append('/');
 
-            if ( metadata.getArtifactId().length() > 0 )
-            {
-                path.append( metadata.getArtifactId() ).append( '/' );
+            if (metadata.getArtifactId().length() > 0) {
+                path.append(metadata.getArtifactId()).append('/');
 
-                if ( metadata.getVersion().length() > 0 )
-                {
-                    path.append( metadata.getVersion() ).append( '/' );
+                if (metadata.getVersion().length() > 0) {
+                    path.append(metadata.getVersion()).append('/');
                 }
             }
         }
 
-        path.append( insertRepositoryKey( metadata.getType(), repositoryKey ) );
+        path.append(insertRepositoryKey(metadata.getType(), repositoryKey));
 
         return path.toString();
     }
 
-    private String insertRepositoryKey( String filename, String repositoryKey )
-    {
+    private String insertRepositoryKey(String filename, String repositoryKey) {
         String result;
-        int idx = filename.indexOf( '.' );
-        if ( idx < 0 )
-        {
+        int idx = filename.indexOf('.');
+        if (idx < 0) {
             result = filename + '-' + repositoryKey;
-        }
-        else
-        {
-            result = filename.substring( 0, idx ) + '-' + repositoryKey + filename.substring( idx );
+        } else {
+            result = filename.substring(0, idx) + '-' + repositoryKey + filename.substring(idx);
         }
         return result;
     }
 
-    public LocalArtifactResult find( RepositorySystemSession session, LocalArtifactRequest request )
-    {
-        String path = getPathForLocalArtifact( request.getArtifact() );
-        File file = new File( getRepository().getBasedir(), path );
+    public LocalArtifactResult find(RepositorySystemSession session, LocalArtifactRequest request) {
+        String path = getPathForLocalArtifact(request.getArtifact());
+        File file = new File(getRepository().getBasedir(), path);
 
-        LocalArtifactResult result = new LocalArtifactResult( request );
-        if ( file.isFile() )
-        {
-            result.setFile( file );
-            result.setAvailable( true );
+        LocalArtifactResult result = new LocalArtifactResult(request);
+        if (file.isFile()) {
+            result.setFile(file);
+            result.setAvailable(true);
         }
 
         return result;
     }
 
-    public void add( RepositorySystemSession session, LocalArtifactRegistration request )
-    {
+    public void add(RepositorySystemSession session, LocalArtifactRegistration request) {
         // noop
     }
 
-    public LocalMetadataResult find( RepositorySystemSession session, LocalMetadataRequest request )
-    {
-        LocalMetadataResult result = new LocalMetadataResult( request );
+    public LocalMetadataResult find(RepositorySystemSession session, LocalMetadataRequest request) {
+        LocalMetadataResult result = new LocalMetadataResult(request);
 
         String path;
 
@@ -162,31 +138,25 @@
         String context = request.getContext();
         RemoteRepository remote = request.getRepository();
 
-        if ( remote != null )
-        {
-            path = getPathForRemoteMetadata( metadata, remote, context );
-        }
-        else
-        {
-            path = getPathForLocalMetadata( metadata );
+        if (remote != null) {
+            path = getPathForRemoteMetadata(metadata, remote, context);
+        } else {
+            path = getPathForLocalMetadata(metadata);
         }
 
-        File file = new File( getRepository().getBasedir(), path );
-        if ( file.isFile() )
-        {
-            result.setFile( file );
+        File file = new File(getRepository().getBasedir(), path);
+        if (file.isFile()) {
+            result.setFile(file);
         }
 
         return result;
     }
 
-    public void add( RepositorySystemSession session, LocalMetadataRegistration request )
-    {
+    public void add(RepositorySystemSession session, LocalMetadataRegistration request) {
         // noop
     }
 
-    public String toString()
-    {
-        return String.valueOf( getRepository() );
+    public String toString() {
+        return String.valueOf(getRepository());
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java b/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
index d2cba20..402fd30 100644
--- a/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/MavenProjectTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.io.IOException;
@@ -36,201 +35,184 @@
 import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class MavenProjectTest
-    extends AbstractMavenProjectTestCase
-{
+class MavenProjectTest extends AbstractMavenProjectTestCase {
 
     @Test
-    public void testShouldInterpretChildPathAdjustmentBasedOnModulePaths()
-        throws IOException
-    {
+    void testShouldInterpretChildPathAdjustmentBasedOnModulePaths() throws IOException {
         Model parentModel = new Model();
-        parentModel.addModule( "../child" );
+        parentModel.addModule("../child");
 
-        MavenProject parentProject = new MavenProject( parentModel );
+        MavenProject parentProject = new MavenProject(parentModel);
 
         Model childModel = new Model();
-        childModel.setArtifactId( "artifact" );
+        childModel.setArtifactId("artifact");
 
-        MavenProject childProject = new MavenProject( childModel );
+        MavenProject childProject = new MavenProject(childModel);
 
-        File childFile =
-            new File( System.getProperty( "java.io.tmpdir" ), "maven-project-tests" + System.currentTimeMillis()
-                + "/child/pom.xml" );
+        File childFile = new File(
+                System.getProperty("java.io.tmpdir"),
+                "maven-project-tests" + System.currentTimeMillis() + "/child/pom.xml");
 
-        childProject.setFile( childFile );
+        childProject.setFile(childFile);
 
-        String adjustment = parentProject.getModulePathAdjustment( childProject );
+        String adjustment = parentProject.getModulePathAdjustment(childProject);
 
-        assertNotNull( adjustment );
+        assertNotNull(adjustment);
 
-        assertEquals( "..", adjustment );
+        assertEquals("..", adjustment);
     }
 
     @Test
-    public void testIdentityProtoInheritance()
-    {
+    void testIdentityProtoInheritance() {
         Parent parent = new Parent();
 
-        parent.setGroupId( "test-group" );
-        parent.setVersion( "1000" );
-        parent.setArtifactId( "test-artifact" );
+        parent.setGroupId("test-group");
+        parent.setVersion("1000");
+        parent.setArtifactId("test-artifact");
 
         Model model = new Model();
 
-        model.setParent( parent );
-        model.setArtifactId( "real-artifact" );
+        model.setParent(parent);
+        model.setArtifactId("real-artifact");
 
-        MavenProject project = new MavenProject( model );
+        MavenProject project = new MavenProject(model);
 
-        assertEquals( "test-group", project.getGroupId(), "groupId proto-inheritance failed." );
-        assertEquals( "real-artifact", project.getArtifactId(), "artifactId is masked." );
-        assertEquals( "1000", project.getVersion(), "version proto-inheritance failed." );
+        assertEquals("test-group", project.getGroupId(), "groupId proto-inheritance failed.");
+        assertEquals("real-artifact", project.getArtifactId(), "artifactId is masked.");
+        assertEquals("1000", project.getVersion(), "version proto-inheritance failed.");
 
         // draw the NPE.
         project.getId();
     }
 
     @Test
-    public void testEmptyConstructor()
-    {
+    void testEmptyConstructor() {
         MavenProject project = new MavenProject();
 
-        assertEquals( MavenProject.EMPTY_PROJECT_GROUP_ID + ":" + MavenProject.EMPTY_PROJECT_ARTIFACT_ID + ":jar:"
-                        + MavenProject.EMPTY_PROJECT_VERSION, project.getId() );
+        assertEquals(
+                MavenProject.EMPTY_PROJECT_GROUP_ID + ":" + MavenProject.EMPTY_PROJECT_ARTIFACT_ID + ":jar:"
+                        + MavenProject.EMPTY_PROJECT_VERSION,
+                project.getId());
     }
 
     @Test
-    public void testClone()
-        throws Exception
-    {
-        File f = getFileForClasspathResource( "canonical-pom.xml" );
-        MavenProject projectToClone = getProject( f );
+    void testClone() throws Exception {
+        File f = getFileForClasspathResource("canonical-pom.xml");
+        MavenProject projectToClone = getProject(f);
 
         MavenProject clonedProject = projectToClone.clone();
-        assertEquals( "maven-core", clonedProject.getArtifactId() );
+        assertEquals("maven-core", clonedProject.getArtifactId());
         Map<?, ?> clonedMap = clonedProject.getManagedVersionMap();
-        assertNotNull( clonedMap, "ManagedVersionMap not copied" );
-        assertTrue( clonedMap.isEmpty(), "ManagedVersionMap is not empty" );
+        assertNotNull(clonedMap, "ManagedVersionMap not copied");
+        assertTrue(clonedMap.isEmpty(), "ManagedVersionMap is not empty");
     }
 
     @Test
-    public void testCloneWithDependencyManagement()
-        throws Exception
-    {
-        File f = getFileForClasspathResource( "dependencyManagement-pom.xml" );
-        MavenProject projectToClone = getProjectWithDependencies( f );
+    void testCloneWithDependencyManagement() throws Exception {
+        File f = getFileForClasspathResource("dependencyManagement-pom.xml");
+        MavenProject projectToClone = getProjectWithDependencies(f);
         DependencyManagement dep = projectToClone.getDependencyManagement();
-        assertNotNull( dep, "No dependencyManagement" );
+        assertNotNull(dep, "No dependencyManagement");
         List<?> list = dep.getDependencies();
-        assertNotNull( list, "No dependencies" );
-        assertTrue( !list.isEmpty(), "Empty dependency list" );
+        assertNotNull(list, "No dependencies");
+        assertTrue(!list.isEmpty(), "Empty dependency list");
 
         Map<?, ?> map = projectToClone.getManagedVersionMap();
-        assertNotNull( map, "No ManagedVersionMap" );
-        assertTrue( !map.isEmpty(), "ManagedVersionMap is empty" );
+        assertNotNull(map, "No ManagedVersionMap");
+        assertTrue(!map.isEmpty(), "ManagedVersionMap is empty");
 
         MavenProject clonedProject = projectToClone.clone();
-        assertEquals( "maven-core", clonedProject.getArtifactId() );
+        assertEquals("maven-core", clonedProject.getArtifactId());
         Map<?, ?> clonedMap = clonedProject.getManagedVersionMap();
-        assertNotNull( clonedMap, "ManagedVersionMap not copied" );
-        assertTrue( !clonedMap.isEmpty(), "ManagedVersionMap is empty" );
-        assertTrue( clonedMap.containsKey( "maven-test:maven-test-b:jar" ), "ManagedVersionMap does not contain test key" );
+        assertNotNull(clonedMap, "ManagedVersionMap not copied");
+        assertTrue(!clonedMap.isEmpty(), "ManagedVersionMap is empty");
+        assertTrue(clonedMap.containsKey("maven-test:maven-test-b:jar"), "ManagedVersionMap does not contain test key");
     }
 
     @Test
-    public void testGetModulePathAdjustment()
-        throws IOException
-    {
+    void testGetModulePathAdjustment() throws IOException {
         Model moduleModel = new Model();
 
-        MavenProject module = new MavenProject( moduleModel );
-        module.setFile( new File( "module-dir/pom.xml" ) );
+        MavenProject module = new MavenProject(moduleModel);
+        module.setFile(new File("module-dir/pom.xml"));
 
         Model parentModel = new Model();
-        parentModel.addModule( "../module-dir" );
+        parentModel.addModule("../module-dir");
 
-        MavenProject parent = new MavenProject( parentModel );
-        parent.setFile( new File( "parent-dir/pom.xml" ) );
+        MavenProject parent = new MavenProject(parentModel);
+        parent.setFile(new File("parent-dir/pom.xml"));
 
-        String pathAdjustment = parent.getModulePathAdjustment( module );
+        String pathAdjustment = parent.getModulePathAdjustment(module);
 
-        assertEquals( "..", pathAdjustment );
+        assertEquals("..", pathAdjustment);
     }
 
     @Test
-    public void testCloneWithDistributionManagement()
-        throws Exception
-    {
+    void testCloneWithDistributionManagement() throws Exception {
 
-        File f = getFileForClasspathResource( "distributionManagement-pom.xml" );
-        MavenProject projectToClone = getProject( f );
+        File f = getFileForClasspathResource("distributionManagement-pom.xml");
+        MavenProject projectToClone = getProject(f);
 
         MavenProject clonedProject = projectToClone.clone();
-        assertNotNull( clonedProject.getDistributionManagementArtifactRepository(), "clonedProject - distributionManagement" );
+        assertNotNull(
+                clonedProject.getDistributionManagementArtifactRepository(), "clonedProject - distributionManagement");
     }
 
     @Test
-    public void testCloneWithActiveProfile()
-        throws Exception
-    {
+    void testCloneWithActiveProfile() throws Exception {
 
-        File f = getFileForClasspathResource( "withActiveByDefaultProfile-pom.xml" );
-        MavenProject projectToClone = getProject( f );
+        File f = getFileForClasspathResource("withActiveByDefaultProfile-pom.xml");
+        MavenProject projectToClone = getProject(f);
         List<Profile> activeProfilesOrig = projectToClone.getActiveProfiles();
 
-        assertEquals( 1, activeProfilesOrig.size(), "Expecting 1 active profile" );
+        assertEquals(1, activeProfilesOrig.size(), "Expecting 1 active profile");
 
         MavenProject clonedProject = projectToClone.clone();
 
         List<Profile> activeProfilesClone = clonedProject.getActiveProfiles();
 
-        assertEquals( 1, activeProfilesClone.size(), "Expecting 1 active profile" );
+        assertEquals(1, activeProfilesClone.size(), "Expecting 1 active profile");
 
-        assertNotSame( activeProfilesOrig, activeProfilesClone,
-                      "The list of active profiles should have been cloned too but is same" );
+        assertNotSame(
+                activeProfilesOrig,
+                activeProfilesClone,
+                "The list of active profiles should have been cloned too but is same");
     }
 
     @Test
-    public void testCloneWithBaseDir()
-        throws Exception
-    {
-        File f = getFileForClasspathResource( "canonical-pom.xml" );
-        MavenProject projectToClone = getProject( f );
-        projectToClone.setPomFile( new File( new File( f.getParentFile(), "target" ), "flattened.xml" ) );
+    void testCloneWithBaseDir() throws Exception {
+        File f = getFileForClasspathResource("canonical-pom.xml");
+        MavenProject projectToClone = getProject(f);
+        projectToClone.setPomFile(new File(new File(f.getParentFile(), "target"), "flattened.xml"));
         MavenProject clonedProject = projectToClone.clone();
-        assertEquals( projectToClone.getFile(), clonedProject.getFile(), "POM file is preserved across clone" );
-        assertEquals( projectToClone.getBasedir(), clonedProject.getBasedir(), "Base directory is preserved across clone" );
+        assertEquals(projectToClone.getFile(), clonedProject.getFile(), "POM file is preserved across clone");
+        assertEquals(
+                projectToClone.getBasedir(), clonedProject.getBasedir(), "Base directory is preserved across clone");
     }
 
     @Test
-    public void testUndefinedOutputDirectory()
-        throws Exception
-    {
+    void testUndefinedOutputDirectory() throws Exception {
         MavenProject p = new MavenProject();
-        assertNoNulls( p.getCompileClasspathElements() );
-        assertNoNulls( p.getSystemClasspathElements() );
-        assertNoNulls( p.getRuntimeClasspathElements() );
-        assertNoNulls( p.getTestClasspathElements() );
+        assertNoNulls(p.getCompileClasspathElements());
+        assertNoNulls(p.getSystemClasspathElements());
+        assertNoNulls(p.getRuntimeClasspathElements());
+        assertNoNulls(p.getTestClasspathElements());
     }
 
     @Test
-    public void testAddDotFile()
-    {
+    void testAddDotFile() {
         MavenProject project = new MavenProject();
 
-        File basedir = new File( System.getProperty( "java.io.tmpdir" ) );
-        project.setFile( new File( basedir, "file" ) );
+        File basedir = new File(System.getProperty("java.io.tmpdir"));
+        project.setFile(new File(basedir, "file"));
 
-        project.addCompileSourceRoot( basedir.getAbsolutePath() );
-        project.addCompileSourceRoot( "." );
+        project.addCompileSourceRoot(basedir.getAbsolutePath());
+        project.addCompileSourceRoot(".");
 
-        assertEquals( 1, project.getCompileSourceRoots().size() );
+        assertEquals(1, project.getCompileSourceRoots().size());
     }
 
-    private void assertNoNulls( List<String> elements )
-    {
-        assertFalse( elements.contains( null ) );
+    private void assertNoNulls(List<String> elements) {
+        assertFalse(elements.contains(null));
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java
index c2ab83c..feb6556 100644
--- a/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/PomConstructionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
+
+import javax.inject.Inject;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -26,16 +27,18 @@
 import java.util.Map;
 import java.util.Properties;
 
-import javax.inject.Inject;
-
-import org.codehaus.plexus.testing.PlexusTest;
 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.bridge.MavenRepositorySystem;
+import org.apache.maven.model.Model;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginExecution;
+import org.apache.maven.model.Profile;
+import org.apache.maven.model.ReportPlugin;
+import org.apache.maven.model.ReportSet;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.project.harness.PomTestWrapper;
-import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
+import org.codehaus.plexus.testing.PlexusTest;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
 import org.eclipse.aether.repository.LocalRepository;
@@ -48,15 +51,16 @@
 import static org.hamcrest.Matchers.lessThan;
 import static org.hamcrest.Matchers.startsWith;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertSame;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 @PlexusTest
-public class PomConstructionTest
-{
+class PomConstructionTest {
     private static String BASE_DIR = "src/test";
 
     private static String BASE_POM_DIR = BASE_DIR + "/resources-project-builder";
@@ -67,16 +71,14 @@
     private DefaultProjectBuilder projectBuilder;
 
     @Inject
-    private RepositorySystem repositorySystem;
+    private MavenRepositorySystem repositorySystem;
 
     private File testDirectory;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        testDirectory = new File( getBasedir(), BASE_POM_DIR );
-        new File( getBasedir(), BASE_MIXIN_DIR );
+    void setUp() throws Exception {
+        testDirectory = new File(getBasedir(), BASE_POM_DIR);
+        new File(getBasedir(), BASE_MIXIN_DIR);
     }
 
     /**
@@ -85,10 +87,8 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testEmptyUrl()
-        throws Exception
-    {
-        buildPom( "empty-distMng-repo-url" );
+    void testEmptyUrl() throws Exception {
+        buildPom("empty-distMng-repo-url");
     }
 
     /**
@@ -98,16 +98,14 @@
      */
     /* MNG-786*/
     @Test
-    public void testProfileModules()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "profile-module", "a" );
-        assertEquals( "test-prop", pom.getValue( "properties[1]/b" ) );// verifies profile applied
-        assertEquals( 4, ( (List<?>) pom.getValue( "modules" ) ).size() );
-        assertEquals( "module-2", pom.getValue( "modules[1]" ) );
-        assertEquals( "module-1", pom.getValue( "modules[2]" ) );
-        assertEquals( "module-3", pom.getValue( "modules[3]" ) );
-        assertEquals( "module-4", pom.getValue( "modules[4]" ) );
+    void testProfileModules() throws Exception {
+        PomTestWrapper pom = buildPom("profile-module", "a");
+        assertEquals("test-prop", pom.getValue("properties[1]/b")); // verifies profile applied
+        assertEquals(4, ((List<?>) pom.getValue("modules")).size());
+        assertEquals("module-2", pom.getValue("modules[1]"));
+        assertEquals("module-1", pom.getValue("modules[2]"));
+        assertEquals("module-3", pom.getValue("modules[3]"));
+        assertEquals("module-4", pom.getValue("modules[4]"));
     }
 
     /**
@@ -116,40 +114,228 @@
      * @throws Exception in case of issue
      */
     @Test
-    public void testParentInheritance()
-        throws Exception
-    {
-        buildPom( "parent-inheritance/sub" );
+    void testParentInheritance() throws Exception {
+        buildPom("parent-inheritance/sub");
     }
 
     /*MNG-3995*/
     @Test
-    public void testExecutionConfigurationJoin()
-       throws Exception
-    {
-        PomTestWrapper pom = buildPom( "execution-configuration-join" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/configuration[1]/fileset[1]" ) ).size() );
+    void testExecutionConfigurationJoin() throws Exception {
+        PomTestWrapper pom = buildPom("execution-configuration-join");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/configuration[1]/fileset[1]")).size());
     }
 
     /*MNG-3803*/
     @Test
-    public void testPluginConfigProperties()
-       throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-properties" );
-        assertEquals( "my.property", pom.getValue( "build/plugins[1]/configuration[1]/systemProperties[1]/property[1]/name" ) );
+    void testPluginConfigProperties() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-properties");
+        assertEquals(
+                "my.property", pom.getValue("build/plugins[1]/configuration[1]/systemProperties[1]/property[1]/name"));
     }
 
     /*MNG-3900*/
     @Test
-    public void testProfilePropertiesInterpolation()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "profile-properties-interpolation", "interpolation-profile" );
-        assertEquals( "PASSED", pom.getValue( "properties[1]/test" ) );
-        assertEquals( "PASSED", pom.getValue( "properties[1]/property" ) );
+    void testProfilePropertiesInterpolation() throws Exception {
+        PomTestWrapper pom = buildPom("profile-properties-interpolation", "interpolation-profile");
+        assertEquals("PASSED", pom.getValue("properties[1]/test"));
+        assertEquals("PASSED", pom.getValue("properties[1]/property"));
     }
 
+    /*MNG-7750*/
+    private void checkBuildPluginWithArtifactId(
+            List<Plugin> plugins, String artifactId, String expectedId, String expectedConfig) {
+        Plugin plugin = plugins.stream()
+                .filter(p -> p.getArtifactId().equals(artifactId))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(plugin, "Unable to find plugin with artifactId: " + artifactId);
+        List<PluginExecution> pluginExecutions = plugin.getExecutions();
+        PluginExecution pluginExecution = pluginExecutions.stream()
+                .filter(pe -> pe.getId().equals(expectedId))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(pluginExecution, "Wrong id for \"" + artifactId + "\"");
+
+        String config = pluginExecution.getConfiguration().toString();
+        assertTrue(
+                config.contains(expectedConfig),
+                "Wrong config for \"" + artifactId + "\": (" + config + ") does not contain :" + expectedConfig);
+    }
+
+    private boolean isActiveProfile(MavenProject project, Profile activeProfile) {
+        return project.getActiveProfiles().stream().anyMatch(p -> p.getId().equals(activeProfile.getId()));
+    }
+
+    @Test
+    void testBuildPluginInterpolation() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-interpolation-build", "activeProfile");
+        Model originalModel = pom.getMavenProject().getOriginalModel();
+
+        // =============================================
+        assertEquals("||${project.basedir}||", originalModel.getProperties().get("prop-outside"));
+
+        List<Plugin> outsidePlugins = originalModel.getBuild().getPlugins();
+        assertEquals(1, outsidePlugins.size());
+
+        checkBuildPluginWithArtifactId(
+                outsidePlugins,
+                "plugin-all-profiles",
+                "Outside ||${project.basedir}||",
+                "<plugin-all-profiles-out>Outside ||${project.basedir}||</plugin-all-profiles-out>");
+
+        // =============================================
+        Profile activeProfile = originalModel.getProfiles().stream()
+                .filter(profile -> profile.getId().equals("activeProfile"))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(activeProfile, "Unable to find the activeProfile");
+
+        assertTrue(
+                isActiveProfile(pom.getMavenProject(), activeProfile),
+                "The activeProfile should be active in the maven project");
+
+        assertEquals("||${project.basedir}||", activeProfile.getProperties().get("prop-active"));
+
+        List<Plugin> activeProfilePlugins = activeProfile.getBuild().getPlugins();
+        assertEquals(2, activeProfilePlugins.size(), "Number of active profile plugins");
+
+        checkBuildPluginWithArtifactId(
+                activeProfilePlugins,
+                "plugin-all-profiles",
+                "Active all ||${project.basedir}||",
+                "<plugin-all-profiles-in>Active all ||${project.basedir}||</plugin-all-profiles-in>");
+
+        checkBuildPluginWithArtifactId(
+                activeProfilePlugins,
+                "only-active-profile",
+                "Active only ||${project.basedir}||",
+                "<plugin-in-active-profile-only>Active only ||${project.basedir}||</plugin-in-active-profile-only>");
+
+        // =============================================
+
+        Profile inactiveProfile = originalModel.getProfiles().stream()
+                .filter(profile -> profile.getId().equals("inactiveProfile"))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(inactiveProfile, "Unable to find the inactiveProfile");
+
+        assertFalse(
+                isActiveProfile(pom.getMavenProject(), inactiveProfile),
+                "The inactiveProfile should NOT be active in the maven project");
+
+        assertEquals("||${project.basedir}||", inactiveProfile.getProperties().get("prop-inactive"));
+
+        List<Plugin> inactiveProfilePlugins = inactiveProfile.getBuild().getPlugins();
+        assertEquals(2, inactiveProfilePlugins.size(), "Number of active profile plugins");
+
+        checkBuildPluginWithArtifactId(
+                inactiveProfilePlugins,
+                "plugin-all-profiles",
+                "Inactive all ||${project.basedir}||",
+                "<plugin-all-profiles-ina>Inactive all ||${project.basedir}||</plugin-all-profiles-ina>");
+
+        checkBuildPluginWithArtifactId(
+                inactiveProfilePlugins,
+                "only-inactive-profile",
+                "Inactive only ||${project.basedir}||",
+                "<plugin-in-inactive-only>Inactive only ||${project.basedir}||</plugin-in-inactive-only>");
+    }
+
+    private void checkReportPluginWithArtifactId(
+            List<ReportPlugin> plugins, String artifactId, String expectedId, String expectedConfig) {
+        ReportPlugin plugin = plugins.stream()
+                .filter(p -> p.getArtifactId().equals(artifactId))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(plugin, "Unable to find plugin with artifactId: " + artifactId);
+        List<ReportSet> pluginReportSets = plugin.getReportSets();
+        ReportSet reportSet = pluginReportSets.stream()
+                .filter(rs -> rs.getId().equals(expectedId))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(reportSet, "Wrong id for \"" + artifactId + "\"");
+
+        String config = reportSet.getConfiguration().toString();
+        assertTrue(
+                config.contains(expectedConfig),
+                "Wrong config for \"" + artifactId + "\": (" + config + ") does not contain :" + expectedConfig);
+    }
+
+    @Test
+    void testReportingPluginInterpolation() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-interpolation-reporting", "activeProfile");
+        Model originalModel = pom.getMavenProject().getOriginalModel();
+
+        // =============================================
+        assertEquals("||${project.basedir}||", originalModel.getProperties().get("prop-outside"));
+
+        List<ReportPlugin> outsidePlugins = originalModel.getReporting().getPlugins();
+        assertEquals(1, outsidePlugins.size(), "Wrong number of plugins found");
+
+        checkReportPluginWithArtifactId(
+                outsidePlugins,
+                "plugin-all-profiles",
+                "Outside ||${project.basedir}||",
+                "<plugin-all-profiles-out>Outside ||${project.basedir}||</plugin-all-profiles-out>");
+
+        // =============================================
+        Profile activeProfile = originalModel.getProfiles().stream()
+                .filter(profile -> profile.getId().equals("activeProfile"))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(activeProfile, "Unable to find the activeProfile");
+
+        assertTrue(
+                isActiveProfile(pom.getMavenProject(), activeProfile),
+                "The activeProfile should be active in the maven project");
+
+        assertEquals("||${project.basedir}||", activeProfile.getProperties().get("prop-active"));
+
+        List<ReportPlugin> activeProfilePlugins = activeProfile.getReporting().getPlugins();
+        assertEquals(2, activeProfilePlugins.size(), "The activeProfile should be active in the maven project");
+
+        checkReportPluginWithArtifactId(
+                activeProfilePlugins,
+                "plugin-all-profiles",
+                "Active all ||${project.basedir}||",
+                "<plugin-all-profiles-in>Active all ||${project.basedir}||</plugin-all-profiles-in>");
+
+        checkReportPluginWithArtifactId(
+                activeProfilePlugins,
+                "only-active-profile",
+                "Active only ||${project.basedir}||",
+                "<plugin-in-active-profile-only>Active only ||${project.basedir}||</plugin-in-active-profile-only>");
+
+        // =============================================
+
+        Profile inactiveProfile = originalModel.getProfiles().stream()
+                .filter(profile -> profile.getId().equals("inactiveProfile"))
+                .findFirst()
+                .orElse(null);
+        assertNotNull(inactiveProfile, "Unable to find the inactiveProfile");
+
+        assertFalse(
+                isActiveProfile(pom.getMavenProject(), inactiveProfile),
+                "The inactiveProfile should NOT be active in the maven project");
+
+        assertEquals("||${project.basedir}||", inactiveProfile.getProperties().get("prop-inactive"));
+
+        List<ReportPlugin> inactiveProfilePlugins =
+                inactiveProfile.getReporting().getPlugins();
+        assertEquals(2, inactiveProfilePlugins.size(), "Number of active profile plugins");
+
+        checkReportPluginWithArtifactId(
+                inactiveProfilePlugins,
+                "plugin-all-profiles",
+                "Inactive all ||${project.basedir}||",
+                "<plugin-all-profiles-ina>Inactive all ||${project.basedir}||</plugin-all-profiles-ina>");
+
+        checkReportPluginWithArtifactId(
+                inactiveProfilePlugins,
+                "only-inactive-profile",
+                "Inactive only ||${project.basedir}||",
+                "<plugin-in-inactive-only>Inactive only ||${project.basedir}||</plugin-in-inactive-only>");
+    }
 
     // Some better conventions for the test poms needs to be created and each of these tests
     // that represent a verification of a specification item needs to be a couple lines at most.
@@ -157,11 +343,9 @@
     // them into a resolver, create the expression to extract the data to validate the Model, and the URI
     // to validate the properties. We also need a way to navigate from the Tex specification documents to
     // the test in question and vice versa. A little Eclipse plugin would do the trick.
-    public void testThatExecutionsWithoutIdsAreMergedAndTheChildWins()
-        throws Exception
-    {
-        PomTestWrapper tester = buildPom( "micromailer" );
-        assertModelEquals( tester, "child-descriptor", "build/plugins[1]/executions[1]/goals[1]" );
+    public void testThatExecutionsWithoutIdsAreMergedAndTheChildWins() throws Exception {
+        PomTestWrapper tester = buildPom("micromailer");
+        assertModelEquals(tester, "child-descriptor", "build/plugins[1]/executions[1]/goals[1]");
     }
 
     /*MNG-
@@ -174,22 +358,16 @@
 
     /*MNG- 4010*/
     @Test
-    public void testDuplicateExclusionsDependency()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "duplicate-exclusions-dependency/sub" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencies[1]/exclusions" ) ).size() );
-
+    void testDuplicateExclusionsDependency() throws Exception {
+        PomTestWrapper pom = buildPom("duplicate-exclusions-dependency/sub");
+        assertEquals(1, ((List<?>) pom.getValue("dependencies[1]/exclusions")).size());
     }
 
     /*MNG- 4008*/
     @Test
-    public void testMultipleFilters()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "multiple-filters" );
-        assertEquals( 4, ( (List<?>) pom.getValue( "build/filters" ) ).size() );
-
+    void testMultipleFilters() throws Exception {
+        PomTestWrapper pom = buildPom("multiple-filters");
+        assertEquals(4, ((List<?>) pom.getValue("build/filters")).size());
     }
 
     /* MNG-4005: postponed to 3.1
@@ -254,25 +432,21 @@
     */
 
     @Test
-    public void testDuplicateDependenciesCauseLastDeclarationToBePickedInLenientMode()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "unique-dependency-key/deps", true, null, null );
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencies" ) ).size() );
-        assertEquals( "0.2", pom.getValue( "dependencies[1]/version" ) );
+    void testDuplicateDependenciesCauseLastDeclarationToBePickedInLenientMode() throws Exception {
+        PomTestWrapper pom = buildPom("unique-dependency-key/deps", true, null, null);
+        assertEquals(1, ((List<?>) pom.getValue("dependencies")).size());
+        assertEquals("0.2", pom.getValue("dependencies[1]/version"));
     }
 
     /* MNG-3567*/
     @Test
-    public void testParentInterpolation()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "parent-interpolation/sub" );
-        pom = new PomTestWrapper( pom.getMavenProject().getParent() );
-        assertEquals( "1.3.0-SNAPSHOT", pom.getValue( "build/plugins[1]/version" ) );
+    void testParentInterpolation() throws Exception {
+        PomTestWrapper pom = buildPom("parent-interpolation/sub");
+        pom = new PomTestWrapper(pom.getMavenProject().getParent());
+        assertEquals("1.3.0-SNAPSHOT", pom.getValue("build/plugins[1]/version"));
     }
 
-/*
+    /*
     public void testMaven()
         throws Exception
     {
@@ -288,1653 +462,1450 @@
 
     /* MNG-3567*/
     @Test
-    public void testPluginManagementInherited()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "pluginmanagement-inherited/sub" );
-        assertEquals( "1.0-alpha-21", pom.getValue( "build/plugins[1]/version" ) );
+    void testPluginManagementInherited() throws Exception {
+        PomTestWrapper pom = buildPom("pluginmanagement-inherited/sub");
+        assertEquals("1.0-alpha-21", pom.getValue("build/plugins[1]/version"));
     }
 
-     /* MNG-2174*/
+    /* MNG-2174*/
     @Test
-    public void testPluginManagementDependencies()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-management-dependencies/sub", "test" );
-        assertEquals( "1.0-alpha-21", pom.getValue( "build/plugins[1]/version" ) );
-        assertEquals( "1.0", pom.getValue( "build/plugins[1]/dependencies[1]/version" ) );
+    void testPluginManagementDependencies() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-management-dependencies/sub", "test");
+        assertEquals("1.0-alpha-21", pom.getValue("build/plugins[1]/version"));
+        assertEquals("1.0", pom.getValue("build/plugins[1]/dependencies[1]/version"));
     }
 
-
     /* MNG-3877*/
     @Test
-    public void testReportingInterpolation()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "reporting-interpolation" );
-        assertEquals( createPath( Arrays.asList( System.getProperty( "user.dir" ), "src", "test",
-                                                 "resources-project-builder", "reporting-interpolation", "target",
-                                                 "site" ) ), pom.getValue( "reporting/outputDirectory" ) );
+    void testReportingInterpolation() throws Exception {
+        PomTestWrapper pom = buildPom("reporting-interpolation");
+        assertEquals(
+                createPath(Arrays.asList(
+                        System.getProperty("user.dir"),
+                        "src",
+                        "test",
+                        "resources-project-builder",
+                        "reporting-interpolation",
+                        "target",
+                        "site")),
+                pom.getValue("reporting/outputDirectory"));
     }
 
     @Test
-    public void testPluginOrder()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-order" );
-        assertEquals( "plexus-component-metadata", pom.getValue( "build/plugins[1]/artifactId" ) );
-        assertEquals( "maven-surefire-plugin", pom.getValue( "build/plugins[2]/artifactId" ) );
+    void testPluginOrder() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-order");
+        assertEquals("plexus-component-metadata", pom.getValue("build/plugins[1]/artifactId"));
+        assertEquals("maven-surefire-plugin", pom.getValue("build/plugins[2]/artifactId"));
     }
 
     @Test
-    public void testErroneousJoiningOfDifferentPluginsWithEqualDependencies()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "equal-plugin-deps" );
-        assertEquals( "maven-it-plugin-a", pom.getValue( "build/plugins[1]/artifactId" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/dependencies" ) ).size() );
-        assertEquals( "maven-it-plugin-b", pom.getValue( "build/plugins[2]/artifactId" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/dependencies" ) ).size() );
+    void testErroneousJoiningOfDifferentPluginsWithEqualDependencies() throws Exception {
+        PomTestWrapper pom = buildPom("equal-plugin-deps");
+        assertEquals("maven-it-plugin-a", pom.getValue("build/plugins[1]/artifactId"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/dependencies")).size());
+        assertEquals("maven-it-plugin-b", pom.getValue("build/plugins[2]/artifactId"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/dependencies")).size());
     }
 
     /** MNG-3821 */
     @Test
-    public void testErroneousJoiningOfDifferentPluginsWithEqualExecutionIds()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "equal-plugin-exec-ids" );
-        assertEquals( "maven-it-plugin-a", pom.getValue( "build/plugins[1]/artifactId" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "maven-it-plugin-b", pom.getValue( "build/plugins[2]/artifactId" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "maven-it-plugin-a", pom.getValue( "reporting/plugins[1]/artifactId" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "reporting/plugins[1]/reportSets" ) ).size() );
-        assertEquals( "maven-it-plugin-b", pom.getValue( "reporting/plugins[2]/artifactId" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "reporting/plugins[1]/reportSets" ) ).size() );
+    void testErroneousJoiningOfDifferentPluginsWithEqualExecutionIds() throws Exception {
+        PomTestWrapper pom = buildPom("equal-plugin-exec-ids");
+        assertEquals("maven-it-plugin-a", pom.getValue("build/plugins[1]/artifactId"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("maven-it-plugin-b", pom.getValue("build/plugins[2]/artifactId"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("maven-it-plugin-a", pom.getValue("reporting/plugins[1]/artifactId"));
+        assertEquals(1, ((List<?>) pom.getValue("reporting/plugins[1]/reportSets")).size());
+        assertEquals("maven-it-plugin-b", pom.getValue("reporting/plugins[2]/artifactId"));
+        assertEquals(1, ((List<?>) pom.getValue("reporting/plugins[1]/reportSets")).size());
     }
 
-     /** MNG-3998 */
+    /** MNG-3998 */
     @Test
-    public void testExecutionConfiguration()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "execution-configuration" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "src/main/mdo/nexus.xml",
-                      ( pom.getValue( "build/plugins[1]/executions[1]/configuration[1]/model" ) ) );
-        assertEquals( "src/main/mdo/security.xml",
-                      ( pom.getValue( "build/plugins[1]/executions[2]/configuration[1]/model" ) ) );
+    void testExecutionConfiguration() throws Exception {
+        PomTestWrapper pom = buildPom("execution-configuration");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("src/main/mdo/nexus.xml", (pom.getValue("build/plugins[1]/executions[1]/configuration[1]/model")));
+        assertEquals(
+                "src/main/mdo/security.xml", (pom.getValue("build/plugins[1]/executions[2]/configuration[1]/model")));
     }
 
     /*
-    public void testPluginConfigDuplicate()
-    throws Exception
-{
-    PomTestWrapper pom = buildPom( "plugin-config-duplicate/dup" );
-}
-*/
-    @Test
-    public void testSingleConfigurationInheritance()
+        public void testPluginConfigDuplicate()
         throws Exception
     {
-        PomTestWrapper pom = buildPom( "single-configuration-inheritance" );
+        PomTestWrapper pom = buildPom( "plugin-config-duplicate/dup" );
+    }
+    */
+    @Test
+    void testSingleConfigurationInheritance() throws Exception {
+        PomTestWrapper pom = buildPom("single-configuration-inheritance");
 
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/configuration[1]/rules" ) ).size() );
-        assertEquals( "2.0.6",
-                      pom.getValue( "build/plugins[1]/executions[1]/configuration[1]/rules[1]/requireMavenVersion[1]/version" ) );
-        assertEquals( "[1.4,)",
-                      pom.getValue( "build/plugins[1]/executions[1]/configuration[1]/rules[1]/requireJavaVersion[1]/version" ) );
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/configuration[1]/rules")).size());
+        assertEquals(
+                "2.0.6",
+                pom.getValue(
+                        "build/plugins[1]/executions[1]/configuration[1]/rules[1]/requireMavenVersion[1]/version"));
+        assertEquals(
+                "[1.4,)",
+                pom.getValue("build/plugins[1]/executions[1]/configuration[1]/rules[1]/requireJavaVersion[1]/version"));
     }
 
     @Test
-    public void testConfigWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "config-with-plugin-mng" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "src/main/mdo/security.xml", pom.getValue( "build/plugins[1]/executions[2]/configuration[1]/model" ) );
-        assertEquals( "1.0.8", pom.getValue( "build/plugins[1]/executions[1]/configuration[1]/version" ) );
+    void testConfigWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("config-with-plugin-mng");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals(
+                "src/main/mdo/security.xml", pom.getValue("build/plugins[1]/executions[2]/configuration[1]/model"));
+        assertEquals("1.0.8", pom.getValue("build/plugins[1]/executions[1]/configuration[1]/version"));
     }
 
     /** MNG-3965 */
     @Test
-    public void testExecutionConfigurationSubcollections()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "execution-configuration-subcollections" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/configuration[1]/rules[1]/bannedDependencies" ) ).size() );
+    void testExecutionConfigurationSubcollections() throws Exception {
+        PomTestWrapper pom = buildPom("execution-configuration-subcollections");
+        assertEquals(
+                2,
+                ((List<?>) pom.getValue("build/plugins[1]/executions[1]/configuration[1]/rules[1]/bannedDependencies"))
+                        .size());
     }
 
     /** MNG-3985 */
     @Test
-    public void testMultipleRepositories()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "multiple-repos/sub" );
-        assertEquals( 3, ( (List<?>) pom.getValue( "repositories" ) ).size() );
+    void testMultipleRepositories() throws Exception {
+        PomTestWrapper pom = buildPom("multiple-repos/sub");
+        assertEquals(2, ((List<?>) pom.getValue("repositories")).size());
     }
 
     /** MNG-3965 */
     @Test
-    public void testMultipleExecutionIds()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "dual-execution-ids/sub" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
+    void testMultipleExecutionIds() throws Exception {
+        PomTestWrapper pom = buildPom("dual-execution-ids/sub");
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
     }
 
     /** MNG-3997 */
     @Test
-    public void testConsecutiveEmptyElements()
-        throws Exception
-    {
-        buildPom( "consecutive_empty_elements" );
+    void testConsecutiveEmptyElements() throws Exception {
+        buildPom("consecutive_empty_elements");
     }
 
     @Test
-    public void testOrderOfGoalsFromPluginExecutionWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-goals-order/wo-plugin-mgmt" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/goals" ) ).size() );
-        assertEquals( "b", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "a", pom.getValue( "build/plugins[1]/executions[1]/goals[2]" ) );
-        assertEquals( "d", pom.getValue( "build/plugins[1]/executions[1]/goals[3]" ) );
-        assertEquals( "c", pom.getValue( "build/plugins[1]/executions[1]/goals[4]" ) );
-        assertEquals( "e", pom.getValue( "build/plugins[1]/executions[1]/goals[5]" ) );
+    void testOrderOfGoalsFromPluginExecutionWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-goals-order/wo-plugin-mgmt");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/goals")).size());
+        assertEquals("b", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("a", pom.getValue("build/plugins[1]/executions[1]/goals[2]"));
+        assertEquals("d", pom.getValue("build/plugins[1]/executions[1]/goals[3]"));
+        assertEquals("c", pom.getValue("build/plugins[1]/executions[1]/goals[4]"));
+        assertEquals("e", pom.getValue("build/plugins[1]/executions[1]/goals[5]"));
     }
 
     /* MNG-3886*/
     @Test
-    public void testOrderOfGoalsFromPluginExecutionWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-goals-order/w-plugin-mgmt" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/goals" ) ).size() );
-        assertEquals( "b", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "a", pom.getValue( "build/plugins[1]/executions[1]/goals[2]" ) );
-        assertEquals( "d", pom.getValue( "build/plugins[1]/executions[1]/goals[3]" ) );
-        assertEquals( "c", pom.getValue( "build/plugins[1]/executions[1]/goals[4]" ) );
-        assertEquals( "e", pom.getValue( "build/plugins[1]/executions[1]/goals[5]" ) );
+    void testOrderOfGoalsFromPluginExecutionWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-goals-order/w-plugin-mgmt");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/goals")).size());
+        assertEquals("b", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("a", pom.getValue("build/plugins[1]/executions[1]/goals[2]"));
+        assertEquals("d", pom.getValue("build/plugins[1]/executions[1]/goals[3]"));
+        assertEquals("c", pom.getValue("build/plugins[1]/executions[1]/goals[4]"));
+        assertEquals("e", pom.getValue("build/plugins[1]/executions[1]/goals[5]"));
     }
 
     @Test
-    public void testOrderOfPluginExecutionsWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-order/wo-plugin-mgmt" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "b", pom.getValue( "build/plugins[1]/executions[1]/id" ) );
-        assertEquals( "a", pom.getValue( "build/plugins[1]/executions[2]/id" ) );
-        assertEquals( "d", pom.getValue( "build/plugins[1]/executions[3]/id" ) );
-        assertEquals( "c", pom.getValue( "build/plugins[1]/executions[4]/id" ) );
-        assertEquals( "e", pom.getValue( "build/plugins[1]/executions[5]/id" ) );
+    void testOrderOfPluginExecutionsWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-order/wo-plugin-mgmt");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("b", pom.getValue("build/plugins[1]/executions[1]/id"));
+        assertEquals("a", pom.getValue("build/plugins[1]/executions[2]/id"));
+        assertEquals("d", pom.getValue("build/plugins[1]/executions[3]/id"));
+        assertEquals("c", pom.getValue("build/plugins[1]/executions[4]/id"));
+        assertEquals("e", pom.getValue("build/plugins[1]/executions[5]/id"));
     }
 
     /* MNG-3887 */
     @Test
-    public void testOrderOfPluginExecutionsWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-order/w-plugin-mgmt" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "b", pom.getValue( "build/plugins[1]/executions[1]/id" ) );
-        assertEquals( "a", pom.getValue( "build/plugins[1]/executions[2]/id" ) );
-        assertEquals( "d", pom.getValue( "build/plugins[1]/executions[3]/id" ) );
-        assertEquals( "c", pom.getValue( "build/plugins[1]/executions[4]/id" ) );
-        assertEquals( "e", pom.getValue( "build/plugins[1]/executions[5]/id" ) );
+    void testOrderOfPluginExecutionsWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-order/w-plugin-mgmt");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("b", pom.getValue("build/plugins[1]/executions[1]/id"));
+        assertEquals("a", pom.getValue("build/plugins[1]/executions[2]/id"));
+        assertEquals("d", pom.getValue("build/plugins[1]/executions[3]/id"));
+        assertEquals("c", pom.getValue("build/plugins[1]/executions[4]/id"));
+        assertEquals("e", pom.getValue("build/plugins[1]/executions[5]/id"));
     }
 
     @Test
-    public void testMergeOfPluginExecutionsWhenChildInheritsPluginVersion()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-merging-wo-version/sub" );
-        assertEquals( 4, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
+    void testMergeOfPluginExecutionsWhenChildInheritsPluginVersion() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-merging-wo-version/sub");
+        assertEquals(4, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
     }
 
     /* MNG-3943*/
     @Test
-    public void testMergeOfPluginExecutionsWhenChildAndParentUseDifferentPluginVersions()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-merging-version-insensitive/sub" );
-        assertEquals( 4, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
+    void testMergeOfPluginExecutionsWhenChildAndParentUseDifferentPluginVersions() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-merging-version-insensitive/sub");
+        assertEquals(4, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
     }
 
-
     @Test
-    public void testInterpolationWithXmlMarkup()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "xml-markup-interpolation" );
-        assertEquals( "<?xml version='1.0'?>Tom&Jerry", pom.getValue( "properties/xmlTest" ) );
+    void testInterpolationWithXmlMarkup() throws Exception {
+        PomTestWrapper pom = buildPom("xml-markup-interpolation");
+        assertEquals("<?xml version='1.0'?>Tom&Jerry", pom.getValue("properties/xmlTest"));
     }
 
     /* MNG-3925 */
     @Test
-    public void testOrderOfMergedPluginExecutionsWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "merged-plugin-exec-order/wo-plugin-mgmt/sub" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "parent-1", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "parent-2", pom.getValue( "build/plugins[1]/executions[2]/goals[1]" ) );
-        assertEquals( "child-default", pom.getValue( "build/plugins[1]/executions[3]/goals[1]" ) );
-        assertEquals( "child-1", pom.getValue( "build/plugins[1]/executions[4]/goals[1]" ) );
-        assertEquals( "child-2", pom.getValue( "build/plugins[1]/executions[5]/goals[1]" ) );
+    void testOrderOfMergedPluginExecutionsWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("merged-plugin-exec-order/wo-plugin-mgmt/sub");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("parent-1", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("parent-2", pom.getValue("build/plugins[1]/executions[2]/goals[1]"));
+        assertEquals("child-default", pom.getValue("build/plugins[1]/executions[3]/goals[1]"));
+        assertEquals("child-1", pom.getValue("build/plugins[1]/executions[4]/goals[1]"));
+        assertEquals("child-2", pom.getValue("build/plugins[1]/executions[5]/goals[1]"));
     }
 
     @Test
-    public void testOrderOfMergedPluginExecutionsWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "merged-plugin-exec-order/w-plugin-mgmt/sub" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "parent-1", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "parent-2", pom.getValue( "build/plugins[1]/executions[2]/goals[1]" ) );
-        assertEquals( "child-default", pom.getValue( "build/plugins[1]/executions[3]/goals[1]" ) );
-        assertEquals( "child-1", pom.getValue( "build/plugins[1]/executions[4]/goals[1]" ) );
-        assertEquals( "child-2", pom.getValue( "build/plugins[1]/executions[5]/goals[1]" ) );
+    void testOrderOfMergedPluginExecutionsWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("merged-plugin-exec-order/w-plugin-mgmt/sub");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("parent-1", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("parent-2", pom.getValue("build/plugins[1]/executions[2]/goals[1]"));
+        assertEquals("child-default", pom.getValue("build/plugins[1]/executions[3]/goals[1]"));
+        assertEquals("child-1", pom.getValue("build/plugins[1]/executions[4]/goals[1]"));
+        assertEquals("child-2", pom.getValue("build/plugins[1]/executions[5]/goals[1]"));
     }
 
     /* MNG-3984*/
     @Test
-    public void testDifferentContainersWithSameId()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "join-different-containers-same-id" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/goals" ) ).size() );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/pluginManagement/plugins[@artifactId='maven-it-plugin-b']/executions[1]/goals" ) ).size() );
+    void testDifferentContainersWithSameId() throws Exception {
+        PomTestWrapper pom = buildPom("join-different-containers-same-id");
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/goals")).size());
+        assertEquals(
+                1,
+                ((List<?>) pom.getValue(
+                                "build/pluginManagement/plugins[@artifactId='maven-it-plugin-b']/executions[1]/goals"))
+                        .size());
     }
 
     /* MNG-3937*/
     @Test
-    public void testOrderOfMergedPluginExecutionGoalsWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "merged-plugin-exec-goals-order/wo-plugin-mgmt/sub" );
+    void testOrderOfMergedPluginExecutionGoalsWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("merged-plugin-exec-goals-order/wo-plugin-mgmt/sub");
 
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/goals" ) ).size() );
-        assertEquals( "child-a", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "merged", pom.getValue( "build/plugins[1]/executions[1]/goals[2]" ) );
-        assertEquals( "child-b", pom.getValue( "build/plugins[1]/executions[1]/goals[3]" ) );
-        assertEquals( "parent-b", pom.getValue( "build/plugins[1]/executions[1]/goals[4]" ) );
-        assertEquals( "parent-a", pom.getValue( "build/plugins[1]/executions[1]/goals[5]" ) );
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/goals")).size());
+        assertEquals("child-a", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("merged", pom.getValue("build/plugins[1]/executions[1]/goals[2]"));
+        assertEquals("child-b", pom.getValue("build/plugins[1]/executions[1]/goals[3]"));
+        assertEquals("parent-b", pom.getValue("build/plugins[1]/executions[1]/goals[4]"));
+        assertEquals("parent-a", pom.getValue("build/plugins[1]/executions[1]/goals[5]"));
     }
 
     @Test
-    public void testOrderOfMergedPluginExecutionGoalsWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "merged-plugin-exec-goals-order/w-plugin-mgmt/sub" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/goals" ) ).size() );
-        assertEquals( "child-a", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "merged", pom.getValue( "build/plugins[1]/executions[1]/goals[2]" ) );
-        assertEquals( "child-b", pom.getValue( "build/plugins[1]/executions[1]/goals[3]" ) );
-        assertEquals( "parent-b", pom.getValue( "build/plugins[1]/executions[1]/goals[4]" ) );
-        assertEquals( "parent-a", pom.getValue( "build/plugins[1]/executions[1]/goals[5]" ) );
+    void testOrderOfMergedPluginExecutionGoalsWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("merged-plugin-exec-goals-order/w-plugin-mgmt/sub");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/goals")).size());
+        assertEquals("child-a", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("merged", pom.getValue("build/plugins[1]/executions[1]/goals[2]"));
+        assertEquals("child-b", pom.getValue("build/plugins[1]/executions[1]/goals[3]"));
+        assertEquals("parent-b", pom.getValue("build/plugins[1]/executions[1]/goals[4]"));
+        assertEquals("parent-a", pom.getValue("build/plugins[1]/executions[1]/goals[5]"));
     }
 
     /*MNG-3938*/
     @Test
-    public void testOverridingOfInheritedPluginExecutionsWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-merging/wo-plugin-mgmt/sub" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "child-default", pom.getValue( "build/plugins[1]/executions[@id='default']/phase" ) );
-        assertEquals( "child-non-default", pom.getValue( "build/plugins[1]/executions[@id='non-default']/phase" ) );
+    void testOverridingOfInheritedPluginExecutionsWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-merging/wo-plugin-mgmt/sub");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("child-default", pom.getValue("build/plugins[1]/executions[@id='default']/phase"));
+        assertEquals("child-non-default", pom.getValue("build/plugins[1]/executions[@id='non-default']/phase"));
     }
 
     /* MNG-3938 */
     @Test
-    public void testOverridingOfInheritedPluginExecutionsWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-merging/w-plugin-mgmt/sub" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "child-default", pom.getValue( "build/plugins[1]/executions[@id='default']/phase" ) );
-        assertEquals( "child-non-default", pom.getValue( "build/plugins[1]/executions[@id='non-default']/phase" ) );
+    void testOverridingOfInheritedPluginExecutionsWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-merging/w-plugin-mgmt/sub");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("child-default", pom.getValue("build/plugins[1]/executions[@id='default']/phase"));
+        assertEquals("child-non-default", pom.getValue("build/plugins[1]/executions[@id='non-default']/phase"));
     }
 
-
     /* MNG-3906*/
     @Test
-    public void testOrderOfMergedPluginDependenciesWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "merged-plugin-class-path-order/wo-plugin-mgmt/sub" );
+    void testOrderOfMergedPluginDependenciesWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("merged-plugin-class-path-order/wo-plugin-mgmt/sub");
 
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/dependencies" ) ).size() );
-        assertNotNull( pom.getValue( "build/plugins[1]/dependencies[1]" ) );
-        assertEquals( "c", pom.getValue( "build/plugins[1]/dependencies[1]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[1]/version" ) );
-        assertEquals( "a", pom.getValue( "build/plugins[1]/dependencies[2]/artifactId" ) );
-        assertEquals( "2", pom.getValue( "build/plugins[1]/dependencies[2]/version" ) );
-        assertEquals( "b", pom.getValue( "build/plugins[1]/dependencies[3]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[3]/version" ) );
-        assertEquals( "e", pom.getValue( "build/plugins[1]/dependencies[4]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[4]/version" ) );
-        assertEquals( "d", pom.getValue( "build/plugins[1]/dependencies[5]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[5]/version" ) );
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/dependencies")).size());
+        assertNotNull(pom.getValue("build/plugins[1]/dependencies[1]"));
+        assertEquals("c", pom.getValue("build/plugins[1]/dependencies[1]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[1]/version"));
+        assertEquals("a", pom.getValue("build/plugins[1]/dependencies[2]/artifactId"));
+        assertEquals("2", pom.getValue("build/plugins[1]/dependencies[2]/version"));
+        assertEquals("b", pom.getValue("build/plugins[1]/dependencies[3]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[3]/version"));
+        assertEquals("e", pom.getValue("build/plugins[1]/dependencies[4]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[4]/version"));
+        assertEquals("d", pom.getValue("build/plugins[1]/dependencies[5]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[5]/version"));
     }
 
     @Test
-    public void testOrderOfMergedPluginDependenciesWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "merged-plugin-class-path-order/w-plugin-mgmt/sub" );
-        assertEquals( 5, ( (List<?>) pom.getValue( "build/plugins[1]/dependencies" ) ).size() );
-        assertEquals( "c", pom.getValue( "build/plugins[1]/dependencies[1]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[1]/version" ) );
-        assertEquals( "a", pom.getValue( "build/plugins[1]/dependencies[2]/artifactId" ) );
-        assertEquals( "2", pom.getValue( "build/plugins[1]/dependencies[2]/version" ) );
-        assertEquals( "b", pom.getValue( "build/plugins[1]/dependencies[3]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[3]/version" ) );
-        assertEquals( "e", pom.getValue( "build/plugins[1]/dependencies[4]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[4]/version" ) );
-        assertEquals( "d", pom.getValue( "build/plugins[1]/dependencies[5]/artifactId" ) );
-        assertEquals( "1", pom.getValue( "build/plugins[1]/dependencies[5]/version" ) );
+    void testOrderOfMergedPluginDependenciesWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("merged-plugin-class-path-order/w-plugin-mgmt/sub");
+        assertEquals(5, ((List<?>) pom.getValue("build/plugins[1]/dependencies")).size());
+        assertEquals("c", pom.getValue("build/plugins[1]/dependencies[1]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[1]/version"));
+        assertEquals("a", pom.getValue("build/plugins[1]/dependencies[2]/artifactId"));
+        assertEquals("2", pom.getValue("build/plugins[1]/dependencies[2]/version"));
+        assertEquals("b", pom.getValue("build/plugins[1]/dependencies[3]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[3]/version"));
+        assertEquals("e", pom.getValue("build/plugins[1]/dependencies[4]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[4]/version"));
+        assertEquals("d", pom.getValue("build/plugins[1]/dependencies[5]/artifactId"));
+        assertEquals("1", pom.getValue("build/plugins[1]/dependencies[5]/version"));
     }
 
     @Test
-    public void testInterpolationOfNestedBuildDirectories()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "nested-build-dir-interpolation" );
-        assertEquals( new File( pom.getBasedir(), "target/classes/dir0" ),
-                      new File( (String) pom.getValue( "properties/dir0" ) ) );
-        assertEquals( new File( pom.getBasedir(), "src/test/dir1" ),
-                      new File( (String) pom.getValue( "properties/dir1" ) ) );
-        assertEquals( new File( pom.getBasedir(), "target/site/dir2" ),
-                      new File( (String) pom.getValue( "properties/dir2" ) ) );
+    void testInterpolationOfNestedBuildDirectories() throws Exception {
+        PomTestWrapper pom = buildPom("nested-build-dir-interpolation");
+        assertEquals(
+                new File(pom.getBasedir(), "target/classes/dir0"), new File((String) pom.getValue("properties/dir0")));
+        assertEquals(new File(pom.getBasedir(), "src/test/dir1"), new File((String) pom.getValue("properties/dir1")));
+        assertEquals(
+                new File(pom.getBasedir(), "target/site/dir2"), new File((String) pom.getValue("properties/dir2")));
     }
 
     @Test
-    public void testAppendArtifactIdOfChildToInheritedUrls()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "url-inheritance/sub" );
-        assertEquals( "https://parent.url/child", pom.getValue( "url" ) );
-        assertEquals( "https://parent.url/org", pom.getValue( "organization/url" ) );
-        assertEquals( "https://parent.url/license.txt", pom.getValue( "licenses[1]/url" ) );
-        assertEquals( "https://parent.url/viewvc/child", pom.getValue( "scm/url" ) );
-        assertEquals( "https://parent.url/scm/child", pom.getValue( "scm/connection" ) );
-        assertEquals( "https://parent.url/scm/child", pom.getValue( "scm/developerConnection" ) );
-        assertEquals( "https://parent.url/issues", pom.getValue( "issueManagement/url" ) );
-        assertEquals( "https://parent.url/ci", pom.getValue( "ciManagement/url" ) );
-        assertEquals( "https://parent.url/dist", pom.getValue( "distributionManagement/repository/url" ) );
-        assertEquals( "https://parent.url/snaps", pom.getValue( "distributionManagement/snapshotRepository/url" ) );
-        assertEquals( "https://parent.url/site/child", pom.getValue( "distributionManagement/site/url" ) );
-        assertEquals( "https://parent.url/download", pom.getValue( "distributionManagement/downloadUrl" ) );
+    void testAppendArtifactIdOfChildToInheritedUrls() throws Exception {
+        PomTestWrapper pom = buildPom("url-inheritance/sub");
+        assertEquals("https://parent.url/child", pom.getValue("url"));
+        assertEquals("https://parent.url/org", pom.getValue("organization/url"));
+        assertEquals("https://parent.url/license.txt", pom.getValue("licenses[1]/url"));
+        assertEquals("https://parent.url/viewvc/child", pom.getValue("scm/url"));
+        assertEquals("https://parent.url/scm/child", pom.getValue("scm/connection"));
+        assertEquals("https://parent.url/scm/child", pom.getValue("scm/developerConnection"));
+        assertEquals("https://parent.url/issues", pom.getValue("issueManagement/url"));
+        assertEquals("https://parent.url/ci", pom.getValue("ciManagement/url"));
+        assertEquals("https://parent.url/dist", pom.getValue("distributionManagement/repository/url"));
+        assertEquals("https://parent.url/snaps", pom.getValue("distributionManagement/snapshotRepository/url"));
+        assertEquals("https://parent.url/site/child", pom.getValue("distributionManagement/site/url"));
+        assertEquals("https://parent.url/download", pom.getValue("distributionManagement/downloadUrl"));
     }
 
     /* MNG-3846*/
     @Test
-    public void testAppendArtifactIdOfParentAndChildToInheritedUrls()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "url-inheritance/another-parent/sub" );
-        assertEquals( "https://parent.url/ap/child", pom.getValue( "url" ) );
-        assertEquals( "https://parent.url/org", pom.getValue( "organization/url" ) );
-        assertEquals( "https://parent.url/license.txt", pom.getValue( "licenses[1]/url" ) );
-        assertEquals( "https://parent.url/viewvc/ap/child", pom.getValue( "scm/url" ) );
-        assertEquals( "https://parent.url/scm/ap/child", pom.getValue( "scm/connection" ) );
-        assertEquals( "https://parent.url/scm/ap/child", pom.getValue( "scm/developerConnection" ) );
-        assertEquals( "https://parent.url/issues", pom.getValue( "issueManagement/url" ) );
-        assertEquals( "https://parent.url/ci", pom.getValue( "ciManagement/url" ) );
-        assertEquals( "https://parent.url/dist", pom.getValue( "distributionManagement/repository/url" ) );
-        assertEquals( "https://parent.url/snaps", pom.getValue( "distributionManagement/snapshotRepository/url" ) );
-        assertEquals( "https://parent.url/site/ap/child", pom.getValue( "distributionManagement/site/url" ) );
-        assertEquals( "https://parent.url/download", pom.getValue( "distributionManagement/downloadUrl" ) );
+    void testAppendArtifactIdOfParentAndChildToInheritedUrls() throws Exception {
+        PomTestWrapper pom = buildPom("url-inheritance/another-parent/sub");
+        assertEquals("https://parent.url/ap/child", pom.getValue("url"));
+        assertEquals("https://parent.url/org", pom.getValue("organization/url"));
+        assertEquals("https://parent.url/license.txt", pom.getValue("licenses[1]/url"));
+        assertEquals("https://parent.url/viewvc/ap/child", pom.getValue("scm/url"));
+        assertEquals("https://parent.url/scm/ap/child", pom.getValue("scm/connection"));
+        assertEquals("https://parent.url/scm/ap/child", pom.getValue("scm/developerConnection"));
+        assertEquals("https://parent.url/issues", pom.getValue("issueManagement/url"));
+        assertEquals("https://parent.url/ci", pom.getValue("ciManagement/url"));
+        assertEquals("https://parent.url/dist", pom.getValue("distributionManagement/repository/url"));
+        assertEquals("https://parent.url/snaps", pom.getValue("distributionManagement/snapshotRepository/url"));
+        assertEquals("https://parent.url/site/ap/child", pom.getValue("distributionManagement/site/url"));
+        assertEquals("https://parent.url/download", pom.getValue("distributionManagement/downloadUrl"));
     }
 
     @Test
-    public void testNonInheritedElementsInSubtreesOverriddenByChild()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "limited-inheritance/child" );
-        assertNull( pom.getValue( "organization/url" ) );
-        assertNull( pom.getValue( "issueManagement/system" ) );
-        assertEquals( 0, ( (List<?>) pom.getValue( "ciManagement/notifiers" ) ).size() );
-        assertEquals( "child-distros", pom.getValue( "distributionManagement/repository/id" ) );
-        assertEquals( "ssh://child.url/distros", pom.getValue( "distributionManagement/repository/url" ) );
-        assertNull( pom.getValue( "distributionManagement/repository/name" ) );
-        assertEquals( true, pom.getValue( "distributionManagement/repository/uniqueVersion" ) );
-        assertEquals( "default", pom.getValue( "distributionManagement/repository/layout" ) );
-        assertEquals( "child-snaps", pom.getValue( "distributionManagement/snapshotRepository/id" ) );
-        assertEquals( "ssh://child.url/snaps", pom.getValue( "distributionManagement/snapshotRepository/url" ) );
-        assertNull( pom.getValue( "distributionManagement/snapshotRepository/name" ) );
-        assertEquals( true, pom.getValue( "distributionManagement/snapshotRepository/uniqueVersion" ) );
-        assertEquals( "default", pom.getValue( "distributionManagement/snapshotRepository/layout" ) );
-        assertEquals( "child-site", pom.getValue( "distributionManagement/site/id" ) );
-        assertEquals( "scp://child.url/site", pom.getValue( "distributionManagement/site/url" ) );
-        assertNull( pom.getValue( "distributionManagement/site/name" ) );
+    void testNonInheritedElementsInSubtreesOverriddenByChild() throws Exception {
+        PomTestWrapper pom = buildPom("limited-inheritance/child");
+        assertNull(pom.getValue("organization/url"));
+        assertNull(pom.getValue("issueManagement/system"));
+        assertEquals(0, ((List<?>) pom.getValue("ciManagement/notifiers")).size());
+        assertEquals("child-distros", pom.getValue("distributionManagement/repository/id"));
+        assertEquals("ssh://child.url/distros", pom.getValue("distributionManagement/repository/url"));
+        assertNull(pom.getValue("distributionManagement/repository/name"));
+        assertEquals(true, pom.getValue("distributionManagement/repository/uniqueVersion"));
+        assertEquals("default", pom.getValue("distributionManagement/repository/layout"));
+        assertEquals("child-snaps", pom.getValue("distributionManagement/snapshotRepository/id"));
+        assertEquals("ssh://child.url/snaps", pom.getValue("distributionManagement/snapshotRepository/url"));
+        assertNull(pom.getValue("distributionManagement/snapshotRepository/name"));
+        assertEquals(true, pom.getValue("distributionManagement/snapshotRepository/uniqueVersion"));
+        assertEquals("default", pom.getValue("distributionManagement/snapshotRepository/layout"));
+        assertEquals("child-site", pom.getValue("distributionManagement/site/id"));
+        assertEquals("scp://child.url/site", pom.getValue("distributionManagement/site/url"));
+        assertNull(pom.getValue("distributionManagement/site/name"));
     }
 
     @Test
-    public void testXmlTextCoalescing()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "xml-coalesce-text" );
-        assertEquals( "A  Test  Project Property", pom.getValue( "properties/prop0" ) );
-        assertEquals( "That's a test!", pom.getValue( "properties/prop1" ) );
-        assertEquals( 32 * 1024,
-                      pom.getValue( "properties/prop2" ).toString().trim().replaceAll( "[\n\r]", "" ).length() );
+    void testXmlTextCoalescing() throws Exception {
+        PomTestWrapper pom = buildPom("xml-coalesce-text");
+        assertEquals("A  Test  Project Property", pom.getValue("properties/prop0"));
+        assertEquals("That's a test!", pom.getValue("properties/prop1"));
+        assertEquals(
+                32 * 1024,
+                pom.getValue("properties/prop2")
+                        .toString()
+                        .trim()
+                        .replaceAll("[\n\r]", "")
+                        .length());
     }
 
     @Test
-    public void testFullInterpolationOfNestedExpressions()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "full-interpolation" );
-        for ( int i = 0; i < 24; i++ )
-        {
-            String index = ( ( i < 10 ) ? "0" : "" ) + i;
-            assertEquals( "PASSED", pom.getValue( "properties/property" + index ) );
+    void testFullInterpolationOfNestedExpressions() throws Exception {
+        PomTestWrapper pom = buildPom("full-interpolation");
+        for (int i = 0; i < 24; i++) {
+            String index = ((i < 10) ? "0" : "") + i;
+            assertEquals("PASSED", pom.getValue("properties/property" + index));
         }
     }
 
-
     @Test
-    public void testInterpolationWithBasedirAlignedDirectories()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "basedir-aligned-interpolation" );
-        assertEquals( new File( pom.getBasedir(), "src/main/java" ),
-                      new File( pom.getValue( "properties/buildMainSrc" ).toString() ) );
-        assertEquals( new File( pom.getBasedir(), "src/test/java" ),
-                      new File( pom.getValue( "properties/buildTestSrc" ).toString() ) );
-        assertEquals( new File( pom.getBasedir(), "src/main/scripts" ),
-                      new File( pom.getValue( "properties/buildScriptSrc" ).toString() ) );
-        assertEquals( new File( pom.getBasedir(), "target" ),
-                      new File( pom.getValue( "properties/buildOut" ).toString() ) );
-        assertEquals( new File( pom.getBasedir(), "target/classes" ),
-                      new File( pom.getValue( "properties/buildMainOut" ).toString() ) );
-        assertEquals( new File( pom.getBasedir(), "target/test-classes" ),
-                      new File( pom.getValue( "properties/buildTestOut" ).toString() ) );
-        assertEquals( new File( pom.getBasedir(), "target/site" ),
-                      new File( pom.getValue( "properties/siteOut" ).toString() ) );
+    void testInterpolationWithBasedirAlignedDirectories() throws Exception {
+        PomTestWrapper pom = buildPom("basedir-aligned-interpolation");
+        assertEquals(
+                new File(pom.getBasedir(), "src/main/java"),
+                new File(pom.getValue("properties/buildMainSrc").toString()));
+        assertEquals(
+                new File(pom.getBasedir(), "src/test/java"),
+                new File(pom.getValue("properties/buildTestSrc").toString()));
+        assertEquals(
+                new File(pom.getBasedir(), "src/main/scripts"),
+                new File(pom.getValue("properties/buildScriptSrc").toString()));
+        assertEquals(
+                new File(pom.getBasedir(), "target"),
+                new File(pom.getValue("properties/buildOut").toString()));
+        assertEquals(
+                new File(pom.getBasedir(), "target/classes"),
+                new File(pom.getValue("properties/buildMainOut").toString()));
+        assertEquals(
+                new File(pom.getBasedir(), "target/test-classes"),
+                new File(pom.getValue("properties/buildTestOut").toString()));
+        assertEquals(
+                new File(pom.getBasedir(), "target/site"),
+                new File(pom.getValue("properties/siteOut").toString()));
     }
 
     /* MNG-3944*/
     @Test
-    public void testInterpolationOfBasedirInPomWithUnusualName()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "basedir-interpolation/pom-with-unusual-name.xml" );
-        assertEquals( pom.getBasedir(), new File( pom.getValue( "properties/prop0" ).toString() ) );
-        assertEquals( pom.getBasedir(), new File( pom.getValue( "properties/prop1" ).toString() ) );
+    void testInterpolationOfBasedirInPomWithUnusualName() throws Exception {
+        PomTestWrapper pom = buildPom("basedir-interpolation/pom-with-unusual-name.xml");
+        assertEquals(pom.getBasedir(), new File(pom.getValue("properties/prop0").toString()));
+        assertEquals(pom.getBasedir(), new File(pom.getValue("properties/prop1").toString()));
     }
 
     /* MNG-3979 */
     @Test
-    public void testJoiningOfContainersWhenChildHasEmptyElements()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "id-container-joining-with-empty-elements/sub" );
-        assertNotNull( pom );
+    void testJoiningOfContainersWhenChildHasEmptyElements() throws Exception {
+        PomTestWrapper pom = buildPom("id-container-joining-with-empty-elements/sub");
+        assertNotNull(pom);
     }
 
     @Test
-    public void testOrderOfPluginConfigurationElementsWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-order/wo-plugin-mgmt" );
-        assertEquals( "one", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[1]" ) );
-        assertEquals( "two", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[2]" ) );
-        assertEquals( "three", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[3]" ) );
-        assertEquals( "four", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[4]" ) );
+    void testOrderOfPluginConfigurationElementsWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-order/wo-plugin-mgmt");
+        assertEquals("one", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[1]"));
+        assertEquals("two", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[2]"));
+        assertEquals("three", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[3]"));
+        assertEquals("four", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[4]"));
     }
 
     /* MNG-3827*/
     @Test
-    public void testOrderOfPluginConfigurationElementsWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-order/w-plugin-mgmt" );
-        assertEquals( "one", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[1]" ) );
-        assertEquals( "two", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[2]" ) );
-        assertEquals( "three", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[3]" ) );
-        assertEquals( "four", pom.getValue( "build/plugins[1]/configuration/stringParams/stringParam[4]" ) );
+    void testOrderOfPluginConfigurationElementsWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-order/w-plugin-mgmt");
+        assertEquals("one", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[1]"));
+        assertEquals("two", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[2]"));
+        assertEquals("three", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[3]"));
+        assertEquals("four", pom.getValue("build/plugins[1]/configuration/stringParams/stringParam[4]"));
     }
 
     @Test
-    public void testOrderOfPluginExecutionConfigurationElementsWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-config-order/wo-plugin-mgmt" );
+    void testOrderOfPluginExecutionConfigurationElementsWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-config-order/wo-plugin-mgmt");
         String prefix = "build/plugins[1]/executions[1]/configuration/";
-        assertEquals( "one", pom.getValue( prefix + "stringParams/stringParam[1]" ) );
-        assertEquals( "two", pom.getValue( prefix + "stringParams/stringParam[2]" ) );
-        assertEquals( "three", pom.getValue( prefix + "stringParams/stringParam[3]" ) );
-        assertEquals( "four", pom.getValue( prefix + "stringParams/stringParam[4]" ) );
-        assertEquals( "key1", pom.getValue( prefix + "propertiesParam/property[1]/name" ) );
-        assertEquals( "key2", pom.getValue( prefix + "propertiesParam/property[2]/name" ) );
+        assertEquals("one", pom.getValue(prefix + "stringParams/stringParam[1]"));
+        assertEquals("two", pom.getValue(prefix + "stringParams/stringParam[2]"));
+        assertEquals("three", pom.getValue(prefix + "stringParams/stringParam[3]"));
+        assertEquals("four", pom.getValue(prefix + "stringParams/stringParam[4]"));
+        assertEquals("key1", pom.getValue(prefix + "propertiesParam/property[1]/name"));
+        assertEquals("key2", pom.getValue(prefix + "propertiesParam/property[2]/name"));
     }
 
     /* MNG-3864*/
     @Test
-    public void testOrderOfPluginExecutionConfigurationElementsWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-config-order/w-plugin-mgmt" );
+    void testOrderOfPluginExecutionConfigurationElementsWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-config-order/w-plugin-mgmt");
         String prefix = "build/plugins[1]/executions[1]/configuration/";
-        assertEquals( "one", pom.getValue( prefix + "stringParams/stringParam[1]" ) );
-        assertEquals( "two", pom.getValue( prefix + "stringParams/stringParam[2]" ) );
-        assertEquals( "three", pom.getValue( prefix + "stringParams/stringParam[3]" ) );
-        assertEquals( "four", pom.getValue( prefix + "stringParams/stringParam[4]" ) );
-        assertEquals( "key1", pom.getValue( prefix + "propertiesParam/property[1]/name" ) );
-        assertEquals( "key2", pom.getValue( prefix + "propertiesParam/property[2]/name" ) );
+        assertEquals("one", pom.getValue(prefix + "stringParams/stringParam[1]"));
+        assertEquals("two", pom.getValue(prefix + "stringParams/stringParam[2]"));
+        assertEquals("three", pom.getValue(prefix + "stringParams/stringParam[3]"));
+        assertEquals("four", pom.getValue(prefix + "stringParams/stringParam[4]"));
+        assertEquals("key1", pom.getValue(prefix + "propertiesParam/property[1]/name"));
+        assertEquals("key2", pom.getValue(prefix + "propertiesParam/property[2]/name"));
     }
 
     /* MNG-3836*/
     @Test
-    public void testMergeOfInheritedPluginConfiguration()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-merging/child" );
+    void testMergeOfInheritedPluginConfiguration() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-merging/child");
 
         String prefix = "build/plugins[1]/configuration/";
-        assertEquals( "PASSED", pom.getValue( prefix + "propertiesFile" ) );
-        assertEquals( "PASSED", pom.getValue( prefix + "parent" ) );
-        assertEquals( "PASSED-1", pom.getValue( prefix + "stringParams/stringParam[1]" ) );
-        assertEquals( "PASSED-3", pom.getValue( prefix + "stringParams/stringParam[2]" ) );
-        assertEquals( "PASSED-2", pom.getValue( prefix + "stringParams/stringParam[3]" ) );
-        assertEquals( "PASSED-4", pom.getValue( prefix + "stringParams/stringParam[4]" ) );
-        assertEquals( "PASSED-1", pom.getValue( prefix + "listParam/listParam[1]" ) );
-        assertEquals( "PASSED-3", pom.getValue( prefix + "listParam/listParam[2]" ) );
-        assertEquals( "PASSED-2", pom.getValue( prefix + "listParam/listParam[3]" ) );
-        assertEquals( "PASSED-4", pom.getValue( prefix + "listParam/listParam[4]" ) );
+        assertEquals("PASSED", pom.getValue(prefix + "propertiesFile"));
+        assertEquals("PASSED", pom.getValue(prefix + "parent"));
+        assertEquals("PASSED-1", pom.getValue(prefix + "stringParams/stringParam[1]"));
+        assertEquals("PASSED-3", pom.getValue(prefix + "stringParams/stringParam[2]"));
+        assertEquals("PASSED-2", pom.getValue(prefix + "stringParams/stringParam[3]"));
+        assertEquals("PASSED-4", pom.getValue(prefix + "stringParams/stringParam[4]"));
+        assertEquals("PASSED-1", pom.getValue(prefix + "listParam/listParam[1]"));
+        assertEquals("PASSED-3", pom.getValue(prefix + "listParam/listParam[2]"));
+        assertEquals("PASSED-2", pom.getValue(prefix + "listParam/listParam[3]"));
+        assertEquals("PASSED-4", pom.getValue(prefix + "listParam/listParam[4]"));
     }
 
     /* MNG-2591 */
     @Test
-    public void testAppendOfInheritedPluginConfigurationWithNoProfile()
-        throws Exception
-    {
-        testAppendOfInheritedPluginConfiguration( "no-profile" );
+    void testAppendOfInheritedPluginConfigurationWithNoProfile() throws Exception {
+        testAppendOfInheritedPluginConfiguration("no-profile");
     }
 
     /* MNG-2591*/
     @Test
-    public void testAppendOfInheritedPluginConfigurationWithActiveProfile()
-        throws Exception
-    {
-        testAppendOfInheritedPluginConfiguration( "with-profile" );
+    void testAppendOfInheritedPluginConfigurationWithActiveProfile() throws Exception {
+        testAppendOfInheritedPluginConfiguration("with-profile");
     }
 
-    private void testAppendOfInheritedPluginConfiguration( String test )
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-append/" + test + "/subproject" );
+    private void testAppendOfInheritedPluginConfiguration(String test) throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-append/" + test + "/subproject");
         String prefix = "build/plugins[1]/configuration/";
-        assertEquals( "PARENT-1", pom.getValue( prefix + "stringParams/stringParam[1]" ) );
-        assertEquals( "PARENT-3", pom.getValue( prefix + "stringParams/stringParam[2]" ) );
-        assertEquals( "PARENT-2", pom.getValue( prefix + "stringParams/stringParam[3]" ) );
-        assertEquals( "PARENT-4", pom.getValue( prefix + "stringParams/stringParam[4]" ) );
-        assertEquals( "CHILD-1", pom.getValue( prefix + "stringParams/stringParam[5]" ) );
-        assertEquals( "CHILD-3", pom.getValue( prefix + "stringParams/stringParam[6]" ) );
-        assertEquals( "CHILD-2", pom.getValue( prefix + "stringParams/stringParam[7]" ) );
-        assertEquals( "CHILD-4", pom.getValue( prefix + "stringParams/stringParam[8]" ) );
-        assertNull( pom.getValue( prefix + "stringParams/stringParam[9]" ) );
-        assertEquals( "PARENT-1", pom.getValue( prefix + "listParam/listParam[1]" ) );
-        assertEquals( "PARENT-3", pom.getValue( prefix + "listParam/listParam[2]" ) );
-        assertEquals( "PARENT-2", pom.getValue( prefix + "listParam/listParam[3]" ) );
-        assertEquals( "PARENT-4", pom.getValue( prefix + "listParam/listParam[4]" ) );
-        assertEquals( "CHILD-1", pom.getValue( prefix + "listParam/listParam[5]" ) );
-        assertEquals( "CHILD-3", pom.getValue( prefix + "listParam/listParam[6]" ) );
-        assertEquals( "CHILD-2", pom.getValue( prefix + "listParam/listParam[7]" ) );
-        assertEquals( "CHILD-4", pom.getValue( prefix + "listParam/listParam[8]" ) );
-        assertNull( pom.getValue( prefix + "listParam/listParam[9]" ) );
+        assertEquals("PARENT-1", pom.getValue(prefix + "stringParams/stringParam[1]"));
+        assertEquals("PARENT-3", pom.getValue(prefix + "stringParams/stringParam[2]"));
+        assertEquals("PARENT-2", pom.getValue(prefix + "stringParams/stringParam[3]"));
+        assertEquals("PARENT-4", pom.getValue(prefix + "stringParams/stringParam[4]"));
+        assertEquals("CHILD-1", pom.getValue(prefix + "stringParams/stringParam[5]"));
+        assertEquals("CHILD-3", pom.getValue(prefix + "stringParams/stringParam[6]"));
+        assertEquals("CHILD-2", pom.getValue(prefix + "stringParams/stringParam[7]"));
+        assertEquals("CHILD-4", pom.getValue(prefix + "stringParams/stringParam[8]"));
+        assertNull(pom.getValue(prefix + "stringParams/stringParam[9]"));
+        assertEquals("PARENT-1", pom.getValue(prefix + "listParam/listParam[1]"));
+        assertEquals("PARENT-3", pom.getValue(prefix + "listParam/listParam[2]"));
+        assertEquals("PARENT-2", pom.getValue(prefix + "listParam/listParam[3]"));
+        assertEquals("PARENT-4", pom.getValue(prefix + "listParam/listParam[4]"));
+        assertEquals("CHILD-1", pom.getValue(prefix + "listParam/listParam[5]"));
+        assertEquals("CHILD-3", pom.getValue(prefix + "listParam/listParam[6]"));
+        assertEquals("CHILD-2", pom.getValue(prefix + "listParam/listParam[7]"));
+        assertEquals("CHILD-4", pom.getValue(prefix + "listParam/listParam[8]"));
+        assertNull(pom.getValue(prefix + "listParam/listParam[9]"));
     }
 
     /* MNG-4000 */
     @Test
-    public void testMultiplePluginExecutionsWithAndWithoutIdsWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-w-and-wo-id/wo-plugin-mgmt" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "log-string", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "log-string", pom.getValue( "build/plugins[1]/executions[2]/goals[1]" ) );
+    void testMultiplePluginExecutionsWithAndWithoutIdsWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-w-and-wo-id/wo-plugin-mgmt");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("log-string", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("log-string", pom.getValue("build/plugins[1]/executions[2]/goals[1]"));
     }
 
     @Test
-    public void testMultiplePluginExecutionsWithAndWithoutIdsWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-w-and-wo-id/w-plugin-mgmt" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "log-string", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( "log-string", pom.getValue( "build/plugins[1]/executions[2]/goals[1]" ) );
+    void testMultiplePluginExecutionsWithAndWithoutIdsWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-w-and-wo-id/w-plugin-mgmt");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("log-string", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals("log-string", pom.getValue("build/plugins[1]/executions[2]/goals[1]"));
     }
 
     @Test
-    public void testDependencyOrderWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "dependency-order/wo-plugin-mgmt" );
-        assertEquals( 4, ( (List<?>) pom.getValue( "dependencies" ) ).size() );
-        assertEquals( "a", pom.getValue( "dependencies[1]/artifactId" ) );
-        assertEquals( "c", pom.getValue( "dependencies[2]/artifactId" ) );
-        assertEquals( "b", pom.getValue( "dependencies[3]/artifactId" ) );
-        assertEquals( "d", pom.getValue( "dependencies[4]/artifactId" ) );
+    void testDependencyOrderWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("dependency-order/wo-plugin-mgmt");
+        assertEquals(4, ((List<?>) pom.getValue("dependencies")).size());
+        assertEquals("a", pom.getValue("dependencies[1]/artifactId"));
+        assertEquals("c", pom.getValue("dependencies[2]/artifactId"));
+        assertEquals("b", pom.getValue("dependencies[3]/artifactId"));
+        assertEquals("d", pom.getValue("dependencies[4]/artifactId"));
     }
 
     @Test
-    public void testDependencyOrderWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "dependency-order/w-plugin-mgmt" );
-        assertEquals( 4, ( (List<?>) pom.getValue( "dependencies" ) ).size() );
-        assertEquals( "a", pom.getValue( "dependencies[1]/artifactId" ) );
-        assertEquals( "c", pom.getValue( "dependencies[2]/artifactId" ) );
-        assertEquals( "b", pom.getValue( "dependencies[3]/artifactId" ) );
-        assertEquals( "d", pom.getValue( "dependencies[4]/artifactId" ) );
+    void testDependencyOrderWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("dependency-order/w-plugin-mgmt");
+        assertEquals(4, ((List<?>) pom.getValue("dependencies")).size());
+        assertEquals("a", pom.getValue("dependencies[1]/artifactId"));
+        assertEquals("c", pom.getValue("dependencies[2]/artifactId"));
+        assertEquals("b", pom.getValue("dependencies[3]/artifactId"));
+        assertEquals("d", pom.getValue("dependencies[4]/artifactId"));
     }
 
     @Test
-    public void testBuildDirectoriesUsePlatformSpecificFileSeparator()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "platform-file-separator" );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/directory" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/outputDirectory" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/testOutputDirectory" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/sourceDirectory" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/testSourceDirectory" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/resources[1]/directory" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/testResources[1]/directory" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "build/filters[1]" ) );
-        assertPathWithNormalizedFileSeparators( pom.getValue( "reporting/outputDirectory" ) );
+    void testBuildDirectoriesUsePlatformSpecificFileSeparator() throws Exception {
+        PomTestWrapper pom = buildPom("platform-file-separator");
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/directory"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/outputDirectory"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/testOutputDirectory"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/sourceDirectory"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/testSourceDirectory"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/resources[1]/directory"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/testResources[1]/directory"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("build/filters[1]"));
+        assertPathWithNormalizedFileSeparators(pom.getValue("reporting/outputDirectory"));
     }
 
     /* MNG-4008 */
     @Test
-    public void testMergedFilterOrder()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "merged-filter-order/sub" );
+    void testMergedFilterOrder() throws Exception {
+        PomTestWrapper pom = buildPom("merged-filter-order/sub");
 
-        assertEquals( 7, ( (List<?>) pom.getValue( "build/filters" ) ).size() );
-        assertThat( pom.getValue( "build/filters[1]" ).toString(), endsWith( "child-a.properties" ) );
-        assertThat( pom.getValue( "build/filters[2]" ).toString(), endsWith( "child-c.properties" ) );
-        assertThat( pom.getValue( "build/filters[3]" ).toString(), endsWith( "child-b.properties" ) );
-        assertThat( pom.getValue( "build/filters[4]" ).toString(), endsWith( "child-d.properties" ) );
-        assertThat( pom.getValue( "build/filters[5]" ).toString(), endsWith( "parent-c.properties" ) );
-        assertThat( pom.getValue( "build/filters[6]" ).toString(), endsWith( "parent-b.properties" ) );
-        assertThat( pom.getValue( "build/filters[7]" ).toString(), endsWith( "parent-d.properties" ) );
+        assertEquals(7, ((List<?>) pom.getValue("build/filters")).size());
+        assertThat(pom.getValue("build/filters[1]").toString(), endsWith("child-a.properties"));
+        assertThat(pom.getValue("build/filters[2]").toString(), endsWith("child-c.properties"));
+        assertThat(pom.getValue("build/filters[3]").toString(), endsWith("child-b.properties"));
+        assertThat(pom.getValue("build/filters[4]").toString(), endsWith("child-d.properties"));
+        assertThat(pom.getValue("build/filters[5]").toString(), endsWith("parent-c.properties"));
+        assertThat(pom.getValue("build/filters[6]").toString(), endsWith("parent-b.properties"));
+        assertThat(pom.getValue("build/filters[7]").toString(), endsWith("parent-d.properties"));
     }
 
     /** MNG-4027*/
     @Test
-    public void testProfileInjectedDependencies()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "profile-injected-dependencies" );
-        assertEquals( 4, ( (List<?>) pom.getValue( "dependencies" ) ).size() );
-        assertEquals( "a", pom.getValue( "dependencies[1]/artifactId" ) );
-        assertEquals( "c", pom.getValue( "dependencies[2]/artifactId" ) );
-        assertEquals( "b", pom.getValue( "dependencies[3]/artifactId" ) );
-        assertEquals( "d", pom.getValue( "dependencies[4]/artifactId" ) );
+    void testProfileInjectedDependencies() throws Exception {
+        PomTestWrapper pom = buildPom("profile-injected-dependencies");
+        assertEquals(4, ((List<?>) pom.getValue("dependencies")).size());
+        assertEquals("a", pom.getValue("dependencies[1]/artifactId"));
+        assertEquals("c", pom.getValue("dependencies[2]/artifactId"));
+        assertEquals("b", pom.getValue("dependencies[3]/artifactId"));
+        assertEquals("d", pom.getValue("dependencies[4]/artifactId"));
     }
 
     /** IT-0021*/
     @Test
-    public void testProfileDependenciesMultipleProfiles()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "profile-dependencies-multiple-profiles", "profile-1", "profile-2" );
-        assertEquals(2,  ( (List<?>) pom.getValue( "dependencies" ) ).size() );
+    void testProfileDependenciesMultipleProfiles() throws Exception {
+        PomTestWrapper pom = buildPom("profile-dependencies-multiple-profiles", "profile-1", "profile-2");
+        assertEquals(2, ((List<?>) pom.getValue("dependencies")).size());
     }
 
     @Test
-    public void testDependencyInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "dependency-inheritance/sub" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencies" ) ).size() );
-        assertEquals( "4.13.1", pom.getValue( "dependencies[1]/version" ) );
+    void testDependencyInheritance() throws Exception {
+        PomTestWrapper pom = buildPom("dependency-inheritance/sub");
+        assertEquals(1, ((List<?>) pom.getValue("dependencies")).size());
+        assertEquals("4.13.1", pom.getValue("dependencies[1]/version"));
     }
 
     /** MNG-4034 */
     @Test
-    public void testManagedProfileDependency()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "managed-profile-dependency/sub", "maven-core-it" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencies" ) ).size() );
-        assertEquals( "org.apache.maven.its", pom.getValue( "dependencies[1]/groupId" ) );
-        assertEquals( "maven-core-it-support", pom.getValue( "dependencies[1]/artifactId" ) );
-        assertEquals( "1.3", pom.getValue( "dependencies[1]/version" ) );
-        assertEquals( "runtime", pom.getValue( "dependencies[1]/scope" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencies[1]/exclusions" ) ).size() );
-        assertEquals( "commons-lang", pom.getValue( "dependencies[1]/exclusions[1]/groupId" ) );
+    void testManagedProfileDependency() throws Exception {
+        PomTestWrapper pom = this.buildPom("managed-profile-dependency/sub", "maven-core-it");
+        assertEquals(1, ((List<?>) pom.getValue("dependencies")).size());
+        assertEquals("org.apache.maven.its", pom.getValue("dependencies[1]/groupId"));
+        assertEquals("maven-core-it-support", pom.getValue("dependencies[1]/artifactId"));
+        assertEquals("1.3", pom.getValue("dependencies[1]/version"));
+        assertEquals("runtime", pom.getValue("dependencies[1]/scope"));
+        assertEquals(1, ((List<?>) pom.getValue("dependencies[1]/exclusions")).size());
+        assertEquals("commons-lang", pom.getValue("dependencies[1]/exclusions[1]/groupId"));
     }
 
     /** MNG-4040 */
     @Test
-    public void testProfileModuleInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "profile-module-inheritance/sub", "dist" );
-        assertEquals( 0, ( (List<?>) pom.getValue( "modules" ) ).size() );
+    void testProfileModuleInheritance() throws Exception {
+        PomTestWrapper pom = this.buildPom("profile-module-inheritance/sub", "dist");
+        assertEquals(0, ((List<?>) pom.getValue("modules")).size());
     }
 
     /** MNG-3621 */
     @Test
-    public void testUncPath()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "unc-path/sub" );
-        assertEquals( "file:////host/site/test-child", pom.getValue( "distributionManagement/site/url" ) );
+    void testUncPath() throws Exception {
+        PomTestWrapper pom = this.buildPom("unc-path/sub");
+        assertEquals("file:////host/site/test-child", pom.getValue("distributionManagement/site/url"));
     }
 
     /** MNG-2006 */
     @Test
-    public void testUrlAppendWithChildPathAdjustment()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "url-append/child" );
-        assertEquals( "https://project.url/child", pom.getValue( "url" ) );
-        assertEquals( "https://viewvc.project.url/child", pom.getValue( "scm/url" ) );
-        assertEquals( "https://scm.project.url/child", pom.getValue( "scm/connection" ) );
-        assertEquals( "https://scm.project.url/child", pom.getValue( "scm/developerConnection" ) );
-        assertEquals( "https://site.project.url/child", pom.getValue( "distributionManagement/site/url" ) );
+    void testUrlAppendWithChildPathAdjustment() throws Exception {
+        PomTestWrapper pom = this.buildPom("url-append/child");
+        assertEquals("https://project.url/child", pom.getValue("url"));
+        assertEquals("https://viewvc.project.url/child", pom.getValue("scm/url"));
+        assertEquals("https://scm.project.url/child", pom.getValue("scm/connection"));
+        assertEquals("https://scm.project.url/child", pom.getValue("scm/developerConnection"));
+        assertEquals("https://site.project.url/child", pom.getValue("distributionManagement/site/url"));
     }
 
     /** MNG-0479 */
     @Test
-    public void testRepoInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "repo-inheritance" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "repositories" ) ).size() );
-        assertEquals( "it0043", pom.getValue( "repositories[1]/name" ) );
+    void testRepoInheritance() throws Exception {
+        PomTestWrapper pom = this.buildPom("repo-inheritance");
+        assertEquals(1, ((List<?>) pom.getValue("repositories")).size());
+        assertEquals("it0043", pom.getValue("repositories[1]/name"));
     }
 
     @Test
-    public void testEmptyScm()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "empty-scm" );
-        assertNull( pom.getValue( "scm" ) );
+    void testEmptyScm() throws Exception {
+        PomTestWrapper pom = this.buildPom("empty-scm");
+        assertNull(pom.getValue("scm"));
     }
 
     @Test
-    public void testPluginConfigurationUsingAttributesWithoutPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-attributes/wo-plugin-mgmt" );
-        assertEquals( "src", pom.getValue( "build/plugins[1]/configuration/domParam/copy/@todir" ) );
-        assertEquals( "true", pom.getValue( "build/plugins[1]/configuration/domParam/copy/@overwrite" ) );
-        assertEquals( "target", pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@dir" ) );
-        assertNull( pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@todir" ) );
-        assertNull( pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@overwrite" ) );
+    void testPluginConfigurationUsingAttributesWithoutPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-attributes/wo-plugin-mgmt");
+        assertEquals("src", pom.getValue("build/plugins[1]/configuration/domParam/copy/@todir"));
+        assertEquals("true", pom.getValue("build/plugins[1]/configuration/domParam/copy/@overwrite"));
+        assertEquals("target", pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@dir"));
+        assertNull(pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@todir"));
+        assertNull(pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@overwrite"));
     }
 
     /** MNG-4053*/
     @Test
-    public void testPluginConfigurationUsingAttributesWithPluginManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-attributes/w-plugin-mgmt" );
-        assertEquals( "src", pom.getValue( "build/plugins[1]/configuration/domParam/copy/@todir" ) );
-        assertEquals( "true", pom.getValue( "build/plugins[1]/configuration/domParam/copy/@overwrite" ) );
-        assertEquals( "target", pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@dir" ) );
-        assertNull( pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@todir" ) );
-        assertNull( pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@overwrite" ) );
+    void testPluginConfigurationUsingAttributesWithPluginManagement() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-attributes/w-plugin-mgmt");
+        assertEquals("src", pom.getValue("build/plugins[1]/configuration/domParam/copy/@todir"));
+        assertEquals("true", pom.getValue("build/plugins[1]/configuration/domParam/copy/@overwrite"));
+        assertEquals("target", pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@dir"));
+        assertNull(pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@todir"));
+        assertNull(pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@overwrite"));
     }
 
     @Test
-    public void testPluginConfigurationUsingAttributesWithPluginManagementAndProfile()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-config-attributes/w-profile", "maven-core-it" );
-        assertEquals( "src", pom.getValue( "build/plugins[1]/configuration/domParam/copy/@todir" ) );
-        assertEquals( "true", pom.getValue( "build/plugins[1]/configuration/domParam/copy/@overwrite" ) );
-        assertEquals( "target", pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@dir" ) );
-        assertNull( pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@todir" ) );
-        assertNull( pom.getValue( "build/plugins[1]/configuration/domParam/copy/fileset/@overwrite" ) );
+    void testPluginConfigurationUsingAttributesWithPluginManagementAndProfile() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-config-attributes/w-profile", "maven-core-it");
+        assertEquals("src", pom.getValue("build/plugins[1]/configuration/domParam/copy/@todir"));
+        assertEquals("true", pom.getValue("build/plugins[1]/configuration/domParam/copy/@overwrite"));
+        assertEquals("target", pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@dir"));
+        assertNull(pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@todir"));
+        assertNull(pom.getValue("build/plugins[1]/configuration/domParam/copy/fileset/@overwrite"));
     }
 
     @Test
-    public void testPomEncoding()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "pom-encoding/utf-8" );
-        assertEquals( "TEST-CHARS: \u00DF\u0131\u03A3\u042F\u05D0\u20AC", pom.getValue( "description" ) );
-        pom = buildPom( "pom-encoding/latin-1" );
-        assertEquals( "TEST-CHARS: \u00C4\u00D6\u00DC\u00E4\u00F6\u00FC\u00DF", pom.getValue( "description" ) );
+    void testPomEncoding() throws Exception {
+        PomTestWrapper pom = buildPom("pom-encoding/utf-8");
+        assertEquals("TEST-CHARS: \u00DF\u0131\u03A3\u042F\u05D0\u20AC", pom.getValue("description"));
+        pom = buildPom("pom-encoding/latin-1");
+        assertEquals("TEST-CHARS: \u00C4\u00D6\u00DC\u00E4\u00F6\u00FC\u00DF", pom.getValue("description"));
     }
 
     /* MNG-4070 */
     @Test
-    public void testXmlWhitespaceHandling()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "xml-whitespace/sub" );
-        assertEquals( "org.apache.maven.its.mng4070", pom.getValue( "groupId" ) );
+    void testXmlWhitespaceHandling() throws Exception {
+        PomTestWrapper pom = buildPom("xml-whitespace/sub");
+        assertEquals("org.apache.maven.its.mng4070", pom.getValue("groupId"));
     }
 
     /* MNG-3760*/
     @Test
-    public void testInterpolationOfBaseUri()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "baseuri-interpolation/pom.xml" );
-        assertNotEquals( pom.getBasedir().toURI().toString(), pom.getValue( "properties/prop1" ).toString() );
+    void testInterpolationOfBaseUri() throws Exception {
+        PomTestWrapper pom = buildPom("baseuri-interpolation/pom.xml");
+        assertNotEquals(
+                pom.getBasedir().toURI().toString(),
+                pom.getValue("properties/prop1").toString());
     }
 
     /* MNG-6386 */
     @Test
-    public void testInterpolationOfRfc3986BaseUri()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "baseuri-interpolation/pom.xml" );
-        String prop1 = pom.getValue( "properties/prop1" ).toString();
-        assertEquals( pom.getBasedir().toPath().toUri().toASCIIString(), prop1 );
-        assertThat( prop1, startsWith( "file:///" ) );
+    void testInterpolationOfRfc3986BaseUri() throws Exception {
+        PomTestWrapper pom = buildPom("baseuri-interpolation/pom.xml");
+        String prop1 = pom.getValue("properties/prop1").toString();
+        assertEquals(pom.getBasedir().toPath().toUri().toASCIIString(), prop1);
+        assertThat(prop1, startsWith("file:///"));
     }
 
     /* MNG-3811*/
     @Test
-    public void testReportingPluginConfig()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "reporting-plugin-config/sub" );
+    void testReportingPluginConfig() throws Exception {
+        PomTestWrapper pom = buildPom("reporting-plugin-config/sub");
 
-        assertEquals( 3, ( (List<?>) pom.getValue( "reporting/plugins[1]/configuration/stringParams" ) ).size() );
-        assertEquals( "parentParam", pom.getValue( "reporting/plugins[1]/configuration/stringParams[1]/stringParam[1]" ) );
-        assertEquals( "childParam", pom.getValue( "reporting/plugins[1]/configuration/stringParams[1]/stringParam[2]" ) );
-        assertEquals( "  preserve space  ", pom.getValue( "reporting/plugins[1]/configuration/stringParams[1]/stringParam[3]" ) );
-        assertEquals( "true", pom.getValue( "reporting/plugins[1]/configuration/booleanParam" ) );
+        assertEquals(3, ((List<?>) pom.getValue("reporting/plugins[1]/configuration/stringParams")).size());
+        assertEquals("parentParam", pom.getValue("reporting/plugins[1]/configuration/stringParams[1]/stringParam[1]"));
+        assertEquals("childParam", pom.getValue("reporting/plugins[1]/configuration/stringParams[1]/stringParam[2]"));
+        assertEquals(
+                "  preserve space  ",
+                pom.getValue("reporting/plugins[1]/configuration/stringParams[1]/stringParam[3]"));
+        assertEquals("true", pom.getValue("reporting/plugins[1]/configuration/booleanParam"));
     }
 
     @Test
-    public void testPropertiesNoDuplication()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "properties-no-duplication/sub" );
-        assertEquals( 1, ( (Properties) pom.getValue( "properties" ) ).size() );
-        assertEquals( "child", pom.getValue( "properties/pomProfile" ) );
+    void testPropertiesNoDuplication() throws Exception {
+        PomTestWrapper pom = buildPom("properties-no-duplication/sub");
+        assertEquals(3, ((Properties) pom.getValue("properties")).size());
+        assertEquals("child", pom.getValue("properties/pomProfile"));
     }
 
     @Test
-    public void testPomInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "pom-inheritance/sub" );
-        assertEquals( "parent-description", pom.getValue( "description" ) );
-        assertEquals( "jar", pom.getValue( "packaging" ) );
+    void testPomInheritance() throws Exception {
+        PomTestWrapper pom = buildPom("pom-inheritance/sub");
+        assertEquals("parent-description", pom.getValue("description"));
+        assertEquals("jar", pom.getValue("packaging"));
     }
 
     @Test
-    public void testCompleteModelWithoutParent()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "complete-model/wo-parent" );
+    void testCompleteModelWithoutParent() throws Exception {
+        PomTestWrapper pom = buildPom("complete-model/wo-parent");
 
-        testCompleteModel( pom );
+        testCompleteModel(pom);
     }
 
     @Test
-    public void testCompleteModelWithParent()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "complete-model/w-parent/sub" );
+    void testCompleteModelWithParent() throws Exception {
+        PomTestWrapper pom = buildPom("complete-model/w-parent/sub");
 
-        testCompleteModel( pom );
+        testCompleteModel(pom);
     }
 
-    private void testCompleteModel( PomTestWrapper pom )
-        throws Exception
-    {
-        assertEquals( "4.0.0", pom.getValue( "modelVersion" ) );
+    private void testCompleteModel(PomTestWrapper pom) throws Exception {
+        assertEquals("4.0.0", pom.getValue("modelVersion"));
 
-        assertEquals( "org.apache.maven.its.mng", pom.getValue( "groupId" ) );
-        assertEquals( "test", pom.getValue( "artifactId" ) );
-        assertEquals( "0.2", pom.getValue( "version" ) );
-        assertEquals( "pom", pom.getValue( "packaging" ) );
+        assertEquals("org.apache.maven.its.mng", pom.getValue("groupId"));
+        assertEquals("test", pom.getValue("artifactId"));
+        assertEquals("0.2", pom.getValue("version"));
+        assertEquals("pom", pom.getValue("packaging"));
 
-        assertEquals( "project-name", pom.getValue( "name" ) );
-        assertEquals( "project-description", pom.getValue( "description" ) );
-        assertEquals( "https://project.url/", pom.getValue( "url" ) );
-        assertEquals( "2009", pom.getValue( "inceptionYear" ) );
+        assertEquals("project-name", pom.getValue("name"));
+        assertEquals("project-description", pom.getValue("description"));
+        assertEquals("https://project.url/", pom.getValue("url"));
+        assertEquals("2009", pom.getValue("inceptionYear"));
 
-        assertEquals( "project-org", pom.getValue( "organization/name" ) );
-        assertEquals( "https://project-org.url/", pom.getValue( "organization/url" ) );
+        assertEquals("project-org", pom.getValue("organization/name"));
+        assertEquals("https://project-org.url/", pom.getValue("organization/url"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "licenses" ) ).size() );
-        assertEquals( "project-license", pom.getValue( "licenses[1]/name" ) );
-        assertEquals( "https://project.url/license", pom.getValue( "licenses[1]/url" ) );
-        assertEquals( "repo", pom.getValue( "licenses[1]/distribution" ) );
-        assertEquals( "free", pom.getValue( "licenses[1]/comments" ) );
+        assertEquals(1, ((List<?>) pom.getValue("licenses")).size());
+        assertEquals("project-license", pom.getValue("licenses[1]/name"));
+        assertEquals("https://project.url/license", pom.getValue("licenses[1]/url"));
+        assertEquals("repo", pom.getValue("licenses[1]/distribution"));
+        assertEquals("free", pom.getValue("licenses[1]/comments"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "developers" ) ).size() );
-        assertEquals( "dev", pom.getValue( "developers[1]/id" ) );
-        assertEquals( "project-developer", pom.getValue( "developers[1]/name" ) );
-        assertEquals( "developer@", pom.getValue( "developers[1]/email" ) );
-        assertEquals( "https://developer", pom.getValue( "developers[1]/url" ) );
-        assertEquals( "developer", pom.getValue( "developers[1]/organization" ) );
-        assertEquals( "https://devel.org", pom.getValue( "developers[1]/organizationUrl" ) );
-        assertEquals( "-1", pom.getValue( "developers[1]/timezone" ) );
-        assertEquals( "yes", pom.getValue( "developers[1]/properties/developer" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "developers[1]/roles" ) ).size() );
-        assertEquals( "devel", pom.getValue( "developers[1]/roles[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("developers")).size());
+        assertEquals("dev", pom.getValue("developers[1]/id"));
+        assertEquals("project-developer", pom.getValue("developers[1]/name"));
+        assertEquals("developer@", pom.getValue("developers[1]/email"));
+        assertEquals("https://developer", pom.getValue("developers[1]/url"));
+        assertEquals("developer", pom.getValue("developers[1]/organization"));
+        assertEquals("https://devel.org", pom.getValue("developers[1]/organizationUrl"));
+        assertEquals("-1", pom.getValue("developers[1]/timezone"));
+        assertEquals("yes", pom.getValue("developers[1]/properties/developer"));
+        assertEquals(1, ((List<?>) pom.getValue("developers[1]/roles")).size());
+        assertEquals("devel", pom.getValue("developers[1]/roles[1]"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "contributors" ) ).size() );
-        assertEquals( "project-contributor", pom.getValue( "contributors[1]/name" ) );
-        assertEquals( "contributor@", pom.getValue( "contributors[1]/email" ) );
-        assertEquals( "https://contributor", pom.getValue( "contributors[1]/url" ) );
-        assertEquals( "contributor", pom.getValue( "contributors[1]/organization" ) );
-        assertEquals( "https://contrib.org", pom.getValue( "contributors[1]/organizationUrl" ) );
-        assertEquals( "+1", pom.getValue( "contributors[1]/timezone" ) );
-        assertEquals( "yes", pom.getValue( "contributors[1]/properties/contributor" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "contributors[1]/roles" ) ).size() );
-        assertEquals( "contrib", pom.getValue( "contributors[1]/roles[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("contributors")).size());
+        assertEquals("project-contributor", pom.getValue("contributors[1]/name"));
+        assertEquals("contributor@", pom.getValue("contributors[1]/email"));
+        assertEquals("https://contributor", pom.getValue("contributors[1]/url"));
+        assertEquals("contributor", pom.getValue("contributors[1]/organization"));
+        assertEquals("https://contrib.org", pom.getValue("contributors[1]/organizationUrl"));
+        assertEquals("+1", pom.getValue("contributors[1]/timezone"));
+        assertEquals("yes", pom.getValue("contributors[1]/properties/contributor"));
+        assertEquals(1, ((List<?>) pom.getValue("contributors[1]/roles")).size());
+        assertEquals("contrib", pom.getValue("contributors[1]/roles[1]"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "mailingLists" ) ).size() );
-        assertEquals( "project-mailing-list", pom.getValue( "mailingLists[1]/name" ) );
-        assertEquals( "subscribe@", pom.getValue( "mailingLists[1]/subscribe" ) );
-        assertEquals( "unsubscribe@", pom.getValue( "mailingLists[1]/unsubscribe" ) );
-        assertEquals( "post@", pom.getValue( "mailingLists[1]/post" ) );
-        assertEquals( "mail-archive", pom.getValue( "mailingLists[1]/archive" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "mailingLists[1]/otherArchives" ) ).size() );
-        assertEquals( "other-archive", pom.getValue( "mailingLists[1]/otherArchives[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("mailingLists")).size());
+        assertEquals("project-mailing-list", pom.getValue("mailingLists[1]/name"));
+        assertEquals("subscribe@", pom.getValue("mailingLists[1]/subscribe"));
+        assertEquals("unsubscribe@", pom.getValue("mailingLists[1]/unsubscribe"));
+        assertEquals("post@", pom.getValue("mailingLists[1]/post"));
+        assertEquals("mail-archive", pom.getValue("mailingLists[1]/archive"));
+        assertEquals(1, ((List<?>) pom.getValue("mailingLists[1]/otherArchives")).size());
+        assertEquals("other-archive", pom.getValue("mailingLists[1]/otherArchives[1]"));
 
-        assertEquals( "2.0.1", pom.getValue( "prerequisites/maven" ) );
+        assertEquals("2.0.1", pom.getValue("prerequisites/maven"));
 
-        assertEquals( "https://project.url/trunk", pom.getValue( "scm/url" ) );
-        assertEquals( "https://project.url/scm", pom.getValue( "scm/connection" ) );
-        assertEquals( "https://project.url/scm", pom.getValue( "scm/developerConnection" ) );
-        assertEquals( "TAG", pom.getValue( "scm/tag" ) );
+        assertEquals("https://project.url/trunk", pom.getValue("scm/url"));
+        assertEquals("https://project.url/scm", pom.getValue("scm/connection"));
+        assertEquals("https://project.url/scm", pom.getValue("scm/developerConnection"));
+        assertEquals("TAG", pom.getValue("scm/tag"));
 
-        assertEquals( "issues", pom.getValue( "issueManagement/system" ) );
-        assertEquals( "https://project.url/issues", pom.getValue( "issueManagement/url" ) );
+        assertEquals("issues", pom.getValue("issueManagement/system"));
+        assertEquals("https://project.url/issues", pom.getValue("issueManagement/url"));
 
-        assertEquals( "ci", pom.getValue( "ciManagement/system" ) );
-        assertEquals( "https://project.url/ci", pom.getValue( "ciManagement/url" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "ciManagement/notifiers" ) ).size() );
-        assertEquals( "irc", pom.getValue( "ciManagement/notifiers[1]/type" ) );
-        assertEquals( "ci@", pom.getValue( "ciManagement/notifiers[1]/address" ) );
-        assertEquals( Boolean.TRUE, pom.getValue( "ciManagement/notifiers[1]/sendOnError" ) );
-        assertEquals( Boolean.FALSE, pom.getValue( "ciManagement/notifiers[1]/sendOnFailure" ) );
-        assertEquals( Boolean.FALSE, pom.getValue( "ciManagement/notifiers[1]/sendOnWarning" ) );
-        assertEquals( Boolean.FALSE, pom.getValue( "ciManagement/notifiers[1]/sendOnSuccess" ) );
-        assertEquals( "ci", pom.getValue( "ciManagement/notifiers[1]/configuration/ciProp" ) );
+        assertEquals("ci", pom.getValue("ciManagement/system"));
+        assertEquals("https://project.url/ci", pom.getValue("ciManagement/url"));
+        assertEquals(1, ((List<?>) pom.getValue("ciManagement/notifiers")).size());
+        assertEquals("irc", pom.getValue("ciManagement/notifiers[1]/type"));
+        assertEquals("ci@", pom.getValue("ciManagement/notifiers[1]/address"));
+        assertEquals(Boolean.TRUE, pom.getValue("ciManagement/notifiers[1]/sendOnError"));
+        assertEquals(Boolean.FALSE, pom.getValue("ciManagement/notifiers[1]/sendOnFailure"));
+        assertEquals(Boolean.FALSE, pom.getValue("ciManagement/notifiers[1]/sendOnWarning"));
+        assertEquals(Boolean.FALSE, pom.getValue("ciManagement/notifiers[1]/sendOnSuccess"));
+        assertEquals("ci", pom.getValue("ciManagement/notifiers[1]/configuration/ciProp"));
 
-        assertEquals( "project.distros", pom.getValue( "distributionManagement/repository/id" ) );
-        assertEquals( "distros", pom.getValue( "distributionManagement/repository/name" ) );
-        assertEquals( "https://project.url/dist", pom.getValue( "distributionManagement/repository/url" ) );
-        assertEquals( Boolean.TRUE, pom.getValue( "distributionManagement/repository/uniqueVersion" ) );
+        assertEquals("project.distros", pom.getValue("distributionManagement/repository/id"));
+        assertEquals("distros", pom.getValue("distributionManagement/repository/name"));
+        assertEquals("https://project.url/dist", pom.getValue("distributionManagement/repository/url"));
+        assertEquals(Boolean.TRUE, pom.getValue("distributionManagement/repository/uniqueVersion"));
 
-        assertEquals( "project.snaps", pom.getValue( "distributionManagement/snapshotRepository/id" ) );
-        assertEquals( "snaps", pom.getValue( "distributionManagement/snapshotRepository/name" ) );
-        assertEquals( "https://project.url/snaps", pom.getValue( "distributionManagement/snapshotRepository/url" ) );
-        assertEquals( Boolean.FALSE, pom.getValue( "distributionManagement/snapshotRepository/uniqueVersion" ) );
+        assertEquals("project.snaps", pom.getValue("distributionManagement/snapshotRepository/id"));
+        assertEquals("snaps", pom.getValue("distributionManagement/snapshotRepository/name"));
+        assertEquals("https://project.url/snaps", pom.getValue("distributionManagement/snapshotRepository/url"));
+        assertEquals(Boolean.FALSE, pom.getValue("distributionManagement/snapshotRepository/uniqueVersion"));
 
-        assertEquals( "project.site", pom.getValue( "distributionManagement/site/id" ) );
-        assertEquals( "docs", pom.getValue( "distributionManagement/site/name" ) );
-        assertEquals( "https://project.url/site", pom.getValue( "distributionManagement/site/url" ) );
+        assertEquals("project.site", pom.getValue("distributionManagement/site/id"));
+        assertEquals("docs", pom.getValue("distributionManagement/site/name"));
+        assertEquals("https://project.url/site", pom.getValue("distributionManagement/site/url"));
 
-        assertEquals( "https://project.url/download", pom.getValue( "distributionManagement/downloadUrl" ) );
-        assertEquals( "reloc-gid", pom.getValue( "distributionManagement/relocation/groupId" ) );
-        assertEquals( "reloc-aid", pom.getValue( "distributionManagement/relocation/artifactId" ) );
-        assertEquals( "reloc-version", pom.getValue( "distributionManagement/relocation/version" ) );
-        assertEquals( "project-reloc-msg", pom.getValue( "distributionManagement/relocation/message" ) );
+        assertEquals("https://project.url/download", pom.getValue("distributionManagement/downloadUrl"));
+        assertEquals("reloc-gid", pom.getValue("distributionManagement/relocation/groupId"));
+        assertEquals("reloc-aid", pom.getValue("distributionManagement/relocation/artifactId"));
+        assertEquals("reloc-version", pom.getValue("distributionManagement/relocation/version"));
+        assertEquals("project-reloc-msg", pom.getValue("distributionManagement/relocation/message"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "modules" ) ).size() );
-        assertEquals( "sub", pom.getValue( "modules[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("modules")).size());
+        assertEquals("sub", pom.getValue("modules[1]"));
 
-        assertEquals( 1, ( (Map<?, ?>) pom.getValue( "properties" ) ).size() );
-        assertEquals( "project-property", pom.getValue( "properties[1]/itProperty" ) );
+        assertEquals(3, ((Map<?, ?>) pom.getValue("properties")).size());
+        assertEquals("project-property", pom.getValue("properties[1]/itProperty"));
+        assertEquals("UTF-8", pom.getValue("properties[1]/project.build.sourceEncoding"));
+        assertEquals("UTF-8", pom.getValue("properties[1]/project.reporting.outputEncoding"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencyManagement/dependencies" ) ).size() );
-        assertEquals( "org.apache.maven.its", pom.getValue( "dependencyManagement/dependencies[1]/groupId" ) );
-        assertEquals( "managed-dep", pom.getValue( "dependencyManagement/dependencies[1]/artifactId" ) );
-        assertEquals( "0.1", pom.getValue( "dependencyManagement/dependencies[1]/version" ) );
-        assertEquals( "war", pom.getValue( "dependencyManagement/dependencies[1]/type" ) );
-        assertEquals( "runtime", pom.getValue( "dependencyManagement/dependencies[1]/scope" ) );
-        assertEquals( Boolean.FALSE, pom.getValue( "dependencyManagement/dependencies[1]/optional" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencyManagement/dependencies[1]/exclusions" ) ).size() );
-        assertEquals( "org.apache.maven.its",
-                      pom.getValue( "dependencyManagement/dependencies[1]/exclusions[1]/groupId" ) );
-        assertEquals( "excluded-managed-dep",
-                      pom.getValue( "dependencyManagement/dependencies[1]/exclusions[1]/artifactId" ) );
+        assertEquals(1, ((List<?>) pom.getValue("dependencyManagement/dependencies")).size());
+        assertEquals("org.apache.maven.its", pom.getValue("dependencyManagement/dependencies[1]/groupId"));
+        assertEquals("managed-dep", pom.getValue("dependencyManagement/dependencies[1]/artifactId"));
+        assertEquals("0.1", pom.getValue("dependencyManagement/dependencies[1]/version"));
+        assertEquals("war", pom.getValue("dependencyManagement/dependencies[1]/type"));
+        assertEquals("runtime", pom.getValue("dependencyManagement/dependencies[1]/scope"));
+        assertEquals(Boolean.FALSE, pom.getValue("dependencyManagement/dependencies[1]/optional"));
+        assertEquals(1, ((List<?>) pom.getValue("dependencyManagement/dependencies[1]/exclusions")).size());
+        assertEquals(
+                "org.apache.maven.its", pom.getValue("dependencyManagement/dependencies[1]/exclusions[1]/groupId"));
+        assertEquals(
+                "excluded-managed-dep", pom.getValue("dependencyManagement/dependencies[1]/exclusions[1]/artifactId"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencies" ) ).size() );
-        assertEquals( "org.apache.maven.its", pom.getValue( "dependencies[1]/groupId" ) );
-        assertEquals( "dep", pom.getValue( "dependencies[1]/artifactId" ) );
-        assertEquals( "0.2", pom.getValue( "dependencies[1]/version" ) );
-        assertEquals( "ejb", pom.getValue( "dependencies[1]/type" ) );
-        assertEquals( "test", pom.getValue( "dependencies[1]/scope" ) );
-        assertEquals( Boolean.TRUE, pom.getValue( "dependencies[1]/optional" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "dependencies[1]/exclusions" ) ).size() );
-        assertEquals( "org.apache.maven.its", pom.getValue( "dependencies[1]/exclusions[1]/groupId" ) );
-        assertEquals( "excluded-dep", pom.getValue( "dependencies[1]/exclusions[1]/artifactId" ) );
+        assertEquals(1, ((List<?>) pom.getValue("dependencies")).size());
+        assertEquals("org.apache.maven.its", pom.getValue("dependencies[1]/groupId"));
+        assertEquals("dep", pom.getValue("dependencies[1]/artifactId"));
+        assertEquals("0.2", pom.getValue("dependencies[1]/version"));
+        assertEquals("ejb", pom.getValue("dependencies[1]/type"));
+        assertEquals("test", pom.getValue("dependencies[1]/scope"));
+        assertEquals(Boolean.TRUE, pom.getValue("dependencies[1]/optional"));
+        assertEquals(1, ((List<?>) pom.getValue("dependencies[1]/exclusions")).size());
+        assertEquals("org.apache.maven.its", pom.getValue("dependencies[1]/exclusions[1]/groupId"));
+        assertEquals("excluded-dep", pom.getValue("dependencies[1]/exclusions[1]/artifactId"));
 
-        assertEquals( 2, ( (List<?>) pom.getValue( "repositories" ) ).size() );
-        assertEquals( "project-remote-repo", pom.getValue( "repositories[1]/id" ) );
-        assertEquals( "https://project.url/remote", pom.getValue( "repositories[1]/url" ) );
-        assertEquals( "repo", pom.getValue( "repositories[1]/name" ) );
-        assertEquals( RepositorySystem.DEFAULT_REMOTE_REPO_ID, pom.getValue( "repositories[2]/id" ) );
-        assertEquals( RepositorySystem.DEFAULT_REMOTE_REPO_URL, pom.getValue( "repositories[2]/url" ) );
+        assertEquals(1, ((List<?>) pom.getValue("repositories")).size());
+        assertEquals("project-remote-repo", pom.getValue("repositories[1]/id"));
+        assertEquals("https://project.url/remote", pom.getValue("repositories[1]/url"));
+        assertEquals("repo", pom.getValue("repositories[1]/name"));
 
-        assertEquals( "test", pom.getValue( "build/defaultGoal" ) );
-        assertEquals( "coreit", pom.getValue( "build/finalName" ) );
+        assertEquals("test", pom.getValue("build/defaultGoal"));
+        assertEquals("coreit", pom.getValue("build/finalName"));
 
-        assertPathSuffixEquals( "build", pom.getValue( "build/directory" ) );
-        assertPathSuffixEquals( "build/main", pom.getValue( "build/outputDirectory" ) );
-        assertPathSuffixEquals( "build/test", pom.getValue( "build/testOutputDirectory" ) );
-        assertPathSuffixEquals( "sources/main", pom.getValue( "build/sourceDirectory" ) );
-        assertPathSuffixEquals( "sources/test", pom.getValue( "build/testSourceDirectory" ) );
-        assertPathSuffixEquals( "sources/scripts", pom.getValue( "build/scriptSourceDirectory" ) );
+        assertPathSuffixEquals("build", pom.getValue("build/directory"));
+        assertPathSuffixEquals("build/main", pom.getValue("build/outputDirectory"));
+        assertPathSuffixEquals("build/test", pom.getValue("build/testOutputDirectory"));
+        assertPathSuffixEquals("sources/main", pom.getValue("build/sourceDirectory"));
+        assertPathSuffixEquals("sources/test", pom.getValue("build/testSourceDirectory"));
+        assertPathSuffixEquals("sources/scripts", pom.getValue("build/scriptSourceDirectory"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/filters" ) ).size() );
-        assertPathSuffixEquals( "src/main/filter/it.properties", pom.getValue( "build/filters[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("build/filters")).size());
+        assertPathSuffixEquals("src/main/filter/it.properties", pom.getValue("build/filters[1]"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/resources" ) ).size() );
-        assertPathSuffixEquals( "res/main", pom.getValue( "build/resources[1]/directory" ) );
-        assertPathSuffixEquals( "main", pom.getValue( "build/resources[1]/targetPath" ) );
-        assertEquals( Boolean.TRUE, pom.getValue( "build/resources[1]/filtering" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/resources[1]/includes" ) ).size() );
-        assertPathSuffixEquals( "main.included", pom.getValue( "build/resources[1]/includes[1]" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/resources[1]/excludes" ) ).size() );
-        assertPathSuffixEquals( "main.excluded", pom.getValue( "build/resources[1]/excludes[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("build/resources")).size());
+        assertPathSuffixEquals("res/main", pom.getValue("build/resources[1]/directory"));
+        assertPathSuffixEquals("main", pom.getValue("build/resources[1]/targetPath"));
+        assertEquals(Boolean.TRUE, pom.getValue("build/resources[1]/filtering"));
+        assertEquals(1, ((List<?>) pom.getValue("build/resources[1]/includes")).size());
+        assertPathSuffixEquals("main.included", pom.getValue("build/resources[1]/includes[1]"));
+        assertEquals(1, ((List<?>) pom.getValue("build/resources[1]/excludes")).size());
+        assertPathSuffixEquals("main.excluded", pom.getValue("build/resources[1]/excludes[1]"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/testResources" ) ).size() );
-        assertPathSuffixEquals( "res/test", pom.getValue( "build/testResources[1]/directory" ) );
-        assertPathSuffixEquals( "test", pom.getValue( "build/testResources[1]/targetPath" ) );
-        assertEquals( Boolean.TRUE, pom.getValue( "build/testResources[1]/filtering" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/testResources[1]/includes" ) ).size() );
-        assertPathSuffixEquals( "test.included", pom.getValue( "build/testResources[1]/includes[1]" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/testResources[1]/excludes" ) ).size() );
-        assertPathSuffixEquals( "test.excluded", pom.getValue( "build/testResources[1]/excludes[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("build/testResources")).size());
+        assertPathSuffixEquals("res/test", pom.getValue("build/testResources[1]/directory"));
+        assertPathSuffixEquals("test", pom.getValue("build/testResources[1]/targetPath"));
+        assertEquals(Boolean.TRUE, pom.getValue("build/testResources[1]/filtering"));
+        assertEquals(1, ((List<?>) pom.getValue("build/testResources[1]/includes")).size());
+        assertPathSuffixEquals("test.included", pom.getValue("build/testResources[1]/includes[1]"));
+        assertEquals(1, ((List<?>) pom.getValue("build/testResources[1]/excludes")).size());
+        assertPathSuffixEquals("test.excluded", pom.getValue("build/testResources[1]/excludes[1]"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/extensions" ) ).size() );
-        assertEquals( "org.apache.maven.its.ext", pom.getValue( "build/extensions[1]/groupId" ) );
-        assertEquals( "ext", pom.getValue( "build/extensions[1]/artifactId" ) );
-        assertEquals( "3.0", pom.getValue( "build/extensions[1]/version" ) );
+        assertEquals(1, ((List<?>) pom.getValue("build/extensions")).size());
+        assertEquals("org.apache.maven.its.ext", pom.getValue("build/extensions[1]/groupId"));
+        assertEquals("ext", pom.getValue("build/extensions[1]/artifactId"));
+        assertEquals("3.0", pom.getValue("build/extensions[1]/version"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins" ) ).size() );
-        assertEquals( "org.apache.maven.its.plugins", pom.getValue( "build/plugins[1]/groupId" ) );
-        assertEquals( "maven-it-plugin-build", pom.getValue( "build/plugins[1]/artifactId" ) );
-        assertEquals( "2.1-SNAPSHOT", pom.getValue( "build/plugins[1]/version" ) );
-        assertEquals( "test.properties", pom.getValue( "build/plugins[1]/configuration/outputFile" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/executions" ) ).size() );
-        assertEquals( "test", pom.getValue( "build/plugins[1]/executions[1]/id" ) );
-        assertEquals( "validate", pom.getValue( "build/plugins[1]/executions[1]/phase" ) );
-        assertEquals( "pom.properties", pom.getValue( "build/plugins[1]/executions[1]/configuration/outputFile" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/executions[1]/goals" ) ).size() );
-        assertEquals( "eval", pom.getValue( "build/plugins[1]/executions[1]/goals[1]" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/dependencies" ) ).size() );
-        assertEquals( "org.apache.maven.its", pom.getValue( "build/plugins[1]/dependencies[1]/groupId" ) );
-        assertEquals( "build-plugin-dep", pom.getValue( "build/plugins[1]/dependencies[1]/artifactId" ) );
-        assertEquals( "0.3", pom.getValue( "build/plugins[1]/dependencies[1]/version" ) );
-        assertEquals( "zip", pom.getValue( "build/plugins[1]/dependencies[1]/type" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins[1]/dependencies[1]/exclusions" ) ).size() );
-        assertEquals( "org.apache.maven.its", pom.getValue( "build/plugins[1]/dependencies[1]/exclusions[1]/groupId" ) );
-        assertEquals( "excluded-build-plugin-dep",
-                      pom.getValue( "build/plugins[1]/dependencies[1]/exclusions[1]/artifactId" ) );
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins")).size());
+        assertEquals("org.apache.maven.its.plugins", pom.getValue("build/plugins[1]/groupId"));
+        assertEquals("maven-it-plugin-build", pom.getValue("build/plugins[1]/artifactId"));
+        assertEquals("2.1-SNAPSHOT", pom.getValue("build/plugins[1]/version"));
+        assertEquals("test.properties", pom.getValue("build/plugins[1]/configuration/outputFile"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/executions")).size());
+        assertEquals("test", pom.getValue("build/plugins[1]/executions[1]/id"));
+        assertEquals("validate", pom.getValue("build/plugins[1]/executions[1]/phase"));
+        assertEquals("pom.properties", pom.getValue("build/plugins[1]/executions[1]/configuration/outputFile"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/executions[1]/goals")).size());
+        assertEquals("eval", pom.getValue("build/plugins[1]/executions[1]/goals[1]"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/dependencies")).size());
+        assertEquals("org.apache.maven.its", pom.getValue("build/plugins[1]/dependencies[1]/groupId"));
+        assertEquals("build-plugin-dep", pom.getValue("build/plugins[1]/dependencies[1]/artifactId"));
+        assertEquals("0.3", pom.getValue("build/plugins[1]/dependencies[1]/version"));
+        assertEquals("zip", pom.getValue("build/plugins[1]/dependencies[1]/type"));
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins[1]/dependencies[1]/exclusions")).size());
+        assertEquals("org.apache.maven.its", pom.getValue("build/plugins[1]/dependencies[1]/exclusions[1]/groupId"));
+        assertEquals(
+                "excluded-build-plugin-dep", pom.getValue("build/plugins[1]/dependencies[1]/exclusions[1]/artifactId"));
 
-        assertEquals( Boolean.TRUE, pom.getValue( "reporting/excludeDefaults" ) );
-        assertPathSuffixEquals( "docs", pom.getValue( "reporting/outputDirectory" ) );
+        assertEquals(Boolean.TRUE, pom.getValue("reporting/excludeDefaults"));
+        assertPathSuffixEquals("docs", pom.getValue("reporting/outputDirectory"));
 
-        assertEquals( 1, ( (List<?>) pom.getValue( "reporting/plugins" ) ).size() );
-        assertEquals( "org.apache.maven.its.plugins", pom.getValue( "reporting/plugins[1]/groupId" ) );
-        assertEquals( "maven-it-plugin-reporting", pom.getValue( "reporting/plugins[1]/artifactId" ) );
-        assertEquals( "2.0-SNAPSHOT", pom.getValue( "reporting/plugins[1]/version" ) );
-        assertEquals( "test.html", pom.getValue( "reporting/plugins[1]/configuration/outputFile" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "reporting/plugins[1]/reportSets" ) ).size() );
-        assertEquals( "it", pom.getValue( "reporting/plugins[1]/reportSets[1]/id" ) );
-        assertEquals( "index.html", pom.getValue( "reporting/plugins[1]/reportSets[1]/configuration/outputFile" ) );
-        assertEquals( 1, ( (List<?>) pom.getValue( "reporting/plugins[1]/reportSets[1]/reports" ) ).size() );
-        assertEquals( "run", pom.getValue( "reporting/plugins[1]/reportSets[1]/reports[1]" ) );
+        assertEquals(1, ((List<?>) pom.getValue("reporting/plugins")).size());
+        assertEquals("org.apache.maven.its.plugins", pom.getValue("reporting/plugins[1]/groupId"));
+        assertEquals("maven-it-plugin-reporting", pom.getValue("reporting/plugins[1]/artifactId"));
+        assertEquals("2.0-SNAPSHOT", pom.getValue("reporting/plugins[1]/version"));
+        assertEquals("test.html", pom.getValue("reporting/plugins[1]/configuration/outputFile"));
+        assertEquals(1, ((List<?>) pom.getValue("reporting/plugins[1]/reportSets")).size());
+        assertEquals("it", pom.getValue("reporting/plugins[1]/reportSets[1]/id"));
+        assertEquals("index.html", pom.getValue("reporting/plugins[1]/reportSets[1]/configuration/outputFile"));
+        assertEquals(1, ((List<?>) pom.getValue("reporting/plugins[1]/reportSets[1]/reports")).size());
+        assertEquals("run", pom.getValue("reporting/plugins[1]/reportSets[1]/reports[1]"));
     }
 
     /* MNG-2309*/
     @Test
-    public void testProfileInjectionOrder()
-        throws Exception
-    {
-        PomTestWrapper pom =
-            buildPom( "profile-injection-order", "pom-a", "pom-b", "pom-e", "pom-c", "pom-d" );
-        assertEquals( "e", pom.getValue( "properties[1]/pomProperty" ) );
+    void testProfileInjectionOrder() throws Exception {
+        PomTestWrapper pom = buildPom("profile-injection-order", "pom-a", "pom-b", "pom-e", "pom-c", "pom-d");
+        assertEquals("e", pom.getValue("properties[1]/pomProperty"));
     }
 
     @Test
-    public void testPropertiesInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "properties-inheritance/sub" );
-        assertEquals( "parent-property", pom.getValue( "properties/parentProperty" ) );
-        assertEquals( "child-property", pom.getValue( "properties/childProperty" ) );
-        assertEquals( "child-override", pom.getValue( "properties/overriddenProperty" ) );
+    void testPropertiesInheritance() throws Exception {
+        PomTestWrapper pom = buildPom("properties-inheritance/sub");
+        assertEquals("parent-property", pom.getValue("properties/parentProperty"));
+        assertEquals("child-property", pom.getValue("properties/childProperty"));
+        assertEquals("child-override", pom.getValue("properties/overriddenProperty"));
     }
 
     /* MNG-4102*/
     @Test
-    public void testInheritedPropertiesInterpolatedWithValuesFromChildWithoutProfiles()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "inherited-properties-interpolation/no-profile/sub" );
+    void testInheritedPropertiesInterpolatedWithValuesFromChildWithoutProfiles() throws Exception {
+        PomTestWrapper pom = buildPom("inherited-properties-interpolation/no-profile/sub");
 
-        assertEquals( "CHILD", pom.getValue( "properties/overridden" ) );
-        assertEquals( "CHILD", pom.getValue( "properties/interpolated" ) );
+        assertEquals("CHILD", pom.getValue("properties/overridden"));
+        assertEquals("CHILD", pom.getValue("properties/interpolated"));
     }
 
     /* MNG-4102 */
     @Test
-    public void testInheritedPropertiesInterpolatedWithValuesFromChildWithActiveProfiles()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "inherited-properties-interpolation/active-profile/sub" );
+    void testInheritedPropertiesInterpolatedWithValuesFromChildWithActiveProfiles() throws Exception {
+        PomTestWrapper pom = buildPom("inherited-properties-interpolation/active-profile/sub");
 
-        assertEquals( 1, pom.getMavenProject().getModel().getProfiles().size() );
+        assertEquals(1, pom.getMavenProject().getModel().getProfiles().size());
 
-        buildPom( "inherited-properties-interpolation/active-profile/sub", "it-parent", "it-child" );
-        assertEquals( "CHILD", pom.getValue( "properties/overridden" ) );
-        assertEquals( "CHILD", pom.getValue( "properties/interpolated" ) );
+        buildPom("inherited-properties-interpolation/active-profile/sub", "it-parent", "it-child");
+        assertEquals("CHILD", pom.getValue("properties/overridden"));
+        assertEquals("CHILD", pom.getValue("properties/interpolated"));
     }
 
     /* MNG-3545 */
     @Test
-    public void testProfileDefaultActivation()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "profile-default-deactivation", "profile4" );
-        assertEquals( 1, pom.getMavenProject().getActiveProfiles().size() );
-        assertEquals( 1, ( (List<?>) pom.getValue( "build/plugins" ) ).size() );
-        assertEquals( "2.1", pom.getValue( "build/plugins[1]/version" ) );
+    void testProfileDefaultActivation() throws Exception {
+        PomTestWrapper pom = buildPom("profile-default-deactivation", "profile4");
+        assertEquals(1, pom.getMavenProject().getActiveProfiles().size());
+        assertEquals(1, ((List<?>) pom.getValue("build/plugins")).size());
+        assertEquals("2.1", pom.getValue("build/plugins[1]/version"));
     }
 
     /* MNG-1995 */
     @Test
-    public void testBooleanInterpolation()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "boolean-interpolation" );
-        assertEquals(true, pom.getValue( "repositories[1]/releases/enabled" ) );
-        assertEquals(true, pom.getValue( "build/resources[1]/filtering" ) );
+    void testBooleanInterpolation() throws Exception {
+        PomTestWrapper pom = buildPom("boolean-interpolation");
+        assertEquals(true, pom.getValue("repositories[1]/releases/enabled"));
+        assertEquals(true, pom.getValue("build/resources[1]/filtering"));
     }
 
-
     /* MNG-3899 */
     @Test
-    public void testBuildExtensionInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "build-extension-inheritance/sub" );
-        assertEquals( 3, ( (List<?>) pom.getValue( "build/extensions" ) ).size() );
-        assertEquals( "b", pom.getValue( "build/extensions[1]/artifactId" ) );
-        assertEquals( "a", pom.getValue( "build/extensions[2]/artifactId" ) );
-        assertEquals( "0.2", pom.getValue( "build/extensions[2]/version" ) );
-        assertEquals( "c", pom.getValue( "build/extensions[3]/artifactId" ) );
+    void testBuildExtensionInheritance() throws Exception {
+        PomTestWrapper pom = buildPom("build-extension-inheritance/sub");
+        assertEquals(3, ((List<?>) pom.getValue("build/extensions")).size());
+        assertEquals("b", pom.getValue("build/extensions[1]/artifactId"));
+        assertEquals("a", pom.getValue("build/extensions[2]/artifactId"));
+        assertEquals("0.2", pom.getValue("build/extensions[2]/version"));
+        assertEquals("c", pom.getValue("build/extensions[3]/artifactId"));
     }
 
     /*MNG-1957*/
     @Test
-    public void testJdkActivation()
-        throws Exception
-    {
+    void testJdkActivation() throws Exception {
         Properties props = new Properties();
-        props.put( "java.version", "1.5.0_15" );
+        props.put("java.version", "1.5.0_15");
 
-        PomTestWrapper pom = buildPom( "jdk-activation", props, null );
-        assertEquals( 3, pom.getMavenProject().getActiveProfiles().size() );
-        assertEquals( "PASSED", pom.getValue( "properties/jdkProperty3" ) );
-        assertEquals( "PASSED", pom.getValue( "properties/jdkProperty2" ) );
-        assertEquals( "PASSED", pom.getValue( "properties/jdkProperty1" ) );
+        PomTestWrapper pom = buildPom("jdk-activation", props, null);
+        assertEquals(3, pom.getMavenProject().getActiveProfiles().size());
+        assertEquals("PASSED", pom.getValue("properties/jdkProperty3"));
+        assertEquals("PASSED", pom.getValue("properties/jdkProperty2"));
+        assertEquals("PASSED", pom.getValue("properties/jdkProperty1"));
     }
 
     /* MNG-2174 */
     @Test
-    public void testProfilePluginMngDependencies()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "profile-plugin-mng-dependencies/sub", "maven-core-it" );
-        assertEquals( "a", pom.getValue( "build/plugins[1]/dependencies[1]/artifactId" ) );
+    void testProfilePluginMngDependencies() throws Exception {
+        PomTestWrapper pom = buildPom("profile-plugin-mng-dependencies/sub", "maven-core-it");
+        assertEquals("a", pom.getValue("build/plugins[1]/dependencies[1]/artifactId"));
     }
 
     /** MNG-4116 */
     @Test
-    public void testPercentEncodedUrlsMustNotBeDecoded()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "url-no-decoding" );
-        assertEquals( "https://maven.apache.org/spacy%20path", pom.getValue( "url" ) );
-        assertEquals( "https://svn.apache.org/viewvc/spacy%20path", pom.getValue( "scm/url" ) );
-        assertEquals( "scm:svn:svn+ssh://svn.apache.org/spacy%20path", pom.getValue( "scm/connection" ) );
-        assertEquals( "scm:svn:svn+ssh://svn.apache.org/spacy%20path", pom.getValue( "scm/developerConnection" ) );
-        assertEquals( "https://issues.apache.org/spacy%20path", pom.getValue( "issueManagement/url" ) );
-        assertEquals( "https://ci.apache.org/spacy%20path", pom.getValue( "ciManagement/url" ) );
-        assertEquals( "scm:svn:svn+ssh://dist.apache.org/spacy%20path",
-                      pom.getValue( "distributionManagement/repository/url" ) );
-        assertEquals( "scm:svn:svn+ssh://snap.apache.org/spacy%20path",
-                      pom.getValue( "distributionManagement/snapshotRepository/url" ) );
-        assertEquals( "scm:svn:svn+ssh://site.apache.org/spacy%20path",
-                      pom.getValue( "distributionManagement/site/url" ) );
+    void testPercentEncodedUrlsMustNotBeDecoded() throws Exception {
+        PomTestWrapper pom = this.buildPom("url-no-decoding");
+        assertEquals("https://maven.apache.org/spacy%20path", pom.getValue("url"));
+        assertEquals("https://svn.apache.org/viewvc/spacy%20path", pom.getValue("scm/url"));
+        assertEquals("scm:svn:svn+ssh://svn.apache.org/spacy%20path", pom.getValue("scm/connection"));
+        assertEquals("scm:svn:svn+ssh://svn.apache.org/spacy%20path", pom.getValue("scm/developerConnection"));
+        assertEquals("https://issues.apache.org/spacy%20path", pom.getValue("issueManagement/url"));
+        assertEquals("https://ci.apache.org/spacy%20path", pom.getValue("ciManagement/url"));
+        assertEquals(
+                "scm:svn:svn+ssh://dist.apache.org/spacy%20path",
+                pom.getValue("distributionManagement/repository/url"));
+        assertEquals(
+                "scm:svn:svn+ssh://snap.apache.org/spacy%20path",
+                pom.getValue("distributionManagement/snapshotRepository/url"));
+        assertEquals("scm:svn:svn+ssh://site.apache.org/spacy%20path", pom.getValue("distributionManagement/site/url"));
     }
 
     @Test
-    public void testPluginManagementInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "plugin-management-inheritance" );
-        assertEquals( "0.1-stub-SNAPSHOT",
-                      pom.getValue( "build/pluginManagement/plugins[@artifactId='maven-compiler-plugin']/version" ) );
+    void testPluginManagementInheritance() throws Exception {
+        PomTestWrapper pom = this.buildPom("plugin-management-inheritance");
+        assertEquals(
+                "0.1-stub-SNAPSHOT",
+                pom.getValue("build/pluginManagement/plugins[@artifactId='maven-compiler-plugin']/version"));
     }
 
     @Test
-    public void testProfilePlugins()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "profile-plugins", "standard" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins" ) ).size() );
-        assertEquals( "maven-assembly2-plugin", pom.getValue( "build/plugins[2]/artifactId" ) );
+    void testProfilePlugins() throws Exception {
+        PomTestWrapper pom = this.buildPom("profile-plugins", "standard");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins")).size());
+        assertEquals("maven-assembly2-plugin", pom.getValue("build/plugins[2]/artifactId"));
     }
 
     @Test
-    public void testPluginInheritanceSimple()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "plugin-inheritance-simple/sub" );
-        assertEquals( 2, ( (List<?>) pom.getValue( "build/plugins" ) ).size() );
+    void testPluginInheritanceSimple() throws Exception {
+        PomTestWrapper pom = this.buildPom("plugin-inheritance-simple/sub");
+        assertEquals(2, ((List<?>) pom.getValue("build/plugins")).size());
     }
 
     @Test
-    public void testPluginManagementDuplicate()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "plugin-management-duplicate/sub" );
-        assertEquals( 8, ( (List<?>) pom.getValue( "build/pluginManagement/plugins" ) ).size() );
+    void testPluginManagementDuplicate() throws Exception {
+        PomTestWrapper pom = this.buildPom("plugin-management-duplicate/sub");
+        assertEquals(7, ((List<?>) pom.getValue("build/pluginManagement/plugins")).size());
     }
 
     @Test
-    public void testDistributionManagement()
-        throws Exception
-    {
-        PomTestWrapper pom = this.buildPom( "distribution-management" );
-        assertEquals( "legacy", pom.getValue( "distributionManagement/repository/layout" ) );
+    void testDistributionManagement() throws Exception {
+        PomTestWrapper pom = this.buildPom("distribution-management");
+        assertEquals("legacy", pom.getValue("distributionManagement/repository/layout"));
     }
 
     @Test
-    public void testDependencyScopeInheritance()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "dependency-scope-inheritance/sub" );
-        String scope = (String) pom.getValue( "dependencies[1]/scope" );
-        assertEquals( "compile", scope );
+    void testDependencyScopeInheritance() throws Exception {
+        PomTestWrapper pom = buildPom("dependency-scope-inheritance/sub");
+        String scope = (String) pom.getValue("dependencies[1]/scope");
+        assertEquals("compile", scope);
     }
 
     @Test
-    public void testDependencyScope()
-        throws Exception
-    {
-        buildPom( "dependency-scope/sub" );
+    void testDependencyScope() throws Exception {
+        buildPom("dependency-scope/sub");
     }
 
-    //This will fail on a validation error if incorrect
-    public void testDependencyManagementWithInterpolation()
-        throws Exception
-    {
-        buildPom( "dependency-management-with-interpolation/sub" );
+    // This will fail on a validation error if incorrect
+    public void testDependencyManagementWithInterpolation() throws Exception {
+        buildPom("dependency-management-with-interpolation/sub");
     }
 
     @Test
-    public void testInterpolationWithSystemProperty()
-        throws Exception
-    {
+    void testInterpolationWithSystemProperty() throws Exception {
         Properties sysProps = new Properties();
-        sysProps.setProperty( "system.property", "PASSED" );
-        PomTestWrapper pom = buildPom( "system-property-interpolation", sysProps, null );
-        assertEquals( "PASSED", pom.getValue( "name" ) );
+        sysProps.setProperty("system.property", "PASSED");
+        PomTestWrapper pom = buildPom("system-property-interpolation", sysProps, null);
+        assertEquals("PASSED", pom.getValue("name"));
     }
 
     /* MNG-4129 */
     @Test
-    public void testPluginExecutionInheritanceWhenChildDoesNotDeclarePlugin()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-inheritance/wo-merge" );
-        @SuppressWarnings( "unchecked" )
-        List<PluginExecution> executions =
-            (List<PluginExecution>) pom.getValue( "build/pluginsAsMap[@name='org.apache.maven.its.plugins:maven-it-plugin-log-file']/executions" );
-        assertEquals( 1, executions.size() );
-        assertEquals( "inherited-execution", executions.get( 0 ).getId() );
+    void testPluginExecutionInheritanceWhenChildDoesNotDeclarePlugin() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-inheritance/wo-merge");
+        @SuppressWarnings("unchecked")
+        List<PluginExecution> executions = (List<PluginExecution>) pom.getValue(
+                "build/pluginsAsMap[@name='org.apache.maven.its.plugins:maven-it-plugin-log-file']/executions");
+        assertEquals(1, executions.size());
+        assertEquals("inherited-execution", executions.get(0).getId());
     }
 
     @Test
-    public void testPluginExecutionInheritanceWhenChildDoesDeclarePluginAsWell()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-inheritance/w-merge" );
-        @SuppressWarnings( "unchecked" )
-        List<PluginExecution> executions =
-            (List<PluginExecution>) pom.getValue( "build/pluginsAsMap[@name='org.apache.maven.its.plugins:maven-it-plugin-log-file']/executions" );
-        assertEquals( 1, executions.size() );
-        assertEquals( "inherited-execution", executions.get( 0 ).getId() );
+    void testPluginExecutionInheritanceWhenChildDoesDeclarePluginAsWell() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-inheritance/w-merge");
+        @SuppressWarnings("unchecked")
+        List<PluginExecution> executions = (List<PluginExecution>) pom.getValue(
+                "build/pluginsAsMap[@name='org.apache.maven.its.plugins:maven-it-plugin-log-file']/executions");
+        assertEquals(1, executions.size());
+        assertEquals("inherited-execution", executions.get(0).getId());
     }
 
     /* MNG-4193 */
     @Test
-    public void testValidationErrorUponNonUniqueArtifactRepositoryId()
-        throws Exception
-    {
+    void testValidationErrorUponNonUniqueArtifactRepositoryId() throws Exception {
         assertThrows(
                 ProjectBuildingException.class,
-                () -> buildPom( "unique-repo-id/artifact-repo" ),
-                "Non-unique repository ids did not cause validation error" );
+                () -> buildPom("unique-repo-id/artifact-repo"),
+                "Non-unique repository ids did not cause validation error");
     }
 
     /* MNG-4193 */
     @Test
-    public void testValidationErrorUponNonUniquePluginRepositoryId()
-        throws Exception
-    {
+    void testValidationErrorUponNonUniquePluginRepositoryId() throws Exception {
         assertThrows(
                 ProjectBuildingException.class,
-                () -> buildPom( "unique-repo-id/plugin-repo" ),
-                "Non-unique repository ids did not cause validation error" );
+                () -> buildPom("unique-repo-id/plugin-repo"),
+                "Non-unique repository ids did not cause validation error");
     }
 
     /* MNG-4193 */
     @Test
-    public void testValidationErrorUponNonUniqueArtifactRepositoryIdInProfile()
-        throws Exception
-    {
+    void testValidationErrorUponNonUniqueArtifactRepositoryIdInProfile() throws Exception {
         assertThrows(
                 ProjectBuildingException.class,
-                () -> buildPom( "unique-repo-id/artifact-repo-in-profile" ),
-                "Non-unique repository ids did not cause validation error" );
+                () -> buildPom("unique-repo-id/artifact-repo-in-profile"),
+                "Non-unique repository ids did not cause validation error");
     }
 
     /* MNG-4193 */
     @Test
-    public void testValidationErrorUponNonUniquePluginRepositoryIdInProfile()
-        throws Exception
-    {
+    void testValidationErrorUponNonUniquePluginRepositoryIdInProfile() throws Exception {
         assertThrows(
                 ProjectBuildingException.class,
-                () -> buildPom( "unique-repo-id/plugin-repo-in-profile" ),
-                "Non-unique repository ids did not cause validation error" );
+                () -> buildPom("unique-repo-id/plugin-repo-in-profile"),
+                "Non-unique repository ids did not cause validation error");
     }
 
     /** MNG-3843 */
     @Test
-    public void testPrerequisitesAreNotInherited()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "prerequisites-inheritance/child" );
-        assertSame( null, pom.getValue( "prerequisites" ) );
+    void testPrerequisitesAreNotInherited() throws Exception {
+        PomTestWrapper pom = buildPom("prerequisites-inheritance/child");
+        assertSame(null, pom.getValue("prerequisites"));
     }
 
     @Test
-    public void testLicensesAreInheritedButNotAggregated()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "licenses-inheritance/child-2" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "licenses" ) ).size() );
-        assertEquals( "child-license", pom.getValue( "licenses[1]/name" ) );
-        assertEquals( "https://child.url/license", pom.getValue( "licenses[1]/url" ) );
+    void testLicensesAreInheritedButNotAggregated() throws Exception {
+        PomTestWrapper pom = buildPom("licenses-inheritance/child-2");
+        assertEquals(1, ((List<?>) pom.getValue("licenses")).size());
+        assertEquals("child-license", pom.getValue("licenses[1]/name"));
+        assertEquals("https://child.url/license", pom.getValue("licenses[1]/url"));
     }
 
     @Test
-    public void testDevelopersAreInheritedButNotAggregated()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "developers-inheritance/child-2" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "developers" ) ).size() );
-        assertEquals( "child-developer", pom.getValue( "developers[1]/name" ) );
+    void testDevelopersAreInheritedButNotAggregated() throws Exception {
+        PomTestWrapper pom = buildPom("developers-inheritance/child-2");
+        assertEquals(1, ((List<?>) pom.getValue("developers")).size());
+        assertEquals("child-developer", pom.getValue("developers[1]/name"));
     }
 
     @Test
-    public void testContributorsAreInheritedButNotAggregated()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "contributors-inheritance/child-2" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "contributors" ) ).size() );
-        assertEquals( "child-contributor", pom.getValue( "contributors[1]/name" ) );
+    void testContributorsAreInheritedButNotAggregated() throws Exception {
+        PomTestWrapper pom = buildPom("contributors-inheritance/child-2");
+        assertEquals(1, ((List<?>) pom.getValue("contributors")).size());
+        assertEquals("child-contributor", pom.getValue("contributors[1]/name"));
     }
 
     @Test
-    public void testMailingListsAreInheritedButNotAggregated()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "mailing-lists-inheritance/child-2" );
-        assertEquals( 1, ( (List<?>) pom.getValue( "mailingLists" ) ).size() );
-        assertEquals( "child-mailing-list", pom.getValue( "mailingLists[1]/name" ) );
+    void testMailingListsAreInheritedButNotAggregated() throws Exception {
+        PomTestWrapper pom = buildPom("mailing-lists-inheritance/child-2");
+        assertEquals(1, ((List<?>) pom.getValue("mailingLists")).size());
+        assertEquals("child-mailing-list", pom.getValue("mailingLists[1]/name"));
     }
 
     @Test
-    public void testPluginInheritanceOrder()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-inheritance-order/child" );
+    void testPluginInheritanceOrder() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-inheritance-order/child");
 
-        assertEquals( "maven-it-plugin-log-file", pom.getValue( "build/plugins[1]/artifactId" ) );
-        assertEquals( "maven-it-plugin-expression", pom.getValue( "build/plugins[2]/artifactId" ) );
-        assertEquals( "maven-it-plugin-configuration", pom.getValue( "build/plugins[3]/artifactId" ) );
+        assertEquals("maven-it-plugin-log-file", pom.getValue("build/plugins[1]/artifactId"));
+        assertEquals("maven-it-plugin-expression", pom.getValue("build/plugins[2]/artifactId"));
+        assertEquals("maven-it-plugin-configuration", pom.getValue("build/plugins[3]/artifactId"));
 
-        assertEquals( "maven-it-plugin-log-file", pom.getValue( "reporting/plugins[1]/artifactId" ) );
-        assertEquals( "maven-it-plugin-expression", pom.getValue( "reporting/plugins[2]/artifactId" ) );
-        assertEquals( "maven-it-plugin-configuration", pom.getValue( "reporting/plugins[3]/artifactId" ) );
+        assertEquals("maven-it-plugin-log-file", pom.getValue("reporting/plugins[1]/artifactId"));
+        assertEquals("maven-it-plugin-expression", pom.getValue("reporting/plugins[2]/artifactId"));
+        assertEquals("maven-it-plugin-configuration", pom.getValue("reporting/plugins[3]/artifactId"));
     }
 
     @Test
-    public void testCliPropsDominateProjectPropsDuringInterpolation()
-        throws Exception
-    {
+    void testCliPropsDominateProjectPropsDuringInterpolation() throws Exception {
         Properties props = new Properties();
-        props.setProperty( "testProperty", "PASSED" );
-        PomTestWrapper pom = buildPom( "interpolation-cli-wins", null, props );
+        props.setProperty("testProperty", "PASSED");
+        PomTestWrapper pom = buildPom("interpolation-cli-wins", null, props);
 
-        assertEquals( "PASSED", pom.getValue( "properties/interpolatedProperty" ) );
+        assertEquals("PASSED", pom.getValue("properties/interpolatedProperty"));
     }
 
     @Test
-    public void testParentPomPackagingMustBePom()
-        throws Exception
-    {
+    void testParentPomPackagingMustBePom() throws Exception {
         assertThrows(
                 ProjectBuildingException.class,
-                () -> buildPom( "parent-pom-packaging/sub" ),
-                "Wrong packaging of parent POM was not rejected" );
+                () -> buildPom("parent-pom-packaging/sub"),
+                "Wrong packaging of parent POM was not rejected");
     }
 
     /** MNG-522, MNG-3018 */
     @Test
-    public void testManagedPluginConfigurationAppliesToImplicitPluginsIntroducedByPackaging()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-management-for-implicit-plugin/child" );
-        assertEquals( "passed.txt",
-                      pom.getValue( "build/plugins[@artifactId='maven-resources-plugin']/configuration/pathname" ) );
-        assertEquals( "passed.txt",
-                      pom.getValue( "build/plugins[@artifactId='maven-it-plugin-log-file']/configuration/logFile" ) );
+    void testManagedPluginConfigurationAppliesToImplicitPluginsIntroducedByPackaging() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-management-for-implicit-plugin/child");
+        assertEquals(
+                "passed.txt",
+                pom.getValue("build/plugins[@artifactId='maven-resources-plugin']/configuration/pathname"));
+        assertEquals(
+                "passed.txt",
+                pom.getValue("build/plugins[@artifactId='maven-it-plugin-log-file']/configuration/logFile"));
     }
 
     @Test
-    public void testDefaultPluginsExecutionContributedByPackagingExecuteBeforeUserDefinedExecutions()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-order-and-default-exec" );
-        @SuppressWarnings( "unchecked" )
+    void testDefaultPluginsExecutionContributedByPackagingExecuteBeforeUserDefinedExecutions() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-order-and-default-exec");
+        @SuppressWarnings("unchecked")
         List<PluginExecution> executions =
-            (List<PluginExecution>) pom.getValue( "build/plugins[@artifactId='maven-resources-plugin']/executions" );
-        assertNotNull( executions );
-        assertEquals( 4, executions.size() );
-        assertEquals( "default-resources", executions.get( 0 ).getId() );
-        assertEquals( "default-testResources", executions.get( 1 ).getId() );
-        assertEquals( "test-1", executions.get( 2 ).getId() );
-        assertEquals( "test-2", executions.get( 3 ).getId() );
+                (List<PluginExecution>) pom.getValue("build/plugins[@artifactId='maven-resources-plugin']/executions");
+        assertNotNull(executions);
+        assertEquals(4, executions.size());
+        assertEquals("default-resources", executions.get(0).getId());
+        assertEquals("default-testResources", executions.get(1).getId());
+        assertEquals("test-1", executions.get(2).getId());
+        assertEquals("test-2", executions.get(3).getId());
     }
 
     @Test
-    public void testPluginDeclarationsRetainPomOrderAfterInjectionOfDefaultPlugins()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-exec-order-with-lifecycle" );
-        @SuppressWarnings( "unchecked" )
-        List<Plugin> plugins = (List<Plugin>) pom.getValue( "build/plugins" );
+    void testPluginDeclarationsRetainPomOrderAfterInjectionOfDefaultPlugins() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-exec-order-with-lifecycle");
+        @SuppressWarnings("unchecked")
+        List<Plugin> plugins = (List<Plugin>) pom.getValue("build/plugins");
         int resourcesPlugin = -1;
         int customPlugin = -1;
-        for ( int i = 0; i < plugins.size(); i++ )
-        {
-            Plugin plugin = plugins.get( i );
-            if ( "maven-resources-plugin".equals( plugin.getArtifactId() ) )
-            {
-                assertThat( resourcesPlugin, lessThan( 0 ) );
+        for (int i = 0; i < plugins.size(); i++) {
+            Plugin plugin = plugins.get(i);
+            if ("maven-resources-plugin".equals(plugin.getArtifactId())) {
+                assertThat(resourcesPlugin, lessThan(0));
                 resourcesPlugin = i;
-            }
-            else if ( "maven-it-plugin-log-file".equals( plugin.getArtifactId() ) )
-            {
-                assertThat( customPlugin, lessThan( 0 ) );
+            } else if ("maven-it-plugin-log-file".equals(plugin.getArtifactId())) {
+                assertThat(customPlugin, lessThan(0));
                 customPlugin = i;
             }
         }
-        assertEquals( customPlugin, resourcesPlugin - 1, plugins.toString() );
+        assertEquals(customPlugin, resourcesPlugin - 1, plugins.toString());
     }
 
     /** MNG-4415 */
     @Test
-    public void testPluginOrderAfterMergingWithInheritedPlugins()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-inheritance-merge-order/sub" );
+    void testPluginOrderAfterMergingWithInheritedPlugins() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-inheritance-merge-order/sub");
 
         List<String> expected = new ArrayList<>();
-        expected.add( "maven-it-plugin-error" );
-        expected.add( "maven-it-plugin-configuration" );
-        expected.add( "maven-it-plugin-dependency-resolution" );
-        expected.add( "maven-it-plugin-packaging" );
-        expected.add( "maven-it-plugin-log-file" );
-        expected.add( "maven-it-plugin-expression" );
-        expected.add( "maven-it-plugin-fork" );
-        expected.add( "maven-it-plugin-touch" );
+        expected.add("maven-it-plugin-error");
+        expected.add("maven-it-plugin-configuration");
+        expected.add("maven-it-plugin-dependency-resolution");
+        expected.add("maven-it-plugin-packaging");
+        expected.add("maven-it-plugin-log-file");
+        expected.add("maven-it-plugin-expression");
+        expected.add("maven-it-plugin-fork");
+        expected.add("maven-it-plugin-touch");
 
         List<String> actual = new ArrayList<>();
-        @SuppressWarnings( "unchecked" )
-        List<Plugin> plugins = (List<Plugin>) pom.getValue( "build/plugins" );
-        for ( Plugin plugin : plugins )
-        {
-            actual.add( plugin.getArtifactId() );
+        @SuppressWarnings("unchecked")
+        List<Plugin> plugins = (List<Plugin>) pom.getValue("build/plugins");
+        for (Plugin plugin : plugins) {
+            actual.add(plugin.getArtifactId());
         }
 
-        actual.retainAll( expected );
+        actual.retainAll(expected);
 
-        assertEquals( actual, expected );
+        assertEquals(actual, expected);
     }
 
     /** MNG-4416 */
     @Test
-    public void testPluginOrderAfterMergingWithInjectedPlugins()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "plugin-injection-merge-order" );
+    void testPluginOrderAfterMergingWithInjectedPlugins() throws Exception {
+        PomTestWrapper pom = buildPom("plugin-injection-merge-order");
 
         List<String> expected = new ArrayList<>();
-        expected.add( "maven-it-plugin-error" );
-        expected.add( "maven-it-plugin-configuration" );
-        expected.add( "maven-it-plugin-dependency-resolution" );
-        expected.add( "maven-it-plugin-packaging" );
-        expected.add( "maven-it-plugin-log-file" );
-        expected.add( "maven-it-plugin-expression" );
-        expected.add( "maven-it-plugin-fork" );
-        expected.add( "maven-it-plugin-touch" );
+        expected.add("maven-it-plugin-error");
+        expected.add("maven-it-plugin-configuration");
+        expected.add("maven-it-plugin-dependency-resolution");
+        expected.add("maven-it-plugin-packaging");
+        expected.add("maven-it-plugin-log-file");
+        expected.add("maven-it-plugin-expression");
+        expected.add("maven-it-plugin-fork");
+        expected.add("maven-it-plugin-touch");
 
         List<String> actual = new ArrayList<>();
-        @SuppressWarnings( "unchecked" )
-        List<Plugin> plugins = (List<Plugin>) pom.getValue( "build/plugins" );
-        for ( Plugin plugin : plugins )
-        {
-            actual.add( plugin.getArtifactId() );
+        @SuppressWarnings("unchecked")
+        List<Plugin> plugins = (List<Plugin>) pom.getValue("build/plugins");
+        for (Plugin plugin : plugins) {
+            actual.add(plugin.getArtifactId());
         }
 
-        actual.retainAll( expected );
+        actual.retainAll(expected);
 
-        assertEquals( actual, expected );
+        assertEquals(actual, expected);
     }
 
     @Test
-    public void testProjectArtifactIdIsNotInheritedButMandatory()
-        throws Exception
-    {
+    void testProjectArtifactIdIsNotInheritedButMandatory() throws Exception {
         assertThrows(
                 ProjectBuildingException.class,
-                () -> buildPom( "artifact-id-inheritance/child" ),
-                "Missing artifactId did not cause validation error" );
+                () -> buildPom("artifact-id-inheritance/child"),
+                "Missing artifactId did not cause validation error");
     }
 
-    private void assertPathSuffixEquals( String expected, Object actual )
-    {
+    private void assertPathSuffixEquals(String expected, Object actual) {
         String a = actual.toString();
-        a = a.substring( a.length() - expected.length() ).replace( '\\', '/' );
-        assertEquals( expected, a );
+        a = a.substring(a.length() - expected.length()).replace('\\', '/');
+        assertEquals(expected, a);
     }
 
-    private void assertPathWithNormalizedFileSeparators( Object value )
-    {
-        assertEquals( new File( value.toString() ).getPath(), value.toString() );
+    private void assertPathWithNormalizedFileSeparators(Object value) {
+        assertEquals(new File(value.toString()).getPath(), value.toString());
     }
 
-    private PomTestWrapper buildPom( String pomPath, String... profileIds )
-        throws Exception
-    {
-        return buildPom( pomPath, null, null, profileIds );
+    private PomTestWrapper buildPom(String pomPath, String... profileIds) throws Exception {
+        return buildPom(pomPath, null, null, profileIds);
     }
 
-    private PomTestWrapper buildPom( String pomPath, Properties systemProperties, Properties userProperties, String... profileIds )
-        throws Exception
-    {
-        return buildPom( pomPath, false, systemProperties, userProperties, profileIds );
+    private PomTestWrapper buildPom(
+            String pomPath, Properties systemProperties, Properties userProperties, String... profileIds)
+            throws Exception {
+        return buildPom(pomPath, false, systemProperties, userProperties, profileIds);
     }
 
-    private PomTestWrapper buildPom( String pomPath, boolean lenientValidation, Properties systemProperties,
-                                     Properties userProperties, String... profileIds )
-        throws Exception
-    {
-        File pomFile = new File( testDirectory, pomPath );
-        if ( pomFile.isDirectory() )
-        {
-            pomFile = new File( pomFile, "pom.xml" );
+    private PomTestWrapper buildPom(
+            String pomPath,
+            boolean lenientValidation,
+            Properties systemProperties,
+            Properties userProperties,
+            String... profileIds)
+            throws Exception {
+        File pomFile = new File(testDirectory, pomPath);
+        if (pomFile.isDirectory()) {
+            pomFile = new File(pomFile, "pom.xml");
         }
 
         ProjectBuildingRequest config = new DefaultProjectBuildingRequest();
 
         String localRepoUrl =
-            System.getProperty( "maven.repo.local", System.getProperty( "user.home" ) + "/.m2/repository" );
+                System.getProperty("maven.repo.local", System.getProperty("user.home") + "/.m2/repository");
         localRepoUrl = "file://" + localRepoUrl;
-        config.setLocalRepository( repositorySystem.createArtifactRepository( "local", localRepoUrl, new DefaultRepositoryLayout(), null, null ) );
-        config.setActiveProfileIds( Arrays.asList( profileIds ) );
-        config.setSystemProperties( systemProperties );
-        config.setUserProperties( userProperties );
-        config.setValidationLevel( lenientValidation ? ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0
-                        : ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
+        config.setLocalRepository(repositorySystem.createArtifactRepository(
+                "local", localRepoUrl, new DefaultRepositoryLayout(), null, null));
+        config.setActiveProfileIds(Arrays.asList(profileIds));
+        config.setSystemProperties(systemProperties);
+        config.setUserProperties(userProperties);
+        config.setValidationLevel(
+                lenientValidation
+                        ? ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0
+                        : ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
 
         DefaultRepositorySystemSession repoSession = MavenRepositorySystemUtils.newSession();
-        LocalRepository localRepo = new LocalRepository( config.getLocalRepository().getBasedir() );
-        repoSession.setLocalRepositoryManager( new SimpleLocalRepositoryManagerFactory().newInstance( repoSession, localRepo ) );
-        config.setRepositorySession( repoSession );
+        LocalRepository localRepo =
+                new LocalRepository(config.getLocalRepository().getBasedir());
+        repoSession.setLocalRepositoryManager(
+                new SimpleLocalRepositoryManagerFactory().newInstance(repoSession, localRepo));
+        config.setRepositorySession(repoSession);
 
-        return new PomTestWrapper( pomFile, projectBuilder.build( pomFile, config ).getProject() );
+        return new PomTestWrapper(pomFile, projectBuilder.build(pomFile, config).getProject());
     }
 
-    protected void assertModelEquals( PomTestWrapper pom, Object expected, String expression )
-    {
-        assertEquals( expected, pom.getValue( expression ) );
+    protected void assertModelEquals(PomTestWrapper pom, Object expected, String expression) {
+        assertEquals(expected, pom.getValue(expression));
     }
 
-    private static String createPath( List<String> elements )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-        for ( String s : elements )
-        {
-            buffer.append( s ).append( File.separator );
+    private static String createPath(List<String> elements) {
+        StringBuilder buffer = new StringBuilder(256);
+        for (String s : elements) {
+            buffer.append(s).append(File.separator);
         }
-        return buffer.toString().substring( 0, buffer.toString().length() - 1 );
+        return buffer.toString().substring(0, buffer.toString().length() - 1);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
index 8cc47a8..637d05b 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuilderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -30,6 +31,8 @@
 import org.apache.commons.io.FileUtils;
 import org.apache.maven.AbstractCoreMavenComponentTestCase;
 import org.apache.maven.execution.MavenSession;
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.InputLocation;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.building.FileModelSource;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -52,26 +55,20 @@
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-
-public class ProjectBuilderTest
-    extends AbstractCoreMavenComponentTestCase
-{
+class ProjectBuilderTest extends AbstractCoreMavenComponentTestCase {
     @Override
-    protected String getProjectsDirectory()
-    {
+    protected String getProjectsDirectory() {
         return "src/test/projects/project-builder";
     }
 
     @Test
-    public void testSystemScopeDependencyIsPresentInTheCompileClasspathElements()
-        throws Exception
-    {
-        File pom = getProject( "it0063" );
+    void testSystemScopeDependencyIsPresentInTheCompileClasspathElements() throws Exception {
+        File pom = getProject("it0063");
 
         Properties eps = new Properties();
-        eps.setProperty( "jre.home", new File( pom.getParentFile(), "jdk/jre" ).getPath() );
+        eps.setProperty("jre.home", new File(pom.getParentFile(), "jdk/jre").getPath());
 
-        MavenSession session = createMavenSession( pom, eps );
+        MavenSession session = createMavenSession(pom, eps);
         MavenProject project = session.getCurrentProject();
 
         // Here we will actually not have any artifacts because the ProjectDependenciesResolver is not involved here. So
@@ -81,56 +78,56 @@
     }
 
     @Test
-    public void testBuildFromModelSource()
-        throws Exception
-    {
-        File pomFile = new File( "src/test/resources/projects/modelsource/module01/pom.xml" );
-        MavenSession mavenSession = createMavenSession( pomFile );
+    void testBuildFromModelSource() throws Exception {
+        File pomFile = new File("src/test/resources/projects/modelsource/module01/pom.xml");
+        MavenSession mavenSession = createMavenSession(pomFile);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
-        ModelSource modelSource = new FileModelSource( pomFile );
-        ProjectBuildingResult result =
-            getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( modelSource, configuration );
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
+        ModelSource modelSource = new FileModelSource(pomFile);
+        ProjectBuildingResult result = getContainer()
+                .lookup(org.apache.maven.project.ProjectBuilder.class)
+                .build(modelSource, configuration);
 
-        assertNotNull( result.getProject().getParentFile() );
+        assertNotNull(result.getProject().getParentFile());
     }
 
     @Test
-    public void testVersionlessManagedDependency()
-        throws Exception
-    {
-        File pomFile = new File( "src/test/resources/projects/versionless-managed-dependency.xml" );
-        MavenSession mavenSession = createMavenSession( null );
+    void testVersionlessManagedDependency() throws Exception {
+        File pomFile = new File("src/test/resources/projects/versionless-managed-dependency.xml");
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
 
-        ProjectBuildingException e = assertThrows( ProjectBuildingException.class,
-                      () -> getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( pomFile, configuration ) );
-        assertThat( e.getResults(), contains( projectBuildingResultWithProblemMessage(
-                "'dependencies.dependency.version' for org.apache.maven.its:a:jar is missing" ) ) );
-        assertThat( e.getResults(), contains( projectBuildingResultWithLocation( 17, 9 ) ) );
+        ProjectBuildingException e = assertThrows(ProjectBuildingException.class, () -> getContainer()
+                .lookup(org.apache.maven.project.ProjectBuilder.class)
+                .build(pomFile, configuration));
+        assertThat(
+                e.getResults(),
+                contains(projectBuildingResultWithProblemMessage(
+                        "'dependencies.dependency.version' for org.apache.maven.its:a:jar is missing")));
+        assertThat(e.getResults(), contains(projectBuildingResultWithLocation(5, 9)));
     }
 
     @Test
-    public void testResolveDependencies()
-        throws Exception
-    {
-        File pomFile = new File( "src/test/resources/projects/basic-resolveDependencies.xml" );
-        MavenSession mavenSession = createMavenSession( null );
+    void testResolveDependencies() throws Exception {
+        File pomFile = new File("src/test/resources/projects/basic-resolveDependencies.xml");
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
-        configuration.setResolveDependencies( true );
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
+        configuration.setResolveDependencies(true);
 
         // single project build entry point
-        ProjectBuildingResult result = getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( pomFile, configuration );
-        assertEquals( 1, result.getProject().getArtifacts().size() );
+        ProjectBuildingResult result = getContainer()
+                .lookup(org.apache.maven.project.ProjectBuilder.class)
+                .build(pomFile, configuration);
+        assertEquals(1, result.getProject().getArtifacts().size());
         // multi projects build entry point
-        List<ProjectBuildingResult> results =
-                getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( Collections.singletonList( pomFile ), false,
-                                                                           configuration );
-        assertEquals( 1, results.size() );
-        MavenProject mavenProject = results.get( 0 ).getProject();
-        assertEquals( 1, mavenProject.getArtifacts().size() );
+        List<ProjectBuildingResult> results = getContainer()
+                .lookup(org.apache.maven.project.ProjectBuilder.class)
+                .build(Collections.singletonList(pomFile), false, configuration);
+        assertEquals(1, results.size());
+        MavenProject mavenProject = results.get(0).getProject();
+        assertEquals(1, mavenProject.getArtifacts().size());
 
         final MavenProject project = mavenProject;
         final AtomicInteger artifactsResultInAnotherThread = new AtomicInteger();
@@ -142,228 +139,246 @@
         });
         t.start();
         t.join();
-        assertEquals( project.getArtifacts().size(), artifactsResultInAnotherThread.get() );
+        assertEquals(project.getArtifacts().size(), artifactsResultInAnotherThread.get());
     }
 
     @Test
-    public void testDontResolveDependencies()
-        throws Exception
-    {
-        File pomFile = new File( "src/test/resources/projects/basic-resolveDependencies.xml" );
-        MavenSession mavenSession = createMavenSession( null );
+    void testDontResolveDependencies() throws Exception {
+        File pomFile = new File("src/test/resources/projects/basic-resolveDependencies.xml");
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
-        configuration.setResolveDependencies( false );
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
+        configuration.setResolveDependencies(false);
 
         // single project build entry point
-        ProjectBuildingResult result = getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( pomFile, configuration );
-        assertEquals( 0, result.getProject().getArtifacts().size() );
+        ProjectBuildingResult result = getContainer()
+                .lookup(org.apache.maven.project.ProjectBuilder.class)
+                .build(pomFile, configuration);
+        assertEquals(0, result.getProject().getArtifacts().size());
         // multi projects build entry point
-        List<ProjectBuildingResult> results = getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( Collections.singletonList( pomFile ), false, configuration );
-        assertEquals( 1, results.size() );
-        MavenProject mavenProject = results.get( 0 ).getProject();
-        assertEquals( 0, mavenProject.getArtifacts().size() );
+        List<ProjectBuildingResult> results = getContainer()
+                .lookup(org.apache.maven.project.ProjectBuilder.class)
+                .build(Collections.singletonList(pomFile), false, configuration);
+        assertEquals(1, results.size());
+        MavenProject mavenProject = results.get(0).getProject();
+        assertEquals(0, mavenProject.getArtifacts().size());
     }
 
     @Test
-    public void testReadModifiedPoms( @TempDir Path tempDir ) throws Exception {
+    void testReadModifiedPoms(@TempDir Path tempDir) throws Exception {
         // TODO a similar test should be created to test the dependency management (basically all usages
         // of DefaultModelBuilder.getCache() are affected by MNG-6530
 
-        FileUtils.copyDirectory( new File( "src/test/resources/projects/grandchild-check" ), tempDir.toFile() );
-        MavenSession mavenSession = createMavenSession( null );
+        FileUtils.copyDirectory(new File("src/test/resources/projects/grandchild-check"), tempDir.toFile());
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
-        org.apache.maven.project.ProjectBuilder projectBuilder = getContainer().lookup( org.apache.maven.project.ProjectBuilder.class );
-        File child = new File( tempDir.toFile(), "child/pom.xml" );
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
+        org.apache.maven.project.ProjectBuilder projectBuilder =
+                getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
+        File child = new File(tempDir.toFile(), "child/pom.xml");
         // build project once
-        projectBuilder.build( child, configuration );
+        projectBuilder.build(child, configuration);
         // modify parent
-        File parent = new File( tempDir.toFile(), "pom.xml" );
-        String parentContent = FileUtils.readFileToString( parent, "UTF-8" );
-        parentContent = parentContent.replaceAll( "<packaging>pom</packaging>",
-                 "<packaging>pom</packaging><properties><addedProperty>addedValue</addedProperty></properties>" );
-        FileUtils.write( parent, parentContent, "UTF-8" );
+        File parent = new File(tempDir.toFile(), "pom.xml");
+        String parentContent = new String(Files.readAllBytes(parent.toPath()), StandardCharsets.UTF_8);
+        parentContent = parentContent.replace(
+                "<packaging>pom</packaging>",
+                "<packaging>pom</packaging><properties><addedProperty>addedValue</addedProperty></properties>");
+        Files.write(parent.toPath(), parentContent.getBytes(StandardCharsets.UTF_8));
         // re-build pom with modified parent
-        ProjectBuildingResult result = projectBuilder.build( child, configuration );
-        assertThat( result.getProject().getProperties(), hasKey( (Object) "addedProperty" ) );
+        ProjectBuildingResult result = projectBuilder.build(child, configuration);
+        assertThat(result.getProject().getProperties(), hasKey((Object) "addedProperty"));
     }
 
     @Test
-    public void testReadErroneousMavenProjectContainsReference()
-        throws Exception
-    {
-        File pomFile = new File( "src/test/resources/projects/artifactMissingVersion.xml" ).getAbsoluteFile();
-        MavenSession mavenSession = createMavenSession( null );
+    void testReadErroneousMavenProjectContainsReference() throws Exception {
+        File pomFile = new File("src/test/resources/projects/artifactMissingVersion/pom.xml").getAbsoluteFile();
+        MavenSession mavenSession = createMavenSession(null);
+        mavenSession.getRequest().setRootDirectory(pomFile.getParentFile().toPath());
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
+        configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
         org.apache.maven.project.ProjectBuilder projectBuilder =
-                getContainer().lookup( org.apache.maven.project.ProjectBuilder.class );
+                getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
 
         // single project build entry point
         ProjectBuildingException ex1 =
-            assertThrows( ProjectBuildingException.class, () -> projectBuilder.build( pomFile, configuration ) );
+                assertThrows(ProjectBuildingException.class, () -> projectBuilder.build(pomFile, configuration));
 
-        assertEquals( 1, ex1.getResults().size() );
-        MavenProject project1 = ex1.getResults().get( 0 ).getProject();
-        assertNotNull( project1 );
-        assertEquals( "testArtifactMissingVersion", project1.getArtifactId() );
-        assertEquals( pomFile, project1.getFile() );
+        assertEquals(1, ex1.getResults().size());
+        MavenProject project1 = ex1.getResults().get(0).getProject();
+        assertNotNull(project1);
+        assertEquals("testArtifactMissingVersion", project1.getArtifactId());
+        assertEquals(pomFile, project1.getFile());
 
         // multi projects build entry point
-        ProjectBuildingException ex2 =
-            assertThrows( ProjectBuildingException.class,
-                          () -> projectBuilder.build( Collections.singletonList( pomFile ), false, configuration ) );
+        ProjectBuildingException ex2 = assertThrows(
+                ProjectBuildingException.class,
+                () -> projectBuilder.build(Collections.singletonList(pomFile), false, configuration));
 
-        assertEquals( 1, ex2.getResults().size() );
-        MavenProject project2 = ex2.getResults().get( 0 ).getProject();
-        assertNotNull( project2 );
-        assertEquals( "testArtifactMissingVersion", project2.getArtifactId() );
-        assertEquals( pomFile, project2.getFile() );
+        assertEquals(1, ex2.getResults().size());
+        MavenProject project2 = ex2.getResults().get(0).getProject();
+        assertNotNull(project2);
+        assertEquals("testArtifactMissingVersion", project2.getArtifactId());
+        assertEquals(pomFile, project2.getFile());
     }
 
     @Test
-    public void testReadInvalidPom()
-        throws Exception
-    {
-        File pomFile = new File( "src/test/resources/projects/badPom.xml" ).getAbsoluteFile();
-        MavenSession mavenSession = createMavenSession( null );
+    void testReadInvalidPom() throws Exception {
+        File pomFile = new File("src/test/resources/projects/badPom.xml").getAbsoluteFile();
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
+        configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
         org.apache.maven.project.ProjectBuilder projectBuilder =
-                getContainer().lookup( org.apache.maven.project.ProjectBuilder.class );
+                getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
 
         // single project build entry point
-        Exception ex = assertThrows( Exception.class, () -> projectBuilder.build( pomFile, configuration ) );
-        assertThat( ex.getMessage(), containsString( "expected START_TAG or END_TAG not TEXT" ) );
+        Exception ex = assertThrows(Exception.class, () -> projectBuilder.build(pomFile, configuration));
+        assertThat(ex.getMessage(), containsString("Received non-all-whitespace CHARACTERS or CDATA event"));
 
         // multi projects build entry point
-        ProjectBuildingException pex =
-            assertThrows( ProjectBuildingException.class,
-                          () -> projectBuilder.build( Collections.singletonList( pomFile ), false, configuration ) );
-        assertEquals( 1, pex.getResults().size() );
-        assertNotNull( pex.getResults().get( 0 ).getPomFile() );
-        assertThat( pex.getResults().get( 0 ).getProblems().size(), greaterThan( 0 ) );
-        assertThat( pex.getResults(), contains( projectBuildingResultWithProblemMessage( "expected START_TAG or END_TAG not TEXT" ) ) );
+        ProjectBuildingException pex = assertThrows(
+                ProjectBuildingException.class,
+                () -> projectBuilder.build(Collections.singletonList(pomFile), false, configuration));
+        assertEquals(1, pex.getResults().size());
+        assertNotNull(pex.getResults().get(0).getPomFile());
+        assertThat(pex.getResults().get(0).getProblems().size(), greaterThan(0));
+        assertThat(
+                pex.getResults(),
+                contains(projectBuildingResultWithProblemMessage(
+                        "Received non-all-whitespace CHARACTERS or CDATA event in nextTag()")));
     }
 
     @Test
-    public void testReadParentAndChildWithRegularVersionSetParentFile()
-        throws Exception
-    {
-        List<File> toRead = new ArrayList<>( 2 );
-        File parentPom = getProject( "MNG-6723" );
-        toRead.add( parentPom );
-        toRead.add( new File( parentPom.getParentFile(), "child/pom.xml" ) );
-        MavenSession mavenSession = createMavenSession( null );
+    void testReadParentAndChildWithRegularVersionSetParentFile() throws Exception {
+        List<File> toRead = new ArrayList<>(2);
+        File parentPom = getProject("MNG-6723");
+        toRead.add(parentPom);
+        toRead.add(new File(parentPom.getParentFile(), "child/pom.xml"));
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
+        configuration.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
         org.apache.maven.project.ProjectBuilder projectBuilder =
-                getContainer().lookup( org.apache.maven.project.ProjectBuilder.class );
+                getContainer().lookup(org.apache.maven.project.ProjectBuilder.class);
 
         // read poms separately
         boolean parentFileWasFoundOnChild = false;
-        for ( File file : toRead )
-        {
-            List<ProjectBuildingResult> results = projectBuilder.build( Collections.singletonList( file ), false, configuration );
-            assertResultShowNoError( results );
-            MavenProject project = findChildProject( results );
-            if ( project != null )
-            {
-                assertEquals( parentPom, project.getParentFile() );
+        for (File file : toRead) {
+            List<ProjectBuildingResult> results =
+                    projectBuilder.build(Collections.singletonList(file), false, configuration);
+            assertResultShowNoError(results);
+            MavenProject project = findChildProject(results);
+            if (project != null) {
+                assertEquals(parentPom, project.getParentFile());
                 parentFileWasFoundOnChild = true;
             }
         }
-        assertTrue( parentFileWasFoundOnChild );
+        assertTrue(parentFileWasFoundOnChild);
 
         // read projects together
-        List<ProjectBuildingResult> results = projectBuilder.build( toRead, false, configuration );
-        assertResultShowNoError( results );
-        assertEquals( parentPom, findChildProject( results ).getParentFile() );
-        Collections.reverse( toRead );
-        results = projectBuilder.build( toRead, false, configuration );
-        assertResultShowNoError( results );
-        assertEquals( parentPom, findChildProject( results ).getParentFile() );
+        List<ProjectBuildingResult> results = projectBuilder.build(toRead, false, configuration);
+        assertResultShowNoError(results);
+        assertEquals(parentPom, findChildProject(results).getParentFile());
+        Collections.reverse(toRead);
+        results = projectBuilder.build(toRead, false, configuration);
+        assertResultShowNoError(results);
+        assertEquals(parentPom, findChildProject(results).getParentFile());
     }
 
-    private MavenProject findChildProject( List<ProjectBuildingResult> results )
-    {
-        for ( ProjectBuildingResult result : results )
-        {
-            if ( result.getPomFile().getParentFile().getName().equals( "child" ) )
-            {
+    private MavenProject findChildProject(List<ProjectBuildingResult> results) {
+        for (ProjectBuildingResult result : results) {
+            if (result.getPomFile().getParentFile().getName().equals("child")) {
                 return result.getProject();
             }
         }
         return null;
     }
 
-    private void assertResultShowNoError( List<ProjectBuildingResult> results )
-    {
-        for ( ProjectBuildingResult result : results )
-        {
-            assertThat( result.getProblems(), is( empty() ) );
-            assertNotNull( result.getProject() );
+    private void assertResultShowNoError(List<ProjectBuildingResult> results) {
+        for (ProjectBuildingResult result : results) {
+            assertThat(result.getProblems(), is(empty()));
+            assertNotNull(result.getProject());
         }
     }
 
     @Test
-    public void testBuildProperties()
-            throws Exception
-    {
-        File file = new File( getProject( "MNG-6716" ).getParentFile(), "project/pom.xml" );
-        MavenSession mavenSession = createMavenSession( null );
+    void testBuildProperties() throws Exception {
+        File file = new File(getProject("MNG-6716").getParentFile(), "project/pom.xml");
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
-        configuration.setResolveDependencies( true );
-        List<ProjectBuildingResult> result = projectBuilder.build( Collections.singletonList( file ), true, configuration );
-        MavenProject project = result.get( 0 ).getProject();
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
+        configuration.setResolveDependencies(true);
+        List<ProjectBuildingResult> result = projectBuilder.build(Collections.singletonList(file), true, configuration);
+        MavenProject project = result.get(0).getProject();
         // verify a few typical parameters are not duplicated
-        assertEquals( 1, project.getTestCompileSourceRoots().size() );
-        assertEquals( 1, project.getCompileSourceRoots().size() );
-        assertEquals( 1, project.getMailingLists().size() );
-        assertEquals( 1, project.getResources().size() );
+        assertEquals(1, project.getTestCompileSourceRoots().size());
+        assertEquals(1, project.getCompileSourceRoots().size());
+        assertEquals(1, project.getMailingLists().size());
+        assertEquals(1, project.getResources().size());
     }
 
     @Test
-    public void testPropertyInPluginManagementGroupId()
-            throws Exception
-    {
-        File pom = getProject( "MNG-6983" );
+    void testPropertyInPluginManagementGroupId() throws Exception {
+        File pom = getProject("MNG-6983");
 
-        MavenSession session = createMavenSession( pom );
+        MavenSession session = createMavenSession(pom);
         MavenProject project = session.getCurrentProject();
 
         for (Plugin buildPlugin : project.getBuildPlugins()) {
-            assertNotNull( "Missing version for build plugin " + buildPlugin.getKey(), buildPlugin.getVersion() );
+            assertNotNull(buildPlugin.getVersion(), "Missing version for build plugin " + buildPlugin.getKey());
         }
     }
 
     @Test
-    public void testBuildFromModelSourceResolvesBasedir()
-        throws Exception
-    {
-        File pomFile = new File( "src/test/resources/projects/modelsourcebasedir/pom.xml" );
-        MavenSession mavenSession = createMavenSession( null );
+    void testBuildFromModelSourceResolvesBasedir() throws Exception {
+        File pomFile = new File("src/test/resources/projects/modelsourcebasedir/pom.xml");
+        MavenSession mavenSession = createMavenSession(null);
         ProjectBuildingRequest configuration = new DefaultProjectBuildingRequest();
-        configuration.setRepositorySession( mavenSession.getRepositorySession() );
-        ModelSource modelSource = new FileModelSource( pomFile );
-        ProjectBuildingResult result =
-            getContainer().lookup( org.apache.maven.project.ProjectBuilder.class ).build( modelSource, configuration );
+        configuration.setRepositorySession(mavenSession.getRepositorySession());
+        ModelSource modelSource = new FileModelSource(pomFile);
+        ProjectBuildingResult result = getContainer()
+                .lookup(org.apache.maven.project.ProjectBuilder.class)
+                .build(modelSource, configuration);
 
-        assertEquals( pomFile.getAbsoluteFile(), result.getProject().getModel().getPomFile().getAbsoluteFile() );
+        assertEquals(
+                pomFile.getAbsoluteFile(),
+                result.getProject().getModel().getPomFile().getAbsoluteFile());
         int errors = 0;
-        for ( ModelProblem p : result.getProblems() )
-        {
-            if ( p.getSeverity() == ModelProblem.Severity.ERROR )
-            {
+        for (ModelProblem p : result.getProblems()) {
+            if (p.getSeverity() == ModelProblem.Severity.ERROR) {
                 errors++;
             }
         }
-        assertEquals( 0, errors );
+        assertEquals(0, errors);
     }
 
+    @Test
+    void testLocationTrackingResolution() throws Exception {
+        File pom = getProject("MNG-7648");
+
+        MavenSession session = createMavenSession(pom);
+        MavenProject project = session.getCurrentProject();
+
+        InputLocation dependencyLocation = null;
+        for (Dependency dependency : project.getDependencies()) {
+            if (dependency.getManagementKey().equals("org.apache.maven.its:a:jar")) {
+                dependencyLocation = dependency.getLocation("version");
+            }
+        }
+        assertNotNull(dependencyLocation, "missing dependency");
+        assertEquals(
+                "org.apache.maven.its:bom:0.1", dependencyLocation.getSource().getModelId());
+
+        InputLocation pluginLocation = null;
+        for (Plugin plugin : project.getBuildPlugins()) {
+            if (plugin.getKey().equals("org.apache.maven.plugins:maven-clean-plugin")) {
+                pluginLocation = plugin.getLocation("version");
+            }
+        }
+        assertNotNull(pluginLocation, "missing build plugin");
+        assertEquals(
+                "org.apache.maven.its:parent:0.1", pluginLocation.getSource().getModelId());
+    }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithLocationMatcher.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithLocationMatcher.java
index fafcb42..235561f 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithLocationMatcher.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithLocationMatcher.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
-import org.apache.maven.model.building.ModelProblem;
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.hamcrest.Matcher;
@@ -29,63 +27,53 @@
 /**
  * Hamcrest matcher to help create fluent assertions about {@link ProjectBuildingResult} instances.
  */
-class ProjectBuildingResultWithLocationMatcher extends BaseMatcher<ProjectBuildingResult>
-{
+class ProjectBuildingResultWithLocationMatcher extends BaseMatcher<ProjectBuildingResult> {
     private final int columnNumber;
     private final int lineNumber;
 
-    ProjectBuildingResultWithLocationMatcher( int columnNumber, int lineNumber )
-    {
+    ProjectBuildingResultWithLocationMatcher(int columnNumber, int lineNumber) {
         this.columnNumber = columnNumber;
         this.lineNumber = lineNumber;
     }
 
     @Override
-    public boolean matches( Object o )
-    {
-        if ( !( o instanceof ProjectBuildingResult ) )
-        {
+    public boolean matches(Object o) {
+        if (!(o instanceof ProjectBuildingResult)) {
             return false;
         }
 
         final ProjectBuildingResult r = (ProjectBuildingResult) o;
 
         return r.getProblems().stream()
-                .anyMatch( p -> p.getLineNumber() == lineNumber && p.getColumnNumber() == columnNumber );
+                .anyMatch(p -> p.getLineNumber() == lineNumber && p.getColumnNumber() == columnNumber);
     }
 
     @Override
-    public void describeTo( Description description )
-    {
-        description.appendText( "a ProjectBuildingResult with location " )
-                .appendText( formatLocation( columnNumber, lineNumber ) );
+    public void describeTo(Description description) {
+        description
+                .appendText("a ProjectBuildingResult with location ")
+                .appendText(formatLocation(columnNumber, lineNumber));
     }
 
-    private String formatLocation( int columnNumber, int lineNumber )
-    {
-        return String.format( "line %d, column %d", lineNumber, columnNumber );
+    private String formatLocation(int columnNumber, int lineNumber) {
+        return String.format("line %d, column %d", lineNumber, columnNumber);
     }
 
     @Override
-    public void describeMismatch(final Object o, final Description description)
-    {
-        if ( !( o instanceof ProjectBuildingResult ) )
-        {
-            super.describeMismatch( o, description );
-        }
-        else
-        {
+    public void describeMismatch(final Object o, final Description description) {
+        if (!(o instanceof ProjectBuildingResult)) {
+            super.describeMismatch(o, description);
+        } else {
             final ProjectBuildingResult r = (ProjectBuildingResult) o;
-            description.appendText( "was a ProjectBuildingResult with locations " );
+            description.appendText("was a ProjectBuildingResult with locations ");
             String messages = r.getProblems().stream()
-                    .map( p -> formatLocation( p.getColumnNumber(), p.getLineNumber() ) )
-                    .collect( joining( ", ") );
-            description.appendText( messages );
+                    .map(p -> formatLocation(p.getColumnNumber(), p.getLineNumber()))
+                    .collect(joining(", "));
+            description.appendText(messages);
         }
     }
 
-    static Matcher<ProjectBuildingResult> projectBuildingResultWithLocation( int columnNumber, int lineNumber )
-    {
-        return new ProjectBuildingResultWithLocationMatcher( columnNumber, lineNumber );
+    static Matcher<ProjectBuildingResult> projectBuildingResultWithLocation(int columnNumber, int lineNumber) {
+        return new ProjectBuildingResultWithLocationMatcher(columnNumber, lineNumber);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithProblemMessageMatcher.java b/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithProblemMessageMatcher.java
index 0ae052a..efbde86 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithProblemMessageMatcher.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ProjectBuildingResultWithProblemMessageMatcher.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import org.apache.maven.model.building.ModelProblem;
 import org.hamcrest.BaseMatcher;
@@ -29,56 +28,45 @@
 /**
  * Hamcrest matcher to help create fluent assertions about {@link ProjectBuildingResult} instances.
  */
-class ProjectBuildingResultWithProblemMessageMatcher extends BaseMatcher<ProjectBuildingResult>
-{
+class ProjectBuildingResultWithProblemMessageMatcher extends BaseMatcher<ProjectBuildingResult> {
     private final String problemMessage;
 
-    ProjectBuildingResultWithProblemMessageMatcher( String problemMessage ) {
+    ProjectBuildingResultWithProblemMessageMatcher(String problemMessage) {
         this.problemMessage = problemMessage;
     }
 
     @Override
-    public boolean matches( Object o )
-    {
-        if ( !( o instanceof ProjectBuildingResult ) )
-        {
+    public boolean matches(Object o) {
+        if (!(o instanceof ProjectBuildingResult)) {
             return false;
         }
 
         final ProjectBuildingResult r = (ProjectBuildingResult) o;
 
-        return r.getProblems().stream()
-                .anyMatch( p -> p.getMessage().contains( problemMessage ) );
+        return r.getProblems().stream().anyMatch(p -> p.getMessage().contains(problemMessage));
     }
 
     @Override
-    public void describeTo( Description description )
-    {
-        description.appendText( "a ProjectBuildingResult with message " )
-                .appendValue(problemMessage);
+    public void describeTo(Description description) {
+        description.appendText("a ProjectBuildingResult with message ").appendValue(problemMessage);
     }
 
     @Override
-    public void describeMismatch(final Object o, final Description description)
-    {
-        if ( !( o instanceof ProjectBuildingResult ) )
-        {
-            super.describeMismatch( o, description );
-        }
-        else
-        {
+    public void describeMismatch(final Object o, final Description description) {
+        if (!(o instanceof ProjectBuildingResult)) {
+            super.describeMismatch(o, description);
+        } else {
             final ProjectBuildingResult r = (ProjectBuildingResult) o;
-            description.appendText( "was a ProjectBuildingResult with messages " );
+            description.appendText("was a ProjectBuildingResult with messages ");
             String messages = r.getProblems().stream()
-                    .map( ModelProblem::getMessage )
-                    .map( m -> "\"" + m + "\"" + System.lineSeparator() )
-                    .collect( joining( ", ") );
-            description.appendText( messages );
+                    .map(ModelProblem::getMessage)
+                    .map(m -> "\"" + m + "\"" + System.lineSeparator())
+                    .collect(joining(", "));
+            description.appendText(messages);
         }
     }
 
-    static Matcher<ProjectBuildingResult> projectBuildingResultWithProblemMessage( String message )
-    {
-        return new ProjectBuildingResultWithProblemMessageMatcher( message );
+    static Matcher<ProjectBuildingResult> projectBuildingResultWithProblemMessage(String message) {
+        return new ProjectBuildingResultWithProblemMessageMatcher(message);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectModelResolverTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectModelResolverTest.java
index 709b88c..ec8cb75 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ProjectModelResolverTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ProjectModelResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project;
 
 import java.io.File;
 import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.maven.artifact.InvalidRepositoryException;
+import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.Parent;
 import org.apache.maven.model.resolution.ModelResolver;
@@ -36,195 +37,181 @@
 import org.junit.jupiter.api.Test;
 
 import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
-import static org.hamcrest.Matchers.startsWith;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
 /**
  * Test cases for the project {@code ModelResolver} implementation.
  *
- * @author Christian Schulte
  * @since 3.5.0
  */
-public class ProjectModelResolverTest extends AbstractMavenProjectTestCase
-{
+class ProjectModelResolverTest extends AbstractMavenProjectTestCase {
 
     /**
      * Creates a new {@code ProjectModelResolverTest} instance.
      */
-    public ProjectModelResolverTest()
-    {
+    public ProjectModelResolverTest() {
         super();
     }
 
     @Test
-    public void testResolveParentThrowsUnresolvableModelExceptionWhenNotFound() throws Exception
-    {
+    void testResolveParentThrowsUnresolvableModelExceptionWhenNotFound() throws Exception {
         final Parent parent = new Parent();
-        parent.setGroupId( "org.apache" );
-        parent.setArtifactId( "apache" );
-        parent.setVersion( "0" );
+        parent.setGroupId("org.apache");
+        parent.setArtifactId("apache");
+        parent.setVersion("0");
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( parent ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertNotNull( e.getMessage() );
-        assertThat( e.getMessage(), startsWith( "Could not find artifact org.apache:apache:pom:0 in central" ) );
+                () -> newModelResolver().resolveModel(parent.getDelegate(), new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertNotNull(e.getMessage());
+        assertThat(e.getMessage(), containsString("Could not find artifact org.apache:apache:pom:0 in central"));
     }
 
     @Test
-    public void testResolveParentThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception
-    {
+    void testResolveParentThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception {
         final Parent parent = new Parent();
-        parent.setGroupId( "org.apache" );
-        parent.setArtifactId( "apache" );
-        parent.setVersion( "[2.0,2.1)" );
+        parent.setGroupId("org.apache");
+        parent.setArtifactId("apache");
+        parent.setVersion("[2.0,2.1)");
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( parent ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertEquals( "No versions matched the requested parent version range '[2.0,2.1)'",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(parent.getDelegate(), new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertEquals("No versions matched the requested parent version range '[2.0,2.1)'", e.getMessage());
     }
 
     @Test
-    public void testResolveParentThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception
-    {
+    void testResolveParentThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception {
         final Parent parent = new Parent();
-        parent.setGroupId( "org.apache" );
-        parent.setArtifactId( "apache" );
-        parent.setVersion( "[1,)" );
+        parent.setGroupId("org.apache");
+        parent.setArtifactId("apache");
+        parent.setVersion("[1,)");
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( parent ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertEquals( "The requested parent version range '[1,)' does not specify an upper bound",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(parent.getDelegate(), new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertEquals("The requested parent version range '[1,)' does not specify an upper bound", e.getMessage());
     }
 
     @Test
-    public void testResolveParentSuccessfullyResolvesExistingParentWithoutRange() throws Exception
-    {
+    void testResolveParentSuccessfullyResolvesExistingParentWithoutRange() throws Exception {
         final Parent parent = new Parent();
-        parent.setGroupId( "org.apache" );
-        parent.setArtifactId( "apache" );
-        parent.setVersion( "1" );
+        parent.setGroupId("org.apache");
+        parent.setArtifactId("apache");
+        parent.setVersion("1");
 
-        assertNotNull( this.newModelResolver().resolveModel( parent ) );
-        assertEquals( "1", parent.getVersion() );
+        assertNotNull(this.newModelResolver().resolveModel(parent.getDelegate(), new AtomicReference<>()));
+        assertEquals("1", parent.getVersion());
     }
 
     @Test
-    public void testResolveParentSuccessfullyResolvesExistingParentUsingHighestVersion() throws Exception
-    {
+    void testResolveParentSuccessfullyResolvesExistingParentUsingHighestVersion() throws Exception {
         final Parent parent = new Parent();
-        parent.setGroupId( "org.apache" );
-        parent.setArtifactId( "apache" );
-        parent.setVersion( "(,2.0)" );
+        parent.setGroupId("org.apache");
+        parent.setArtifactId("apache");
+        parent.setVersion("(,2.0)");
 
-        assertNotNull( this.newModelResolver().resolveModel( parent ) );
-        assertEquals( "1", parent.getVersion() );
+        AtomicReference<org.apache.maven.api.model.Parent> modified = new AtomicReference<>();
+        assertNotNull(this.newModelResolver().resolveModel(parent.getDelegate(), modified));
+        assertEquals("1", modified.get().getVersion());
     }
 
     @Test
-    public void testResolveDependencyThrowsUnresolvableModelExceptionWhenNotFound() throws Exception
-    {
+    void testResolveDependencyThrowsUnresolvableModelExceptionWhenNotFound() throws Exception {
         final Dependency dependency = new Dependency();
-        dependency.setGroupId( "org.apache" );
-        dependency.setArtifactId( "apache" );
-        dependency.setVersion( "0" );
+        dependency.setGroupId("org.apache");
+        dependency.setArtifactId("apache");
+        dependency.setVersion("0");
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( dependency ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertNotNull( e.getMessage() );
-        assertThat( e.getMessage(), startsWith( "Could not find artifact org.apache:apache:pom:0 in central" ) );
+                () -> newModelResolver().resolveModel(dependency.getDelegate(), new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertNotNull(e.getMessage());
+        assertThat(e.getMessage(), containsString("Could not find artifact org.apache:apache:pom:0 in central"));
     }
 
     @Test
-    public void testResolveDependencyThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception
-    {
+    void testResolveDependencyThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception {
         final Dependency dependency = new Dependency();
-        dependency.setGroupId( "org.apache" );
-        dependency.setArtifactId( "apache" );
-        dependency.setVersion( "[2.0,2.1)" );
+        dependency.setGroupId("org.apache");
+        dependency.setArtifactId("apache");
+        dependency.setVersion("[2.0,2.1)");
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( dependency ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertEquals( "No versions matched the requested dependency version range '[2.0,2.1)'",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(dependency.getDelegate(), new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertEquals("No versions matched the requested dependency version range '[2.0,2.1)'", e.getMessage());
     }
 
     @Test
-    public void testResolveDependencyThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception
-    {
+    void testResolveDependencyThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception {
         final Dependency dependency = new Dependency();
-        dependency.setGroupId( "org.apache" );
-        dependency.setArtifactId( "apache" );
-        dependency.setVersion( "[1,)" );
+        dependency.setGroupId("org.apache");
+        dependency.setArtifactId("apache");
+        dependency.setVersion("[1,)");
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( dependency ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertEquals( "The requested dependency version range '[1,)' does not specify an upper bound",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(dependency.getDelegate(), new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertEquals("The requested dependency version range '[1,)' does not specify an upper bound", e.getMessage());
     }
 
     @Test
-    public void testResolveDependencySuccessfullyResolvesExistingDependencyWithoutRange() throws Exception
-    {
+    void testResolveDependencySuccessfullyResolvesExistingDependencyWithoutRange() throws Exception {
         final Dependency dependency = new Dependency();
-        dependency.setGroupId( "org.apache" );
-        dependency.setArtifactId( "apache" );
-        dependency.setVersion( "1" );
+        dependency.setGroupId("org.apache");
+        dependency.setArtifactId("apache");
+        dependency.setVersion("1");
 
-        assertNotNull( this.newModelResolver().resolveModel( dependency ) );
-        assertEquals( "1", dependency.getVersion() );
+        assertNotNull(this.newModelResolver().resolveModel(dependency.getDelegate(), new AtomicReference<>()));
+        assertEquals("1", dependency.getVersion());
     }
 
     @Test
-    public void testResolveDependencySuccessfullyResolvesExistingDependencyUsingHighestVersion() throws Exception
-    {
+    void testResolveDependencySuccessfullyResolvesExistingDependencyUsingHighestVersion() throws Exception {
         final Dependency dependency = new Dependency();
-        dependency.setGroupId( "org.apache" );
-        dependency.setArtifactId( "apache" );
-        dependency.setVersion( "(,2.0)" );
+        dependency.setGroupId("org.apache");
+        dependency.setArtifactId("apache");
+        dependency.setVersion("(,2.0)");
 
-        assertNotNull( this.newModelResolver().resolveModel( dependency ) );
-        assertEquals( "1", dependency.getVersion() );
+        AtomicReference<org.apache.maven.api.model.Dependency> modified = new AtomicReference<>();
+        assertNotNull(this.newModelResolver().resolveModel(dependency.getDelegate(), modified));
+        assertEquals("1", modified.get().getVersion());
     }
 
-    private ModelResolver newModelResolver() throws Exception
-    {
-        final File localRepo = new File( this.getLocalRepository().getBasedir() );
+    private ModelResolver newModelResolver() throws Exception {
+        final File localRepo = new File(this.getLocalRepository().getBasedir());
         final DefaultRepositorySystemSession repoSession = MavenRepositorySystemUtils.newSession();
-        repoSession.setLocalRepositoryManager( new LegacyLocalRepositoryManager( localRepo ) );
+        repoSession.setLocalRepositoryManager(new LegacyLocalRepositoryManager(localRepo));
 
-        return new ProjectModelResolver( repoSession, null, getContainer().lookup( RepositorySystem.class ),
-                                         getContainer().lookup( RemoteRepositoryManager.class ),
-                                         this.getRemoteRepositories(),
-                                         ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT, null );
-
+        return new ProjectModelResolver(
+                repoSession,
+                null,
+                getContainer().lookup(RepositorySystem.class),
+                getContainer().lookup(RemoteRepositoryManager.class),
+                this.getRemoteRepositories(),
+                ProjectBuildingRequest.RepositoryMerging.REQUEST_DOMINANT,
+                null);
     }
 
-    private List<RemoteRepository> getRemoteRepositories()
-        throws InvalidRepositoryException
-    {
-        final File repoDir = new File( getBasedir(), "src/test/remote-repo" ).getAbsoluteFile();
-        final RemoteRepository remoteRepository =
-            new RemoteRepository.Builder( org.apache.maven.repository.RepositorySystem.DEFAULT_REMOTE_REPO_ID,
-                                          "default", repoDir.toURI().toASCIIString() ).build();
+    private List<RemoteRepository> getRemoteRepositories() throws InvalidRepositoryException {
+        final File repoDir = new File(getBasedir(), "src/test/remote-repo").getAbsoluteFile();
+        final RemoteRepository remoteRepository = new RemoteRepository.Builder(
+                        MavenRepositorySystem.DEFAULT_REMOTE_REPO_ID,
+                        "default",
+                        repoDir.toURI().toASCIIString())
+                .build();
 
-        return Collections.singletonList( remoteRepository );
+        return Collections.singletonList(remoteRepository);
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/ProjectSorterTest.java b/maven-core/src/test/java/org/apache/maven/project/ProjectSorterTest.java
index ec15951..abfa2d5 100644
--- a/maven-core/src/test/java/org/apache/maven/project/ProjectSorterTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/ProjectSorterTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,11 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.hamcrest.Matchers.hasItem;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertThrows;
+package org.apache.maven.project;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -37,332 +31,304 @@
 import org.apache.maven.model.PluginManagement;
 import org.junit.jupiter.api.Test;
 
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasItem;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 /**
  * Test sorting projects by dependencies.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class ProjectSorterTest
-{
-    private Parent createParent( MavenProject project )
-    {
-        return createParent( project.getGroupId(), project.getArtifactId(), project.getVersion() );
+class ProjectSorterTest {
+    private Parent createParent(MavenProject project) {
+        return createParent(project.getGroupId(), project.getArtifactId(), project.getVersion());
     }
 
-    private Parent createParent( String groupId, String artifactId, String version )
-    {
+    private Parent createParent(String groupId, String artifactId, String version) {
         Parent plugin = new Parent();
-        plugin.setGroupId( groupId );
-        plugin.setArtifactId( artifactId );
-        plugin.setVersion( version );
+        plugin.setGroupId(groupId);
+        plugin.setArtifactId(artifactId);
+        plugin.setVersion(version);
         return plugin;
     }
 
-    private Dependency createDependency( MavenProject project )
-    {
-        return createDependency( project.getGroupId(), project.getArtifactId(), project.getVersion() );
+    private Dependency createDependency(MavenProject project) {
+        return createDependency(project.getGroupId(), project.getArtifactId(), project.getVersion());
     }
 
-    private Dependency createDependency( String groupId, String artifactId, String version )
-    {
+    private Dependency createDependency(String groupId, String artifactId, String version) {
         Dependency dependency = new Dependency();
-        dependency.setGroupId( groupId );
-        dependency.setArtifactId( artifactId );
-        dependency.setVersion( version );
+        dependency.setGroupId(groupId);
+        dependency.setArtifactId(artifactId);
+        dependency.setVersion(version);
         return dependency;
     }
 
-    private Plugin createPlugin( MavenProject project )
-    {
-        return createPlugin( project.getGroupId(), project.getArtifactId(), project.getVersion() );
+    private Plugin createPlugin(MavenProject project) {
+        return createPlugin(project.getGroupId(), project.getArtifactId(), project.getVersion());
     }
 
-    private Plugin createPlugin( String groupId, String artifactId, String version )
-    {
+    private Plugin createPlugin(String groupId, String artifactId, String version) {
         Plugin plugin = new Plugin();
-        plugin.setGroupId( groupId );
-        plugin.setArtifactId( artifactId );
-        plugin.setVersion( version );
+        plugin.setGroupId(groupId);
+        plugin.setArtifactId(artifactId);
+        plugin.setVersion(version);
         return plugin;
     }
 
-    private Extension createExtension( String groupId, String artifactId, String version )
-    {
+    private Extension createExtension(String groupId, String artifactId, String version) {
         Extension extension = new Extension();
-        extension.setGroupId( groupId );
-        extension.setArtifactId( artifactId );
-        extension.setVersion( version );
+        extension.setGroupId(groupId);
+        extension.setArtifactId(artifactId);
+        extension.setVersion(version);
         return extension;
     }
 
-    private static MavenProject createProject( String groupId, String artifactId, String version )
-    {
+    private static MavenProject createProject(String groupId, String artifactId, String version) {
         Model model = new Model();
-        model.setGroupId( groupId );
-        model.setArtifactId( artifactId );
-        model.setVersion( version );
-        model.setBuild( new Build() );
-        return new MavenProject( model );
+        model.setGroupId(groupId);
+        model.setArtifactId(artifactId);
+        model.setVersion(version);
+        model.setBuild(new Build());
+        return new MavenProject(model);
     }
 
     @Test
-    public void testShouldNotFailWhenPluginDepReferencesCurrentProject()
-        throws Exception
-    {
-        MavenProject project = createProject( "group", "artifact", "1.0" );
+    void testShouldNotFailWhenPluginDepReferencesCurrentProject() throws Exception {
+        MavenProject project = createProject("group", "artifact", "1.0");
 
         Build build = project.getModel().getBuild();
 
-        Plugin plugin = createPlugin( "other.group", "other-artifact", "1.0" );
+        Plugin plugin = createPlugin("other.group", "other-artifact", "1.0");
 
-        Dependency dep = createDependency( "group", "artifact", "1.0" );
+        Dependency dep = createDependency("group", "artifact", "1.0");
 
-        plugin.addDependency( dep );
+        plugin.addDependency(dep);
 
-        build.addPlugin( plugin );
+        build.addPlugin(plugin);
 
-        new ProjectSorter( Collections.singletonList( project ) );
+        new ProjectSorter(Collections.singletonList(project));
     }
 
     @Test
-    public void testShouldNotFailWhenManagedPluginDepReferencesCurrentProject()
-        throws Exception
-    {
-        MavenProject project = createProject( "group", "artifact", "1.0" );
+    void testShouldNotFailWhenManagedPluginDepReferencesCurrentProject() throws Exception {
+        MavenProject project = createProject("group", "artifact", "1.0");
 
         Build build = project.getModel().getBuild();
 
         PluginManagement pMgmt = new PluginManagement();
 
-        Plugin plugin = createPlugin( "other.group", "other-artifact", "1.0" );
+        Plugin plugin = createPlugin("other.group", "other-artifact", "1.0");
 
-        Dependency dep = createDependency( "group", "artifact", "1.0" );
+        Dependency dep = createDependency("group", "artifact", "1.0");
 
-        plugin.addDependency( dep );
+        plugin.addDependency(dep);
 
-        pMgmt.addPlugin( plugin );
+        pMgmt.addPlugin(plugin);
 
-        build.setPluginManagement( pMgmt );
+        build.setPluginManagement(pMgmt);
 
-        new ProjectSorter( Collections.singletonList( project ) );
+        new ProjectSorter(Collections.singletonList(project));
     }
 
     @Test
-    public void testShouldNotFailWhenProjectReferencesNonExistentProject()
-        throws Exception
-    {
-        MavenProject project = createProject( "group", "artifact", "1.0" );
+    void testShouldNotFailWhenProjectReferencesNonExistentProject() throws Exception {
+        MavenProject project = createProject("group", "artifact", "1.0");
 
         Build build = project.getModel().getBuild();
 
-        Extension extension = createExtension( "other.group", "other-artifact", "1.0" );
+        Extension extension = createExtension("other.group", "other-artifact", "1.0");
 
-        build.addExtension( extension );
+        build.addExtension(extension);
 
-        new ProjectSorter( Collections.singletonList( project ) );
+        new ProjectSorter(Collections.singletonList(project));
     }
 
     @Test
-    public void testMatchingArtifactIdsDifferentGroupIds()
-        throws Exception
-    {
+    void testMatchingArtifactIdsDifferentGroupIds() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
-        MavenProject project1 = createProject( "groupId1", "artifactId", "1.0" );
-        projects.add( project1 );
-        MavenProject project2 = createProject( "groupId2", "artifactId", "1.0" );
-        projects.add( project2 );
-        project1.getDependencies().add( createDependency( project2 ) );
+        MavenProject project1 = createProject("groupId1", "artifactId", "1.0");
+        projects.add(project1);
+        MavenProject project2 = createProject("groupId2", "artifactId", "1.0");
+        projects.add(project2);
+        project1.getDependencies().add(createDependency(project2));
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
+        projects = new ProjectSorter(projects).getSortedProjects();
 
-        assertEquals( project2, projects.get( 0 ) );
-        assertEquals( project1, projects.get( 1 ) );
+        assertEquals(project2, projects.get(0));
+        assertEquals(project1, projects.get(1));
     }
 
     @Test
-    public void testMatchingGroupIdsDifferentArtifactIds()
-        throws Exception
-    {
+    void testMatchingGroupIdsDifferentArtifactIds() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
-        MavenProject project1 = createProject( "groupId", "artifactId1", "1.0" );
-        projects.add( project1 );
-        MavenProject project2 = createProject( "groupId", "artifactId2", "1.0" );
-        projects.add( project2 );
-        project1.getDependencies().add( createDependency( project2 ) );
+        MavenProject project1 = createProject("groupId", "artifactId1", "1.0");
+        projects.add(project1);
+        MavenProject project2 = createProject("groupId", "artifactId2", "1.0");
+        projects.add(project2);
+        project1.getDependencies().add(createDependency(project2));
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
+        projects = new ProjectSorter(projects).getSortedProjects();
 
-        assertEquals( project2, projects.get( 0 ) );
-        assertEquals( project1, projects.get( 1 ) );
+        assertEquals(project2, projects.get(0));
+        assertEquals(project1, projects.get(1));
     }
 
     @Test
-    public void testMatchingIdsAndVersions()
-        throws Exception
-    {
+    void testMatchingIdsAndVersions() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
-        MavenProject project1 = createProject( "groupId", "artifactId", "1.0" );
-        projects.add( project1 );
-        MavenProject project2 = createProject( "groupId", "artifactId", "1.0" );
-        projects.add( project2 );
+        MavenProject project1 = createProject("groupId", "artifactId", "1.0");
+        projects.add(project1);
+        MavenProject project2 = createProject("groupId", "artifactId", "1.0");
+        projects.add(project2);
 
         assertThrows(
                 DuplicateProjectException.class,
-                () -> new ProjectSorter( projects ).getSortedProjects(),
-                "Duplicate projects should fail" );
+                () -> new ProjectSorter(projects).getSortedProjects(),
+                "Duplicate projects should fail");
     }
 
     @Test
-    public void testMatchingIdsAndDifferentVersions()
-        throws Exception
-    {
+    void testMatchingIdsAndDifferentVersions() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
-        MavenProject project1 = createProject( "groupId", "artifactId", "1.0" );
-        projects.add( project1 );
-        MavenProject project2 = createProject( "groupId", "artifactId", "2.0" );
-        projects.add( project2 );
+        MavenProject project1 = createProject("groupId", "artifactId", "1.0");
+        projects.add(project1);
+        MavenProject project2 = createProject("groupId", "artifactId", "2.0");
+        projects.add(project2);
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
-        assertEquals( project1, projects.get( 0 ) );
-        assertEquals( project2, projects.get( 1 ) );
+        projects = new ProjectSorter(projects).getSortedProjects();
+        assertEquals(project1, projects.get(0));
+        assertEquals(project2, projects.get(1));
     }
 
     @Test
-    public void testPluginDependenciesInfluenceSorting()
-        throws Exception
-    {
+    void testPluginDependenciesInfluenceSorting() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
 
-        MavenProject parentProject = createProject( "groupId", "parent", "1.0" );
-        projects.add( parentProject );
+        MavenProject parentProject = createProject("groupId", "parent", "1.0");
+        projects.add(parentProject);
 
-        MavenProject declaringProject = createProject( "groupId", "declarer", "1.0" );
-        declaringProject.setParent( parentProject );
-        declaringProject.getModel().setParent( createParent( parentProject ) );
-        projects.add( declaringProject );
+        MavenProject declaringProject = createProject("groupId", "declarer", "1.0");
+        declaringProject.setParent(parentProject);
+        declaringProject.getModel().setParent(createParent(parentProject));
+        projects.add(declaringProject);
 
-        MavenProject pluginLevelDepProject = createProject( "groupId", "plugin-level-dep", "1.0" );
-        pluginLevelDepProject.setParent( parentProject );
-        pluginLevelDepProject.getModel().setParent( createParent( parentProject ) );
-        projects.add( pluginLevelDepProject );
+        MavenProject pluginLevelDepProject = createProject("groupId", "plugin-level-dep", "1.0");
+        pluginLevelDepProject.setParent(parentProject);
+        pluginLevelDepProject.getModel().setParent(createParent(parentProject));
+        projects.add(pluginLevelDepProject);
 
-        MavenProject pluginProject = createProject( "groupId", "plugin", "1.0" );
-        pluginProject.setParent( parentProject );
-        pluginProject.getModel().setParent( createParent( parentProject ) );
-        projects.add( pluginProject );
+        MavenProject pluginProject = createProject("groupId", "plugin", "1.0");
+        pluginProject.setParent(parentProject);
+        pluginProject.getModel().setParent(createParent(parentProject));
+        projects.add(pluginProject);
 
-        Plugin plugin = createPlugin( pluginProject );
+        Plugin plugin = createPlugin(pluginProject);
 
-        plugin.addDependency( createDependency( pluginLevelDepProject ) );
+        plugin.addDependency(createDependency(pluginLevelDepProject));
 
         Build build = declaringProject.getModel().getBuild();
 
-        build.addPlugin( plugin );
+        build.addPlugin(plugin);
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
+        declaringProject.getModel().setBuild(build);
 
-        assertEquals( parentProject, projects.get( 0 ) );
+        projects = new ProjectSorter(projects).getSortedProjects();
+
+        assertEquals(parentProject, projects.get(0));
 
         // the order of these two is non-deterministic, based on when they're added to the reactor.
-        assertThat( projects, hasItem( pluginProject ) );
-        assertThat( projects, hasItem( pluginLevelDepProject ) );
+        assertThat(projects, hasItem(pluginProject));
+        assertThat(projects, hasItem(pluginLevelDepProject));
 
         // the declaring project MUST be listed after the plugin and its plugin-level dep, though.
-        assertEquals( declaringProject, projects.get( 3 ) );
+        assertEquals(declaringProject, projects.get(3));
     }
 
     @Test
-    public void testPluginDependenciesInfluenceSorting_DeclarationInParent()
-        throws Exception
-    {
+    void testPluginDependenciesInfluenceSorting_DeclarationInParent() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
 
-        MavenProject parentProject = createProject( "groupId", "parent-declarer", "1.0" );
-        projects.add( parentProject );
+        MavenProject parentProject = createProject("groupId", "parent-declarer", "1.0");
+        projects.add(parentProject);
 
-        MavenProject pluginProject = createProject( "groupId", "plugin", "1.0" );
-        pluginProject.setParent( parentProject );
-        pluginProject.getModel().setParent( createParent( parentProject ) );
-        projects.add( pluginProject );
+        MavenProject pluginProject = createProject("groupId", "plugin", "1.0");
+        pluginProject.setParent(parentProject);
+        pluginProject.getModel().setParent(createParent(parentProject));
+        projects.add(pluginProject);
 
-        MavenProject pluginLevelDepProject = createProject( "groupId", "plugin-level-dep", "1.0" );
-        pluginLevelDepProject.setParent( parentProject );
-        pluginLevelDepProject.getModel().setParent( createParent( parentProject ) );
-        projects.add( pluginLevelDepProject );
+        MavenProject pluginLevelDepProject = createProject("groupId", "plugin-level-dep", "1.0");
+        pluginLevelDepProject.setParent(parentProject);
+        pluginLevelDepProject.getModel().setParent(createParent(parentProject));
+        projects.add(pluginLevelDepProject);
 
-        Plugin plugin = createPlugin( pluginProject );
+        Plugin plugin = createPlugin(pluginProject);
 
-        plugin.addDependency( createDependency( pluginLevelDepProject ) );
+        plugin.addDependency(createDependency(pluginLevelDepProject));
 
         Build build = parentProject.getModel().getBuild();
 
-        build.addPlugin( plugin );
+        build.addPlugin(plugin);
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
+        projects = new ProjectSorter(projects).getSortedProjects();
 
-        assertEquals( parentProject, projects.get( 0 ) );
+        assertEquals(parentProject, projects.get(0));
 
         // the order of these two is non-deterministic, based on when they're added to the reactor.
-        assertThat( projects, hasItem( pluginProject ) );
-        assertThat( projects, hasItem( pluginLevelDepProject ) );
+        assertThat(projects, hasItem(pluginProject));
+        assertThat(projects, hasItem(pluginLevelDepProject));
     }
 
     @Test
-    public void testPluginVersionsAreConsidered()
-        throws Exception
-    {
+    void testPluginVersionsAreConsidered() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
 
-        MavenProject pluginProjectA = createProject( "group", "plugin-a", "2.0-SNAPSHOT" );
-        projects.add( pluginProjectA );
-        pluginProjectA.getModel().getBuild().addPlugin( createPlugin( "group", "plugin-b", "1.0" ) );
+        MavenProject pluginProjectA = createProject("group", "plugin-a", "2.0-SNAPSHOT");
+        projects.add(pluginProjectA);
+        pluginProjectA.getModel().getBuild().addPlugin(createPlugin("group", "plugin-b", "1.0"));
 
-        MavenProject pluginProjectB = createProject( "group", "plugin-b", "2.0-SNAPSHOT" );
-        projects.add( pluginProjectB );
-        pluginProjectB.getModel().getBuild().addPlugin( createPlugin( "group", "plugin-a", "1.0" ) );
+        MavenProject pluginProjectB = createProject("group", "plugin-b", "2.0-SNAPSHOT");
+        projects.add(pluginProjectB);
+        pluginProjectB.getModel().getBuild().addPlugin(createPlugin("group", "plugin-a", "1.0"));
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
+        projects = new ProjectSorter(projects).getSortedProjects();
 
-        assertThat( projects, hasItem( pluginProjectA ) );
-        assertThat( projects, hasItem( pluginProjectB ) );
+        assertThat(projects, hasItem(pluginProjectA));
+        assertThat(projects, hasItem(pluginProjectB));
     }
 
     @Test
-    public void testDependencyPrecedesProjectThatUsesSpecificDependencyVersion()
-        throws Exception
-    {
+    void testDependencyPrecedesProjectThatUsesSpecificDependencyVersion() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
 
-        MavenProject usingProject = createProject( "group", "project", "1.0" );
-        projects.add( usingProject );
-        usingProject.getModel().addDependency( createDependency( "group", "dependency", "1.0" ) );
+        MavenProject usingProject = createProject("group", "project", "1.0");
+        projects.add(usingProject);
+        usingProject.getModel().addDependency(createDependency("group", "dependency", "1.0"));
 
-        MavenProject pluginProject = createProject( "group", "dependency", "1.0" );
-        projects.add( pluginProject );
+        MavenProject pluginProject = createProject("group", "dependency", "1.0");
+        projects.add(pluginProject);
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
+        projects = new ProjectSorter(projects).getSortedProjects();
 
-        assertEquals( pluginProject, projects.get( 0 ) );
-        assertEquals( usingProject, projects.get( 1 ) );
+        assertEquals(pluginProject, projects.get(0));
+        assertEquals(usingProject, projects.get(1));
     }
 
     @Test
-    public void testDependencyPrecedesProjectThatUsesUnresolvedDependencyVersion()
-        throws Exception
-    {
+    void testDependencyPrecedesProjectThatUsesUnresolvedDependencyVersion() throws Exception {
         List<MavenProject> projects = new ArrayList<>();
 
-        MavenProject usingProject = createProject( "group", "project", "1.0" );
-        projects.add( usingProject );
-        usingProject.getModel().addDependency( createDependency( "group", "dependency", "[1.0,)" ) );
+        MavenProject usingProject = createProject("group", "project", "1.0");
+        projects.add(usingProject);
+        usingProject.getModel().addDependency(createDependency("group", "dependency", "[1.0,)"));
 
-        MavenProject pluginProject = createProject( "group", "dependency", "1.0" );
-        projects.add( pluginProject );
+        MavenProject pluginProject = createProject("group", "dependency", "1.0");
+        projects.add(pluginProject);
 
-        projects = new ProjectSorter( projects ).getSortedProjects();
+        projects = new ProjectSorter(projects).getSortedProjects();
 
-        assertEquals( pluginProject, projects.get( 0 ) );
-        assertEquals( usingProject, projects.get( 1 ) );
+        assertEquals(pluginProject, projects.get(0));
+        assertEquals(usingProject, projects.get(1));
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/TestMetadataSource.java b/maven-core/src/test/java/org/apache/maven/project/TestMetadataSource.java
deleted file mode 100644
index 17fca10..0000000
--- a/maven-core/src/test/java/org/apache/maven/project/TestMetadataSource.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.apache.maven.project;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.factory.ArtifactFactory;
-import org.apache.maven.artifact.metadata.ArtifactMetadataRetrievalException;
-import org.apache.maven.artifact.metadata.ResolutionGroup;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.metadata.RepositoryMetadataManager;
-import org.apache.maven.plugin.LegacySupport;
-import org.apache.maven.project.artifact.MavenMetadataCache;
-import org.apache.maven.project.artifact.MavenMetadataSource;
-
-@SuppressWarnings( "deprecation" )
-@Named( "classpath" )
-@Singleton
-public class TestMetadataSource
-    extends MavenMetadataSource
-{
-
-    public TestMetadataSource( RepositoryMetadataManager repositoryMetadataManager, ArtifactFactory repositorySystem, ProjectBuilder projectBuilder, MavenMetadataCache cache, LegacySupport legacySupport) {
-        super( repositoryMetadataManager, repositorySystem, projectBuilder, cache, legacySupport );
-    }
-
-    @Override
-    public ResolutionGroup retrieve( Artifact artifact, ArtifactRepository localRepository,
-                                     List<ArtifactRepository> remoteRepositories )
-        throws ArtifactMetadataRetrievalException
-    {
-        ResolutionGroup rg = super.retrieve( artifact, localRepository, remoteRepositories );
-
-        for ( Artifact a : rg.getArtifacts() )
-        {
-            a.setResolved( true );
-        }
-
-        return rg;
-    }
-}
diff --git a/maven-core/src/test/java/org/apache/maven/project/artifact/DefaultMavenMetadataCacheTest.java b/maven-core/src/test/java/org/apache/maven/project/artifact/DefaultMavenMetadataCacheTest.java
deleted file mode 100644
index 2d5c1ba..0000000
--- a/maven-core/src/test/java/org/apache/maven/project/artifact/DefaultMavenMetadataCacheTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.resolver.filter.ExcludesArtifactFilter;
-import org.apache.maven.project.artifact.DefaultMavenMetadataCache.CacheKey;
-import org.apache.maven.repository.DelegatingLocalArtifactRepository;
-import org.apache.maven.repository.RepositorySystem;
-import org.apache.maven.repository.TestRepositorySystem;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.BeforeEach;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotSame;
-
-/**
- * @author Igor Fedorenko
- */
-public class DefaultMavenMetadataCacheTest
-{
-    private RepositorySystem repositorySystem;
-
-    @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        repositorySystem = new TestRepositorySystem( null, null );
-    }
-
-    @AfterEach
-    public void tearDown()
-        throws Exception
-    {
-        repositorySystem = null;
-    }
-
-    @Test
-    public void testCacheKey()
-        throws Exception
-    {
-        Artifact a1 = repositorySystem.createArtifact( "testGroup", "testArtifact", "1.2.3", "jar" );
-        @SuppressWarnings( "deprecation" )
-        ArtifactRepository lr1 = new DelegatingLocalArtifactRepository( repositorySystem.createDefaultLocalRepository() );
-        ArtifactRepository rr1 = repositorySystem.createDefaultRemoteRepository();
-        a1.setDependencyFilter( new ExcludesArtifactFilter( Arrays.asList( "foo" ) ) );
-
-        Artifact a2 = repositorySystem.createArtifact( "testGroup", "testArtifact", "1.2.3", "jar" );
-        @SuppressWarnings( "deprecation" )
-        ArtifactRepository lr2 = new DelegatingLocalArtifactRepository( repositorySystem.createDefaultLocalRepository() );
-        ArtifactRepository rr2 = repositorySystem.createDefaultRemoteRepository();
-        a2.setDependencyFilter( new ExcludesArtifactFilter( Arrays.asList( "foo" ) ) );
-
-        // sanity checks
-        assertNotSame( a1, a2 );
-        assertNotSame( lr1, lr2 );
-        assertNotSame( rr1, rr2 );
-
-        CacheKey k1 = new CacheKey( a1, false, lr1, Collections.singletonList( rr1 ) );
-        CacheKey k2 = new CacheKey( a2, false, lr2, Collections.singletonList( rr2 ) );
-
-        assertEquals(k1.hashCode(), k2.hashCode());
-    }
-}
diff --git a/maven-core/src/test/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCacheTest.java b/maven-core/src/test/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCacheTest.java
index 16317ff..575d106 100644
--- a/maven-core/src/test/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCacheTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/artifact/DefaultProjectArtifactsCacheTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.artifact;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.artifact;
 
 import java.util.LinkedHashSet;
 import java.util.Set;
@@ -28,45 +27,44 @@
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-public class DefaultProjectArtifactsCacheTest
-{
+
+class DefaultProjectArtifactsCacheTest {
 
     private ProjectArtifactsCache cache;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
+    void setUp() throws Exception {
         cache = new DefaultProjectArtifactsCache();
     }
 
     @Test
-    public void testProjectDependencyOrder() throws Exception
-    {
-        ProjectArtifactsCache.Key project1 = new ProjectArtifactsCache.Key(){};
+    void testProjectDependencyOrder() throws Exception {
+        ProjectArtifactsCache.Key project1 = new ProjectArtifactsCache.Key() {};
 
-        Set<Artifact> artifacts = new LinkedHashSet<>( 4 );
-        artifacts.add( new DefaultArtifact( "g", "a1", "v", "compile", "jar", "", null ) );
-        artifacts.add( new DefaultArtifact( "g", "a2", "v", "compile", "jar", "", null ) );
-        artifacts.add( new DefaultArtifact( "g", "a3", "v", "compile", "jar", "", null ) );
-        artifacts.add( new DefaultArtifact( "g", "a4", "v", "compile", "jar", "", null ) );
+        Set<Artifact> artifacts = new LinkedHashSet<>(4);
+        artifacts.add(new DefaultArtifact("g", "a1", "v", "compile", "jar", "", null));
+        artifacts.add(new DefaultArtifact("g", "a2", "v", "compile", "jar", "", null));
+        artifacts.add(new DefaultArtifact("g", "a3", "v", "compile", "jar", "", null));
+        artifacts.add(new DefaultArtifact("g", "a4", "v", "compile", "jar", "", null));
 
-        cache.put( project1, artifacts );
+        cache.put(project1, artifacts);
 
-        assertArrayEquals( artifacts.toArray( new Artifact[0] ),
-                           cache.get( project1 ).getArtifacts().toArray( new Artifact[0] ) );
+        assertArrayEquals(
+                artifacts.toArray(new Artifact[0]),
+                cache.get(project1).getArtifacts().toArray(new Artifact[0]));
 
-        ProjectArtifactsCache.Key project2 = new ProjectArtifactsCache.Key(){};
+        ProjectArtifactsCache.Key project2 = new ProjectArtifactsCache.Key() {};
 
-        Set<Artifact> reversedArtifacts = new LinkedHashSet<>( 4 );
-        artifacts.add( new DefaultArtifact( "g", "a4", "v", "compile", "jar", "", null ) );
-        artifacts.add( new DefaultArtifact( "g", "a3", "v", "compile", "jar", "", null ) );
-        artifacts.add( new DefaultArtifact( "g", "a2", "v", "compile", "jar", "", null ) );
-        artifacts.add( new DefaultArtifact( "g", "a1", "v", "compile", "jar", "", null ) );
+        Set<Artifact> reversedArtifacts = new LinkedHashSet<>(4);
+        artifacts.add(new DefaultArtifact("g", "a4", "v", "compile", "jar", "", null));
+        artifacts.add(new DefaultArtifact("g", "a3", "v", "compile", "jar", "", null));
+        artifacts.add(new DefaultArtifact("g", "a2", "v", "compile", "jar", "", null));
+        artifacts.add(new DefaultArtifact("g", "a1", "v", "compile", "jar", "", null));
 
-        cache.put( project2, reversedArtifacts );
+        cache.put(project2, reversedArtifacts);
 
-        assertArrayEquals( reversedArtifacts.toArray( new Artifact[0] ),
-                           cache.get( project2 ).getArtifacts().toArray( new Artifact[0] ) );
+        assertArrayEquals(
+                reversedArtifacts.toArray(new Artifact[0]),
+                cache.get(project2).getArtifacts().toArray(new Artifact[0]));
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/artifact/MavenMetadataSourceTest.java b/maven-core/src/test/java/org/apache/maven/project/artifact/MavenMetadataSourceTest.java
deleted file mode 100644
index 7d5150d..0000000
--- a/maven-core/src/test/java/org/apache/maven/project/artifact/MavenMetadataSourceTest.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package org.apache.maven.project.artifact;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import javax.inject.Inject;
-
-import org.apache.maven.repository.RepositorySystem;
-import org.codehaus.plexus.testing.PlexusTest;
-import org.codehaus.plexus.PlexusContainer;
-import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
-
-@PlexusTest
-public class MavenMetadataSourceTest
-{
-    @Inject
-    private RepositorySystem repositorySystem;
-
-    @Inject
-    PlexusContainer container;
-
-    @Test
-    @Disabled
-    public void testShouldNotCarryExclusionsOverFromDependencyToDependency()
-        throws Exception
-    {
-        /*
-        Dependency dep1 = new Dependency();
-        dep1.setGroupId( "test" );
-        dep1.setArtifactId( "test-artifact" );
-        dep1.setVersion( "1" );
-        dep1.setType( "jar" );
-
-        Exclusion exc = new Exclusion();
-        exc.setGroupId( "test" );
-        exc.setArtifactId( "test-artifact3" );
-
-        dep1.addExclusion( exc );
-
-        Dependency dep2 = new Dependency();
-        dep2.setGroupId( "test" );
-        dep2.setArtifactId( "test-artifact2" );
-        dep2.setVersion( "1" );
-        dep2.setType( "jar" );
-
-        List<Dependency> deps = new ArrayList<>();
-        deps.add( dep1 );
-        deps.add( dep2 );
-
-        ArtifactFactory factory = container.lookup( ArtifactFactory.class );
-
-        ArtifactFilter dependencyFilter = new ScopeArtifactFilter( Artifact.SCOPE_COMPILE );
-
-        MavenProject project = new MavenProject( new Model() );
-
-        Set<Artifact> result = project.createArtifacts( dependencyFilter );
-
-        for (Iterator<Artifact> it = result.iterator(); it.hasNext(); )
-        {
-            Artifact artifact = it.next();
-
-            if ( "test-artifact2".equals( artifact.getArtifactId() ) )
-            {
-                ArtifactFilter filter = artifact.getDependencyFilter();
-
-                assertSame( dependencyFilter, filter );
-            }
-        }
-        */
-    }
-
-    @Test
-    @Disabled("TODO restore these if it makes sense")
-    public void testShouldUseCompileScopeIfDependencyScopeEmpty()
-        throws Exception
-    {
-        /*
-        String groupId = "org.apache.maven";
-        String artifactId = "maven-model";
-
-        Dependency dep = new Dependency();
-
-        dep.setGroupId( groupId );
-        dep.setArtifactId( artifactId );
-        dep.setVersion( "2.0-alpha-3" );
-
-        Model model = new Model();
-
-        model.addDependency( dep );
-
-        MavenProject project = new MavenProject( model, repositorySystem );
-
-        project.setArtifacts( project.createArtifacts( null ) );
-
-        String key = ArtifactUtils.versionlessKey( groupId, artifactId );
-
-        Map artifactMap = project.getArtifactMap();
-
-        assertNotNull( artifactMap, "artifact-map should not be null." );
-        assertEquals( 1, artifactMap.size(), "artifact-map should contain 1 element." );
-
-        Artifact artifact = (Artifact) artifactMap.get( key );
-
-        assertNotNull( artifact, "dependency artifact not found in map." );
-        assertEquals( Artifact.SCOPE_COMPILE, artifact.getScope(), "dependency artifact has wrong scope." );
-
-        //check for back-propagation of default scope.
-        assertEquals( Artifact.SCOPE_COMPILE, dep.getScope(), "default scope NOT back-propagated to dependency." );
-        */
-    }
-
-    @Test
-    @Disabled
-    public void testShouldUseInjectedTestScopeFromDependencyManagement()
-        throws Exception
-    {
-        /*
-        String groupId = "org.apache.maven";
-        String artifactId = "maven-model";
-
-        Dependency dep = new Dependency();
-
-        dep.setGroupId( groupId );
-        dep.setArtifactId( artifactId );
-        dep.setVersion( "2.0-alpha-3" );
-
-        Model model = new Model();
-
-        model.addDependency( dep );
-
-        Dependency mgd = new Dependency();
-        mgd.setGroupId( groupId );
-        mgd.setArtifactId( artifactId );
-        mgd.setScope( Artifact.SCOPE_TEST );
-
-        DependencyManagement depMgmt = new DependencyManagement();
-
-        depMgmt.addDependency( mgd );
-
-        model.setDependencyManagement( depMgmt );
-
-        MavenProject project = new MavenProject( model, repositorySystem );
-
-        TestModelDefaultsInjector injector = new TestModelDefaultsInjector();
-
-        injector.injectDefaults( model );
-
-        project.setArtifacts( project.createArtifacts( null ) );
-
-        String key = ArtifactUtils.versionlessKey( groupId, artifactId );
-
-        Map artifactMap = project.getArtifactMap();
-
-        assertNotNull( artifactMap, "artifact-map should not be null." );
-        assertEquals( 1, artifactMap.size(), "artifact-map should contain 1 element." );
-
-        Artifact artifact = (Artifact) artifactMap.get( key );
-
-        assertNotNull( artifact, "dependency artifact not found in map." );
-        assertEquals( "dependency artifact has wrong scope.", Artifact.SCOPE_TEST, artifact.getScope() );
-
-        //check for back-propagation of default scope.
-        assertEquals( "default scope NOT back-propagated to dependency.", Artifact.SCOPE_TEST, dep.getScope() );
-        */
-    }
-
-}
diff --git a/maven-core/src/test/java/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.java b/maven-core/src/test/java/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.java
index f966237..9cae373 100644
--- a/maven-core/src/test/java/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.java
+++ b/maven-core/src/test/java/org/apache/maven/project/canonical/CanonicalProjectBuilderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.canonical;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,39 +16,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.canonical;
 
 import java.io.File;
 import java.util.List;
 
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginExecution;
 import org.apache.maven.project.AbstractMavenProjectTestCase;
 import org.apache.maven.project.MavenProject;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
- * @author Jason van Zyl
  */
-public class CanonicalProjectBuilderTest
-    extends AbstractMavenProjectTestCase
-{
+class CanonicalProjectBuilderTest extends AbstractMavenProjectTestCase {
     @Test
-    public void testProjectBuilder()
-        throws Exception
-    {
-        File f = getFileForClasspathResource( "canonical-pom.xml" );
+    void testProjectBuilder() throws Exception {
+        File f = getFileForClasspathResource("canonical-pom.xml");
 
-        MavenProject project = getProject( f );
+        MavenProject project = getProject(f);
 
         // ----------------------------------------------------------------------
         // Top-level elements
         // ----------------------------------------------------------------------
 
-        assertEquals( "4.0.0", project.getModelVersion() );
+        assertEquals("4.0.0", project.getModelVersion());
 
         // ----------------------------------------------------------------------
         // Plugins
@@ -63,27 +57,29 @@
         String key = "org.apache.maven.plugins:maven-plexus-plugin";
 
         Plugin plugin = null;
-        for ( Plugin check : plugins )
-        {
-            if ( key.equals( check.getKey() ) )
-            {
+        for (Plugin check : plugins) {
+            if (key.equals(check.getKey())) {
                 plugin = check;
                 break;
             }
         }
 
-        assertNotNull( plugin );
+        assertNotNull(plugin);
 
-        assertEquals( "1.0", plugin.getVersion() );
+        assertEquals("1.0", plugin.getVersion());
 
-        Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
+        XmlNode configuration = plugin.getDelegate().getConfiguration();
 
-        assertEquals( "src/conf/plexus.conf", configuration.getChild( "plexusConfiguration" ).getValue() );
+        assertEquals(
+                "src/conf/plexus.conf",
+                configuration.getChild("plexusConfiguration").getValue());
 
-        assertEquals( "src/conf/plexus.properties",
-                      configuration.getChild( "plexusConfigurationPropertiesFile" ).getValue() );
+        assertEquals(
+                "src/conf/plexus.properties",
+                configuration.getChild("plexusConfigurationPropertiesFile").getValue());
 
-        assertEquals( "Continuum", configuration.getChild( "plexusApplicationName" ).getValue() );
+        assertEquals(
+                "Continuum", configuration.getChild("plexusApplicationName").getValue());
 
         // ----------------------------------------------------------------------
         // Goal specific configuration
@@ -91,15 +87,16 @@
 
         List<PluginExecution> executions = plugin.getExecutions();
 
-        PluginExecution execution = executions.get( 0 );
+        PluginExecution execution = executions.get(0);
 
-        String g0 = execution.getGoals().get( 0 );
+        String g0 = execution.getGoals().get(0);
 
-        assertEquals( "plexus:runtime", g0 );
+        assertEquals("plexus:runtime", g0);
 
-        configuration = (Xpp3Dom) execution.getConfiguration();
+        configuration = execution.getDelegate().getConfiguration();
 
-        assertEquals( "ContinuumPro", configuration.getChild( "plexusApplicationName" ).getValue() );
+        assertEquals(
+                "ContinuumPro", configuration.getChild("plexusApplicationName").getValue());
 
         // Plugin1 [antlr]
     }
diff --git a/maven-core/src/test/java/org/apache/maven/project/harness/PomTestWrapper.java b/maven-core/src/test/java/org/apache/maven/project/harness/PomTestWrapper.java
index aa203e9..e34071a 100644
--- a/maven-core/src/test/java/org/apache/maven/project/harness/PomTestWrapper.java
+++ b/maven-core/src/test/java/org/apache/maven/project/harness/PomTestWrapper.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.harness;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.harness;
 
 import java.io.File;
 import java.util.Iterator;
@@ -28,8 +27,7 @@
 import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl;
 import org.apache.maven.project.MavenProject;
 
-public class PomTestWrapper
-{
+public class PomTestWrapper {
 
     private File pomFile;
 
@@ -37,37 +35,31 @@
 
     private MavenProject mavenProject;
 
-    static
-    {
-        JXPathContextReferenceImpl.addNodePointerFactory( new Xpp3DomPointerFactory() );
+    static {
+        JXPathContextReferenceImpl.addNodePointerFactory(new Xpp3DomPointerFactory());
     }
 
-    public PomTestWrapper( File pomFile, MavenProject mavenProject )
-    {
-        this.mavenProject = Objects.requireNonNull( mavenProject, "mavenProject cannot be null" );
+    public PomTestWrapper(File pomFile, MavenProject mavenProject) {
+        this.mavenProject = Objects.requireNonNull(mavenProject, "mavenProject cannot be null");
         this.pomFile = pomFile;
-        context = JXPathContext.newContext( mavenProject.getModel() );
+        context = JXPathContext.newContext(mavenProject.getModel());
     }
 
-    public PomTestWrapper( MavenProject mavenProject )
-    {
-        this.mavenProject = Objects.requireNonNull( mavenProject, "mavenProject cannot be null" );
-        context = JXPathContext.newContext( mavenProject.getModel() );
+    public PomTestWrapper(MavenProject mavenProject) {
+        this.mavenProject = Objects.requireNonNull(mavenProject, "mavenProject cannot be null");
+        context = JXPathContext.newContext(mavenProject.getModel());
     }
 
-    public MavenProject getMavenProject()
-    {
+    public MavenProject getMavenProject() {
         return mavenProject;
     }
 
-    public File getBasedir()
-    {
-        return ( pomFile != null ) ? pomFile.getParentFile() : null;
+    public File getBasedir() {
+        return (pomFile != null) ? pomFile.getParentFile() : null;
     }
 
-    public void setValueOnModel( String expression, Object value )
-    {
-        context.setValue( expression, value );
+    public void setValueOnModel(String expression, Object value) {
+        context.setValue(expression, value);
     }
 
     /*
@@ -81,31 +73,24 @@
     }
     */
 
-    public Iterator<?> getIteratorForXPathExpression( String expression )
-    {
-        return context.iterate( expression );
+    public Iterator<?> getIteratorForXPathExpression(String expression) {
+        return context.iterate(expression);
     }
 
-    public boolean containsXPathExpression( String expression )
-    {
-        return context.getValue( expression ) != null;
+    public boolean containsXPathExpression(String expression) {
+        return context.getValue(expression) != null;
     }
 
-    public Object getValue( String expression )
-    {
-        try
-        {
-            return context.getValue( expression );
-        }
-        catch ( JXPathNotFoundException e )
-        {
+    public Object getValue(String expression) {
+        try {
+            return context.getValue(expression);
+        } catch (JXPathNotFoundException e) {
             return null;
         }
     }
 
-    public boolean xPathExpressionEqualsValue( String expression, String value )
-    {
-        return context.getValue( expression ) != null && context.getValue( expression ).equals( value );
+    public boolean xPathExpressionEqualsValue(String expression, String value) {
+        return context.getValue(expression) != null
+                && context.getValue(expression).equals(value);
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributeIterator.java b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributeIterator.java
index 9b204b2..7349b65 100644
--- a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributeIterator.java
+++ b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributeIterator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.harness;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,29 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.harness;
 
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.apache.commons.jxpath.ri.QName;
 import org.apache.commons.jxpath.ri.model.NodeIterator;
 import org.apache.commons.jxpath.ri.model.NodePointer;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.apache.maven.internal.xml.XmlNodeImpl;
 
 /**
  * An attribute iterator for JXPath to support <code>Xpp3Dom</code>.
  *
- * @author Benjamin Bentmann
  */
-class Xpp3DomAttributeIterator
-    implements NodeIterator
-{
+class Xpp3DomAttributeIterator implements NodeIterator {
 
     private NodePointer parent;
 
-    private Xpp3Dom node;
+    private XmlNodeImpl node;
 
     private List<Map.Entry<String, String>> attributes;
 
@@ -48,42 +43,29 @@
 
     private int position;
 
-    public Xpp3DomAttributeIterator( NodePointer parent, QName qname )
-    {
+    public Xpp3DomAttributeIterator(NodePointer parent, QName qname) {
         this.parent = parent;
-        this.node = (Xpp3Dom) parent.getNode();
+        this.node = (XmlNodeImpl) parent.getNode();
 
-        Map<String, String> map = new LinkedHashMap<>();
-        for ( String name : this.node.getAttributeNames() )
-        {
-            if ( name.equals( qname.getName() ) || "*".equals( qname.getName() ) )
-            {
-                String value = this.node.getAttribute( name );
-                map.put( name, value );
-            }
-        }
-        this.attributes = new ArrayList<>( map.entrySet() );
+        this.attributes = this.node.getAttributes().entrySet().stream()
+                .filter(a -> a.getKey().equals(qname.getName()) || "*".equals(qname.getName()))
+                .collect(Collectors.toList());
     }
 
-    public NodePointer getNodePointer()
-    {
-        if ( position == 0 )
-        {
-            setPosition( 1 );
+    public NodePointer getNodePointer() {
+        if (position == 0) {
+            setPosition(1);
         }
-        return ( attribute == null ) ? null : new Xpp3DomAttributePointer( parent, attribute );
+        return (attribute == null) ? null : new Xpp3DomAttributePointer(parent, attribute);
     }
 
-    public int getPosition()
-    {
+    public int getPosition() {
         return position;
     }
 
-    public boolean setPosition( int position )
-    {
+    public boolean setPosition(int position) {
         this.position = position;
-        attribute = ( position > 0 && position <= attributes.size() ) ? attributes.get( position - 1 ) : null;
+        attribute = (position > 0 && position <= attributes.size()) ? attributes.get(position - 1) : null;
         return attribute != null;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributePointer.java b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributePointer.java
index 04514b1..e61a8e2 100644
--- a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributePointer.java
+++ b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomAttributePointer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.harness;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.harness;
 
 import java.util.Map;
 
@@ -27,79 +26,64 @@
 /**
  * An attribute pointer for JXPath to support <code>Xpp3Dom</code>.
  *
- * @author Benjamin Bentmann
  */
-class Xpp3DomAttributePointer
-    extends NodePointer
-{
+class Xpp3DomAttributePointer extends NodePointer {
 
     private Map.Entry<String, String> attrib;
 
-    public Xpp3DomAttributePointer( NodePointer parent, Map.Entry<String, String> attrib )
-    {
-        super( parent );
+    public Xpp3DomAttributePointer(NodePointer parent, Map.Entry<String, String> attrib) {
+        super(parent);
         this.attrib = attrib;
     }
 
     @Override
-    public int compareChildNodePointers( NodePointer pointer1, NodePointer pointer2 )
-    {
+    public int compareChildNodePointers(NodePointer pointer1, NodePointer pointer2) {
         // should never happen because attributes have no children
         return 0;
     }
 
     @Override
-    public Object getValue()
-    {
+    public Object getValue() {
         return attrib.getValue();
     }
 
     @Override
-    public Object getBaseValue()
-    {
+    public Object getBaseValue() {
         return attrib;
     }
 
     @Override
-    public Object getImmediateNode()
-    {
+    public Object getImmediateNode() {
         return attrib;
     }
 
     @Override
-    public int getLength()
-    {
+    public int getLength() {
         return 1;
     }
 
     @Override
-    public QName getName()
-    {
-        return new QName( null, attrib.getKey() );
+    public QName getName() {
+        return new QName(null, attrib.getKey());
     }
 
     @Override
-    public boolean isActual()
-    {
+    public boolean isActual() {
         return true;
     }
 
     @Override
-    public boolean isCollection()
-    {
+    public boolean isCollection() {
         return false;
     }
 
     @Override
-    public boolean isLeaf()
-    {
+    public boolean isLeaf() {
         return true;
     }
 
     @Override
-    public void setValue( Object value )
-    {
+    public void setValue(Object value) {
         throw new UnsupportedOperationException();
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodeIterator.java b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodeIterator.java
index d137af5..3f506a3 100644
--- a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodeIterator.java
+++ b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodeIterator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.harness;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.harness;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -28,103 +27,84 @@
 import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
 import org.apache.commons.jxpath.ri.model.NodeIterator;
 import org.apache.commons.jxpath.ri.model.NodePointer;
-import org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.api.xml.XmlNode;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * A node iterator for JXPath to support <code>Xpp3Dom</code>.
  *
- * @author Benjamin Bentmann
  */
-class Xpp3DomNodeIterator
-    implements NodeIterator
-{
+class Xpp3DomNodeIterator implements NodeIterator {
 
     private NodePointer parent;
 
     private NodeTest test;
 
-    private Xpp3Dom node;
+    private XmlNode node;
 
-    private Xpp3Dom[] children;
+    private List<XmlNode> children;
 
-    private List<Xpp3Dom> filteredChildren = new ArrayList<>();
+    private List<XmlNode> filteredChildren = new ArrayList<>();
 
     private int filteredIndex;
 
-    private Xpp3Dom child;
+    private XmlNode child;
 
     private int position;
 
-    public Xpp3DomNodeIterator( NodePointer parent, NodeTest test, boolean reverse, NodePointer startWith )
-    {
+    public Xpp3DomNodeIterator(NodePointer parent, NodeTest test, boolean reverse, NodePointer startWith) {
         this.parent = parent;
-        this.node = (Xpp3Dom) parent.getNode();
+        this.node = (XmlNode) parent.getNode();
         this.children = this.node.getChildren();
-        if ( startWith != null )
-        {
+        if (startWith != null) {
             Xpp3Dom startWithNode = (Xpp3Dom) startWith.getNode();
-            for ( ; filteredIndex < children.length; filteredIndex++ )
-            {
-                if ( startWithNode.equals( children[filteredIndex] ) )
-                {
+            for (; filteredIndex < children.size(); filteredIndex++) {
+                if (startWithNode.equals(children.get(filteredIndex))) {
                     filteredIndex++;
                     break;
                 }
             }
         }
         this.test = test;
-        if ( reverse )
-        {
+        if (reverse) {
             throw new UnsupportedOperationException();
         }
     }
 
-    public NodePointer getNodePointer()
-    {
-        if ( position == 0 )
-        {
-            setPosition( 1 );
+    public NodePointer getNodePointer() {
+        if (position == 0) {
+            setPosition(1);
         }
-        return ( child == null ) ? null : new Xpp3DomNodePointer( parent, child );
+        return (child == null) ? null : new Xpp3DomNodePointer(parent, child);
     }
 
-    public int getPosition()
-    {
+    public int getPosition() {
         return position;
     }
 
-    public boolean setPosition( int position )
-    {
+    public boolean setPosition(int position) {
         this.position = position;
-        filterChildren( position );
-        child = ( position > 0 && position <= filteredChildren.size() ) ? filteredChildren.get( position - 1 ) : null;
+        filterChildren(position);
+        child = (position > 0 && position <= filteredChildren.size()) ? filteredChildren.get(position - 1) : null;
         return child != null;
     }
 
-    private void filterChildren( int position )
-    {
-        for ( ; position > filteredChildren.size() && filteredIndex < children.length; filteredIndex++ )
-        {
-            Xpp3Dom child = children[filteredIndex];
-            if ( testNode( child ) )
-            {
-                filteredChildren.add( child );
+    private void filterChildren(int position) {
+        for (; position > filteredChildren.size() && filteredIndex < children.size(); filteredIndex++) {
+            XmlNode child = children.get(filteredIndex);
+            if (testNode(child)) {
+                filteredChildren.add(child);
             }
         }
     }
 
-    private boolean testNode( Xpp3Dom node )
-    {
-        if ( test == null )
-        {
+    private boolean testNode(XmlNode node) {
+        if (test == null) {
             return true;
         }
-        if ( test instanceof NodeNameTest )
-        {
+        if (test instanceof NodeNameTest) {
             String nodeName = node.getName();
-            if ( StringUtils.isEmpty( nodeName ) )
-            {
+            if (nodeName == null || nodeName.isEmpty()) {
                 return false;
             }
 
@@ -133,20 +113,16 @@
             boolean wildcard = nodeNameTest.isWildcard();
             String testName = nodeNameTest.getNodeName().getName();
             String testPrefix = nodeNameTest.getNodeName().getPrefix();
-            if ( wildcard && testPrefix == null )
-            {
+            if (wildcard && testPrefix == null) {
                 return true;
             }
-            if ( wildcard || testName.equals( nodeName ) )
-            {
-                return StringUtils.isEmpty( namespaceURI ) || StringUtils.isEmpty( testPrefix );
+            if (wildcard || testName.equals(nodeName)) {
+                return (namespaceURI == null || namespaceURI.isEmpty()) || (testPrefix == null || testPrefix.isEmpty());
             }
             return false;
         }
-        if ( test instanceof NodeTypeTest )
-        {
-            switch ( ( (NodeTypeTest) test ).getNodeType() )
-            {
+        if (test instanceof NodeTypeTest) {
+            switch (((NodeTypeTest) test).getNodeType()) {
                 case Compiler.NODE_TYPE_NODE:
                     return true;
                 case Compiler.NODE_TYPE_TEXT:
@@ -157,5 +133,4 @@
         }
         return false;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodePointer.java b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodePointer.java
index 19defa1..89d14c6 100644
--- a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodePointer.java
+++ b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomNodePointer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.harness;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.harness;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -26,49 +25,38 @@
 import org.apache.commons.jxpath.ri.compiler.NodeTest;
 import org.apache.commons.jxpath.ri.model.NodeIterator;
 import org.apache.commons.jxpath.ri.model.NodePointer;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.apache.maven.api.xml.XmlNode;
 
 /**
  * A node pointer for JXPath to support <code>Xpp3Dom</code>.
  *
- * @author Benjamin Bentmann
  */
-class Xpp3DomNodePointer
-    extends NodePointer
-{
+class Xpp3DomNodePointer extends NodePointer {
 
-    private Xpp3Dom node;
+    private XmlNode node;
 
-    public Xpp3DomNodePointer( Xpp3Dom node )
-    {
-        super( null );
+    public Xpp3DomNodePointer(XmlNode node) {
+        super(null);
         this.node = node;
     }
 
-    public Xpp3DomNodePointer( NodePointer parent, Xpp3Dom node )
-    {
-        super( parent );
+    public Xpp3DomNodePointer(NodePointer parent, XmlNode node) {
+        super(parent);
         this.node = node;
     }
 
     @Override
-    public int compareChildNodePointers( NodePointer pointer1, NodePointer pointer2 )
-    {
-        Xpp3Dom node1 = (Xpp3Dom) pointer1.getBaseValue();
-        Xpp3Dom node2 = (Xpp3Dom) pointer2.getBaseValue();
-        if ( node1 == node2 )
-        {
+    public int compareChildNodePointers(NodePointer pointer1, NodePointer pointer2) {
+        XmlNode node1 = (XmlNode) pointer1.getBaseValue();
+        XmlNode node2 = (XmlNode) pointer2.getBaseValue();
+        if (node1 == node2) {
             return 0;
         }
-        for ( int i = 0; i < node.getChildCount(); i++ )
-        {
-            Xpp3Dom child = node.getChild( i );
-            if ( child == node1 )
-            {
+        for (XmlNode child : node.getChildren()) {
+            if (child == node1) {
                 return -1;
             }
-            if ( child == node2 )
-            {
+            if (child == node2) {
                 return 1;
             }
         }
@@ -76,80 +64,64 @@
     }
 
     @Override
-    public Object getValue()
-    {
-        return getValue( node );
+    public Object getValue() {
+        return getValue(node);
     }
 
-    private static Object getValue( Xpp3Dom node )
-    {
-        if ( node.getValue() != null )
-        {
+    private static Object getValue(XmlNode node) {
+        if (node.getValue() != null) {
             return node.getValue();
-        }
-        else
-        {
+        } else {
             List<Object> children = new ArrayList<>();
-            for ( int i = 0; i < node.getChildCount(); i++ )
-            {
-                children.add( getValue( node.getChild( i ) ) );
+            for (XmlNode child : node.getChildren()) {
+                children.add(getValue(child));
             }
             return children;
         }
     }
 
     @Override
-    public Object getBaseValue()
-    {
+    public Object getBaseValue() {
         return node;
     }
 
     @Override
-    public Object getImmediateNode()
-    {
+    public Object getImmediateNode() {
         return node;
     }
 
     @Override
-    public int getLength()
-    {
+    public int getLength() {
         return 1;
     }
 
     @Override
-    public QName getName()
-    {
-        return new QName( null, node.getName() );
+    public QName getName() {
+        return new QName(null, node.getName());
     }
 
     @Override
-    public boolean isCollection()
-    {
+    public boolean isCollection() {
         return false;
     }
 
     @Override
-    public boolean isLeaf()
-    {
-        return node.getChildCount() <= 0;
+    public boolean isLeaf() {
+        return node.getChildren().isEmpty();
     }
 
     @Override
-    public void setValue( Object value )
-    {
+    public void setValue(Object value) {
         throw new UnsupportedOperationException();
     }
 
     @Override
-    public NodeIterator childIterator( NodeTest test, boolean reverse, NodePointer startWith )
-    {
-        return new Xpp3DomNodeIterator( this, test, reverse, startWith );
+    public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith) {
+        return new Xpp3DomNodeIterator(this, test, reverse, startWith);
     }
 
     @Override
-    public NodeIterator attributeIterator( QName qname )
-    {
-        return new Xpp3DomAttributeIterator( this, qname );
+    public NodeIterator attributeIterator(QName qname) {
+        return new Xpp3DomAttributeIterator(this, qname);
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomPointerFactory.java b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomPointerFactory.java
index 28c0f8f..536fd0b 100644
--- a/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomPointerFactory.java
+++ b/maven-core/src/test/java/org/apache/maven/project/harness/Xpp3DomPointerFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.project.harness;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,44 +16,42 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.project.harness;
 
 import java.util.Locale;
 
 import org.apache.commons.jxpath.ri.QName;
 import org.apache.commons.jxpath.ri.model.NodePointer;
 import org.apache.commons.jxpath.ri.model.NodePointerFactory;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.apache.maven.api.xml.XmlNode;
 
 /**
  * A node pointer factory for JXPath to support <code>Xpp3Dom</code>.
  *
- * @author Benjamin Bentmann
  */
-public class Xpp3DomPointerFactory
-    implements NodePointerFactory
-{
+public class Xpp3DomPointerFactory implements NodePointerFactory {
 
-    public int getOrder()
-    {
+    public int getOrder() {
         return 200;
     }
 
-    public NodePointer createNodePointer( QName name, Object object, Locale locale )
-    {
-        if ( object instanceof Xpp3Dom )
-        {
-            return new Xpp3DomNodePointer( (Xpp3Dom) object );
+    public NodePointer createNodePointer(QName name, Object object, Locale locale) {
+        if (object instanceof org.codehaus.plexus.util.xml.Xpp3Dom) {
+            object = ((org.codehaus.plexus.util.xml.Xpp3Dom) object).getDom();
+        }
+        if (object instanceof XmlNode) {
+            return new Xpp3DomNodePointer((XmlNode) object);
         }
         return null;
     }
 
-    public NodePointer createNodePointer( NodePointer parent, QName name, Object object )
-    {
-        if ( object instanceof Xpp3Dom )
-        {
-            return new Xpp3DomNodePointer( parent, (Xpp3Dom) object );
+    public NodePointer createNodePointer(NodePointer parent, QName name, Object object) {
+        if (object instanceof org.codehaus.plexus.util.xml.Xpp3Dom) {
+            object = ((org.codehaus.plexus.util.xml.Xpp3Dom) object).getDom();
+        }
+        if (object instanceof XmlNode) {
+            return new Xpp3DomNodePointer(parent, (XmlNode) object);
         }
         return null;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/repository/TestArtifactHandler.java b/maven-core/src/test/java/org/apache/maven/repository/TestArtifactHandler.java
deleted file mode 100644
index db1fecb..0000000
--- a/maven-core/src/test/java/org/apache/maven/repository/TestArtifactHandler.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.artifact.handler.ArtifactHandler;
-
-/**
- * Assists unit testing.
- *
- * @author Benjamin Bentmann
- */
-class TestArtifactHandler
-    implements ArtifactHandler
-{
-
-    private String type;
-
-    private String extension;
-
-    public TestArtifactHandler( String type )
-    {
-        this( type, type );
-    }
-
-    public TestArtifactHandler( String type, String extension )
-    {
-        this.type = type;
-        this.extension = extension;
-    }
-
-    public String getClassifier()
-    {
-        return null;
-    }
-
-    public String getDirectory()
-    {
-        return getPackaging() + "s";
-    }
-
-    public String getExtension()
-    {
-        return extension;
-    }
-
-    public String getLanguage()
-    {
-        return "java";
-    }
-
-    public String getPackaging()
-    {
-        return type;
-    }
-
-    public boolean isAddedToClasspath()
-    {
-        return true;
-    }
-
-    public boolean isIncludesDependencies()
-    {
-        return false;
-    }
-
-}
diff --git a/maven-core/src/test/java/org/apache/maven/repository/TestMavenRepositorySystem.java b/maven-core/src/test/java/org/apache/maven/repository/TestMavenRepositorySystem.java
new file mode 100644
index 0000000..1f1e33e
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/repository/TestMavenRepositorySystem.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.repository;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager;
+import org.apache.maven.artifact.repository.ArtifactRepository;
+import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
+import org.apache.maven.artifact.repository.MavenArtifactRepository;
+import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
+import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.bridge.MavenRepositorySystem;
+
+@Named
+@Priority(10)
+@Singleton
+public class TestMavenRepositorySystem extends MavenRepositorySystem {
+
+    @Inject
+    public TestMavenRepositorySystem(
+            ArtifactHandlerManager artifactHandlerManager, Map<String, ArtifactRepositoryLayout> layouts) {
+        super(artifactHandlerManager, layouts);
+    }
+
+    @Override
+    public ArtifactRepository createDefaultRemoteRepository() throws Exception {
+        return new MavenArtifactRepository(
+                DEFAULT_REMOTE_REPO_ID,
+                "file://"
+                        + new File(System.getProperty("basedir", "."), "src/test/remote-repo")
+                                .getAbsoluteFile()
+                                .toURI()
+                                .getPath(),
+                new DefaultRepositoryLayout(),
+                new ArtifactRepositoryPolicy(),
+                new ArtifactRepositoryPolicy());
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnector.java b/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnector.java
index cb1243c..1a62135 100644
--- a/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnector.java
+++ b/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collection;
 
-import org.codehaus.plexus.util.FileUtils;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.metadata.Metadata;
 import org.eclipse.aether.repository.RemoteRepository;
@@ -40,122 +40,107 @@
 import org.eclipse.aether.transfer.MetadataTransferException;
 
 /**
- * @author Benjamin Bentmann
  */
-public class TestRepositoryConnector
-    implements RepositoryConnector
-{
+public class TestRepositoryConnector implements RepositoryConnector {
 
     private RemoteRepository repository;
 
     private File basedir;
 
-    public TestRepositoryConnector( RemoteRepository repository )
-    {
+    public TestRepositoryConnector(RemoteRepository repository) {
         this.repository = repository;
-        try
-        {
-            basedir = FileUtils.toFile( new URL( repository.getUrl() ) );
-        }
-        catch ( MalformedURLException e )
-        {
-            throw new IllegalStateException( e );
-        }
-    }
-
-    public void close()
-    {
-    }
-
-    public void get( Collection<? extends ArtifactDownload> artifactDownloads,
-                     Collection<? extends MetadataDownload> metadataDownloads )
-    {
-        if ( artifactDownloads != null )
-        {
-            for ( ArtifactDownload download : artifactDownloads )
-            {
-                File remoteFile = new File( basedir, path( download.getArtifact() ) );
-                try
-                {
-                    FileUtils.copyFile( remoteFile, download.getFile() );
+        String repositoryUrl = repository.getUrl();
+        if (repositoryUrl.contains("${")) {
+            // the repository url contains unresolved properties and getting the basedir is not possible
+            // in JDK 20+ 'new URL(string)' will fail if the string contains a curly brace
+            this.basedir = null;
+        } else {
+            try {
+                URL url = new URL(repository.getUrl());
+                if ("file".equals(url.getProtocol())) {
+                    basedir = new File(url.getPath());
                 }
-                catch ( IOException e )
-                {
-                    if ( !remoteFile.exists() )
-                    {
-                        download.setException( new ArtifactNotFoundException( download.getArtifact(), repository ) );
-                    }
-                    else
-                    {
-                        download.setException( new ArtifactTransferException( download.getArtifact(), repository, e ) );
+            } catch (MalformedURLException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+    public void close() {}
+
+    public void get(
+            Collection<? extends ArtifactDownload> artifactDownloads,
+            Collection<? extends MetadataDownload> metadataDownloads) {
+        if (artifactDownloads != null) {
+            for (ArtifactDownload download : artifactDownloads) {
+                File remoteFile = new File(basedir, path(download.getArtifact()));
+                try {
+                    Path dest = download.getFile().toPath();
+                    Files.createDirectories(dest.getParent());
+                    Files.copy(remoteFile.toPath(), dest);
+                } catch (IOException e) {
+                    if (!remoteFile.exists()) {
+                        download.setException(new ArtifactNotFoundException(download.getArtifact(), repository));
+                    } else {
+                        download.setException(new ArtifactTransferException(download.getArtifact(), repository, e));
                     }
                 }
             }
         }
-        if ( metadataDownloads != null )
-        {
-            for ( final MetadataDownload download : metadataDownloads )
-            {
-                File remoteFile = new File( basedir, path( download.getMetadata() ) );
-                try
-                {
-                    FileUtils.copyFile( remoteFile, download.getFile() );
-                }
-                catch ( IOException e )
-                {
-                    if ( !remoteFile.exists() )
-                    {
-                        download.setException( new MetadataNotFoundException( download.getMetadata(), repository ) );
-                    }
-                    else
-                    {
-                        download.setException( new MetadataTransferException( download.getMetadata(), repository, e ) );
+        if (metadataDownloads != null) {
+            for (final MetadataDownload download : metadataDownloads) {
+                File remoteFile = new File(basedir, path(download.getMetadata()));
+                try {
+                    Path dest = download.getFile().toPath();
+                    Files.createDirectories(dest.getParent());
+                    Files.copy(remoteFile.toPath(), dest);
+                } catch (IOException e) {
+                    if (!remoteFile.exists()) {
+                        download.setException(new MetadataNotFoundException(download.getMetadata(), repository));
+                    } else {
+                        download.setException(new MetadataTransferException(download.getMetadata(), repository, e));
                     }
                 }
             }
         }
     }
 
-    private String path( Artifact artifact )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    private String path(Artifact artifact) {
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( artifact.getGroupId().replace( '.', '/' ) ).append( '/' );
+        path.append(artifact.getGroupId().replace('.', '/')).append('/');
 
-        path.append( artifact.getArtifactId() ).append( '/' );
+        path.append(artifact.getArtifactId()).append('/');
 
-        path.append( artifact.getBaseVersion() ).append( '/' );
+        path.append(artifact.getBaseVersion()).append('/');
 
-        path.append( artifact.getArtifactId() ).append( '-' ).append( artifact.getVersion() );
+        path.append(artifact.getArtifactId()).append('-').append(artifact.getVersion());
 
-        if ( artifact.getClassifier().length() > 0 )
-        {
-            path.append( '-' ).append( artifact.getClassifier() );
+        if (artifact.getClassifier().length() > 0) {
+            path.append('-').append(artifact.getClassifier());
         }
 
-        path.append( '.' ).append( artifact.getExtension() );
+        path.append('.').append(artifact.getExtension());
 
         return path.toString();
     }
 
-    private String path( Metadata metadata )
-    {
-        StringBuilder path = new StringBuilder( 128 );
+    private String path(Metadata metadata) {
+        StringBuilder path = new StringBuilder(128);
 
-        path.append( metadata.getGroupId().replace( '.', '/' ) ).append( '/' );
+        path.append(metadata.getGroupId().replace('.', '/')).append('/');
 
-        path.append( metadata.getArtifactId() ).append( '/' );
+        path.append(metadata.getArtifactId()).append('/');
 
-        path.append( "maven-metadata.xml" );
+        path.append("maven-metadata.xml");
 
         return path.toString();
     }
 
-    public void put( Collection<? extends ArtifactUpload> artifactUploads,
-                     Collection<? extends MetadataUpload> metadataUploads )
-    {
+    public void put(
+            Collection<? extends ArtifactUpload> artifactUploads,
+            Collection<? extends MetadataUpload> metadataUploads) {
         // TODO Auto-generated method stub
 
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnectorFactory.java b/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnectorFactory.java
index 1f41e09..a548639 100644
--- a/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnectorFactory.java
+++ b/maven-core/src/test/java/org/apache/maven/repository/TestRepositoryConnectorFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -29,23 +28,17 @@
 import org.eclipse.aether.transfer.NoRepositoryConnectorException;
 
 /**
- * @author Benjamin Bentmann
  */
-@Named( "test" )
+@Named("test")
 @Singleton
-public class TestRepositoryConnectorFactory
-    implements RepositoryConnectorFactory
-{
+public class TestRepositoryConnectorFactory implements RepositoryConnectorFactory {
 
-    public RepositoryConnector newInstance( RepositorySystemSession session, RemoteRepository repository )
-        throws NoRepositoryConnectorException
-    {
-        return new TestRepositoryConnector( repository );
+    public RepositoryConnector newInstance(RepositorySystemSession session, RemoteRepository repository)
+            throws NoRepositoryConnectorException {
+        return new TestRepositoryConnector(repository);
     }
 
-    public float getPriority()
-    {
+    public float getPriority() {
         return 0;
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/repository/TestRepositorySystem.java b/maven-core/src/test/java/org/apache/maven/repository/TestRepositorySystem.java
deleted file mode 100644
index c95f428..0000000
--- a/maven-core/src/test/java/org/apache/maven/repository/TestRepositorySystem.java
+++ /dev/null
@@ -1,337 +0,0 @@
-package org.apache.maven.repository;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.DefaultArtifact;
-import org.apache.maven.artifact.InvalidRepositoryException;
-import org.apache.maven.artifact.factory.ArtifactFactory;
-import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
-import org.apache.maven.artifact.repository.MavenArtifactRepository;
-import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
-import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
-import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
-import org.apache.maven.artifact.resolver.ArtifactResolutionResult;
-import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
-import org.apache.maven.artifact.versioning.VersionRange;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.Repository;
-import org.apache.maven.model.io.ModelReader;
-import org.apache.maven.project.artifact.ArtifactWithDependencies;
-import org.apache.maven.settings.Mirror;
-import org.apache.maven.settings.Proxy;
-import org.apache.maven.settings.Server;
-import org.codehaus.plexus.util.FileUtils;
-import org.codehaus.plexus.util.StringUtils;
-import org.eclipse.aether.RepositorySystemSession;
-
-/**
- * @author Benjamin Bentmann
- */
-@Named
-@Singleton
-public class TestRepositorySystem
-    implements RepositorySystem
-{
-
-    private final ModelReader modelReader;
-
-    private final ArtifactFactory artifactFactory;
-
-    @Inject
-    public TestRepositorySystem( ModelReader modelReader, ArtifactFactory artifactFactory )
-    {
-        this.modelReader = modelReader;
-        this.artifactFactory = artifactFactory;
-    }
-
-    public ArtifactRepository buildArtifactRepository( Repository repository )
-        throws InvalidRepositoryException
-    {
-        return new MavenArtifactRepository( repository.getId(), repository.getUrl(), new DefaultRepositoryLayout(),
-                                            new ArtifactRepositoryPolicy(), new ArtifactRepositoryPolicy() );
-    }
-
-    public Artifact createArtifact( String groupId, String artifactId, String version, String packaging )
-    {
-        return createArtifact( groupId, artifactId, version, null, packaging );
-    }
-
-    public Artifact createArtifact( String groupId, String artifactId, String version, String scope, String type )
-    {
-        return new DefaultArtifact( groupId, artifactId, version, scope, type, null, new TestArtifactHandler( type ) );
-    }
-
-    public ArtifactRepository createArtifactRepository( String id, String url,
-                                                        ArtifactRepositoryLayout repositoryLayout,
-                                                        ArtifactRepositoryPolicy snapshots,
-                                                        ArtifactRepositoryPolicy releases )
-    {
-        return new MavenArtifactRepository( id, url, repositoryLayout, snapshots, releases );
-    }
-
-    public Artifact createArtifactWithClassifier( String groupId, String artifactId, String version, String type,
-                                                  String classifier )
-    {
-        return new DefaultArtifact( groupId, artifactId, version, null, type, classifier,
-                                    new TestArtifactHandler( type ) );
-    }
-
-    public ArtifactRepository createDefaultLocalRepository()
-        throws InvalidRepositoryException
-    {
-        return createLocalRepository( new File( System.getProperty( "basedir", "." ), "target/local-repo" ).getAbsoluteFile() );
-    }
-
-    public ArtifactRepository createDefaultRemoteRepository()
-        throws InvalidRepositoryException
-    {
-        return new MavenArtifactRepository( DEFAULT_REMOTE_REPO_ID, "file://"
-            + new File( System.getProperty( "basedir", "." ), "src/test/remote-repo" ).getAbsoluteFile().toURI().getPath(),
-                                            new DefaultRepositoryLayout(), new ArtifactRepositoryPolicy(),
-                                            new ArtifactRepositoryPolicy() );
-    }
-
-    public Artifact createDependencyArtifact( Dependency dependency )
-    {
-        Artifact artifact =
-            new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(),
-                                 dependency.getScope(), dependency.getType(), dependency.getClassifier(),
-                                 new TestArtifactHandler( dependency.getType() ) );
-
-        if ( Artifact.SCOPE_SYSTEM.equals( dependency.getScope() ) )
-        {
-            artifact.setFile( new File( dependency.getSystemPath() ) );
-            artifact.setResolved( true );
-        }
-
-        return artifact;
-    }
-
-    public ArtifactRepository createLocalRepository( File localRepository )
-        throws InvalidRepositoryException
-    {
-        return new MavenArtifactRepository( DEFAULT_LOCAL_REPO_ID, "file://" + localRepository.toURI().getPath(),
-                                            new DefaultRepositoryLayout(), new ArtifactRepositoryPolicy(),
-                                            new ArtifactRepositoryPolicy() );
-    }
-
-    public Artifact createPluginArtifact( Plugin plugin )
-    {
-        VersionRange versionRange;
-        try
-        {
-            String version = plugin.getVersion();
-            if ( StringUtils.isEmpty( version ) )
-            {
-                version = "RELEASE";
-            }
-            versionRange = VersionRange.createFromVersionSpec( version );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
-            return null;
-        }
-
-        return artifactFactory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), versionRange );
-    }
-
-    public Artifact createProjectArtifact( String groupId, String artifactId, String version )
-    {
-        return createArtifact( groupId, artifactId, version, "pom" );
-    }
-
-    public List<ArtifactRepository> getEffectiveRepositories( List<ArtifactRepository> repositories )
-    {
-        return repositories;
-    }
-
-    public Mirror getMirror( ArtifactRepository repository, List<Mirror> mirrors )
-    {
-        return null;
-    }
-
-    public void injectAuthentication( List<ArtifactRepository> repositories, List<Server> servers )
-    {
-    }
-
-    public void injectMirror( List<ArtifactRepository> repositories, List<Mirror> mirrors )
-    {
-    }
-
-    public void injectProxy( List<ArtifactRepository> repositories, List<Proxy> proxies )
-    {
-    }
-
-    public void publish( ArtifactRepository repository, File source, String remotePath,
-                         ArtifactTransferListener transferListener )
-        throws ArtifactTransferFailedException
-    {
-        // TODO Auto-generated method stub
-
-    }
-
-    public ArtifactResolutionResult resolve( ArtifactResolutionRequest request )
-    {
-        ArtifactResolutionResult result = new ArtifactResolutionResult();
-
-        if ( request.isResolveRoot() )
-        {
-            try
-            {
-                resolve( request.getArtifact(), request );
-                result.addArtifact( request.getArtifact() );
-            }
-            catch ( IOException e )
-            {
-                result.addMissingArtifact( request.getArtifact() );
-            }
-        }
-
-        if ( request.isResolveTransitively() )
-        {
-            Map<String, Artifact> artifacts = new LinkedHashMap<>();
-
-            if ( request.getArtifactDependencies() != null )
-            {
-                for ( Artifact artifact : request.getArtifactDependencies() )
-                {
-                    artifacts.put( artifact.getDependencyConflictId(), artifact );
-                }
-            }
-
-            List<Dependency> dependencies = new ArrayList<>();
-            if ( request.getArtifact() instanceof ArtifactWithDependencies )
-            {
-                dependencies = ( (ArtifactWithDependencies) request.getArtifact() ).getDependencies();
-            }
-            else
-            {
-                Artifact pomArtifact =
-                    createProjectArtifact( request.getArtifact().getGroupId(), request.getArtifact().getArtifactId(),
-                                           request.getArtifact().getVersion() );
-                File pomFile =
-                    new File( request.getLocalRepository().getBasedir(),
-                              request.getLocalRepository().pathOf( pomArtifact ) );
-
-                try
-                {
-                    Model model = modelReader.read( pomFile, null );
-
-                    dependencies = model.getDependencies();
-                }
-                catch ( IOException e )
-                {
-                    e.printStackTrace();
-                }
-            }
-
-            for ( Dependency dependency : dependencies )
-            {
-                Artifact artifact = createDependencyArtifact( dependency );
-                if ( !artifacts.containsKey( artifact.getDependencyConflictId() ) )
-                {
-                    artifacts.put( artifact.getDependencyConflictId(), artifact );
-                }
-            }
-
-            for ( Artifact artifact : artifacts.values() )
-            {
-                try
-                {
-                    resolve( artifact, request );
-                    result.addArtifact( artifact );
-                }
-                catch ( IOException e )
-                {
-                    result.addMissingArtifact( artifact );
-                }
-            }
-        }
-
-        return result;
-    }
-
-    private void resolve( Artifact artifact, ArtifactResolutionRequest request )
-        throws IOException
-    {
-        if ( Artifact.SCOPE_SYSTEM.equals( artifact.getScope() ) )
-        {
-            return;
-        }
-
-        ArtifactRepository localRepo = request.getLocalRepository();
-
-        File localFile = new File( localRepo.getBasedir(), localRepo.pathOf( artifact ) );
-
-        artifact.setFile( localFile );
-
-        if ( !localFile.exists() )
-        {
-            if ( request.getRemoteRepositories().isEmpty() )
-            {
-                throw new IOException( localFile + " does not exist and no remote repositories are configured" );
-            }
-
-            ArtifactRepository remoteRepo = request.getRemoteRepositories().get( 0 );
-
-            File remoteFile = new File( remoteRepo.getBasedir(), remoteRepo.pathOf( artifact ) );
-
-            FileUtils.copyFile( remoteFile, localFile );
-        }
-
-        artifact.setResolved( true );
-    }
-
-    public void retrieve( ArtifactRepository repository, File destination, String remotePath,
-                          ArtifactTransferListener transferListener )
-        throws ArtifactTransferFailedException, ArtifactDoesNotExistException
-    {
-        // TODO Auto-generated method stub
-
-    }
-
-    public void injectMirror( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-    }
-
-    public void injectProxy( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-    }
-
-    public void injectAuthentication( RepositorySystemSession session, List<ArtifactRepository> repositories )
-    {
-    }
-
-}
diff --git a/maven-core/src/test/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformationTest.java b/maven-core/src/test/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformationTest.java
index b6e987e..7a96988 100644
--- a/maven-core/src/test/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformationTest.java
+++ b/maven-core/src/test/java/org/apache/maven/rtinfo/internal/DefaultRuntimeInformationTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.rtinfo.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.rtinfo.internal;
+
+import javax.inject.Inject;
 
 import org.apache.maven.rtinfo.RuntimeInformation;
 import org.codehaus.plexus.testing.PlexusTest;
@@ -28,45 +29,35 @@
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import javax.inject.Inject;
-
 @PlexusTest
-public class DefaultRuntimeInformationTest
-{
+class DefaultRuntimeInformationTest {
     @Inject
     RuntimeInformation rtInfo;
 
     @Test
-    public void testGetMavenVersion()
-    {
+    void testGetMavenVersion() {
         String mavenVersion = rtInfo.getMavenVersion();
-        assertNotNull( mavenVersion );
-        assertTrue( mavenVersion.length() > 0 );
+        assertNotNull(mavenVersion);
+        assertTrue(mavenVersion.length() > 0);
     }
 
     @Test
-    public void testIsMavenVersion()
-    {
-        assertTrue( rtInfo.isMavenVersion( "2.0" ) );
-        assertFalse( rtInfo.isMavenVersion( "9.9" ) );
+    void testIsMavenVersion() {
+        assertTrue(rtInfo.isMavenVersion("2.0"));
+        assertFalse(rtInfo.isMavenVersion("9.9"));
 
-        assertTrue( rtInfo.isMavenVersion( "[2.0.11,2.1.0),[3.0,)" ) );
-        assertFalse( rtInfo.isMavenVersion( "[9.0,)" ) );
+        assertTrue(rtInfo.isMavenVersion("[2.0.11,2.1.0),[3.0,)"));
+        assertFalse(rtInfo.isMavenVersion("[9.0,)"));
 
         assertThrows(
                 IllegalArgumentException.class,
-                () -> rtInfo.isMavenVersion( "[3.0," ),
-                "Bad version range wasn't rejected" );
+                () -> rtInfo.isMavenVersion("[3.0,"),
+                "Bad version range wasn't rejected");
 
         assertThrows(
-                IllegalArgumentException.class,
-                () -> rtInfo.isMavenVersion( "" ),
-                "Bad version range wasn't rejected" );
+                IllegalArgumentException.class, () -> rtInfo.isMavenVersion(""), "Bad version range wasn't rejected");
 
         assertThrows(
-                NullPointerException.class,
-                () -> rtInfo.isMavenVersion( null ),
-                "Bad version range wasn't rejected" );
+                NullPointerException.class, () -> rtInfo.isMavenVersion(null), "Bad version range wasn't rejected");
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/session/scope/SessionScopeProxyTest.java b/maven-core/src/test/java/org/apache/maven/session/scope/SessionScopeProxyTest.java
new file mode 100644
index 0000000..fd3efe8
--- /dev/null
+++ b/maven-core/src/test/java/org/apache/maven/session/scope/SessionScopeProxyTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.session.scope;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import com.google.inject.OutOfScopeException;
+import org.apache.maven.api.Session;
+import org.apache.maven.api.di.SessionScoped;
+import org.apache.maven.session.scope.internal.SessionScope;
+import org.codehaus.plexus.PlexusContainer;
+import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.testing.PlexusTest;
+import org.eclipse.sisu.Typed;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@PlexusTest
+@ExtendWith(MockitoExtension.class)
+public class SessionScopeProxyTest {
+
+    @Mock
+    Session session;
+
+    @Inject
+    SessionScope sessionScope;
+
+    @Inject
+    PlexusContainer container;
+
+    @Test
+    void testProxiedSessionScopedBean() throws ComponentLookupException {
+        ComponentLookupException e =
+                assertThrows(ComponentLookupException.class, () -> container.lookup(MySingletonBean2.class));
+        assertTrue(e.getMessage().matches("[\\s\\S]*: Can not set .* field .* to [\\s\\S]*"));
+
+        MySingletonBean bean = container.lookup(MySingletonBean.class);
+        assertNotNull(bean);
+        assertNotNull(bean.anotherBean);
+        assertSame(bean.anotherBean.getClass(), AnotherBean.class);
+        assertNotNull(bean.myBean);
+        assertNotSame(bean.myBean.getClass(), MySessionScopedBean.class);
+
+        assertThrows(OutOfScopeException.class, () -> bean.myBean.getSession());
+
+        sessionScope.enter();
+        sessionScope.seed(Session.class, this.session);
+        assertNotNull(bean.myBean.getSession());
+        assertNotNull(bean.myBean.getAnotherBean());
+        assertSame(bean.myBean.getAnotherBean().getClass(), AnotherBean.class);
+    }
+
+    @Named
+    static class MySingletonBean {
+        @Inject
+        @Named("scoped")
+        BeanItf myBean;
+
+        @Inject
+        @Named("another")
+        BeanItf2 anotherBean;
+    }
+
+    @Named
+    static class MySingletonBean2 {
+        @Inject
+        @Named("scoped")
+        MySessionScopedBean myBean;
+
+        @Inject
+        @Named("another")
+        BeanItf2 anotherBean;
+    }
+
+    interface BeanItf {
+        Session getSession();
+
+        BeanItf2 getAnotherBean();
+    }
+
+    interface BeanItf2 {}
+
+    @Named("another")
+    @Singleton
+    static class AnotherBean implements BeanItf2 {}
+
+    @Named("scoped")
+    @SessionScoped
+    @Typed
+    static class MySessionScopedBean implements BeanItf {
+        @Inject
+        Session session;
+
+        @Inject
+        BeanItf2 anotherBean;
+
+        public Session getSession() {
+            return session;
+        }
+
+        public BeanItf2 getAnotherBean() {
+            return anotherBean;
+        }
+    }
+}
diff --git a/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java b/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java
index e13382b..bb7193d 100644
--- a/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java
+++ b/maven-core/src/test/java/org/apache/maven/settings/PomConstructionWithSettingsTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,37 +16,38 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings;
+
+import javax.inject.Inject;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
 import java.io.IOException;
-import java.io.Reader;
+import java.io.InputStream;
+import java.nio.file.Files;
 
+import org.apache.maven.api.settings.InputSource;
 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
+import org.apache.maven.bridge.MavenRepositorySystem;
 import org.apache.maven.model.Profile;
 import org.apache.maven.project.DefaultProjectBuilder;
 import org.apache.maven.project.DefaultProjectBuildingRequest;
 import org.apache.maven.project.ProjectBuildingRequest;
 import org.apache.maven.project.harness.PomTestWrapper;
-import org.apache.maven.repository.RepositorySystem;
 import org.apache.maven.repository.internal.MavenRepositorySystemUtils;
-import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader;
+import org.apache.maven.settings.v4.SettingsStaxReader;
 import org.codehaus.plexus.testing.PlexusTest;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory;
 import org.eclipse.aether.repository.LocalRepository;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import javax.inject.Inject;
-
 import static org.codehaus.plexus.testing.PlexusExtension.getBasedir;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
 @PlexusTest
-public class PomConstructionWithSettingsTest
-{
+class PomConstructionWithSettingsTest {
     private static final String BASE_DIR = "src/test";
 
     private static final String BASE_POM_DIR = BASE_DIR + "/resources-settings";
@@ -57,93 +56,76 @@
     private DefaultProjectBuilder projectBuilder;
 
     @Inject
-    private RepositorySystem repositorySystem;
+    private MavenRepositorySystem repositorySystem;
 
     private File testDirectory;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        testDirectory = new File( getBasedir(), BASE_POM_DIR );
+    void setUp() throws Exception {
+        testDirectory = new File(getBasedir(), BASE_POM_DIR);
     }
 
     @Test
-    public void testSettingsNoPom()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "settings-no-pom" );
-        assertEquals( "local-profile-prop-value", pom.getValue( "properties/local-profile-prop" ) );
+    void testSettingsNoPom() throws Exception {
+        PomTestWrapper pom = buildPom("settings-no-pom");
+        assertEquals("local-profile-prop-value", pom.getValue("properties/local-profile-prop"));
     }
 
     /**
      * MNG-4107
      */
     @Test
-    public void testPomAndSettingsInterpolation()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "test-pom-and-settings-interpolation" );
-        assertEquals( "applied", pom.getValue( "properties/settingsProfile" ) );
-        assertEquals( "applied", pom.getValue( "properties/pomProfile" ) );
-        assertEquals( "settings", pom.getValue( "properties/pomVsSettings" ) );
-        assertEquals( "settings", pom.getValue( "properties/pomVsSettingsInterpolated" ) );
+    void testPomAndSettingsInterpolation() throws Exception {
+        PomTestWrapper pom = buildPom("test-pom-and-settings-interpolation");
+        assertEquals("applied", pom.getValue("properties/settingsProfile"));
+        assertEquals("applied", pom.getValue("properties/pomProfile"));
+        assertEquals("settings", pom.getValue("properties/pomVsSettings"));
+        assertEquals("settings", pom.getValue("properties/pomVsSettingsInterpolated"));
     }
 
     /**
      * MNG-4107
      */
     @Test
-    public void testRepositories()
-        throws Exception
-    {
-        PomTestWrapper pom = buildPom( "repositories" );
-        assertEquals( "maven-core-it-0", pom.getValue( "repositories[1]/id" ) );
+    void testRepositories() throws Exception {
+        PomTestWrapper pom = buildPom("repositories");
+        assertEquals("maven-core-it-0", pom.getValue("repositories[1]/id"));
     }
 
-    private PomTestWrapper buildPom( String pomPath )
-        throws Exception
-    {
-        File pomFile = new File( testDirectory + File.separator + pomPath, "pom.xml" );
-        File settingsFile = new File( testDirectory + File.separator + pomPath, "settings.xml" );
-        Settings settings = readSettingsFile( settingsFile );
+    private PomTestWrapper buildPom(String pomPath) throws Exception {
+        File pomFile = new File(testDirectory + File.separator + pomPath, "pom.xml");
+        File settingsFile = new File(testDirectory + File.separator + pomPath, "settings.xml");
+        Settings settings = readSettingsFile(settingsFile);
 
         ProjectBuildingRequest config = new DefaultProjectBuildingRequest();
 
-        for ( org.apache.maven.settings.Profile rawProfile : settings.getProfiles() )
-        {
-            Profile profile = SettingsUtils.convertFromSettingsProfile( rawProfile );
-            config.addProfile( profile );
+        for (org.apache.maven.settings.Profile rawProfile : settings.getProfiles()) {
+            Profile profile = SettingsUtils.convertFromSettingsProfile(rawProfile);
+            config.addProfile(profile);
         }
 
         String localRepoUrl =
-            System.getProperty( "maven.repo.local", System.getProperty( "user.home" ) + "/.m2/repository" );
+                System.getProperty("maven.repo.local", System.getProperty("user.home") + "/.m2/repository");
         localRepoUrl = "file://" + localRepoUrl;
-        config.setLocalRepository(
-            repositorySystem.createArtifactRepository( "local", localRepoUrl, new DefaultRepositoryLayout(), null,
-                                                       null ) );
-        config.setActiveProfileIds( settings.getActiveProfiles() );
+        config.setLocalRepository(repositorySystem.createArtifactRepository(
+                "local", localRepoUrl, new DefaultRepositoryLayout(), null, null));
+        config.setActiveProfileIds(settings.getActiveProfiles());
 
         DefaultRepositorySystemSession repoSession = MavenRepositorySystemUtils.newSession();
-        LocalRepository localRepo = new LocalRepository( config.getLocalRepository().getBasedir() );
+        LocalRepository localRepo =
+                new LocalRepository(config.getLocalRepository().getBasedir());
         repoSession.setLocalRepositoryManager(
-            new SimpleLocalRepositoryManagerFactory().newInstance( repoSession, localRepo ) );
-        config.setRepositorySession( repoSession );
+                new SimpleLocalRepositoryManagerFactory().newInstance(repoSession, localRepo));
+        config.setRepositorySession(repoSession);
 
-        return new PomTestWrapper( pomFile, projectBuilder.build( pomFile, config ).getProject() );
+        return new PomTestWrapper(pomFile, projectBuilder.build(pomFile, config).getProject());
     }
 
-    private static Settings readSettingsFile( File settingsFile )
-        throws IOException, XmlPullParserException
-    {
-        Settings settings = null;
-
-        try ( Reader reader = ReaderFactory.newXmlReader( settingsFile ) )
-        {
-            SettingsXpp3Reader modelReader = new SettingsXpp3Reader();
-
-            settings = modelReader.read( reader );
+    private static Settings readSettingsFile(File settingsFile) throws IOException, XMLStreamException {
+        try (InputStream is = Files.newInputStream(settingsFile.toPath())) {
+            SettingsStaxReader reader = new SettingsStaxReader();
+            InputSource source = new InputSource(settingsFile.toString());
+            return new Settings(reader.read(is, true, source));
         }
-        return settings;
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java b/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java
index 6943c34..1e7250f 100644
--- a/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java
+++ b/maven-core/src/test/java/org/apache/maven/settings/SettingsUtilsTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,113 +16,140 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
-import java.util.Properties;
+import java.util.Map;
 import java.util.Random;
 
+import org.apache.maven.api.settings.Activation;
+import org.apache.maven.api.settings.ActivationFile;
+import org.apache.maven.api.settings.ActivationOS;
+import org.apache.maven.api.settings.ActivationProperty;
+import org.apache.maven.api.settings.Profile;
+import org.apache.maven.api.settings.Repository;
+import org.apache.maven.api.settings.Settings;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-public class SettingsUtilsTest
-{
+class SettingsUtilsTest {
 
     @Test
-    public void testShouldAppendRecessivePluginGroupIds()
-    {
-        Settings dominant = new Settings();
-        dominant.addPluginGroup( "org.apache.maven.plugins" );
-        dominant.addPluginGroup( "org.codehaus.modello" );
+    void testShouldAppendRecessivePluginGroupIds() {
+        Settings dominant = Settings.newBuilder()
+                .pluginGroups(Arrays.asList("org.apache.maven.plugins", "org.codehaus.modello"))
+                .build();
 
-        Settings recessive = new Settings();
-        recessive.addPluginGroup( "org.codehaus.plexus" );
+        Settings recessive = Settings.newBuilder()
+                .pluginGroups(Arrays.asList("org.codehaus.plexus"))
+                .build();
 
-        SettingsUtils.merge( dominant, recessive, Settings.GLOBAL_LEVEL );
+        Settings merged = SettingsUtilsV4.merge(dominant, recessive);
 
-        List<String> pluginGroups = dominant.getPluginGroups();
+        List<String> pluginGroups = merged.getPluginGroups();
 
-        assertNotNull( pluginGroups );
-        assertEquals( 3, pluginGroups.size() );
-        assertEquals( "org.apache.maven.plugins", pluginGroups.get( 0 ) );
-        assertEquals( "org.codehaus.modello", pluginGroups.get( 1 ) );
-        assertEquals( "org.codehaus.plexus", pluginGroups.get( 2 ) );
+        assertNotNull(pluginGroups);
+        assertEquals(3, pluginGroups.size());
+        assertEquals("org.apache.maven.plugins", pluginGroups.get(0));
+        assertEquals("org.codehaus.modello", pluginGroups.get(1));
+        assertEquals("org.codehaus.plexus", pluginGroups.get(2));
     }
 
     @Test
-    public void testRoundTripProfiles()
-    {
+    void testRoundTripProfiles() {
         Random entropy = new Random();
-        Profile p = new Profile();
-        p.setId( "id" + Long.toHexString( entropy.nextLong() ) );
-        Activation a = new Activation();
-        a.setActiveByDefault( entropy.nextBoolean() );
-        a.setJdk( "jdk" + Long.toHexString( entropy.nextLong() ) );
-        ActivationFile af = new ActivationFile();
-        af.setExists( "exists" + Long.toHexString( entropy.nextLong() ) );
-        af.setMissing( "missing" + Long.toHexString( entropy.nextLong() ) );
-        a.setFile( af );
-        ActivationProperty ap = new ActivationProperty();
-        ap.setName( "name" + Long.toHexString( entropy.nextLong() ) );
-        ap.setValue( "value" + Long.toHexString( entropy.nextLong() ) );
-        a.setProperty( ap );
-        ActivationOS ao = new ActivationOS();
-        ao.setArch( "arch" + Long.toHexString( entropy.nextLong() ) );
-        ao.setFamily( "family" + Long.toHexString( entropy.nextLong() ) );
-        ao.setName( "name" + Long.toHexString( entropy.nextLong() ) );
-        ao.setVersion( "version" + Long.toHexString( entropy.nextLong() ) );
-        a.setOs( ao );
-        p.setActivation( a );
-        Properties props = new Properties();
-        int count = entropy.nextInt( 10 );
-        for ( int i = 0; i < count; i++ )
-        {
-            props.setProperty( "name" + Long.toHexString( entropy.nextLong() ),
-                               "value" + Long.toHexString( entropy.nextLong() ) );
+        ActivationFile af = ActivationFile.newBuilder()
+                .exists("exists" + Long.toHexString(entropy.nextLong()))
+                .missing("missing" + Long.toHexString(entropy.nextLong()))
+                .build();
+        ActivationProperty ap = ActivationProperty.newBuilder()
+                .name("name" + Long.toHexString(entropy.nextLong()))
+                .value("value" + Long.toHexString(entropy.nextLong()))
+                .build();
+        ActivationOS ao = ActivationOS.newBuilder()
+                .arch("arch" + Long.toHexString(entropy.nextLong()))
+                .family("family" + Long.toHexString(entropy.nextLong()))
+                .name("name" + Long.toHexString(entropy.nextLong()))
+                .version("version" + Long.toHexString(entropy.nextLong()))
+                .build();
+        Activation a = Activation.newBuilder()
+                .activeByDefault(entropy.nextBoolean())
+                .jdk("jdk" + Long.toHexString(entropy.nextLong()))
+                .file(af)
+                .property(ap)
+                .os(ao)
+                .build();
+        Map<String, String> props = new HashMap<>();
+        int count = entropy.nextInt(10);
+        for (int i = 0; i < count; i++) {
+            props.put("name" + Long.toHexString(entropy.nextLong()), "value" + Long.toHexString(entropy.nextLong()));
         }
-        p.setProperties( props );
-        count = entropy.nextInt( 3 );
+        count = entropy.nextInt(3);
         List<Repository> repos = new ArrayList<>();
-        for ( int i = 0; i < count; i++ )
-        {
-            Repository r = new Repository();
-            r.setId( "id" + Long.toHexString( entropy.nextLong() ) );
-            r.setName( "name" + Long.toHexString( entropy.nextLong() ) );
-            r.setUrl( "url" + Long.toHexString( entropy.nextLong() ) );
-            repos.add( r );
+        for (int i = 0; i < count; i++) {
+            Repository r = Repository.newBuilder()
+                    .id("id" + Long.toHexString(entropy.nextLong()))
+                    .name("name" + Long.toHexString(entropy.nextLong()))
+                    .url("url" + Long.toHexString(entropy.nextLong()))
+                    .build();
+            repos.add(r);
         }
-        p.setRepositories( repos );
-        count = entropy.nextInt( 3 );
-        repos = new ArrayList<>();
-        for ( int i = 0; i < count; i++ )
-        {
-            Repository r = new Repository();
-            r.setId( "id" + Long.toHexString( entropy.nextLong() ) );
-            r.setName( "name" + Long.toHexString( entropy.nextLong() ) );
-            r.setUrl( "url" + Long.toHexString( entropy.nextLong() ) );
-            repos.add( r );
+        count = entropy.nextInt(3);
+        List<Repository> pluginRepos = new ArrayList<>();
+        for (int i = 0; i < count; i++) {
+            Repository r = Repository.newBuilder()
+                    .id("id" + Long.toHexString(entropy.nextLong()))
+                    .name("name" + Long.toHexString(entropy.nextLong()))
+                    .url("url" + Long.toHexString(entropy.nextLong()))
+                    .build();
+            pluginRepos.add(r);
         }
-        p.setPluginRepositories( repos );
+        Profile p = Profile.newBuilder()
+                .id("id" + Long.toHexString(entropy.nextLong()))
+                .activation(a)
+                .properties(props)
+                .repositories(repos)
+                .pluginRepositories(pluginRepos)
+                .build();
 
-        Profile clone = SettingsUtils.convertToSettingsProfile( SettingsUtils.convertFromSettingsProfile( p ) );
+        Profile clone = SettingsUtilsV4.convertToSettingsProfile(SettingsUtilsV4.convertFromSettingsProfile(p));
 
-        assertEquals( p.getId(), clone.getId() );
-        assertEquals( p.getActivation().getJdk(), clone.getActivation().getJdk() );
-        assertEquals( p.getActivation().getFile().getExists(), clone.getActivation().getFile().getExists() );
-        assertEquals( p.getActivation().getFile().getMissing(), clone.getActivation().getFile().getMissing() );
-        assertEquals( p.getActivation().getProperty().getName(), clone.getActivation().getProperty().getName() );
-        assertEquals( p.getActivation().getProperty().getValue(), clone.getActivation().getProperty().getValue() );
-        assertEquals( p.getActivation().getOs().getArch(), clone.getActivation().getOs().getArch() );
-        assertEquals( p.getActivation().getOs().getFamily(), clone.getActivation().getOs().getFamily() );
-        assertEquals( p.getActivation().getOs().getName(), clone.getActivation().getOs().getName() );
-        assertEquals( p.getActivation().getOs().getVersion(), clone.getActivation().getOs().getVersion() );
-        assertEquals( p.getProperties(), clone.getProperties() );
-        assertEquals( p.getRepositories().size(), clone.getRepositories().size() );
+        assertEquals(p.getId(), clone.getId());
+        assertEquals(p.getActivation().getJdk(), clone.getActivation().getJdk());
+        assertEquals(
+                p.getActivation().getFile().getExists(),
+                clone.getActivation().getFile().getExists());
+        assertEquals(
+                p.getActivation().getFile().getMissing(),
+                clone.getActivation().getFile().getMissing());
+        assertEquals(
+                p.getActivation().getProperty().getName(),
+                clone.getActivation().getProperty().getName());
+        assertEquals(
+                p.getActivation().getProperty().getValue(),
+                clone.getActivation().getProperty().getValue());
+        assertEquals(
+                p.getActivation().getOs().getArch(),
+                clone.getActivation().getOs().getArch());
+        assertEquals(
+                p.getActivation().getOs().getFamily(),
+                clone.getActivation().getOs().getFamily());
+        assertEquals(
+                p.getActivation().getOs().getName(),
+                clone.getActivation().getOs().getName());
+        assertEquals(
+                p.getActivation().getOs().getVersion(),
+                clone.getActivation().getOs().getVersion());
+        assertEquals(p.getProperties(), clone.getProperties());
+        assertEquals(p.getRepositories().size(), clone.getRepositories().size());
         // TODO deep compare the lists
-        assertEquals( p.getPluginRepositories().size(), clone.getPluginRepositories().size() );
+        assertEquals(
+                p.getPluginRepositories().size(), clone.getPluginRepositories().size());
         // TODO deep compare the lists
     }
-
 }
diff --git a/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivateTest.java b/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivateTest.java
index 04ab6f1..4c255a3 100644
--- a/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivateTest.java
+++ b/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerPrivateTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+package org.apache.maven.toolchain;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -42,8 +34,14 @@
 import org.mockito.MockitoAnnotations;
 import org.slf4j.Logger;
 
-public class DefaultToolchainManagerPrivateTest
-{
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class DefaultToolchainManagerPrivateTest {
     // Mocks to inject into toolchainManager
     @Mock
     private Logger logger;
@@ -58,106 +56,97 @@
     private ToolchainFactory toolchainFactory_rareType;
 
     @BeforeEach
-    public void setUp()
-    {
+    void setUp() {
 
-        MockitoAnnotations.initMocks( this );
+        MockitoAnnotations.initMocks(this);
 
         Map<String, ToolchainFactory> factories = new HashMap<>();
-        factories.put( "basic", toolchainFactory_basicType );
-        factories.put( "rare", toolchainFactory_rareType );
-        toolchainManager = new DefaultToolchainManagerPrivate( factories, logger );
+        factories.put("basic", toolchainFactory_basicType);
+        factories.put("rare", toolchainFactory_rareType);
+        toolchainManager = new DefaultToolchainManagerPrivate(factories, logger);
     }
 
     @Test
-    public void testToolchainsForAvailableType()
-        throws Exception
-    {
+    void testToolchainsForAvailableType() throws Exception {
         // prepare
-        MavenSession session = mock( MavenSession.class );
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest req = new DefaultMavenExecutionRequest();
-        when( session.getRequest() ).thenReturn( req );
+        when(session.getRequest()).thenReturn(req);
 
-        ToolchainPrivate basicToolchain = mock( ToolchainPrivate.class );
-        when( toolchainFactory_basicType.createDefaultToolchain() ).thenReturn( basicToolchain );
-        ToolchainPrivate rareToolchain = mock( ToolchainPrivate.class );
-        when( toolchainFactory_rareType.createDefaultToolchain() ).thenReturn( rareToolchain );
+        ToolchainPrivate basicToolchain = mock(ToolchainPrivate.class);
+        when(toolchainFactory_basicType.createDefaultToolchain()).thenReturn(basicToolchain);
+        ToolchainPrivate rareToolchain = mock(ToolchainPrivate.class);
+        when(toolchainFactory_rareType.createDefaultToolchain()).thenReturn(rareToolchain);
 
         // execute
-        ToolchainPrivate[] toolchains = toolchainManager.getToolchainsForType( "basic", session );
+        ToolchainPrivate[] toolchains = toolchainManager.getToolchainsForType("basic", session);
 
         // verify
-        verify( logger, never() ).error( anyString() );
-        assertEquals( 1, toolchains.length );
+        verify(logger, never()).error(anyString());
+        assertEquals(1, toolchains.length);
     }
 
     @Test
-    public void testToolchainsForUnknownType()
-        throws Exception
-    {
+    void testToolchainsForUnknownType() throws Exception {
         // prepare
-        MavenSession session = mock( MavenSession.class );
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest req = new DefaultMavenExecutionRequest();
-        when( session.getRequest() ).thenReturn( req );
+        when(session.getRequest()).thenReturn(req);
 
-        ToolchainPrivate basicToolchain = mock( ToolchainPrivate.class );
-        when( toolchainFactory_basicType.createDefaultToolchain() ).thenReturn( basicToolchain );
-        ToolchainPrivate rareToolchain = mock( ToolchainPrivate.class );
-        when( toolchainFactory_rareType.createDefaultToolchain() ).thenReturn( rareToolchain );
+        ToolchainPrivate basicToolchain = mock(ToolchainPrivate.class);
+        when(toolchainFactory_basicType.createDefaultToolchain()).thenReturn(basicToolchain);
+        ToolchainPrivate rareToolchain = mock(ToolchainPrivate.class);
+        when(toolchainFactory_rareType.createDefaultToolchain()).thenReturn(rareToolchain);
 
         // execute
-        ToolchainPrivate[] toolchains = toolchainManager.getToolchainsForType( "unknown", session );
+        ToolchainPrivate[] toolchains = toolchainManager.getToolchainsForType("unknown", session);
 
         // verify
-        verify( logger ).error( "Missing toolchain factory for type: unknown. Possibly caused by misconfigured project." );
-        assertEquals( 0, toolchains.length );
+        verify(logger).error("Missing toolchain factory for type: unknown. Possibly caused by misconfigured project.");
+        assertEquals(0, toolchains.length);
     }
 
     @Test
-    public void testToolchainsForConfiguredType()
-        throws Exception
-    {
+    void testToolchainsForConfiguredType() throws Exception {
         // prepare
-        MavenSession session = mock( MavenSession.class );
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest req = new DefaultMavenExecutionRequest();
-        when( session.getRequest() ).thenReturn( req );
+        when(session.getRequest()).thenReturn(req);
         Map<String, List<ToolchainModel>> groupedToolchains = new HashMap<>();
-        req.setToolchains( groupedToolchains );
+        req.setToolchains(groupedToolchains);
 
         List<ToolchainModel> basicToolchains = new ArrayList<>();
         ToolchainModel basicToolchainModel = new ToolchainModel();
-        basicToolchainModel.setType( "basic" );
-        basicToolchains.add( basicToolchainModel );
-        basicToolchains.add( basicToolchainModel );
-        groupedToolchains.put( "basic", basicToolchains );
+        basicToolchainModel.setType("basic");
+        basicToolchains.add(basicToolchainModel);
+        basicToolchains.add(basicToolchainModel);
+        groupedToolchains.put("basic", basicToolchains);
 
         List<ToolchainModel> rareToolchains = new ArrayList<>();
         ToolchainModel rareToolchainModel = new ToolchainModel();
-        rareToolchainModel.setType( "rare" );
-        rareToolchains.add( rareToolchainModel );
-        groupedToolchains.put( "rare", rareToolchains );
+        rareToolchainModel.setType("rare");
+        rareToolchains.add(rareToolchainModel);
+        groupedToolchains.put("rare", rareToolchains);
 
         // execute
-        ToolchainPrivate[] toolchains = toolchainManager.getToolchainsForType( "basic", session );
+        ToolchainPrivate[] toolchains = toolchainManager.getToolchainsForType("basic", session);
 
         // verify
-        verify( logger, never() ).error( anyString() );
-        assertEquals( 2, toolchains.length );
+        verify(logger, never()).error(anyString());
+        assertEquals(2, toolchains.length);
     }
 
     @Test
-    public void testMisconfiguredToolchain()
-        throws Exception
-    {
+    void testMisconfiguredToolchain() throws Exception {
         // prepare
-        MavenSession session = mock( MavenSession.class );
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest req = new DefaultMavenExecutionRequest();
-        when( session.getRequest() ).thenReturn( req );
+        when(session.getRequest()).thenReturn(req);
 
         // execute
         ToolchainPrivate[] basics = toolchainManager.getToolchainsForType("basic", session);
 
         // verify
-        assertEquals( 0, basics.length );
+        assertEquals(0, basics.length);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerTest.java b/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerTest.java
index 8b2605a..485a737 100644
--- a/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerTest.java
+++ b/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainManagerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,12 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.mockito.Matchers.isA;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
+package org.apache.maven.toolchain;
 
 import java.util.Arrays;
 import java.util.Collections;
@@ -43,9 +36,14 @@
 import org.mockito.MockitoAnnotations;
 import org.slf4j.Logger;
 
-public class DefaultToolchainManagerTest
-{
-     // Mocks to inject into toolchainManager
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.isA;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class DefaultToolchainManagerTest {
+    // Mocks to inject into toolchainManager
     @Mock
     private Logger logger;
 
@@ -59,94 +57,90 @@
     private ToolchainFactory toolchainFactory_rareType;
 
     @BeforeEach
-    public void onSetup() throws Exception
-    {
-        MockitoAnnotations.initMocks( this );
+    void onSetup() throws Exception {
+        MockitoAnnotations.initMocks(this);
 
         Map<String, ToolchainFactory> factories = new HashMap<>();
-        factories.put( "basic", toolchainFactory_basicType );
-        factories.put( "rare", toolchainFactory_rareType );
-        toolchainManager = new DefaultToolchainManager( factories, logger );
+        factories.put("basic", toolchainFactory_basicType);
+        factories.put("rare", toolchainFactory_rareType);
+        toolchainManager = new DefaultToolchainManager(factories, logger);
     }
 
     @Test
-    public void testNoModels()
-    {
-        MavenSession session = mock( MavenSession.class );
+    void testNoModels() {
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest executionRequest = new DefaultMavenExecutionRequest();
-        when( session.getRequest() ).thenReturn( executionRequest );
+        when(session.getRequest()).thenReturn(executionRequest);
 
-        List<Toolchain> toolchains = toolchainManager.getToolchains( session, "unknown", null );
+        List<Toolchain> toolchains = toolchainManager.getToolchains(session, "unknown", null);
 
-        assertEquals( 0, toolchains.size() );
+        assertEquals(0, toolchains.size());
     }
 
     @Test
-    public void testModelNoFactory()
-    {
-        MavenSession session = mock( MavenSession.class );
+    void testModelNoFactory() {
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest executionRequest = new DefaultMavenExecutionRequest();
         Map<String, List<ToolchainModel>> toolchainModels = new HashMap<>();
-        toolchainModels.put( "unknown", Collections.singletonList( new ToolchainModel() ) );
-        executionRequest.setToolchains( toolchainModels );
-        when( session.getRequest() ).thenReturn( executionRequest );
+        toolchainModels.put("unknown", Collections.singletonList(new ToolchainModel()));
+        executionRequest.setToolchains(toolchainModels);
+        when(session.getRequest()).thenReturn(executionRequest);
 
-        List<Toolchain> toolchains = toolchainManager.getToolchains( session, "unknown", null );
+        List<Toolchain> toolchains = toolchainManager.getToolchains(session, "unknown", null);
 
-        assertEquals( 0, toolchains.size() );
-        verify( logger ).error( "Missing toolchain factory for type: unknown. Possibly caused by misconfigured project." );
+        assertEquals(0, toolchains.size());
+        verify(logger).error("Missing toolchain factory for type: unknown. Possibly caused by misconfigured project.");
     }
 
     @Test
-    public void testModelAndFactory()
-    {
-        MavenSession session = mock( MavenSession.class );
+    void testModelAndFactory() {
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest executionRequest = new DefaultMavenExecutionRequest();
         Map<String, List<ToolchainModel>> toolchainModels = new HashMap<>();
-        toolchainModels.put( "basic", Arrays.asList( new ToolchainModel(), new ToolchainModel() ) );
-        toolchainModels.put( "rare", Collections.singletonList( new ToolchainModel() ) );
-        executionRequest.setToolchains( toolchainModels );
-        when( session.getRequest() ).thenReturn( executionRequest );
+        toolchainModels.put("basic", Arrays.asList(new ToolchainModel(), new ToolchainModel()));
+        toolchainModels.put("rare", Collections.singletonList(new ToolchainModel()));
+        executionRequest.setToolchains(toolchainModels);
+        when(session.getRequest()).thenReturn(executionRequest);
 
-        List<Toolchain> toolchains = toolchainManager.getToolchains( session, "rare", null );
+        List<Toolchain> toolchains = toolchainManager.getToolchains(session, "rare", null);
 
-        assertEquals( 1, toolchains.size() );
+        assertEquals(1, toolchains.size());
     }
 
     @Test
-    public void testModelsAndFactory()
-    {
-        MavenSession session = mock( MavenSession.class );
+    void testModelsAndFactory() {
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest executionRequest = new DefaultMavenExecutionRequest();
         Map<String, List<ToolchainModel>> toolchainModels = new HashMap<>();
-        toolchainModels.put( "basic", Arrays.asList( new ToolchainModel(), new ToolchainModel() ) );
-        toolchainModels.put( "rare", Collections.singletonList( new ToolchainModel() ) );
-        executionRequest.setToolchains( toolchainModels );
-        when( session.getRequest() ).thenReturn( executionRequest );
+        toolchainModels.put("basic", Arrays.asList(new ToolchainModel(), new ToolchainModel()));
+        toolchainModels.put("rare", Collections.singletonList(new ToolchainModel()));
+        executionRequest.setToolchains(toolchainModels);
+        when(session.getRequest()).thenReturn(executionRequest);
 
-        List<Toolchain> toolchains = toolchainManager.getToolchains( session, "basic", null );
+        List<Toolchain> toolchains = toolchainManager.getToolchains(session, "basic", null);
 
-        assertEquals( 2, toolchains.size() );
+        assertEquals(2, toolchains.size());
     }
 
     @Test
-    public void testRequirements()
-        throws Exception
-    {
-        MavenSession session = mock( MavenSession.class );
+    void testRequirements() throws Exception {
+        MavenSession session = mock(MavenSession.class);
         MavenExecutionRequest executionRequest = new DefaultMavenExecutionRequest();
         Map<String, List<ToolchainModel>> toolchainModels = new HashMap<>();
-        toolchainModels.put( "basic", Arrays.asList( new ToolchainModel(), new ToolchainModel() ) );
-        toolchainModels.put( "rare", Collections.singletonList( new ToolchainModel() ) );
-        executionRequest.setToolchains( toolchainModels );
-        when( session.getRequest() ).thenReturn( executionRequest );
-        ToolchainPrivate basicPrivate = mock( ToolchainPrivate.class );
-        when( basicPrivate.matchesRequirements( ArgumentMatchers.<String, String>anyMap() ) ).thenReturn( false ).thenReturn( true );
-        when( toolchainFactory_basicType.createToolchain( isA( ToolchainModel.class ) ) ).thenReturn( basicPrivate );
+        toolchainModels.put("basic", Arrays.asList(new ToolchainModel(), new ToolchainModel()));
+        toolchainModels.put("rare", Collections.singletonList(new ToolchainModel()));
+        executionRequest.setToolchains(toolchainModels);
+        when(session.getRequest()).thenReturn(executionRequest);
+        ToolchainPrivate basicPrivate = mock(ToolchainPrivate.class);
+        when(basicPrivate.matchesRequirements(ArgumentMatchers.<String, String>anyMap()))
+                .thenReturn(false)
+                .thenReturn(true);
+        when(toolchainFactory_basicType.createToolchain(isA(ToolchainModel.class)))
+                .thenReturn(basicPrivate);
 
         List<Toolchain> toolchains =
-            toolchainManager.getToolchains( session, "basic", Collections.singletonMap( "key", "value" ) );
+                toolchainManager.getToolchains(session, "basic", Collections.singletonMap("key", "value"));
 
-        assertEquals( 1, toolchains.size() );
+        assertEquals(1, toolchains.size());
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainTest.java b/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainTest.java
index f335003..d6efd84 100644
--- a/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainTest.java
+++ b/maven-core/src/test/java/org/apache/maven/toolchain/DefaultToolchainTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,12 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
+package org.apache.maven.toolchain;
 
 import java.util.Collections;
 
@@ -35,123 +28,112 @@
 import org.mockito.MockitoAnnotations;
 import org.slf4j.Logger;
 
-public class DefaultToolchainTest
-{
-    private final Logger logger = mock( Logger.class );
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+class DefaultToolchainTest {
+    private final Logger logger = mock(Logger.class);
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        MockitoAnnotations.initMocks( this );
+    void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
     }
 
-    private DefaultToolchain newDefaultToolchain( ToolchainModel model )
-    {
-        return new DefaultToolchain( model, logger )
-        {
+    private DefaultToolchain newDefaultToolchain(ToolchainModel model) {
+        return new DefaultToolchain(model, logger) {
             @Override
-            public String findTool( String toolName )
-            {
+            public String findTool(String toolName) {
                 return null;
             }
         };
     }
 
-    private DefaultToolchain newDefaultToolchain( ToolchainModel model, String type )
-    {
-        return new DefaultToolchain( model, type, logger )
-        {
+    private DefaultToolchain newDefaultToolchain(ToolchainModel model, String type) {
+        return new DefaultToolchain(model, type, logger) {
             @Override
-            public String findTool( String toolName )
-            {
+            public String findTool(String toolName) {
                 return null;
             }
         };
     }
 
     @Test
-    public void testGetModel()
-    {
+    void testGetModel() {
         ToolchainModel model = new ToolchainModel();
-        DefaultToolchain toolchain = newDefaultToolchain( model );
-        assertEquals( model, toolchain.getModel() );
+        DefaultToolchain toolchain = newDefaultToolchain(model);
+        assertEquals(model, toolchain.getModel());
     }
 
     @Test
-    public void testGetType()
-    {
+    void testGetType() {
         ToolchainModel model = new ToolchainModel();
-        DefaultToolchain toolchain = newDefaultToolchain( model, "TYPE" );
-        assertEquals( "TYPE", toolchain.getType() );
+        DefaultToolchain toolchain = newDefaultToolchain(model, "TYPE");
+        assertEquals("TYPE", toolchain.getType());
 
-        model.setType( "MODEL_TYPE" );
-        toolchain = newDefaultToolchain( model );
-        assertEquals( "MODEL_TYPE", toolchain.getType() );
+        model.setType("MODEL_TYPE");
+        toolchain = newDefaultToolchain(model);
+        assertEquals("MODEL_TYPE", toolchain.getType());
     }
 
     @Test
-    public void testGetLogger()
-    {
+    void testGetLogger() {
         ToolchainModel model = new ToolchainModel();
-        DefaultToolchain toolchain = newDefaultToolchain( model );
-        assertEquals( logger, toolchain.getLog() );
+        DefaultToolchain toolchain = newDefaultToolchain(model);
+        assertEquals(logger, toolchain.getLog());
     }
 
     @Test
-    public void testMissingRequirementProperty()
-    {
+    void testMissingRequirementProperty() {
         ToolchainModel model = new ToolchainModel();
-        model.setType( "TYPE" );
-        DefaultToolchain toolchain = newDefaultToolchain( model );
+        model.setType("TYPE");
+        DefaultToolchain toolchain = newDefaultToolchain(model);
 
-        assertFalse( toolchain.matchesRequirements( Collections.singletonMap( "name", "John Doe" ) ) );
-        verify( logger ).debug( "Toolchain type:TYPE{} is missing required property: name" );
+        assertFalse(toolchain.matchesRequirements(Collections.singletonMap("name", "John Doe")));
+        verify(logger).debug("Toolchain {} is missing required property: {}", toolchain, "name");
     }
 
-
     @Test
-    public void testNonMatchingRequirementProperty()
-    {
+    void testNonMatchingRequirementProperty() {
         ToolchainModel model = new ToolchainModel();
-        model.setType( "TYPE" );
-        DefaultToolchain toolchain = newDefaultToolchain( model );
-        toolchain.addProvideToken( "name", RequirementMatcherFactory.createExactMatcher( "Jane Doe" ) );
+        model.setType("TYPE");
+        DefaultToolchain toolchain = newDefaultToolchain(model);
+        toolchain.addProvideToken("name", RequirementMatcherFactory.createExactMatcher("Jane Doe"));
 
-        assertFalse( toolchain.matchesRequirements( Collections.singletonMap( "name", "John Doe" ) ) );
-        verify( logger ).debug( "Toolchain type:TYPE{name = Jane Doe} doesn't match required property: name" );
+        assertFalse(toolchain.matchesRequirements(Collections.singletonMap("name", "John Doe")));
+        verify(logger).debug("Toolchain {} doesn't match required property: {}", toolchain, "name");
     }
 
-
     @Test
-    public void testEquals()
-    {
+    void testEquals() {
         ToolchainModel tm1 = new ToolchainModel();
-        tm1.setType( "jdk" );
-        tm1.addProvide( "version", "1.5" );
-        tm1.addProvide( "vendor", "sun" );
+        tm1.setType("jdk");
+        tm1.addProvide("version", "1.5");
+        tm1.addProvide("vendor", "sun");
         Xpp3Dom configuration1 = new Xpp3Dom("configuration");
-        Xpp3Dom jdkHome1 = new Xpp3Dom( "jdkHome" );
+        Xpp3Dom jdkHome1 = new Xpp3Dom("jdkHome");
         jdkHome1.setValue("${env.JAVA_HOME}");
-        configuration1.addChild( jdkHome1 );
-        tm1.setConfiguration( configuration1 );
+        configuration1.addChild(jdkHome1);
+        tm1.setConfiguration(configuration1);
 
         ToolchainModel tm2 = new ToolchainModel();
-        tm1.setType( "jdk" );
-        tm1.addProvide( "version", "1.4" );
-        tm1.addProvide( "vendor", "sun" );
+        tm1.setType("jdk");
+        tm1.addProvide("version", "1.4");
+        tm1.addProvide("vendor", "sun");
         Xpp3Dom configuration2 = new Xpp3Dom("configuration");
-        Xpp3Dom jdkHome2 = new Xpp3Dom( "jdkHome" );
+        Xpp3Dom jdkHome2 = new Xpp3Dom("jdkHome");
         jdkHome2.setValue("${env.JAVA_HOME}");
-        configuration2.addChild( jdkHome2 );
-        tm2.setConfiguration( configuration2 );
+        configuration2.addChild(jdkHome2);
+        tm2.setConfiguration(configuration2);
 
-        DefaultToolchain tc1 = new DefaultJavaToolChain( tm1, null );
-        DefaultToolchain tc2 = new DefaultJavaToolChain( tm2, null );
+        DefaultToolchain tc1 = new DefaultJavaToolChain(tm1, null);
+        DefaultToolchain tc2 = new DefaultJavaToolChain(tm2, null);
 
-        assertEquals( tc1, tc1 );
-        assertNotEquals( tc1, tc2 );
-        assertNotEquals( tc2, tc1 );
-        assertEquals( tc2, tc2 );
+        assertEquals(tc1, tc1);
+        assertNotEquals(tc1, tc2);
+        assertNotEquals(tc2, tc1);
+        assertEquals(tc2, tc2);
     }
 }
diff --git a/maven-core/src/test/java/org/apache/maven/toolchain/RequirementMatcherFactoryTest.java b/maven-core/src/test/java/org/apache/maven/toolchain/RequirementMatcherFactoryTest.java
index 6c167b1..7cb3b23 100644
--- a/maven-core/src/test/java/org/apache/maven/toolchain/RequirementMatcherFactoryTest.java
+++ b/maven-core/src/test/java/org/apache/maven/toolchain/RequirementMatcherFactoryTest.java
@@ -7,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -16,7 +16,6 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 package org.apache.maven.toolchain;
 
 import org.junit.jupiter.api.Test;
@@ -27,46 +26,40 @@
 
 /**
  *
- * @author mkleint
  */
-public class RequirementMatcherFactoryTest
-{
+class RequirementMatcherFactoryTest {
 
     /**
      * Test of createExactMatcher method, of class RequirementMatcherFactory.
      */
     @Test
-    public void testCreateExactMatcher()
-    {
+    void testCreateExactMatcher() {
         RequirementMatcher matcher;
-        matcher = RequirementMatcherFactory.createExactMatcher( "foo" );
-        assertFalse( matcher.matches( "bar" ) );
-        assertFalse( matcher.matches( "foobar" ) );
-        assertFalse( matcher.matches( "foob" ) );
-        assertTrue( matcher.matches( "foo" ) );
+        matcher = RequirementMatcherFactory.createExactMatcher("foo");
+        assertFalse(matcher.matches("bar"));
+        assertFalse(matcher.matches("foobar"));
+        assertFalse(matcher.matches("foob"));
+        assertTrue(matcher.matches("foo"));
     }
 
     /**
      * Test of createVersionMatcher method, of class RequirementMatcherFactory.
      */
     @Test
-    public void testCreateVersionMatcher()
-    {
+    void testCreateVersionMatcher() {
         RequirementMatcher matcher;
-        matcher = RequirementMatcherFactory.createVersionMatcher( "1.5.2" );
-        assertFalse( matcher.matches( "1.5" ) );
-        assertTrue( matcher.matches( "1.5.2" ) );
-        assertFalse( matcher.matches( "[1.4,1.5)" ) );
-        assertFalse( matcher.matches( "[1.5,1.5.2)" ) );
-        assertFalse( matcher.matches( "(1.5.2,1.6)" ) );
-        assertTrue( matcher.matches( "(1.4,1.5.2]" ) );
-        assertTrue( matcher.matches( "(1.5,)" ) );
-        assertEquals( "1.5.2", matcher.toString() );
+        matcher = RequirementMatcherFactory.createVersionMatcher("1.5.2");
+        assertFalse(matcher.matches("1.5"));
+        assertTrue(matcher.matches("1.5.2"));
+        assertFalse(matcher.matches("[1.4,1.5)"));
+        assertFalse(matcher.matches("[1.5,1.5.2)"));
+        assertFalse(matcher.matches("(1.5.2,1.6)"));
+        assertTrue(matcher.matches("(1.4,1.5.2]"));
+        assertTrue(matcher.matches("(1.5,)"));
+        assertEquals("1.5.2", matcher.toString());
 
         // Ensure it is not printed as 1.5.0
-        matcher = RequirementMatcherFactory.createVersionMatcher( "1.5" );
-        assertEquals( "1.5", matcher.toString() );
-
+        matcher = RequirementMatcherFactory.createVersionMatcher("1.5");
+        assertEquals("1.5", matcher.toString());
     }
-
 }
diff --git a/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml b/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml
index 5b51ce0..7214477 100644
--- a/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml
+++ b/maven-core/src/test/projects/lifecycle-executor/project-with-inheritance/pom.xml
@@ -58,7 +58,7 @@
     <plexusInteractivityVersion>1.0-alpha-6</plexusInteractivityVersion>
     <plexusInterpolationVersion>1.1</plexusInterpolationVersion>
     <plexusPluginManagerVersion>1.0-alpha-1</plexusPluginManagerVersion>
-    <plexusUtilsVersion>1.5.8</plexusUtilsVersion>
+    <plexusUtilsVersion>3.0.16</plexusUtilsVersion>
     <plexusJetty6Version>1.6</plexusJetty6Version>
     <plexusWebdavVersion>1.0</plexusWebdavVersion>
     <wagonVersion>1.0-beta-4</wagonVersion>
diff --git a/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml b/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml
index 5b51ce0..7214477 100644
--- a/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml
+++ b/maven-core/src/test/projects/plugin-manager/project-with-inheritance/pom.xml
@@ -58,7 +58,7 @@
     <plexusInteractivityVersion>1.0-alpha-6</plexusInteractivityVersion>
     <plexusInterpolationVersion>1.1</plexusInterpolationVersion>
     <plexusPluginManagerVersion>1.0-alpha-1</plexusPluginManagerVersion>
-    <plexusUtilsVersion>1.5.8</plexusUtilsVersion>
+    <plexusUtilsVersion>3.0.16</plexusUtilsVersion>
     <plexusJetty6Version>1.6</plexusJetty6Version>
     <plexusWebdavVersion>1.0</plexusWebdavVersion>
     <wagonVersion>1.0-beta-4</wagonVersion>
diff --git a/maven-core/src/test/projects/project-builder/MNG-7648/pom.xml b/maven-core/src/test/projects/project-builder/MNG-7648/pom.xml
new file mode 100644
index 0000000..15453de
--- /dev/null
+++ b/maven-core/src/test/projects/project-builder/MNG-7648/pom.xml
@@ -0,0 +1,48 @@
+<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>org.apache.maven.its</groupId>
+        <artifactId>parent</artifactId>
+        <version>0.1</version>
+    </parent>
+
+    <artifactId>location-tracking</artifactId>
+    <packaging>jar</packaging>
+
+    <repositories>
+        <repository>
+            <id>remote-repo</id>
+            <url>file://${basedir}/../../src/test/remote-repo</url>
+        </repository>
+    </repositories>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.maven.its</groupId>
+                <artifactId>bom</artifactId>
+                <version>0.1</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven.its</groupId>
+            <artifactId>a</artifactId>
+            <!-- version from BOM -->
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-clean-plugin</artifactId>
+                <!-- version from parent -->
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/maven-core/src/test/remote-repo/org/apache/maven/its/bom/0.1/bom-0.1.pom b/maven-core/src/test/remote-repo/org/apache/maven/its/bom/0.1/bom-0.1.pom
new file mode 100644
index 0000000..65973c8
--- /dev/null
+++ b/maven-core/src/test/remote-repo/org/apache/maven/its/bom/0.1/bom-0.1.pom
@@ -0,0 +1,21 @@
+<?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>org.apache.maven.its</groupId>
+    <artifactId>bom</artifactId>
+    <version>0.1</version>
+    <packaging>pom</packaging>
+
+    <name>Maven Integration Test :: Dummy BOM</name>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.maven.its</groupId>
+                <artifactId>a</artifactId>
+                <version>0.1</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+</project>
diff --git a/maven-core/src/test/remote-repo/org/apache/maven/its/bom/maven-metadata.xml b/maven-core/src/test/remote-repo/org/apache/maven/its/bom/maven-metadata.xml
new file mode 100644
index 0000000..0733309
--- /dev/null
+++ b/maven-core/src/test/remote-repo/org/apache/maven/its/bom/maven-metadata.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata>
+  <groupId>org.apache.maven.its</groupId>
+  <artifactId>bom</artifactId>
+  <version>0.1</version>
+  <versioning>
+    <versions>
+      <version>0.1</version>
+    </versions>
+  </versioning>
+</metadata>
diff --git a/maven-core/src/test/remote-repo/org/apache/maven/its/parent/0.1/parent-0.1.pom b/maven-core/src/test/remote-repo/org/apache/maven/its/parent/0.1/parent-0.1.pom
new file mode 100644
index 0000000..8b149f2
--- /dev/null
+++ b/maven-core/src/test/remote-repo/org/apache/maven/its/parent/0.1/parent-0.1.pom
@@ -0,0 +1,22 @@
+<?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>org.apache.maven.its</groupId>
+    <artifactId>parent</artifactId>
+    <version>0.1</version>
+    <packaging>pom</packaging>
+
+    <name>Maven Integration Test :: Dummy Parent</name>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <artifactId>maven-clean-plugin</artifactId>
+                    <version>0.1</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+</project>
diff --git a/maven-core/src/test/remote-repo/org/apache/maven/its/parent/maven-metadata.xml b/maven-core/src/test/remote-repo/org/apache/maven/its/parent/maven-metadata.xml
new file mode 100644
index 0000000..3a76b19
--- /dev/null
+++ b/maven-core/src/test/remote-repo/org/apache/maven/its/parent/maven-metadata.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metadata>
+  <groupId>org.apache.maven.its</groupId>
+  <artifactId>parent</artifactId>
+  <version>0.1</version>
+  <versioning>
+    <versions>
+      <version>0.1</version>
+    </versions>
+  </versioning>
+</metadata>
diff --git a/maven-core/src/test/remote-repo/org/apache/maven/maven-plugin-api/2.0/maven-plugin-api-2.0.pom b/maven-core/src/test/remote-repo/org/apache/maven/maven-plugin-api/2.0/maven-plugin-api-2.0.pom
index 5db5973..c1d5cc0 100644
--- a/maven-core/src/test/remote-repo/org/apache/maven/maven-plugin-api/2.0/maven-plugin-api-2.0.pom
+++ b/maven-core/src/test/remote-repo/org/apache/maven/maven-plugin-api/2.0/maven-plugin-api-2.0.pom
@@ -13,7 +13,7 @@
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
-      <version4.13.1</version>
+      <version>4.13.1</version>
       <scope>test</scope>
     </dependency>
   </dependencies>
diff --git a/maven-core/src/test/resources-project-builder/foo/sub/pom.xml b/maven-core/src/test/resources-project-builder/foo/sub/pom.xml
index 4217dcf..8d917d1 100644
--- a/maven-core/src/test/resources-project-builder/foo/sub/pom.xml
+++ b/maven-core/src/test/resources-project-builder/foo/sub/pom.xml
@@ -37,10 +37,6 @@
       <artifactId>plexus-container-default</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven.shared</groupId>
       <artifactId>maven-plugin-testing-harness</artifactId>
       <scope>test</scope>
diff --git a/maven-core/src/test/resources-project-builder/micromailer/pom.xml b/maven-core/src/test/resources-project-builder/micromailer/pom.xml
index 75b362f..545f470 100644
--- a/maven-core/src/test/resources-project-builder/micromailer/pom.xml
+++ b/maven-core/src/test/resources-project-builder/micromailer/pom.xml
@@ -78,8 +78,8 @@
 
     <dependency>
       <groupId>org.apache.velocity</groupId>
-      <artifactId>velocity</artifactId>
-      <version>1.5</version>
+      <artifactId>velocity-engine-core</artifactId>
+      <version>2.3</version>
       <type>jar</type>
       <scope>compile</scope>
     </dependency>
diff --git a/maven-core/src/test/resources-project-builder/plugin-interpolation-build/pom.xml b/maven-core/src/test/resources-project-builder/plugin-interpolation-build/pom.xml
new file mode 100644
index 0000000..5671815
--- /dev/null
+++ b/maven-core/src/test/resources-project-builder/plugin-interpolation-build/pom.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.apache.maven.its.build.plugins</groupId>
+  <artifactId>test</artifactId>
+  <version>1.0</version>
+
+  <name>MNG-7750</name>
+  <description>
+    Test build plugin and execution interpolation.
+  </description>
+
+  <properties>
+    <prop-outside>||${project.basedir}||</prop-outside>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>plugin-all-profiles</artifactId>
+        <executions>
+          <execution>
+            <id>Outside ||${project.basedir}||</id>
+            <configuration>
+              <plugin-all-profiles-out>Outside ||${project.basedir}||</plugin-all-profiles-out>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>activeProfile</id>
+      <properties>
+        <prop-active>||${project.basedir}||</prop-active>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>plugin-all-profiles</artifactId>
+            <executions>
+              <execution>
+                <id>Active all ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-all-profiles-in>Active all ||${project.basedir}||</plugin-all-profiles-in>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <artifactId>only-active-profile</artifactId>
+            <executions>
+              <execution>
+                <id>Active only ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-in-active-profile-only>Active only ||${project.basedir}||</plugin-in-active-profile-only>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+
+    <profile>
+      <id>inactiveProfile</id>
+      <properties>
+        <prop-inactive>||${project.basedir}||</prop-inactive>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>plugin-all-profiles</artifactId>
+            <executions>
+              <execution>
+                <id>Inactive all ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-all-profiles-ina>Inactive all ||${project.basedir}||</plugin-all-profiles-ina>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <artifactId>only-inactive-profile</artifactId>
+            <executions>
+              <execution>
+                <id>Inactive only ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-in-inactive-only>Inactive only ||${project.basedir}||</plugin-in-inactive-only>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+
+  </profiles>
+
+</project>
diff --git a/maven-core/src/test/resources-project-builder/plugin-interpolation-reporting/pom.xml b/maven-core/src/test/resources-project-builder/plugin-interpolation-reporting/pom.xml
new file mode 100644
index 0000000..aeb6f7d
--- /dev/null
+++ b/maven-core/src/test/resources-project-builder/plugin-interpolation-reporting/pom.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.apache.maven.its.reporting.plugins</groupId>
+  <artifactId>test</artifactId>
+  <version>1.0</version>
+
+  <name>MNG-7750</name>
+  <description>
+    Test reporting plugin and reportSet interpolation.
+  </description>
+
+  <properties>
+    <prop-outside>||${project.basedir}||</prop-outside>
+  </properties>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <artifactId>plugin-all-profiles</artifactId>
+        <reportSets>
+          <reportSet>
+            <id>Outside ||${project.basedir}||</id>
+            <configuration>
+              <plugin-all-profiles-out>Outside ||${project.basedir}||</plugin-all-profiles-out>
+            </configuration>
+          </reportSet>
+        </reportSets>
+      </plugin>
+    </plugins>
+  </reporting>
+
+  <profiles>
+    <profile>
+      <id>activeProfile</id>
+      <properties>
+        <prop-active>||${project.basedir}||</prop-active>
+      </properties>
+      <reporting>
+        <plugins>
+          <plugin>
+            <artifactId>plugin-all-profiles</artifactId>
+            <reportSets>
+              <reportSet>
+                <id>Active all ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-all-profiles-in>Active all ||${project.basedir}||</plugin-all-profiles-in>
+                </configuration>
+              </reportSet>
+            </reportSets>
+          </plugin>
+          <plugin>
+            <artifactId>only-active-profile</artifactId>
+            <reportSets>
+              <reportSet>
+                <id>Active only ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-in-active-profile-only>Active only ||${project.basedir}||</plugin-in-active-profile-only>
+                </configuration>
+              </reportSet>
+            </reportSets>
+          </plugin>
+        </plugins>
+      </reporting>
+    </profile>
+
+    <profile>
+      <id>inactiveProfile</id>
+      <properties>
+        <prop-inactive>||${project.basedir}||</prop-inactive>
+      </properties>
+      <reporting>
+        <plugins>
+          <plugin>
+            <artifactId>plugin-all-profiles</artifactId>
+            <reportSets>
+              <reportSet>
+                <id>Inactive all ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-all-profiles-ina>Inactive all ||${project.basedir}||</plugin-all-profiles-ina>
+                </configuration>
+              </reportSet>
+            </reportSets>
+          </plugin>
+          <plugin>
+            <artifactId>only-inactive-profile</artifactId>
+            <reportSets>
+              <reportSet>
+                <id>Inactive only ||${project.basedir}||</id>
+                <configuration>
+                  <plugin-in-inactive-only>Inactive only ||${project.basedir}||</plugin-in-inactive-only>
+                </configuration>
+              </reportSet>
+            </reportSets>
+          </plugin>
+        </plugins>
+      </reporting>
+    </profile>
+
+  </profiles>
+
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar
new file mode 100644
index 0000000..b99c937
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar.sha1
new file mode 100644
index 0000000..9e50b25
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.jar.sha1
@@ -0,0 +1 @@
+760c711c71588bc273d3e56d196d720a7678cd93
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom
new file mode 100644
index 0000000..c46b27f
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom
@@ -0,0 +1,31 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>commons-logging</groupId>
+  <artifactId>commons-logging</artifactId>
+  <name>Logging</name>
+  <version>1.0.3</version>
+  <description>Commons Logging</description>
+  <url>http://jakarta.apache.org/commons/logging/</url>
+  <inceptionYear>2001</inceptionYear>
+  <build />
+  <dependencies>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.6</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>logkit</groupId>
+      <artifactId>logkit</artifactId>
+      <version>1.0.1</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.7</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom.sha1
new file mode 100644
index 0000000..d135fea
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.3/commons-logging-1.0.3.pom.sha1
@@ -0,0 +1 @@
+b7de43bb310eb1dbfd00a34cec30500fa13cb577  /home/projects/maven/repository-staging/to-ibiblio/maven2/commons-logging/commons-logging/1.0.3/commons-logging-1.0.3.pom
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4-javadoc-resources.jar.lastUpdated b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4-javadoc-resources.jar.lastUpdated
new file mode 100644
index 0000000..6dcdbc7
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4-javadoc-resources.jar.lastUpdated
@@ -0,0 +1,4 @@
+#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
+#Thu Sep 24 16:40:08 CEST 2020
+https\://repo.maven.apache.org/maven2/.lastUpdated=1600958408640
+https\://repo.maven.apache.org/maven2/.error=
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar
new file mode 100644
index 0000000..b73a80f
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar.sha1
new file mode 100644
index 0000000..7e0a60e
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.jar.sha1
@@ -0,0 +1 @@
+f029a2aefe2b3e1517573c580f948caac31b1056
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom
new file mode 100644
index 0000000..7c1017d
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom
@@ -0,0 +1,165 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>commons-logging</groupId>
+  <artifactId>commons-logging</artifactId>
+  <name>Logging</name>
+  <version>1.0.4</version>
+  <description>Commons Logging is a thin adapter allowing configurable bridging to other,
+    well known logging systems.</description>
+  <url>http://jakarta.apache.org/commons/logging/</url>
+  <issueManagement>
+    <url>http://issues.apache.org/bugzilla/</url>
+  </issueManagement>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <configuration>
+          <address>commons-dev@jakarta.apache.org</address>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Commons Dev List</name>
+      <subscribe>commons-dev-subscribe@jakarta.apache.org</subscribe>
+      <unsubscribe>commons-dev-unsubscribe@jakarta.apache.org</unsubscribe>
+      <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-dev@jakarta.apache.org</archive>
+    </mailingList>
+    <mailingList>
+      <name>Commons User List</name>
+      <subscribe>commons-user-subscribe@jakarta.apache.org</subscribe>
+      <unsubscribe>commons-user-unsubscribe@jakarta.apache.org</unsubscribe>
+      <archive>http://nagoya.apache.org/eyebrowse/SummarizeList?listName=commons-user@jakarta.apache.org</archive>
+    </mailingList>
+  </mailingLists>
+  <developers>
+    <developer>
+      <id>morgand</id>
+      <name>Morgan Delagrange</name>
+      <email>morgand at apache dot org</email>
+      <organization>Apache</organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>rwaldhoff</id>
+      <name>Rodney Waldhoff</name>
+      <email>rwaldhoff at apache org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>craigmcc</id>
+      <name>Craig McClanahan</name>
+      <email>craigmcc at apache org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>sanders</id>
+      <name>Scott Sanders</name>
+      <email>sanders at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>rdonkin</id>
+      <name>Robert Burrell Donkin</name>
+      <email>rdonkin at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>donaldp</id>
+      <name>Peter Donald</name>
+      <email>donaldp at apache dot org</email>
+      <organization></organization>
+    </developer>
+    <developer>
+      <id>costin</id>
+      <name>Costin Manolache</name>
+      <email>costin at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>rsitze</id>
+      <name>Richard Sitze</name>
+      <email>rsitze at apache dot org</email>
+      <organization>Apache Software Foundation</organization>
+    </developer>
+    <developer>
+      <id>baliuka</id>
+      <name>Juozas Baliuka</name>
+      <email>baliuka@apache.org</email>
+      <organization></organization>
+      <roles>
+        <role>Java Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>/LICENSE.txt</url>
+    </license>
+  </licenses>
+  <scm>
+    <connection>scm:cvs:pserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/logging</connection>
+    <url>http://cvs.apache.org/viewcvs/jakarta-commons/logging/</url>
+  </scm>
+  <organization>
+    <name>The Apache Software Foundation</name>
+    <url>http://jakarta.apache.org</url>
+  </organization>
+  <build>
+    <sourceDirectory>src/java</sourceDirectory>
+    <testSourceDirectory>src/test</testSourceDirectory>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <includes>
+            <include>**/AvalonLoggerTest.java</include>
+          </includes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.6</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>logkit</groupId>
+      <artifactId>logkit</artifactId>
+      <version>1.0.1</version>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.7</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>avalon-framework</groupId>
+      <artifactId>avalon-framework</artifactId>
+      <version>4.1.3</version>
+      <optional>true</optional>
+    </dependency>
+  </dependencies>
+  <distributionManagement>
+    <repository>
+      <id>default</id>
+      <name>Default Repository</name>
+      <url>file:///www/jakarta.apache.org/builds/jakarta-commons/logging/</url>
+    </repository>
+    <site>
+      <id>default</id>
+      <name>Default Site</name>
+      <url>scp://jakarta.apache.org//www/jakarta.apache.org/commons/logging/</url>
+    </site>
+  </distributionManagement>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom.sha1
new file mode 100644
index 0000000..92265fb
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/commons-logging/1.0.4/commons-logging-1.0.4.pom.sha1
@@ -0,0 +1 @@
+7d32e7520b801cabc3dc704d2afe59d020d00c45  /home/projects/maven/repository-staging/to-ibiblio/maven2/commons-logging/commons-logging/1.0.4/commons-logging-1.0.4.pom
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom
new file mode 100644
index 0000000..9593e9e
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Copyright 2005-2006 The Apache Software Foundation.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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>
+
+  <!-- Shared parent. Doesn't define a lot of things about Apache like general mailing lists, but does
+       define the settings common to all projects at Apache -->
+  <groupId>org.apache</groupId>
+  <artifactId>apache</artifactId>
+  <version>3</version>
+  <packaging>pom</packaging>
+  <name>The Apache Software Foundation</name>
+  <description>
+    The Apache Software Foundation provides support for the Apache community of open-source software projects.
+    The Apache projects are characterized by a collaborative, consensus based development process, an open and
+    pragmatic software license, and a desire to create high quality software that leads the way in its field.
+    We consider ourselves not simply a group of projects sharing a server, but rather a community of developers
+    and users.
+  </description>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <organization>
+    <name>Apache Software Foundation</name>
+    <url>http://www.apache.org/</url>
+  </organization>
+  <url>http://www.apache.org/</url>
+  <repositories>
+    <repository>
+      <id>apache.snapshots</id>
+      <name>Apache Snapshot Repository</name>
+      <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+  <distributionManagement>
+    <!-- Site omitted - each project must provide their own -->
+    <repository>
+      <id>apache.releases</id>
+      <name>Apache Release Distribution Repository</name>
+      <url>scp://people.apache.org/www/people.apache.org/repo/m2-ibiblio-rsync-repository</url>
+    </repository>
+    <snapshotRepository>
+      <id>apache.snapshots</id>
+      <name>Apache Development Snapshot Repository</name>
+      <url>scp://people.apache.org/www/people.apache.org/repo/m2-snapshot-repository</url>
+    </snapshotRepository>
+  </distributionManagement>
+  <mailingLists>
+    <mailingList>
+      <name>Apache Announce List</name>
+      <subscribe>announce-subscribe@apache.org</subscribe>
+      <unsubscribe>announce-unsubscribe@apache.org</unsubscribe>
+      <post>announce@apache.org</post>
+      <archive>http://mail-archives.apache.org/mod_mbox/www-announce/</archive>
+    </mailingList>
+  </mailingLists>
+</project>
+
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom.md5
new file mode 100644
index 0000000..b9d0ea1
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom.md5
@@ -0,0 +1 @@
+c857ebbb5f303f435495e40e6c9e45a2
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom.sha1
new file mode 100644
index 0000000..ffb57bb
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/apache/3/apache-3.pom.sha1
@@ -0,0 +1 @@
+1bc0010136a890e2fd38d901a0b7ecdf0e3f9871
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar
new file mode 100644
index 0000000..5bc9c06
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar.md5
new file mode 100644
index 0000000..5ff89e8
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar.md5
@@ -0,0 +1 @@
+430da483dcfb2964a9dcd619c29a6c78
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar.sha1
new file mode 100644
index 0000000..a341880
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.jar.sha1
@@ -0,0 +1 @@
+ea9e3f3fdc25f386d5f9ac861a55b6c3bb773d91
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom
new file mode 100644
index 0000000..4c344c8
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<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">
+  <parent>
+    <artifactId>maven-parent</artifactId>
+    <groupId>org.apache.maven</groupId>
+    <version>5</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.maven.artifact</groupId>
+  <artifactId>maven-artifact</artifactId>
+  <version>3.0-SNAPSHOT</version>
+  <name>Maven Artifact</name>
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/maven/artifact/trunk</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/artifact/trunk</developerConnection>
+    <url>http://svn.apache.org/viewcvs.cgi/maven/artifact/trunk</url>
+  </scm>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+      <version>1.4.5</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-container-default</artifactId>
+      <version>1.0-alpha-32</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-active-collections</artifactId>
+      <version>1.0-beta-1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-provider-api</artifactId>
+      <version>1.0-beta-2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-file</artifactId>
+      <version>1.0-beta-2</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>easymock</groupId>
+      <artifactId>easymock</artifactId>
+      <version>1.2_Java1.3</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.modello</groupId>
+        <artifactId>modello-maven-plugin</artifactId>
+        <version>1.0-alpha-17</version>
+        <configuration>
+          <version>1.0.0</version>
+          <model>src/main/mdo/metadata.mdo</model>
+        </configuration>
+        <executions>
+          <execution>
+            <id>site-docs</id>
+            <phase>pre-site</phase>
+            <goals>
+              <goal>xdoc</goal>
+              <goal>xsd</goal>
+            </goals>
+          </execution>
+          <execution>
+            <id>standard</id>
+            <goals>
+              <goal>java</goal>
+              <goal>xpp3-reader</goal>
+              <goal>xpp3-writer</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/testutils/**</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom.md5
new file mode 100644
index 0000000..11e3536
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom.md5
@@ -0,0 +1 @@
+794377b5385c68c660ee9ca26e6b5cf1
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom.sha1
new file mode 100644
index 0000000..4beb688
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/artifact/maven-artifact/3.0-SNAPSHOT/maven-artifact-3.0-SNAPSHOT.pom.sha1
@@ -0,0 +1 @@
+358254e73f075bcfb9d587d0da553083abd0cc45
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.jar b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.jar
new file mode 100644
index 0000000..0272ee3
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom
new file mode 100644
index 0000000..fee83c9
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom
@@ -0,0 +1,73 @@
+<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>
+  <groupId>org.apache.maven.core.test</groupId>
+  <artifactId>test-extension</artifactId>
+  <packaging>jar</packaging>
+  <version>1</version>
+  <name>test-extension</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven.artifact</groupId>
+      <artifactId>maven-artifact</artifactId>
+      <version>3.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+      <version>1.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus</artifactId>
+      <version>1.0.11</version>
+      <type>pom</type>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-component-api</artifactId>
+      <version>1.0-alpha-16</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-container-default</artifactId>
+      <version>1.0-alpha-16</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.2-beta-2-SNAPSHOT</version>
+        <executions>
+          <execution>
+            <id>repo-assembly</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <descriptors>
+                <descriptor>repo.xml</descriptor>
+              </descriptors>
+              <finalName>test-extension</finalName>
+              <appendAssemblyId>true</appendAssemblyId>
+              <outputDirectory>${pom.basedir}/../../resources/org/apache/maven/extension</outputDirectory>
+              <ignoreDirFormatExtensions>true</ignoreDirFormatExtensions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <distributionManagement>
+    <repository>
+      <id>dummy</id>
+      <url>file:///tmp/dummy-repo</url>
+    </repository>
+  </distributionManagement>
+
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom.md5
new file mode 100644
index 0000000..ad06718
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom.md5
@@ -0,0 +1 @@
+e8f6e0f4ef9c2ed3fb185ef44165fb40
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom.sha1
new file mode 100644
index 0000000..6065ee0
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-extension/1/test-extension-1.pom.sha1
@@ -0,0 +1 @@
+88ace5d78ee32fa0ce59714a4a42a73af3b52bd3
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.jar b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.jar
new file mode 100644
index 0000000..04fe384
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom
new file mode 100644
index 0000000..01aaa42
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom
@@ -0,0 +1,44 @@
+<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>
+  <groupId>org.apache.maven.core.test</groupId>
+  <artifactId>test-lifecycle-and-artifactHandler</artifactId>
+  <packaging>jar</packaging>
+  <version>1</version>
+  <name>test-lifecycle-and-artifactHandler</name>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.2-beta-2-SNAPSHOT</version>
+        <executions>
+          <execution>
+            <id>repo-assembly</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+            <configuration>
+              <descriptors>
+                <descriptor>repo.xml</descriptor>
+              </descriptors>
+              <finalName>test-extension</finalName>
+              <appendAssemblyId>true</appendAssemblyId>
+              <outputDirectory>${pom.basedir}/../../resources/org/apache/maven/extension</outputDirectory>
+              <ignoreDirFormatExtensions>true</ignoreDirFormatExtensions>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+  <distributionManagement>
+    <repository>
+      <id>dummy</id>
+      <url>file:///tmp/dummy-repo</url>
+    </repository>
+  </distributionManagement>
+
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom.md5
new file mode 100644
index 0000000..01d5194
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom.md5
@@ -0,0 +1 @@
+7f10427af029d20cbea57c21d1aec65e
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom.sha1
new file mode 100644
index 0000000..dac1e45
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/core/test/test-lifecycle-and-artifactHandler/1/test-lifecycle-and-artifactHandler-1.pom.sha1
@@ -0,0 +1 @@
+ed98c808239aefb0ec51a8b9e96f191da7fd92e6
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom
new file mode 100644
index 0000000..b41037f
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom
@@ -0,0 +1,304 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ Copyright 2005-2006 The Apache Software Foundation.
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<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>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>3</version>
+    <relativePath>../asf/pom.xml</relativePath>
+  </parent>
+  <groupId>org.apache.maven</groupId>
+  <artifactId>maven-parent</artifactId>
+  <version>4</version>
+  <packaging>pom</packaging>
+  <name>Apache Maven</name>
+  <description>
+    Maven is a software project management and comprehension tool. Based on the concept of a project object model
+    (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
+  </description>
+  <url>http://maven.apache.org/</url>
+  <issueManagement>
+    <system>jira</system>
+    <url>http://jira.codehaus.org/browse/MPA</url>
+  </issueManagement>
+  <ciManagement>
+    <system>continuum</system>
+    <url>http://maven.zones.apache.org:8080/continuum</url>
+    <notifiers>
+      <notifier>
+        <type>mail</type>
+        <configuration>
+          <address>notifications@maven.apache.org</address>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2002</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Maven Announcements List</name>
+      <post>announce@maven.apache.org</post>
+      <subscribe>announce-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>announce-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-announce/</archive>
+    </mailingList>
+    <mailingList>
+      <name>Maven Issues List</name>
+      <post>issues@maven.apache.org</post>
+      <subscribe>issues-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>issues-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-issues/</archive>
+    </mailingList>
+    <mailingList>
+      <name>Maven Notifications List</name>
+      <post>notifications@maven.apache.org</post>
+      <subscribe>notifications-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>notifications-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-notifications/</archive>
+    </mailingList>
+  </mailingLists>
+
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@maven.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Chair</role>
+      </roles>
+      <timezone>-5</timezone>
+    </developer>
+    <developer>
+      <id>brett</id>
+      <name>Brett Porter</name>
+      <email>brett@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+10</timezone>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>kenney</id>
+      <name>Kenney Westerhof</name>
+      <email>kenney@apache.org</email>
+      <organization>Neonics</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>snicoll</id>
+      <name>Stephane Nicoll</name>
+      <email>snicoll@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>vmassol</id>
+      <name>Vincent Massol</name>
+      <email>vmassol@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>fgiust</id>
+      <name>Fabrizio Giustina</name>
+      <email>fgiust@apache.org</email>
+      <organization>openmind</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>epunzalan</id>
+      <name>Edwin Punzalan</name>
+      <email>epunzalan@mergere.com</email>
+      <organization>Mergere</organization>
+      <roles>
+        <role>Committer</role>
+      </roles>
+      <timezone>+8</timezone>
+    </developer>
+    <developer>
+      <id>mperham</id>
+      <name>Mike Perham</name>
+      <email>mperham@gmail.com</email>
+      <organization>IBM</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-6</timezone>
+    </developer>
+    <developer>
+      <id>jdcasey</id>
+      <name>John Casey</name>
+      <email>jdcasey@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-5</timezone>
+    </developer>
+    <developer>
+      <id>trygvis</id>
+      <name>Trygve Laugstol</name>
+      <email>trygvis@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>vsiveton</id>
+      <name>Vincent Siveton</name>
+      <email>vsiveton@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-5</timezone>
+    </developer>
+    <developer>
+      <id>carlos</id>
+      <name>Carlos Sanchez</name>
+      <email>carlos@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>dennisl</id>
+      <name>Dennis Lundberg</name>
+      <email>dennisl@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+  </developers>
+
+  <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scp://people.apache.org/www/maven.apache.org</url>
+    </site>
+  </distributionManagement>
+
+<!-- Disabled until projects have been made to comply
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>cpd-check</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+-->
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-surefire-report-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-checkstyle-plugin</artifactId>
+        <configuration>
+          <configLocation>http://svn.apache.org/repos/asf/maven/plugins/trunk/maven-checkstyle-plugin/src/main/resources/config/maven_checks.xml</configLocation>
+          <headerLocation>http://svn.apache.org/repos/asf/maven/plugins/trunk/maven-checkstyle-plugin/src/main/resources/config/maven-header.txt</headerLocation>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>cobertura-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>taglist-maven-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jxr-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <links>
+            <link>http://java.sun.com/j2ee/1.4/docs/api</link>
+            <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
+            <link>http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/</link>
+            <link>http://jakarta.apache.org/commons/dbcp/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/fileupload/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/httpclient/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/logging/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/pool/apidocs/</link>
+            <link>http://www.junit.org/junit/javadoc/</link>
+            <link>http://logging.apache.org/log4j/docs/api/</link>
+            <link>http://jakarta.apache.org/regexp/apidocs/</link>
+            <link>http://jakarta.apache.org/velocity/api/</link>
+          </links>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/maven/pom/maven/tags/maven-parent-4</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/pom/maven/tags/maven-parent-4</developerConnection>
+    <url>http://svn.apache.org/viewvc/maven/pom/maven/tags/maven-parent-4</url>
+  </scm>
+</project>
+
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom.md5
new file mode 100644
index 0000000..9c41764
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom.md5
@@ -0,0 +1 @@
+2a4e926f3a76c6e74b0b126f513ad4e7
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom.sha1
new file mode 100644
index 0000000..b6caacf
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/4/maven-parent-4.pom.sha1
@@ -0,0 +1 @@
+0fc039b0bd4d17d7c147a30e1d83994629c5297c
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom
new file mode 100644
index 0000000..a512366
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom
@@ -0,0 +1,466 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<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>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>3</version>
+    <relativePath>../asf/pom.xml</relativePath>
+  </parent>
+  <groupId>org.apache.maven</groupId>
+  <artifactId>maven-parent</artifactId>
+  <version>5</version>
+  <packaging>pom</packaging>
+  <name>Apache Maven</name>
+  <description>
+    Maven is a software project management and comprehension tool. Based on the concept of a project object model
+    (POM), Maven can manage a project's build, reporting and documentation from a central piece of information.
+  </description>
+  <url>http://maven.apache.org/</url>
+  <issueManagement>
+    <system>jira</system>
+    <url>http://jira.codehaus.org/browse/MPA</url>
+  </issueManagement>
+  <ciManagement>
+    <system>continuum</system>
+    <url>http://maven.zones.apache.org/continuum</url>
+    <notifiers>
+      <notifier>
+        <type>mail</type>
+        <configuration>
+          <address>notifications@maven.apache.org</address>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2002</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Maven Announcements List</name>
+      <post>announce@maven.apache.org</post>
+      <subscribe>announce-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>announce-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-announce/</archive>
+    </mailingList>
+    <mailingList>
+      <name>Maven Issues List</name>
+      <post>issues@maven.apache.org</post>
+      <subscribe>issues-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>issues-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-issues/</archive>
+    </mailingList>
+    <mailingList>
+      <name>Maven Notifications List</name>
+      <post>notifications@maven.apache.org</post>
+      <subscribe>notifications-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>notifications-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-notifications/</archive>
+    </mailingList>
+  </mailingLists>
+
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@maven.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Chair</role>
+      </roles>
+      <timezone>-5</timezone>
+    </developer>
+    <developer>
+      <id>brett</id>
+      <name>Brett Porter</name>
+      <email>brett@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+10</timezone>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>kenney</id>
+      <name>Kenney Westerhof</name>
+      <email>kenney@apache.org</email>
+      <organization>Neonics</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>snicoll</id>
+      <name>Stephane Nicoll</name>
+      <email>snicoll@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>vmassol</id>
+      <name>Vincent Massol</name>
+      <email>vmassol@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>fgiust</id>
+      <name>Fabrizio Giustina</name>
+      <email>fgiust@apache.org</email>
+      <organization>openmind</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>epunzalan</id>
+      <name>Edwin Punzalan</name>
+      <email>epunzalan@mergere.com</email>
+      <organization>Mergere</organization>
+      <roles>
+        <role>Committer</role>
+      </roles>
+      <timezone>+8</timezone>
+    </developer>
+    <developer>
+      <id>mperham</id>
+      <name>Mike Perham</name>
+      <email>mperham@gmail.com</email>
+      <organization>IBM</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-6</timezone>
+    </developer>
+    <developer>
+      <id>jdcasey</id>
+      <name>John Casey</name>
+      <email>jdcasey@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-5</timezone>
+    </developer>
+    <developer>
+      <id>trygvis</id>
+      <name>Trygve Laugstol</name>
+      <email>trygvis@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>vsiveton</id>
+      <name>Vincent Siveton</name>
+      <email>vsiveton@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-5</timezone>
+    </developer>
+    <developer>
+      <id>carlos</id>
+      <name>Carlos Sanchez</name>
+      <email>carlos@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>dennisl</id>
+      <name>Dennis Lundberg</name>
+      <email>dennisl@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>aheritier</id>
+      <name>Arnaud Heritier</name>
+      <email>aheritier@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+1</timezone>
+    </developer>
+    <developer>
+      <id>handyande</id>
+      <name>Andrew Williams</name>
+      <email>handyande@apache.org</email>
+      <roles>
+        <role>Committer</role>
+      </roles>
+      <timezone>0</timezone>
+    </developer>
+    <developer>
+      <id>jtolentino</id>
+      <name>Ernesto Tolentino Jr.</name>
+      <email>jtolentino@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>+8</timezone>
+    </developer>
+    <developer>
+      <id>joakime</id>
+      <name>Joakim Erdfelt</name>
+      <email>joakime@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-5</timezone>
+    </developer>
+    <developer>
+      <id>jmcconnell</id>
+      <name>Jesse McConnell</name>
+      <email>jmcconnell@apache.org</email>
+      <organization>ASF</organization>
+      <roles>
+        <role>PMC Member</role>
+      </roles>
+      <timezone>-6</timezone>
+    </developer>
+    <developer>
+      <id>wsmoak</id>
+      <name>Wendy Smoak</name>
+      <email>wsmoak@apache.org</email>
+      <roles>
+        <role>Committer</role>
+      </roles>
+      <timezone>-7</timezone>
+    </developer>
+
+  </developers>
+
+  <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scp://people.apache.org/www/maven.apache.org</url>
+    </site>
+  </distributionManagement>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-release-plugin</artifactId>
+          <version>2.0-beta-4</version>
+          <configuration>
+            <!-- This element will be overridden by children -->
+            <tagBase>https://svn.apache.org/repos/asf/maven/pom/tags</tagBase>
+            <useReleaseProfile>false</useReleaseProfile>
+            <goals>deploy</goals>
+            <arguments>-Prelease</arguments>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>ci</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-pmd-plugin</artifactId>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>cpd-check</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <profile>
+      <id>reporting</id>
+      <reporting>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-report-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-checkstyle-plugin</artifactId>
+            <configuration>
+              <configLocation>http://svn.apache.org/repos/asf/maven/plugins/trunk/maven-checkstyle-plugin/src/main/resources/config/maven_checks.xml</configLocation>
+              <headerLocation>http://svn.apache.org/repos/asf/maven/plugins/trunk/maven-checkstyle-plugin/src/main/resources/config/maven-header.txt</headerLocation>
+            </configuration>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-pmd-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>cobertura-maven-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>taglist-maven-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-jxr-plugin</artifactId>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <configuration>
+              <links>
+                <link>http://java.sun.com/j2ee/1.4/docs/api</link>
+                <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
+                <link>http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/</link>
+                <link>http://jakarta.apache.org/commons/dbcp/apidocs/</link>
+                <link>http://jakarta.apache.org/commons/fileupload/apidocs/</link>
+                <link>http://jakarta.apache.org/commons/httpclient/apidocs/</link>
+                <link>http://jakarta.apache.org/commons/logging/apidocs/</link>
+                <link>http://jakarta.apache.org/commons/pool/apidocs/</link>
+                <link>http://www.junit.org/junit/javadoc/</link>
+                <link>http://logging.apache.org/log4j/docs/api/</link>
+                <link>http://jakarta.apache.org/regexp/apidocs/</link>
+                <link>http://jakarta.apache.org/velocity/api/</link>
+              </links>
+            </configuration>
+          </plugin>
+        </plugins>
+      </reporting>
+    </profile>
+    <profile>
+      <id>release</id>
+      <build>
+        <plugins>
+          <!-- We want to sign the artifact, the POM, and all attached artifacts -->
+          <plugin>
+            <artifactId>maven-gpg-plugin</artifactId>
+            <version>1.0-alpha-1</version>
+            <configuration>
+              <passphrase>${gpg.passphrase}</passphrase>
+            </configuration>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>sign</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <!-- We want to deploy the artifact to a staging location for perusal -->
+          <plugin>
+            <inherited>true</inherited>
+            <artifactId>maven-deploy-plugin</artifactId>
+            <version>2.3</version>
+            <configuration>
+              <altDeploymentRepository>${deploy.altRepository}</altDeploymentRepository>
+              <updateReleaseInfo>true</updateReleaseInfo>
+            </configuration>
+          </plugin>
+          <!-- We want to package up license resources in the JARs produced -->
+          <plugin>
+            <artifactId>maven-remote-resources-plugin</artifactId>
+            <version>1.0-alpha-1</version>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>process</goal>
+                </goals>
+                <configuration>
+                  <resourceBundles>
+                    <resourceBundle>org.apache:apache-jar-resource-bundle:1.0</resourceBundle>
+                  </resourceBundles>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-source-plugin</artifactId>
+            <version>2.0.2</version>
+            <executions>
+              <execution>
+                <id>attach-sources</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-javadoc-plugin</artifactId>
+            <version>2.2</version>
+            <executions>
+              <execution>
+                <id>attach-javadocs</id>
+                <goals>
+                  <goal>jar</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+
+  <scm>
+    <connection>scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/maven-parent-5</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/pom/tags/maven-parent-5</developerConnection>
+    <url>https://svn.apache.org/repos/asf/maven/pom/tags/maven-parent-5</url>
+  </scm>
+</project>
+
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom.md5
new file mode 100644
index 0000000..27ba3aa
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom.md5
@@ -0,0 +1 @@
+4da85635ce64dbec5b00232d5bb26453
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom.sha1
new file mode 100644
index 0000000..5d7a3eb
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/maven-parent/5/maven-parent-5.pom.sha1
@@ -0,0 +1 @@
+5c1ab38decaca1ccd08294aeab135047ebbae00d
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar
new file mode 100644
index 0000000..79fcf22
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar.md5
new file mode 100644
index 0000000..60aecbc
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar.md5
@@ -0,0 +1 @@
+f41eb4e07a725eea3332743a29057855
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar.sha1
new file mode 100644
index 0000000..e3f0510
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.jar.sha1
@@ -0,0 +1 @@
+abd1c9ace6e87c94a4b91f5176aeb09d954b23a3
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom
new file mode 100644
index 0000000..dca027b
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom
@@ -0,0 +1,21 @@
+<?xml version="1.0"?><project>
+  <parent>
+    <artifactId>wagon</artifactId>
+    <groupId>org.apache.maven.wagon</groupId>
+    <version>1.0-beta-2</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>wagon-provider-api</artifactId>
+  <name>Maven Wagon API</name>
+  <version>1.0-beta-2</version>
+  <description>Maven Wagon API that defines the contract between different Wagon implementations</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+  </dependencies>
+  <distributionManagement>
+    <status>deployed</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom.md5
new file mode 100644
index 0000000..0f10b3f
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom.md5
@@ -0,0 +1 @@
+97f0a0bd0b81520ccccf8736b1fe380c
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom.sha1
new file mode 100644
index 0000000..56b9559
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-provider-api/1.0-beta-2/wagon-provider-api-1.0-beta-2.pom.sha1
@@ -0,0 +1 @@
+8b3013d0754edbeb694831ddf1c5d1a0019ee042
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom
new file mode 100644
index 0000000..768e3e9
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <artifactId>wagon</artifactId>
+    <groupId>org.apache.maven.wagon</groupId>
+    <version>1.0-beta-2</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>wagon-providers</artifactId>
+  <packaging>pom</packaging>
+  <name>Maven Wagon Providers Parent</name>
+  <modules>
+    <module>wagon-file</module>
+    <module>wagon-ftp</module>
+    <module>wagon-http-lightweight</module>
+    <module>wagon-http</module>
+    <module>wagon-http-shared</module>
+    <module>wagon-ssh-external</module>
+    <module>wagon-ssh-common</module>
+    <module>wagon-ssh-common-test</module>
+    <module>wagon-ssh</module>
+    <module>wagon-ssh-ganymed</module>
+    <module>wagon-webdav</module>
+  </modules>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-ssh-common</artifactId>
+        <version>1.0-beta-2</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-ssh-common-test</artifactId>
+        <version>1.0-beta-2</version>
+        <scope>test</scope>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-provider-test</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven.wagon</groupId>
+      <artifactId>wagon-provider-api</artifactId>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom.md5
new file mode 100644
index 0000000..45931fe
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom.md5
@@ -0,0 +1 @@
+5690a1f456b3360fe06aa4c81ceead2a
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom.sha1
new file mode 100644
index 0000000..e7f68f2
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-providers/1.0-beta-2/wagon-providers-1.0-beta-2.pom.sha1
@@ -0,0 +1 @@
+a98eefeb315d771555c8529695630d3baefd1f6d
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar
new file mode 100644
index 0000000..7ef31a3
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar.md5
new file mode 100644
index 0000000..2eaf8ef
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar.md5
@@ -0,0 +1 @@
+470c6e98201aa4c013cb467362208a6a
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar.sha1
new file mode 100644
index 0000000..7b03766
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.jar.sha1
@@ -0,0 +1 @@
+705d42d0d3bc584e1d01a892bb8bc01928c5b126
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom
new file mode 100644
index 0000000..e2b1fe6
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom
@@ -0,0 +1,50 @@
+<?xml version="1.0"?><project>
+  <parent>
+    <artifactId>wagon-providers</artifactId>
+    <groupId>org.apache.maven.wagon</groupId>
+    <version>1.0-beta-2</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>wagon-webdav</artifactId>
+  <name>Maven Wagon WebDav Provider</name>
+  <version>1.0-beta-2</version>
+  <description>Wagon that gets and puts artifacts through webdav protocol</description>
+  <contributors>
+    <contributor>
+      <name>Henry Isidro</name>
+      <email>hisidro@exist.com</email>
+    </contributor>
+    <contributor>
+      <name>Joakim Erdfelt</name>
+      <email>joakim@erdfelt.com</email>
+    </contributor>
+  </contributors>
+  <dependencies>
+    <dependency>
+      <groupId>slide</groupId>
+      <artifactId>slide-webdavlib</artifactId>
+      <version>2.1</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>
+      <version>1.0.4</version>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>it.could</groupId>
+      <artifactId>webdav</artifactId>
+      <version>0.4</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mortbay.jetty</groupId>
+      <artifactId>jetty</artifactId>
+      <version>4.2.12</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <distributionManagement>
+    <status>deployed</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom.md5
new file mode 100644
index 0000000..7b1262e
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom.md5
@@ -0,0 +1 @@
+fba1e35dd302eba826861b5be7351c4b
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom.sha1
new file mode 100644
index 0000000..39af910
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon-webdav/1.0-beta-2/wagon-webdav-1.0-beta-2.pom.sha1
@@ -0,0 +1 @@
+1f6d30fd6d75cba5b9ff3fb88cb35cf9f2895736
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom
new file mode 100644
index 0000000..ca84acc
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom
@@ -0,0 +1,170 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>maven-parent</artifactId>
+    <groupId>org.apache.maven</groupId>
+    <version>4</version>
+    <relativePath>../pom/maven/pom.xml</relativePath>
+  </parent>
+  <groupId>org.apache.maven.wagon</groupId>
+  <artifactId>wagon</artifactId>
+  <packaging>pom</packaging>
+  <name>Maven Wagon</name>
+  <version>1.0-beta-2</version>
+  <description>Tools to manage artifacts and deployment</description>
+  <url>http://maven.apache.org/wagon</url>
+
+  <issueManagement>
+    <system>jira</system>
+    <url>http://jira.codehaus.org/browse/WAGON</url>
+  </issueManagement>
+  <inceptionYear>2003</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Maven Wagon User List</name>
+      <subscribe>wagon-users-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>wagon-users-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-wagon-users/</archive>
+    </mailingList>
+    <mailingList>
+      <name>Maven Wagon Developer List</name>
+      <subscribe>wagon-dev-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>wagon-dev-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-wagon-dev/</archive>
+    </mailingList>
+    <mailingList>
+      <name>Maven Commits List</name>
+      <subscribe>wagon-commits-subscribe@maven.apache.org</subscribe>
+      <unsubscribe>wagon-commits-unsubscribe@maven.apache.org</unsubscribe>
+      <archive>http://mail-archives.apache.org/mod_mbox/maven-wagon-commits/</archive>
+    </mailingList>
+  </mailingLists>
+  <developers>
+    <developer>
+      <id>michal</id>
+      <name>Michal Maczka</name>
+      <email>michal@codehaus.org</email>
+      <organization>Codehaus</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:svn:https://svn.apache.org/repos/asf/maven/wagon/tags/wagon-1.0-beta-2</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/maven/wagon/tags/wagon-1.0-beta-2</developerConnection>
+    <url>https://svn.apache.org/repos/asf/maven/wagon/tags/wagon-1.0-beta-2</url>
+  </scm>
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-release-plugin</artifactId>
+          <configuration>
+            <tagBase>https://svn.apache.org/repos/asf/maven/wagon/tags</tagBase>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+  <modules>
+    <module>wagon-provider-api</module>
+    <module>wagon-provider-test</module>
+    <module>wagon-providers</module>
+  </modules>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-provider-api</artifactId>
+        <version>1.0-beta-2</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-provider-test</artifactId>
+        <version>1.0-beta-2</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-ssh-common-test</artifactId>
+        <version>1.0-beta-2</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-ssh-common</artifactId>
+        <version>1.0-beta-2</version>
+      </dependency>
+      <dependency>
+        <groupId>junit</groupId>
+        <artifactId>junit</artifactId>
+        <version>4.13.1</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-interactivity-api</artifactId>
+        <version>1.0-alpha-4</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-container-default</artifactId>
+        <version>1.0-alpha-8</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-utils</artifactId>
+        <version>1.0.4</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+  <!-- TODO: point to ref location
+    <distributionManagement>
+      <site>
+        <id>apache.website</id>
+        <url>scp://people.apache.org/www/maven.apache.org/wagon/</url>
+      </site>
+    </distributionManagement>
+  -->
+  <profiles>
+    <profile>
+      <id>sharedResources</id>
+      <pluginRepositories>
+        <pluginRepository>
+          <id>people.apache.org</id>
+          <url>http://people.apache.org/repo/m2-snapshot-repository</url>
+          <snapshots>
+            <enabled>true</enabled>
+          </snapshots>
+        </pluginRepository>
+      </pluginRepositories>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-remote-resources-plugin</artifactId>
+            <version>1.0-alpha-1</version>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>process</goal>
+                </goals>
+                <configuration>
+                  <resourceBundles>
+                    <resourceBundle>org.apache:apache-jar-resource-bundle:1.0</resourceBundle>
+                  </resourceBundles>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom.md5
new file mode 100644
index 0000000..45e066d
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom.md5
@@ -0,0 +1 @@
+e739bffedc84a18c6e10a0958e2006ad
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom.sha1
new file mode 100644
index 0000000..5f82f76
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/apache/maven/wagon/wagon/1.0-beta-2/wagon-1.0-beta-2.pom.sha1
@@ -0,0 +1 @@
+6cf8a47018be792d2b1774d2bacd7541c888ae50
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar
new file mode 100644
index 0000000..d323275
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar.md5
new file mode 100644
index 0000000..1a9a2b6
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar.md5
@@ -0,0 +1 @@
+1078ac2103fe666952a3cbcbff19ec71
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar.sha1
new file mode 100644
index 0000000..17dbef2
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.jar.sha1
@@ -0,0 +1 @@
+c76ce4f9f1a3d04ef849c1d067519b77f07e01f3
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom
new file mode 100644
index 0000000..036543e
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom
@@ -0,0 +1,51 @@
+<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>
+    <artifactId>plexus-components</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.1.6</version>
+  </parent>
+
+  <artifactId>plexus-active-collections</artifactId>
+  <version>1.0-beta-1</version>
+  <name>Plexus Container-Backed Active Collections</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-component-api</artifactId>
+      <version>1.0-alpha-16</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-container-default</artifactId>
+      <version>1.0-alpha-16</version>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/TestComponent.java</exclude>
+            <exclude>**/TestBadComponent.java</exclude>
+            <exclude>**/*TCK.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+  <scm>
+    <connection>scm:svn:https://svn.codehaus.org/plexus/tags/plexus-active-collections-1.0-beta-1</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/tags/plexus-active-collections-1.0-beta-1</developerConnection>
+  </scm>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom.md5
new file mode 100644
index 0000000..1451912
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom.md5
@@ -0,0 +1 @@
+d844f3e1934a76cefc25342bf02f3bff
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom.sha1
new file mode 100644
index 0000000..5442cbc
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-active-collections/1.0-beta-1/plexus-active-collections-1.0-beta-1.pom.sha1
@@ -0,0 +1 @@
+cf6a9d40df4ca79c210b2b8a90ce28fffb202769
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar
new file mode 100644
index 0000000..e214325
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar.md5
new file mode 100644
index 0000000..c7dfa1e
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar.md5
@@ -0,0 +1 @@
+f55402879506f435a386f2c002ed5001
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar.sha1
new file mode 100644
index 0000000..a333efb
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.jar.sha1
@@ -0,0 +1 @@
+fc41205635dab152bf794785be80a0a70fda686e
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom
new file mode 100644
index 0000000..62a4f45
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom
@@ -0,0 +1,94 @@
+<!--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  ~
+  ~  Copyright 2001-2006 The Codehaus Foundation.
+  ~
+  ~  Licensed under the Apache License, Version 2.0 (the "License");
+  ~  you may not use this file except in compliance with the License.
+  ~  You may obtain a copy of the License at
+  ~
+  ~       http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~  Unless required by applicable law or agreed to in writing, software
+  ~  distributed under the License is distributed on an "AS IS" BASIS,
+  ~  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~  See the License for the specific language governing permissions and
+  ~  limitations under the License.
+  -->
+
+<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">
+  <parent>
+    <artifactId>plexus</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.0.10</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus-classworlds</artifactId>
+  <packaging>jar</packaging>
+  <name>Plexus Classworlds</name>
+  <version>1.2-alpha-10</version>
+  <description />
+  <inceptionYear>2002</inceptionYear>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <type>jar</type>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkMode>once</forkMode>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>org/codehaus/plexus/classworlds/event/*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>debug</id>
+      <dependencies>
+        <dependency>
+          <groupId>aspectj</groupId>
+          <artifactId>aspectjrt</artifactId>
+          <version>1.5.0</version>
+        </dependency>
+      </dependencies>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>aspectj-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>compile</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <complianceLevel>1.4</complianceLevel>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/plexus-classworlds/tags/plexus-classworlds-1.2-alpha-10</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/plexus-classworlds/tags/plexus-classworlds-1.2-alpha-10</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/plexus-classworlds/tags/plexus-classworlds-1.2-alpha-10</url>
+  </scm>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom.md5
new file mode 100644
index 0000000..47dbce5
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom.md5
@@ -0,0 +1 @@
+1a7177f5992983aeb393089af67e51dc
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom.sha1
new file mode 100644
index 0000000..eafd9a7
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-10/plexus-classworlds-1.2-alpha-10.pom.sha1
@@ -0,0 +1 @@
+11215912b045533ec9aaba9f63ea27acf6da850e
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar
new file mode 100644
index 0000000..a8f6a7d
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar.md5
new file mode 100644
index 0000000..09c3bba
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar.md5
@@ -0,0 +1 @@
+b00a4521e82cd7cdf502039dd59a1ffb
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar.sha1
new file mode 100644
index 0000000..9a43138
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.jar.sha1
@@ -0,0 +1 @@
+ed03d1eeb9b2576747df0d2883d9006fa5e1febe
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom
new file mode 100644
index 0000000..d2fc895
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom
@@ -0,0 +1,78 @@
+<?xml version="1.0"?><project>
+  <parent>
+    <artifactId>plexus</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.0.9</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus-classworlds</artifactId>
+  <name>Plexus Classworlds</name>
+  <version>1.2-alpha-7</version>
+  <description></description>
+  <inceptionYear>2002</inceptionYear>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/plexus-classworlds/tags/plexus-classworlds-1.2-alpha-7</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/plexus-classworlds/tags/plexus-classworlds-1.2-alpha-7</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/plexus-classworlds/tags/plexus-classworlds-1.2-alpha-7</url>
+  </scm>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkMode>once</forkMode>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>org/codehaus/plexus/classworlds/event/*</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <profiles>
+    <profile>
+      <id>debug</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>aspectj-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <goals>
+                  <goal>compile</goal>
+                </goals>
+              </execution>
+            </executions>
+            <configuration>
+              <complianceLevel>1.4</complianceLevel>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+      <dependencies>
+        <dependency>
+          <groupId>aspectj</groupId>
+          <artifactId>aspectjrt</artifactId>
+          <version>1.5.0</version>
+        </dependency>
+      </dependencies>
+    </profile>
+  </profiles>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+  <distributionManagement>
+    <status>deployed</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom.md5
new file mode 100644
index 0000000..e9083e7
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom.md5
@@ -0,0 +1 @@
+80962d09b250824806ca66b0bd0ad4c1
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom.sha1
new file mode 100644
index 0000000..4b9e8a4
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-classworlds/1.2-alpha-7/plexus-classworlds-1.2-alpha-7.pom.sha1
@@ -0,0 +1 @@
+6944ec0d0cab19adf167332f7197e045d64a577c
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar
new file mode 100644
index 0000000..85669fd
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar.md5
new file mode 100644
index 0000000..1830fc9
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar.md5
@@ -0,0 +1 @@
+4fe3c03b97ff12905d0fb10fc5b36766
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar.sha1
new file mode 100644
index 0000000..7456120
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.jar.sha1
@@ -0,0 +1 @@
+5a2100a1c6a37804b1abfc70000b0ea33b83b7f9
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom
new file mode 100644
index 0000000..b151164
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom
@@ -0,0 +1,63 @@
+<?xml version="1.0"?><project>
+  <parent>
+    <artifactId>plexus-containers</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.0-alpha-16</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>plexus-component-api</artifactId>
+  <name>Plexus Component API</name>
+  <version>1.0-alpha-16</version>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.2</version>
+        <configuration>
+          <excludes>
+            <exclude>**/Test*.java</exclude>
+            <exclude>**/Abstract*.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-classworlds</artifactId>
+    </dependency>
+  </dependencies>
+  <reporting>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-report-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <links>
+            <link>http://java.sun.com/j2ee/1.4/docs/api</link>
+            <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
+            <link>http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/</link>
+            <link>http://jakarta.apache.org/commons/dbcp/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/fileupload/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/httpclient/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/logging/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/pool/apidocs/</link>
+            <link>http://www.junit.org/junit/javadoc/</link>
+            <link>http://logging.apache.org/log4j/docs/api/</link>
+            <link>http://jakarta.apache.org/regexp/apidocs/</link>
+            <link>http://jakarta.apache.org/velocity/api/</link>
+          </links>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+  <distributionManagement>
+    <status>deployed</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom.md5
new file mode 100644
index 0000000..78fc8ac
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom.md5
@@ -0,0 +1 @@
+751ea77f1e617aea90f36d7156762bf5
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom.sha1
new file mode 100644
index 0000000..dea6088
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-16/plexus-component-api-1.0-alpha-16.pom.sha1
@@ -0,0 +1 @@
+53ad54acd9589c497ba54740f0455fec55db64d7
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar
new file mode 100644
index 0000000..5e3a919
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar.md5
new file mode 100644
index 0000000..beb51a4
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar.md5
@@ -0,0 +1 @@
+7146edcc3412c2b54df27edaf66b00a6
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar.sha1
new file mode 100644
index 0000000..4a7df6b
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.jar.sha1
@@ -0,0 +1 @@
+b226de4eb8db939dff4e14eb5aa1be045c39f6f4
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom
new file mode 100644
index 0000000..f6ff7ea
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom
@@ -0,0 +1,61 @@
+<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>org.codehaus.plexus</groupId>
+    <artifactId>plexus-containers</artifactId>
+    <version>1.0-alpha-32</version>
+  </parent>
+  <artifactId>plexus-component-api</artifactId>
+  <name>Plexus Component API</name>
+  <version>1.0-alpha-32</version>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>2.2</version>
+        <configuration>
+          <excludes>
+            <exclude>**/Test*.java</exclude>
+            <exclude>**/Abstract*.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-classworlds</artifactId>
+    </dependency>
+  </dependencies>
+
+  <reporting>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-report-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <links>
+            <link>http://java.sun.com/j2ee/1.4/docs/api</link>
+            <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
+            <link>http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/</link>
+            <link>http://jakarta.apache.org/commons/dbcp/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/fileupload/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/httpclient/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/logging/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/pool/apidocs/</link>
+            <link>http://www.junit.org/junit/javadoc/</link>
+            <link>http://logging.apache.org/log4j/docs/api/</link>
+            <link>http://jakarta.apache.org/regexp/apidocs/</link>
+            <link>http://jakarta.apache.org/velocity/api/</link>
+          </links>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom.md5
new file mode 100644
index 0000000..40890b2
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom.md5
@@ -0,0 +1 @@
+a181ee89516009cff7658eec175ccb23
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom.sha1
new file mode 100644
index 0000000..f854c7a
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-component-api/1.0-alpha-32/plexus-component-api-1.0-alpha-32.pom.sha1
@@ -0,0 +1 @@
+e214782e714b87b38d5605cb8da53b7d98efde06
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom
new file mode 100644
index 0000000..2adef07
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom
@@ -0,0 +1,60 @@
+<!--
+
+ !!!
+
+ NOTE: If you change this file, you MUST bump the version up from 1.0. That is the version of the POM, and was
+ used for releases of plexus-compiler and plexus-archiver in the past.
+
+ !!!
+
+-->
+
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>plexus</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.0.8</version>
+  </parent>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus-components</artifactId>
+  <packaging>pom</packaging>
+  <version>1.1.6</version>
+  <name>Plexus Components Parent Project</name>
+  <!--
+    TODO: should this be pushed down to all the dependencies?
+      - a more stable API JAR may be useful, for the interfaces and classes such as AbstractLogEnabled
+  -->
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-container-default</artifactId>
+      <version>1.0-alpha-8</version>
+    </dependency>
+  </dependencies>
+  <modules>
+    <module>plexus-action</module>
+    <module>plexus-archiver</module>
+    <module>plexus-bayesian</module>
+    <module>plexus-command</module>
+    <module>plexus-compiler</module>
+    <module>plexus-drools</module>
+    <module>plexus-formica</module>
+    <module>plexus-formica-web</module>
+    <module>plexus-hibernate</module>
+    <module>plexus-i18n</module>
+    <module>plexus-interactivity</module>
+    <module>plexus-ircbot</module>
+    <module>plexus-jdo</module>
+    <module>plexus-jetty-httpd</module>
+    <module>plexus-jetty</module>
+    <module>plexus-mimetyper</module>
+    <module>plexus-notification</module>
+    <module>plexus-resource</module>
+    <module>plexus-security</module>
+    <module>plexus-summit</module>
+    <module>plexus-taskqueue</module>
+    <module>plexus-velocity</module>
+    <module>plexus-xmlrpc</module>
+  </modules>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom.md5
new file mode 100644
index 0000000..cf57067
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom.md5
@@ -0,0 +1 @@
+b76cb94eb4ade475f4743d3656c40899
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom.sha1
new file mode 100644
index 0000000..b9f0aa7
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-components/1.1.6/plexus-components-1.1.6.pom.sha1
@@ -0,0 +1 @@
+682713aa402653d0ea5e224870dc899803734519
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar
new file mode 100644
index 0000000..ef2bd90
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar.md5
new file mode 100644
index 0000000..fc1ee0b
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar.md5
@@ -0,0 +1 @@
+00b4ce443fa584a1998cd6f991ea6514
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar.sha1
new file mode 100644
index 0000000..879c889
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.jar.sha1
@@ -0,0 +1 @@
+dcad8d44306c5ecc109b9449f292fb28b75d37ef
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom
new file mode 100644
index 0000000..f5ae548
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom
@@ -0,0 +1,56 @@
+<?xml version="1.0"?><project>
+  <parent>
+    <artifactId>plexus-containers</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.0-alpha-16</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>plexus-container-default</artifactId>
+  <name>Default Plexus Container</name>
+  <version>1.0-alpha-16</version>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkMode>once</forkMode>
+          <excludes>
+            <exclude>**/Test*.java</exclude>
+            <exclude>**/Abstract*.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <descriptorRefs>
+            <descriptorRef>jar-with-dependencies</descriptorRef>
+          </descriptorRefs>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-component-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-classworlds</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>jmock</groupId>
+      <artifactId>jmock</artifactId>
+      <version>1.0.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <distributionManagement>
+    <status>deployed</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom.md5
new file mode 100644
index 0000000..611807a
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom.md5
@@ -0,0 +1 @@
+883b6e1e40cccb06c1d1ce93728b0a9d
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom.sha1
new file mode 100644
index 0000000..ea4d6dc
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-16/plexus-container-default-1.0-alpha-16.pom.sha1
@@ -0,0 +1 @@
+435f5d09ea241e93acaecd4b6680ddb13a36837d
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar
new file mode 100644
index 0000000..308893f
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar.md5
new file mode 100644
index 0000000..291ffea
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar.md5
@@ -0,0 +1 @@
+556231599b5413a7c1f16a5fd15be574
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar.sha1
new file mode 100644
index 0000000..b8ef047
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.jar.sha1
@@ -0,0 +1 @@
+91410b971f9659f76b0ff26a97b9fbac5de2f69e
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom
new file mode 100644
index 0000000..f8b0705
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom
@@ -0,0 +1,98 @@
+<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>org.codehaus.plexus</groupId>
+    <artifactId>plexus-containers</artifactId>
+    <version>1.0-alpha-32</version>
+  </parent>
+  <artifactId>plexus-container-default</artifactId>
+  <name>Default Plexus Container</name>
+  <version>1.0-alpha-32</version>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <forkMode>once</forkMode>
+          <excludes>
+            <exclude>**/Test*.java</exclude>
+            <exclude>**/Abstract*.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>shade-maven-plugin</artifactId>
+        <groupId>org.codehaus.mojo</groupId>
+        <version>1.0-alpha-9</version>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+            <configuration>
+              <artifactSet>
+                <excludes>
+                  <exclude>classworlds:classworlds</exclude>
+                  <exclude>junit:junit</exclude>
+                  <exclude>jmock:jmock</exclude>
+                  <exclude>org.codehaus.plexus:plexus-classworlds</exclude>
+                  <exclude>org.codehaus.plexus:plexus-utils</exclude>
+                </excludes>
+              </artifactSet>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-component-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-utils</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-classworlds</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>jmock</groupId>
+      <artifactId>jmock</artifactId>
+      <version>1.0.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <reporting>
+    <plugins>
+      <!--plugin>
+        <artifactId>maven-surefire-report-plugin</artifactId>
+      </plugin-->
+      <plugin>
+        <artifactId>maven-pmd-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <configuration>
+          <links>
+            <link>http://java.sun.com/j2ee/1.4/docs/api</link>
+            <link>http://java.sun.com/j2se/1.5.0/docs/api</link>
+            <link>http://jakarta.apache.org/commons/collections/apidocs-COLLECTIONS_3_0/</link>
+            <link>http://jakarta.apache.org/commons/dbcp/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/fileupload/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/httpclient/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/logging/apidocs/</link>
+            <link>http://jakarta.apache.org/commons/pool/apidocs/</link>
+            <link>http://www.junit.org/junit/javadoc/</link>
+            <link>http://logging.apache.org/log4j/docs/api/</link>
+            <link>http://jakarta.apache.org/regexp/apidocs/</link>
+            <link>http://jakarta.apache.org/velocity/api/</link>
+          </links>
+        </configuration>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom.md5
new file mode 100644
index 0000000..3b23771
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom.md5
@@ -0,0 +1 @@
+af4ca0022b674405556b3f397e375adc
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom.sha1
new file mode 100644
index 0000000..00b6087
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-container-default/1.0-alpha-32/plexus-container-default-1.0-alpha-32.pom.sha1
@@ -0,0 +1 @@
+8f4d09d36a2345a39301dbd77ef9906c795887f7
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom
new file mode 100644
index 0000000..bdcd0e3
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom
@@ -0,0 +1,49 @@
+<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>org.codehaus.plexus</groupId>
+    <artifactId>plexus</artifactId>
+    <version>1.0.9</version>
+  </parent>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus-containers</artifactId>
+  <packaging>pom</packaging>
+  <name>Parent Plexus Container POM</name>
+  <version>1.0-alpha-16</version>
+  <modules>
+    <module>plexus-component-api</module>
+    <module>plexus-container-default</module>
+  </modules>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/plexus-containers/tags/plexus-containers-1.0-alpha-16</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/plexus-containers/tags/plexus-containers-1.0-alpha-16</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/plexus-containers/tags/plexus-containers-1.0-alpha-16</url>
+  </scm>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-classworlds</artifactId>
+        <version>1.2-alpha-7</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-component-api</artifactId>
+        <version>1.0-alpha-16</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-utils</artifactId>
+        <version>1.3</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom.md5
new file mode 100644
index 0000000..3db22e2
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom.md5
@@ -0,0 +1 @@
+3eee2016e3e307618048e30f088b546e
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom.sha1
new file mode 100644
index 0000000..3eb3627
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom.sha1
@@ -0,0 +1 @@
+46b79dd7d6a8130d2fa81c80b16b695d491548fe
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom
new file mode 100644
index 0000000..8e94894
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom
@@ -0,0 +1,49 @@
+<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>org.codehaus.plexus</groupId>
+    <artifactId>plexus</artifactId>
+    <version>1.0.11</version>
+  </parent>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus-containers</artifactId>
+  <packaging>pom</packaging>
+  <name>Parent Plexus Container POM</name>
+  <version>1.0-alpha-32</version>
+  <modules>
+    <module>plexus-component-api</module>
+    <module>plexus-container-default</module>
+  </modules>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/plexus-containers/tags/plexus-containers-1.0-alpha-32</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/plexus-containers/tags/plexus-containers-1.0-alpha-32</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/plexus-containers/tags/plexus-containers-1.0-alpha-32</url>
+  </scm>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>compile</scope>
+    </dependency>
+  </dependencies>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-classworlds</artifactId>
+        <version>1.2-alpha-10</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-utils</artifactId>
+        <version>1.4.5</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.plexus</groupId>
+        <artifactId>plexus-component-api</artifactId>
+        <version>1.0-alpha-32</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom.md5
new file mode 100644
index 0000000..41815f0
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom.md5
@@ -0,0 +1 @@
+8ac33e07134648d37e2b1253286889a7
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom.sha1
new file mode 100644
index 0000000..4126071
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-32/plexus-containers-1.0-alpha-32.pom.sha1
@@ -0,0 +1 @@
+8486ff9b37d1ade2a4524c6fee72d394f88fbe08
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.jar
new file mode 100644
index 0000000..a2013d4
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.jar.sha1
new file mode 100644
index 0000000..686c680
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.jar.sha1
@@ -0,0 +1 @@
+60783e4623f2e44063cf2d43d9fbacb2816855c2
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom
new file mode 100644
index 0000000..4c60828
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom
@@ -0,0 +1,235 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus-utils</artifactId>
+  <name>Plexus Common Utilities</name>
+  <version>1.0.4</version>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <configuration>
+          <address>dev@plexus.codehaus.org</address>
+        </configuration>
+      </notifier>
+      <notifier>
+        <type>irc</type>
+        <configuration>
+          <port>6667</port>
+          <channel>#plexus</channel>
+          <host>irc.codehaus.org</host>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Plexus Developer List</name>
+      <subscribe>http://lists.codehaus.org/mailman/listinfo/plexus-dev</subscribe>
+      <unsubscribe>http://lists.codehaus.org/mailman/listinfo/plexus-dev</unsubscribe>
+      <archive>http://lists.codehaus.org/pipermail/plexus-dev/</archive>
+    </mailingList>
+  </mailingLists>
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@zenplex.com</email>
+      <organization>Zenplex</organization>
+      <roles>
+        <role>Developer</role>
+        <role>Release Manager</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kaz</id>
+      <name>Pete Kazmier</name>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>jtaylor</id>
+      <name>James Taylor</name>
+      <email>james@jamestaylor.org</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dandiep</id>
+      <name>Dan Diephouse</name>
+      <email>dan@envoisolutions.com</email>
+      <organization>Envoi solutions</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kasper</id>
+      <name>Kasper Nielsen</name>
+      <email>apache@kav.dk</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>bwalding</id>
+      <name>Ben Walding</name>
+      <email>bwalding@codehaus.org</email>
+      <organization>Walding Consulting Services</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>mhw</id>
+      <name>Mark Wilkinson</name>
+      <email>mhw@kremvax.net</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>michal</id>
+      <name>Michal Maczka</name>
+      <email>mmaczka@interia.pl</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>trygvis</id>
+      <name>Trygve Laugstol</name>
+      <email>trygvis@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kenney</id>
+      <name>Kenney Westerhof</name>
+      <email>kenney@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <scm>
+    <connection>scm:svn:svn://svn.codehaus.org/plexus/scm/trunk/plexus-utils</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/trunk/plexus-utils</developerConnection>
+  </scm>
+  <organization>
+    <name>Codehaus</name>
+    <url>http://www.codehaus.org/</url>
+  </organization>
+  <build>
+    <sourceDirectory>src/main/java</sourceDirectory>
+    <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory>
+    <testSourceDirectory>src/test/java</testSourceDirectory>
+    <outputDirectory>target/classes</outputDirectory>
+    <testOutputDirectory>target/test-classes</testOutputDirectory>
+    <resources>
+      <resource>
+        <directory>src/main/resources</directory>
+      </resource>
+    </resources>
+    <testResources>
+      <testResource>
+        <directory>src/test/resources</directory>
+      </testResource>
+    </testResources>
+    <directory>target</directory>
+    <plugins>
+      <plugin>
+        <artifactId>maven-release-plugin</artifactId>
+        <version>2.0-beta-3-SNAPSHOT</version>
+        <configuration>
+          <tagBase>https://svn.codehaus.org/plexus/tags</tagBase>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <version>RELEASE</version>
+        <configuration>
+          <excludes>
+            <exclude implementation="java.lang.String">org/codehaus/plexus/util/FileBasedTestCase.java</exclude>
+            <exclude implementation="java.lang.String">**/Test*.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <repositories>
+    <repository>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <id>snapshots</id>
+      <name>Maven Snapshot Development Repository</name>
+      <url>http://snapshots.maven.codehaus.org/maven2</url>
+    </repository>
+    <repository>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <id>central</id>
+      <name>Maven Repository Switchboard</name>
+      <url>http://repo1.maven.org/maven2</url>
+    </repository>
+  </repositories>
+  <pluginRepositories>
+    <pluginRepository>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+      <id>snapshots-plugins</id>
+      <name>Maven Snapshot Plugins Development Repository</name>
+      <url>http://snapshots.maven.codehaus.org/maven2</url>
+    </pluginRepository>
+    <pluginRepository>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <id>central</id>
+      <name>Maven Plugin Repository</name>
+      <url>http://repo1.maven.org/maven2</url>
+    </pluginRepository>
+  </pluginRepositories>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>3.8.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <reporting>
+    <outputDirectory>target/site</outputDirectory>
+  </reporting>
+  <distributionManagement>
+    <repository>
+      <id>repo1</id>
+      <name>Maven Central Repository</name>
+      <url>scp://repo1.maven.org/home/projects/maven/repository-staging/to-ibiblio/maven2</url>
+    </repository>
+    <snapshotRepository>
+      <id>snapshots</id>
+      <name>Maven Central Development Repository</name>
+      <url>scp://repo1.maven.org/home/projects/maven/repository-staging/snapshots/maven2</url>
+    </snapshotRepository>
+    <status>deployed</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom.sha1
new file mode 100644
index 0000000..f74d077
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom.sha1
@@ -0,0 +1 @@
+a82e1ddd2d795616ac58d73ed246b8ec65326dfa  /home/projects/maven/repository-staging/to-ibiblio/maven2/org/codehaus/plexus/plexus-utils/1.0.4/plexus-utils-1.0.4.pom
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar
new file mode 100644
index 0000000..5c50e17
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar.md5
new file mode 100644
index 0000000..a7ca769
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar.md5
@@ -0,0 +1 @@
+49e112a6c1ad24962643ef9494f9cbe1
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar.sha1
new file mode 100644
index 0000000..28f6dbb
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.jar.sha1
@@ -0,0 +1 @@
+fa632b7f1cb7c50963d0fb7d818ca93c75c10127
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom
new file mode 100644
index 0000000..6cf9079
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?><project>
+  <parent>
+    <artifactId>plexus</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.0.4</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>plexus-utils</artifactId>
+  <name>Plexus Common Utilities</name>
+  <version>1.1</version>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>org/codehaus/plexus/util/FileBasedTestCase.java</exclude>
+            <exclude>**/Test*.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <distributionManagement>
+    <status>deployed</status>
+  </distributionManagement>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom.md5
new file mode 100644
index 0000000..6de9bf4
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom.md5
@@ -0,0 +1 @@
+6e902bab552ae52fef5875d27c4cf0a0
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom.sha1
new file mode 100644
index 0000000..4dc64d4
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.1/plexus-utils-1.1.pom.sha1
@@ -0,0 +1 @@
+15492ecd00920daca9ec15f6acd695b626621e5b
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar
new file mode 100644
index 0000000..449afb9
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar.md5
new file mode 100644
index 0000000..eff56f2
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar.md5
@@ -0,0 +1 @@
+e158df8d1a539cc6482567f9689cc36f
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar.sha1
new file mode 100644
index 0000000..953f76d
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.jar.sha1
@@ -0,0 +1 @@
+56559396674aacd498c298964b691db0177027c0
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom
new file mode 100644
index 0000000..55baddf
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom
@@ -0,0 +1,61 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>plexus</artifactId>
+    <groupId>org.codehaus.plexus</groupId>
+    <version>1.0.11</version>
+    <relativePath>../pom/pom.xml</relativePath>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>plexus-utils</artifactId>
+  <name>Plexus Common Utilities</name>
+  <version>1.4.5</version>
+  <url>http://plexus.codehaus.org/plexus-utils</url>
+  <build>
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <!-- surefire requires plexus-utils to be jdk 1.3 compatible -->
+          <source>1.3</source>
+          <target>1.3</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <!-- required to ensure the test classes are used, not surefire's plexus-utils -->
+          <childDelegation>true</childDelegation>
+          <excludes>
+            <exclude>org/codehaus/plexus/util/FileBasedTestCase.java</exclude>
+            <exclude>**/Test*.java</exclude>
+          </excludes>
+          <systemProperties>
+            <property>
+              <name>JAVA_HOME</name>
+              <value>${JAVA_HOME}</value>
+            </property>
+            <property>
+              <name>M2_HOME</name>
+              <value>${M2_HOME}</value>
+            </property>
+          </systemProperties>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/plexus-utils/tags/plexus-utils-1.4.5</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/plexus-utils/tags/plexus-utils-1.4.5</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/plexus-utils/tags/plexus-utils-1.4.5</url>
+  </scm>
+  <reporting>
+    <plugins>
+      <plugin>
+        <artifactId>maven-javadoc-plugin</artifactId>
+      </plugin>
+      <plugin>
+        <artifactId>maven-jxr-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </reporting>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom.md5
new file mode 100644
index 0000000..905f70a
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom.md5
@@ -0,0 +1 @@
+fccab705018ed5559df9f8e815b79aaa
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom.sha1
new file mode 100644
index 0000000..247cd94
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus-utils/1.4.5/plexus-utils-1.4.5.pom.sha1
@@ -0,0 +1 @@
+0bdc8a7fbce7d9007a93d289a029b43e1196d85c
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom
new file mode 100644
index 0000000..ee904a0
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom
@@ -0,0 +1,273 @@
+<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>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus</artifactId>
+  <packaging>pom</packaging>
+  <name>Plexus</name>
+  <version>1.0.10</version>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <type>mail</type>
+        <configuration>
+          <address>dev@plexus.codehaus.org</address>
+        </configuration>
+      </notifier>
+      <notifier>
+        <type>irc</type>
+        <configuration>
+          <host>irc.codehaus.org</host>
+          <port>6667</port>
+          <channel>#plexus</channel>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Plexus User List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/user%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/user%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/user</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Developer List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/dev%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/dev%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/dev</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Announce List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/announce%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/announce%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/announce</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Commit List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/scm%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/scm%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/scm</archive>
+    </mailingList>
+  </mailingLists>
+  <issueManagement>
+    <system>JIRA</system>
+    <url>http://jira.codehaus.org/browse/PLX</url>
+  </issueManagement>
+
+  <distributionManagement>
+    <repository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Repository</name>
+      <url>dav:https://dav.codehaus.org/repository/plexus</url>
+    </repository>
+    <snapshotRepository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Development Repository</name>
+      <url>dav:https://dav.codehaus.org/snapshots.repository/plexus</url>
+    </snapshotRepository>
+    <site>
+      <id>codehaus.org</id>
+      <url>dav:https://dav.codehaus.org/plexus</url>
+    </site>
+  </distributionManagement>
+  <repositories>
+    <repository>
+      <id>codehaus.snapshots</id>
+      <name>Codehaus Snapshot Development Repository</name>
+      <url>http://snapshots.repository.codehaus.org</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@maven.org</email>
+      <roles>
+        <role>Developer</role>
+        <role>Release Manager</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kaz</id>
+      <name>Pete Kazmier</name>
+      <email />
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>jtaylor</id>
+      <name>James Taylor</name>
+      <email>james@jamestaylor.org</email>
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dandiep</id>
+      <name>Dan Diephouse</name>
+      <email>dan@envoisolutions.com</email>
+      <organization>Envoi solutions</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kasper</id>
+      <name>Kasper Nielsen</name>
+      <email>apache@kav.dk</email>
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>bwalding</id>
+      <name>Ben Walding</name>
+      <email>bwalding@codehaus.org</email>
+      <organization>Walding Consulting Services</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>mhw</id>
+      <name>Mark Wilkinson</name>
+      <email>mhw@kremvax.net</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>michal</id>
+      <name>Michal Maczka</name>
+      <email>mmaczka@interia.pl</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Trygve Laugstol</name>
+      <id>trygvis</id>
+      <email>trygvis@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Kenney Westerhof</name>
+      <id>kenney</id>
+      <email>kenney@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Carlos Sanchez</name>
+      <id>carlos</id>
+      <email>carlos@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Brett Porter</name>
+      <id>brett</id>
+      <email>brett@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>John Casey</name>
+      <id>jdcasey</id>
+      <email>jdcasey@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Andrew Williams</name>
+      <id>handyande</id>
+      <email>andy@handyande.co.uk</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Rahul Thakur</name>
+      <id>rahul</id>
+      <email>rahul.thakur.xdev@gmail.com</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Joakim Erdfelt</name>
+      <id>joakime</id>
+      <email>joakim@erdfelt.com</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Olivier Lamy</name>
+      <id>olamy</id>
+      <email>olamy@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/pom/tags/plexus-1.0.10</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/pom/tags/plexus-1.0.10</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/pom/tags/plexus-1.0.10</url>
+  </scm>
+  <organization>
+    <name>Codehaus</name>
+    <url>http://www.codehaus.org/</url>
+  </organization>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.4</source>
+          <target>1.4</target>
+        </configuration>
+      </plugin>
+    </plugins>
+    <extensions>
+      <extension>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-webdav</artifactId>
+        <version>1.0-beta-2</version>
+      </extension>
+    </extensions>
+  </build>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom.md5
new file mode 100644
index 0000000..7ae43d7
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom.md5
@@ -0,0 +1 @@
+6ab958c91424c0d7c3a2cc861867905e
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom.sha1
new file mode 100644
index 0000000..8ed366f
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.10/plexus-1.0.10.pom.sha1
@@ -0,0 +1 @@
+039c3f6a3cbe1f9e7b4a3309d9d7062b6e390fa7
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom
new file mode 100644
index 0000000..1f491ae
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom
@@ -0,0 +1,308 @@
+<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>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus</artifactId>
+  <packaging>pom</packaging>
+  <name>Plexus</name>
+  <version>1.0.11</version>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <type>mail</type>
+        <configuration>
+          <address>dev@plexus.codehaus.org</address>
+        </configuration>
+      </notifier>
+      <notifier>
+        <type>irc</type>
+        <configuration>
+          <host>irc.codehaus.org</host>
+          <port>6667</port>
+          <channel>#plexus</channel>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <licenses>
+    <license>
+      <name>The Apache Software License, Version 2.0</name>
+      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+  <mailingLists>
+    <mailingList>
+      <name>Plexus User List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/user%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/user%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/user</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Developer List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/dev%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/dev%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/dev</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Announce List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/announce%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/announce%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/announce</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Commit List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/scm%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/scm%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/scm</archive>
+    </mailingList>
+  </mailingLists>
+  <issueManagement>
+    <system>JIRA</system>
+    <url>http://jira.codehaus.org/browse/PLX</url>
+  </issueManagement>
+
+  <distributionManagement>
+    <repository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Repository</name>
+      <url>dav:https://dav.codehaus.org/repository/plexus</url>
+    </repository>
+    <snapshotRepository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Development Repository</name>
+      <url>dav:https://dav.codehaus.org/snapshots.repository/plexus</url>
+    </snapshotRepository>
+    <site>
+      <id>codehaus.org</id>
+      <url>dav:https://dav.codehaus.org/plexus</url>
+    </site>
+  </distributionManagement>
+  <repositories>
+    <repository>
+      <id>codehaus.snapshots</id>
+      <name>Codehaus Snapshot Development Repository</name>
+      <url>http://snapshots.repository.codehaus.org</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@maven.org</email>
+      <roles>
+        <role>Developer</role>
+        <role>Release Manager</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kaz</id>
+      <name>Pete Kazmier</name>
+      <email />
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>jtaylor</id>
+      <name>James Taylor</name>
+      <email>james@jamestaylor.org</email>
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dandiep</id>
+      <name>Dan Diephouse</name>
+      <email>dan@envoisolutions.com</email>
+      <organization>Envoi solutions</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kasper</id>
+      <name>Kasper Nielsen</name>
+      <email>apache@kav.dk</email>
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>bwalding</id>
+      <name>Ben Walding</name>
+      <email>bwalding@codehaus.org</email>
+      <organization>Walding Consulting Services</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>mhw</id>
+      <name>Mark Wilkinson</name>
+      <email>mhw@kremvax.net</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>michal</id>
+      <name>Michal Maczka</name>
+      <email>mmaczka@interia.pl</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Trygve Laugstol</name>
+      <id>trygvis</id>
+      <email>trygvis@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Kenney Westerhof</name>
+      <id>kenney</id>
+      <email>kenney@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Carlos Sanchez</name>
+      <id>carlos</id>
+      <email>carlos@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Brett Porter</name>
+      <id>brett</id>
+      <email>brett@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>John Casey</name>
+      <id>jdcasey</id>
+      <email>jdcasey@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Andrew Williams</name>
+      <id>handyande</id>
+      <email>andy@handyande.co.uk</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Rahul Thakur</name>
+      <id>rahul</id>
+      <email>rahul.thakur.xdev@gmail.com</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Joakim Erdfelt</name>
+      <id>joakime</id>
+      <email>joakim@erdfelt.com</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Olivier Lamy</name>
+      <id>olamy</id>
+      <email>olamy@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/pom/trunk/</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/pom/trunk/</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/pom/trunk/</url>
+  </scm>
+  <organization>
+    <name>Codehaus</name>
+    <url>http://www.codehaus.org/</url>
+  </organization>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.4</source>
+          <target>1.4</target>
+        </configuration>
+      </plugin>
+      <!--
+      <plugin>
+        <artifactId>maven-remote-resources-plugin</artifactId>
+        <version>1.0-alpha-2</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>process</goal>
+            </goals>
+            <configuration>
+              <resourceBundles>
+                <resourceBundle>org.apache:apache-jar-resource-bundle:1.1.1-SNAPSHOT</resourceBundle>
+              </resourceBundles>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      -->
+    </plugins>
+    <extensions>
+      <extension>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-webdav</artifactId>
+        <version>1.0-beta-2</version>
+      </extension>
+    </extensions>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <artifactId>maven-release-plugin</artifactId>
+          <configuration>
+            <goals>deploy</goals>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom.md5
new file mode 100644
index 0000000..2cabbba
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom.md5
@@ -0,0 +1 @@
+bdf8dcfe0877af604f7e19e9ffdf260b
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom.sha1
new file mode 100644
index 0000000..1ba2b3a
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.11/plexus-1.0.11.pom.sha1
@@ -0,0 +1 @@
+4693d4512d50c5159bef1c49def1d2690a327c30
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom
new file mode 100644
index 0000000..0867e8b
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom
@@ -0,0 +1,205 @@
+<project>
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus</artifactId>
+  <packaging>pom</packaging>
+  <name>Plexus</name>
+  <version>1.0.4</version>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <type>mail</type>
+        <configuration>
+          <address>dev@plexus.codehaus.org</address>
+        </configuration>
+      </notifier>
+      <notifier>
+        <type>irc</type>
+        <configuration>
+          <host>irc.codehaus.org</host>
+          <port>6667</port>
+          <channel>#plexus</channel>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Plexus Developer List</name>
+      <subscribe>http://lists.codehaus.org/mailman/listinfo/plexus-dev</subscribe>
+      <unsubscribe>http://lists.codehaus.org/mailman/listinfo/plexus-dev</unsubscribe>
+      <archive>http://lists.codehaus.org/pipermail/plexus-dev/</archive>
+    </mailingList>
+  </mailingLists>
+
+  <distributionManagement>
+    <repository>
+      <id>repo1</id>
+      <name>Maven Central Repository</name>
+      <url>scp://repo1.maven.org/home/projects/maven/repository-staging/to-ibiblio/maven2</url>
+    </repository>
+    <snapshotRepository>
+      <id>snapshots</id>
+      <name>Maven Central Development Repository</name>
+      <url>scp://repo1.maven.org/home/projects/maven/repository-staging/snapshots/maven2</url>
+    </snapshotRepository>
+  </distributionManagement>
+  <repositories>
+    <repository>
+      <id>snapshots</id>
+      <name>Maven Snapshot Development Repository</name>
+      <url>http://snapshots.maven.codehaus.org/maven2</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+  <pluginRepositories>
+    <pluginRepository>
+      <id>snapshots-plugins</id>
+      <name>Maven Snapshot Plugins Development Repository</name>
+      <url>http://snapshots.maven.codehaus.org/maven2</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@zenplex.com</email>
+      <organization>Zenplex</organization>
+      <roles>
+        <role>Developer</role>
+        <role>Release Manager</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kaz</id>
+      <name>Pete Kazmier</name>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>jtaylor</id>
+      <name>James Taylor</name>
+      <email>james@jamestaylor.org</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dandiep</id>
+      <name>Dan Diephouse</name>
+      <email>dan@envoisolutions.com</email>
+      <organization>Envoi solutions</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kasper</id>
+      <name>Kasper Nielsen</name>
+      <email>apache@kav.dk</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>bwalding</id>
+      <name>Ben Walding</name>
+      <email>bwalding@codehaus.org</email>
+      <organization>Walding Consulting Services</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>mhw</id>
+      <name>Mark Wilkinson</name>
+      <email>mhw@kremvax.net</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>michal</id>
+      <name>Michal Maczka</name>
+      <email>mmaczka@interia.pl</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Trygve Laugst&oslash;l</name>
+      <id>trygvis</id>
+      <email>trygvis@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Kenney Westerhof</name>
+      <id>kenney</id>
+      <email>kenney@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <scm>
+    <connection>scm:svn:svn://svn.codehaus.org/plexus/scm/trunk/</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/trunk</developerConnection>
+  </scm>
+  <organization>
+    <name>Codehaus</name>
+    <url>http://www.codehaus.org/</url>
+  </organization>
+  <modules>
+    <module>plexus-appserver</module>
+    <module>plexus-archetypes</module>
+    <module>plexus-components</module>
+    <module>plexus-component-factories</module>
+    <module>plexus-containers</module>
+    <module>plexus-logging</module>
+    <module>plexus-maven-plugin</module>
+    <module>plexus-services</module>
+    <module>plexus-tools</module>
+    <module>plexus-utils</module>
+  </modules>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+        <configuration>
+          <tagBase>https://svn.codehaus.org/plexus/tags</tagBase>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom.md5
new file mode 100644
index 0000000..ec5562d
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom.md5
@@ -0,0 +1 @@
+2e97f3a7666e337ce5d2d98b9c384cae
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom.sha1
new file mode 100644
index 0000000..456d534
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.4/plexus-1.0.4.pom.sha1
@@ -0,0 +1 @@
+06f66b2f7d2eef1d805c11bca91c89984cda4137
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom
new file mode 100644
index 0000000..c6afe11
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom
@@ -0,0 +1,259 @@
+<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus</artifactId>
+  <packaging>pom</packaging>
+  <name>Plexus</name>
+  <version>1.0.8</version>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <type>mail</type>
+        <configuration>
+          <address>dev@plexus.codehaus.org</address>
+        </configuration>
+      </notifier>
+      <notifier>
+        <type>irc</type>
+        <configuration>
+          <host>irc.codehaus.org</host>
+          <port>6667</port>
+          <channel>#plexus</channel>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Plexus Developer List</name>
+      <subscribe>http://lists.codehaus.org/mailman/listinfo/plexus-dev</subscribe>
+      <unsubscribe>http://lists.codehaus.org/mailman/listinfo/plexus-dev</unsubscribe>
+      <archive>http://lists.codehaus.org/pipermail/plexus-dev/</archive>
+    </mailingList>
+  </mailingLists>
+  <issueManagement>
+    <system>JIRA</system>
+    <url>http://jira.codehaus.org/browse/PLX</url>
+  </issueManagement>
+
+  <distributionManagement>
+    <repository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Repository</name>
+      <url>dav:https://dav.codehaus.org/repository/plexus</url>
+    </repository>
+    <snapshotRepository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Development Repository</name>
+      <url>dav:https://dav.codehaus.org/snapshots.repository/plexus</url>
+    </snapshotRepository>
+    <site>
+      <id>codehaus.org</id>
+      <url>dav:https://dav.codehaus.org/plexus</url>
+    </site>
+  </distributionManagement>
+  <repositories>
+    <repository>
+      <id>apache-snapshots</id>
+      <name>Snapshot repository</name>
+      <url>http://people.apache.org/maven-snapshot-repository</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+    <repository>
+      <id>codehaus-snapshots</id>
+      <name>Codehaus Snapshot Development Repository</name>
+      <url>http://snapshots.repository.codehaus.org</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+  <pluginRepositories>
+    <pluginRepository>
+      <id>codehaus-snapshots</id>
+      <name>Codehaus Snapshot Development Repository</name>
+      <url>http://snapshots.repository.codehaus.org</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@maven.org</email>
+      <roles>
+        <role>Developer</role>
+        <role>Release Manager</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kaz</id>
+      <name>Pete Kazmier</name>
+      <email></email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>jtaylor</id>
+      <name>James Taylor</name>
+      <email>james@jamestaylor.org</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dandiep</id>
+      <name>Dan Diephouse</name>
+      <email>dan@envoisolutions.com</email>
+      <organization>Envoi solutions</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kasper</id>
+      <name>Kasper Nielsen</name>
+      <email>apache@kav.dk</email>
+      <organization></organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>bwalding</id>
+      <name>Ben Walding</name>
+      <email>bwalding@codehaus.org</email>
+      <organization>Walding Consulting Services</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>mhw</id>
+      <name>Mark Wilkinson</name>
+      <email>mhw@kremvax.net</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>michal</id>
+      <name>Michal Maczka</name>
+      <email>mmaczka@interia.pl</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Trygve Laugstol</name>
+      <id>trygvis</id>
+      <email>trygvis@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Kenney Westerhof</name>
+      <id>kenney</id>
+      <email>kenney@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Carlos Sanchez</name>
+      <id>carlos</id>
+      <email>carlos@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Brett Porter</name>
+      <id>brett</id>
+      <email>brett@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>John Casey</name>
+      <id>jdcasey</id>
+      <email>jdcasey@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/trunk/</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/trunk</developerConnection>
+  </scm>
+  <organization>
+    <name>Codehaus</name>
+    <url>http://www.codehaus.org/</url>
+  </organization>
+  <modules>
+    <!--
+
+    Until the bug is fixed in Maven which is pulling in the trunk to the
+    appserver build.
+    <module>plexus-appserver</module>
+    -->
+    <module>plexus-archetypes</module>
+    <module>plexus-examples</module>
+    <module>plexus-components</module>
+    <module>plexus-component-factories</module>
+    <module>plexus-containers</module>
+    <module>plexus-logging</module>
+    <module>plexus-maven-plugin</module>
+    <module>plexus-tools</module>
+    <module>plexus-utils</module>
+  </modules>
+  <build>
+    <extensions>
+      <extension>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-webdav</artifactId>
+        <version>1.0-beta-1</version>
+      </extension>
+    </extensions>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+        <configuration>
+          <tagBase>https://svn.codehaus.org/plexus/tags</tagBase>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom.md5
new file mode 100644
index 0000000..e0d40fc
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom.md5
@@ -0,0 +1 @@
+2da4039a1c4c959c75d3e6126f2029cf
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom.sha1
new file mode 100644
index 0000000..5234d56
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.8/plexus-1.0.8.pom.sha1
@@ -0,0 +1 @@
+9e7c8432829962afe796b32587c1bfa841a317d5
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom
new file mode 100644
index 0000000..6f4e500
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom
@@ -0,0 +1,257 @@
+<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>
+  <groupId>org.codehaus.plexus</groupId>
+  <artifactId>plexus</artifactId>
+  <packaging>pom</packaging>
+  <name>Plexus</name>
+  <version>1.0.9</version>
+  <ciManagement>
+    <notifiers>
+      <notifier>
+        <type>mail</type>
+        <configuration>
+          <address>dev@plexus.codehaus.org</address>
+        </configuration>
+      </notifier>
+      <notifier>
+        <type>irc</type>
+        <configuration>
+          <host>irc.codehaus.org</host>
+          <port>6667</port>
+          <channel>#plexus</channel>
+        </configuration>
+      </notifier>
+    </notifiers>
+  </ciManagement>
+  <inceptionYear>2001</inceptionYear>
+  <mailingLists>
+    <mailingList>
+      <name>Plexus User List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/user%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/user%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/user</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Developer List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/dev%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/dev%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/dev</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Announce List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/announce%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/announce%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/announce</archive>
+    </mailingList>
+    <mailingList>
+      <name>Plexus Commit List</name>
+      <subscribe>http://xircles.codehaus.org/manage_email/scm%40plexus.codehaus.org</subscribe>
+      <unsubscribe>http://xircles.codehaus.org/manage_email/scm%40plexus.codehaus.org</unsubscribe>
+      <archive>http://archive.plexus.codehaus.org/scm</archive>
+    </mailingList>
+  </mailingLists>
+  <issueManagement>
+    <system>JIRA</system>
+    <url>http://jira.codehaus.org/browse/PLX</url>
+  </issueManagement>
+
+  <distributionManagement>
+    <repository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Repository</name>
+      <url>dav:https://dav.codehaus.org/repository/plexus</url>
+    </repository>
+    <snapshotRepository>
+      <id>codehaus.org</id>
+      <name>Plexus Central Development Repository</name>
+      <url>dav:https://dav.codehaus.org/snapshots.repository/plexus</url>
+    </snapshotRepository>
+    <site>
+      <id>codehaus.org</id>
+      <url>dav:https://dav.codehaus.org/plexus</url>
+    </site>
+  </distributionManagement>
+  <repositories>
+    <repository>
+      <id>apache-snapshots</id>
+      <name>Snapshot repository</name>
+      <url>http://people.apache.org/maven-snapshot-repository</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+    <repository>
+      <id>codehaus-snapshots</id>
+      <name>Codehaus Snapshot Development Repository</name>
+      <url>http://snapshots.repository.codehaus.org</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+  <pluginRepositories>
+    <pluginRepository>
+      <id>codehaus-snapshots</id>
+      <name>Codehaus Snapshot Development Repository</name>
+      <url>http://snapshots.repository.codehaus.org</url>
+      <releases>
+        <enabled>false</enabled>
+      </releases>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <developers>
+    <developer>
+      <id>jvanzyl</id>
+      <name>Jason van Zyl</name>
+      <email>jason@maven.org</email>
+      <roles>
+        <role>Developer</role>
+        <role>Release Manager</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kaz</id>
+      <name>Pete Kazmier</name>
+      <email />
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>jtaylor</id>
+      <name>James Taylor</name>
+      <email>james@jamestaylor.org</email>
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>dandiep</id>
+      <name>Dan Diephouse</name>
+      <email>dan@envoisolutions.com</email>
+      <organization>Envoi solutions</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>kasper</id>
+      <name>Kasper Nielsen</name>
+      <email>apache@kav.dk</email>
+      <organization />
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>bwalding</id>
+      <name>Ben Walding</name>
+      <email>bwalding@codehaus.org</email>
+      <organization>Walding Consulting Services</organization>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>mhw</id>
+      <name>Mark Wilkinson</name>
+      <email>mhw@kremvax.net</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>michal</id>
+      <name>Michal Maczka</name>
+      <email>mmaczka@interia.pl</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>evenisse</id>
+      <name>Emmanuel Venisse</name>
+      <email>evenisse@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Trygve Laugstol</name>
+      <id>trygvis</id>
+      <email>trygvis@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Kenney Westerhof</name>
+      <id>kenney</id>
+      <email>kenney@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Carlos Sanchez</name>
+      <id>carlos</id>
+      <email>carlos@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Brett Porter</name>
+      <id>brett</id>
+      <email>brett@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>John Casey</name>
+      <id>jdcasey</id>
+      <email>jdcasey@codehaus.org</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <name>Andrew Williams</name>
+      <id>handyande</id>
+      <email>andy@handyande.co.uk</email>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.13.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <scm>
+    <connection>scm:svn:http://svn.codehaus.org/plexus/pom/tags/plexus-1.0.9</connection>
+    <developerConnection>scm:svn:https://svn.codehaus.org/plexus/pom/tags/plexus-1.0.9</developerConnection>
+    <url>http://fisheye.codehaus.org/browse/plexus/pom/tags/plexus-1.0.9</url>
+  </scm>
+  <organization>
+    <name>Codehaus</name>
+    <url>http://www.codehaus.org/</url>
+  </organization>
+  <build>
+    <extensions>
+      <extension>
+        <groupId>org.apache.maven.wagon</groupId>
+        <artifactId>wagon-webdav</artifactId>
+        <version>1.0-beta-1</version>
+      </extension>
+    </extensions>
+  </build>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom.md5 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom.md5
new file mode 100644
index 0000000..3910bf8
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom.md5
@@ -0,0 +1 @@
+acf338e422e5c0d9c6242e4f21e63dc9
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom.sha1
new file mode 100644
index 0000000..df40a70
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/codehaus/plexus/plexus/1.0.9/plexus-1.0.9.pom.sha1
@@ -0,0 +1 @@
+89d241b1e5ee6a72d3dd95d9eb90f635deebcdb2
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc-resources.jar.lastUpdated b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc-resources.jar.lastUpdated
new file mode 100644
index 0000000..d326d8b
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc-resources.jar.lastUpdated
@@ -0,0 +1,4 @@
+#NOTE: This is a Maven Resolver internal implementation file, its format can be changed without prior notice.
+#Wed Jan 05 14:06:51 CET 2022
+https\://repo.maven.apache.org/maven2/.lastUpdated=1641388011987
+https\://repo.maven.apache.org/maven2/.error=
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar
new file mode 100644
index 0000000..eb935e0
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar.sha1
new file mode 100644
index 0000000..304c4b0
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-javadoc.jar.sha1
@@ -0,0 +1 @@
+ad09811315f1d4f5756986575b0ea16b99cd686f
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar
new file mode 100644
index 0000000..c3c110b
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar.sha1
new file mode 100644
index 0000000..ce64bf9
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3-sources.jar.sha1
@@ -0,0 +1 @@
+1dc37250fbc78e23a65a67fbbaf71d2e9cbc3c0b
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
new file mode 100644
index 0000000..9d5fe16
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar
Binary files differ
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar.sha1 b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar.sha1
new file mode 100644
index 0000000..1085ece
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar.sha1
@@ -0,0 +1 @@
+42a25dc3219429f0e5d060061f71acb49bf010a0
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom
new file mode 100644
index 0000000..0721781
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<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>
+
+  <parent>
+    <groupId>org.hamcrest</groupId>
+    <artifactId>hamcrest-parent</artifactId>
+    <version>1.3</version>
+  </parent>
+
+  <artifactId>hamcrest-core</artifactId>
+  <packaging>jar</packaging>
+  <name>Hamcrest Core</name>
+  <description>
+    This is the core API of hamcrest matcher framework to be used by third-party framework providers. This includes the a foundation set of matcher implementations for common operations.
+  </description>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom.sha1
new file mode 100644
index 0000000..53d5f15
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.pom.sha1
@@ -0,0 +1 @@
+872e413497b906e7c9fa85ccc96046c5d1ef7ece
\ No newline at end of file
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom
new file mode 100644
index 0000000..ae4b4b4
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<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>org.hamcrest</groupId>
+  <artifactId>hamcrest-parent</artifactId>
+  <version>1.3</version>
+  <packaging>pom</packaging>
+
+  <name>Hamcrest Maven Parent</name>
+  <url>https://github.com/hamcrest/JavaHamcrest</url>
+  <description>General parent POM for all hamcrest libraries.</description>
+
+  <licenses>
+    <license>
+      <name>New BSD License</name>
+      <url>http://www.opensource.org/licenses/bsd-license.php</url>
+      <distribution>repo</distribution>
+    </license>
+  </licenses>
+
+  <scm>
+    <url>https://github.com/hamcrest/JavaHamcrest</url>
+    <connection>scm:git:git@github.com:hamcrest/JavaHamcrest.git</connection>
+  </scm>
+
+  <developers>
+    <developer>
+      <id>joe.walnes</id>
+      <name>Joe Walnes</name>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>nat.pryce</id>
+      <name>Nat Pryce</name>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>smgfreeman</id>
+      <name>Steve Freeman</name>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>neildunn</id>
+      <name>Neil Dunn</name>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+    <developer>
+      <id>scarytom</id>
+      <name>Tom Denley</name>
+      <roles>
+        <role>Developer</role>
+      </roles>
+    </developer>
+  </developers>
+
+  <modules>
+    <module>hamcrest-core</module>
+    <module>hamcrest-generator</module>
+    <module>hamcrest-library</module>
+    <module>hamcrest-integration</module>
+  </modules>
+</project>
diff --git a/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom.sha1 b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom.sha1
new file mode 100644
index 0000000..c5c5f18
--- /dev/null
+++ b/maven-core/src/test/resources/apiv4-repo/org/hamcrest/hamcrest-parent/1.3/hamcrest-parent-1.3.pom.sha1
@@ -0,0 +1 @@
+80391bd32bfa4837a15215d5e9f07c60555c379a
\ No newline at end of file
diff --git a/maven-core/src/test/resources/consumer/simple/pom.xml b/maven-core/src/test/resources/consumer/simple/pom.xml
new file mode 100644
index 0000000..54e3379
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/simple/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project root="true" xmlns="http://maven.apache.org/POM/4.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0-alpha-8.xsd">
+  <groupId>org.sonatype.mavenbook.multi</groupId>
+  <artifactId>parent</artifactId>
+  <version>0.9-${changelist}-SNAPSHOT</version>
+  <packaging>pom</packaging>
+  <name>Multi Chapter Parent Project</name>
+
+  <!-- Optimized from https://github.com/sonatype/maven-example-en/tree/master/examples/ch-multi -->
+  <modules>
+    <module>simple-parent</module>
+  </modules>
+</project>
diff --git a/maven-core/src/test/resources/consumer/simple/simple-parent/pom.xml b/maven-core/src/test/resources/consumer/simple/simple-parent/pom.xml
new file mode 100644
index 0000000..cec6145
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/simple/simple-parent/pom.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0-alpha-8.xsd">
+  <parent>
+    <groupId>org.sonatype.mavenbook.multi</groupId>
+    <artifactId>parent</artifactId>
+  </parent>
+  <artifactId>simple-parent</artifactId>
+  <packaging>pom</packaging>
+  <name>Multi Chapter Simple Parent Project</name>
+
+  <modules>
+    <module>simple-weather</module>
+    <module>simple-webapp</module>
+
+    <!-- On purpose at the end, project graph is responsible for ordering -->
+    <!-- Build/consumer should not be effected by reverse order -->
+    <module>simple-testutils</module>
+    <module>utils-parent</module>
+  </modules>
+
+  <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-surefire-plugin</artifactId>
+          <version>0.1-stub-SNAPSHOT</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+
+</project>
diff --git a/maven-core/src/test/resources/consumer/simple/simple-parent/simple-testutils/pom.xml b/maven-core/src/test/resources/consumer/simple/simple-parent/simple-testutils/pom.xml
new file mode 100644
index 0000000..ce6a47b
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/simple/simple-parent/simple-testutils/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0-alpha-8.xsd">
+  <parent>
+    <groupId>org.sonatype.mavenbook.multi</groupId>
+    <artifactId>utils-parent</artifactId>
+    <relativePath>../utils-parent/pom.xml</relativePath>
+  </parent>
+  <artifactId>simple-testutils</artifactId>
+</project>
diff --git a/maven-core/src/test/resources/consumer/simple/simple-parent/simple-weather/pom.xml b/maven-core/src/test/resources/consumer/simple/simple-parent/simple-weather/pom.xml
new file mode 100644
index 0000000..7b2e0b2
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/simple/simple-parent/simple-weather/pom.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0-alpha-8.xsd">
+  <parent>
+    <groupId>org.sonatype.mavenbook.multi</groupId>
+    <artifactId>simple-parent</artifactId>
+  </parent>
+  <artifactId>simple-weather</artifactId>
+  <packaging>jar</packaging>
+
+  <name>Multi Chapter Simple Weather API</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.sonatype.mavenbook.multi</groupId>
+      <artifactId>simple-testutils</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/maven-core/src/test/resources/consumer/simple/simple-parent/simple-webapp/pom.xml b/maven-core/src/test/resources/consumer/simple/simple-parent/simple-webapp/pom.xml
new file mode 100644
index 0000000..655d0cc
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/simple/simple-parent/simple-webapp/pom.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.sonatype.mavenbook.multi</groupId>
+    <artifactId>simple-parent</artifactId>
+  </parent>
+
+  <artifactId>simple-webapp</artifactId>
+  <name>Multi Chapter Simple Web Application Project</name>
+  <dependencies>
+    <dependency>
+      <groupId>org.sonatype.mavenbook.multi</groupId>
+      <artifactId>simple-weather</artifactId>
+    </dependency>
+  </dependencies>
+  <build>
+    <finalName>simple-webapp</finalName>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-war-plugin</artifactId>
+          <version>3.3.2</version>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
diff --git a/maven-core/src/test/resources/consumer/simple/simple-parent/utils-parent/pom.xml b/maven-core/src/test/resources/consumer/simple/simple-parent/utils-parent/pom.xml
new file mode 100644
index 0000000..52909d7
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/simple/simple-parent/utils-parent/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0-alpha-8.xsd">
+  <parent>
+    <groupId>org.sonatype.mavenbook.multi</groupId>
+    <artifactId>simple-parent</artifactId>
+  </parent>
+  <artifactId>utils-parent</artifactId>
+  <packaging>pom</packaging>
+</project>
diff --git a/maven-core/src/test/resources/consumer/trivial/child/pom.xml b/maven-core/src/test/resources/consumer/trivial/child/pom.xml
new file mode 100644
index 0000000..25c05af
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/trivial/child/pom.xml
@@ -0,0 +1,18 @@
+<project xmlns="http://maven.apache.org/POM/4.1.0">
+  <parent>
+    <groupId>org.my.group</groupId>
+    <artifactId>parent</artifactId>
+  </parent>
+  <artifactId>child</artifactId>
+  <packaging>jar</packaging>
+
+  <properties>
+    <prop-child>bar</prop-child>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/consumer/trivial/pom.xml b/maven-core/src/test/resources/consumer/trivial/pom.xml
new file mode 100644
index 0000000..14fab6c
--- /dev/null
+++ b/maven-core/src/test/resources/consumer/trivial/pom.xml
@@ -0,0 +1,47 @@
+<project root="true" xmlns="http://maven.apache.org/POM/4.1.0">
+  <groupId>org.my.group</groupId>
+  <artifactId>parent</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <modules>
+    <module>child.xml</module>
+  </modules>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+        <version>2.0.9</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-api</artifactId>
+      <version>5.10.1</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>release</id>
+      <properties>
+        <prop>foo</prop>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <version>3.11.0</version>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/org/apache/maven/extension/test-extension-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom b/maven-core/src/test/resources/org/apache/maven/extension/test-extension-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom
index 1e86758..bdcd0e3 100644
--- a/maven-core/src/test/resources/org/apache/maven/extension/test-extension-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom
+++ b/maven-core/src/test/resources/org/apache/maven/extension/test-extension-repo/org/codehaus/plexus/plexus-containers/1.0-alpha-16/plexus-containers-1.0-alpha-16.pom
@@ -23,7 +23,7 @@
     <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
-      <version4.13.1</version>
+      <version>4.13.1</version>
       <scope>compile</scope>
     </dependency>
   </dependencies>
diff --git a/maven-core/src/test/resources/projects/artifactMissingVersion.xml b/maven-core/src/test/resources/projects/artifactMissingVersion/pom.xml
similarity index 100%
rename from maven-core/src/test/resources/projects/artifactMissingVersion.xml
rename to maven-core/src/test/resources/projects/artifactMissingVersion/pom.xml
diff --git a/maven-core/src/test/resources/projects/future-model-version-pom.xml b/maven-core/src/test/resources/projects/future-model-version-pom.xml
index 1a73a44..c76f97c 100644
--- a/maven-core/src/test/resources/projects/future-model-version-pom.xml
+++ b/maven-core/src/test/resources/projects/future-model-version-pom.xml
@@ -18,7 +18,7 @@
 -->
 
 <project>
-    <modelVersion>4.0.1</modelVersion>
+    <modelVersion>4.9.1</modelVersion>
     <groupId>tests.project</groupId>
     <artifactId>future-model-version</artifactId>
     <version>1</version>
diff --git a/maven-core/src/test/resources/projects/transform/after.pom b/maven-core/src/test/resources/projects/transform/after.pom
index a66fca8..6c970ca 100644
--- a/maven-core/src/test/resources/projects/transform/after.pom
+++ b/maven-core/src/test/resources/projects/transform/after.pom
@@ -1,53 +1,41 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<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">
+<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>
-
   <groupId>test</groupId>
   <artifactId>test</artifactId>
   <version>0.1-SNAPSHOT</version>
   <packaging>pom</packaging>
-
-  
-
   <build>
     <pluginManagement>
       <plugins>
         <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>2.1</version>
           <configuration>
-            <source>  1.5  </source>
+            <source>1.5</source>
             <target xml:space="preserve">  1.5  </target>
           </configuration>
         </plugin>
+        <plugin>
+          <artifactId>maven-ear-plugin</artifactId>
+          <version>3.3.0</version>
+          <configuration>
+            <modules>
+              <module>
+                <test>test</test>
+              </module>
+              <jarModule>
+                <groupId>artifactGroupId</groupId>
+                <artifactId>artifactId</artifactId>
+                <uri>APP-INF/lib/anotherName-1.2.3.jar</uri>
+              </jarModule>
+            </modules>
+          </configuration>
+        </plugin>
       </plugins>
     </pluginManagement>
     <plugins>
       <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-compiler-plugin</artifactId>
         <executions>
           <execution>
@@ -55,12 +43,23 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <artifactId>maven-ear-plugin</artifactId>
+        <configuration>
+          <modules>
+            <webModule>
+              <groupId>artifactGroupId</groupId>
+              <artifactId>artifactId</artifactId>
+              <excluded>true</excluded>
+            </webModule>
+          </modules>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
-
   <profiles>
     <profile>
-      <id>default</id>
+      <id>default-active</id>
       <activation>
         <activeByDefault>true</activeByDefault>
       </activation>
@@ -80,4 +79,4 @@
       </properties>
     </profile>
   </profiles>
-</project>
+</project>
\ No newline at end of file
diff --git a/maven-core/src/test/resources/projects/transform/before.pom b/maven-core/src/test/resources/projects/transform/before.pom
index c6b2bc2..a1cd1e6 100644
--- a/maven-core/src/test/resources/projects/transform/before.pom
+++ b/maven-core/src/test/resources/projects/transform/before.pom
@@ -19,10 +19,11 @@
 under the License.
 -->
 
-<project xmlns="http://maven.apache.org/POM/4.0.0"
+<project xmlns="http://maven.apache.org/POM/4.1.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>
+         xsi:schemaLocation="http://maven.apache.org/POM/4.1.0 https://maven.apache.org/xsd/maven-4.1.0.xsd"
+         root="true">
+  <modelVersion>4.1.0</modelVersion>
 
   <groupId>test</groupId>
   <artifactId>test</artifactId>
@@ -46,6 +47,23 @@
             <target xml:space="preserve">  1.5  </target>
           </configuration>
         </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-ear-plugin</artifactId>
+          <version>3.3.0</version>
+          <configuration>
+            <modules>
+              <module>
+                <test>test</test>
+              </module>
+              <jarModule>
+                <groupId>artifactGroupId</groupId>
+                <artifactId>artifactId</artifactId>
+                <uri>APP-INF/lib/anotherName-1.2.3.jar</uri>
+              </jarModule>
+            </modules>
+          </configuration>
+        </plugin>
       </plugins>
     </pluginManagement>
     <plugins>
@@ -58,12 +76,25 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-ear-plugin</artifactId>
+        <configuration>
+          <modules>
+            <webModule>
+              <groupId>artifactGroupId</groupId>
+              <artifactId>artifactId</artifactId>
+              <excluded>true</excluded>
+            </webModule>
+          </modules>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
   <profiles>
     <profile>
-      <id>default</id>
+      <id>default-active</id>
       <activation>
         <activeByDefault>true</activeByDefault>
       </activation>
diff --git a/maven-core/src/test/resources/projects/tree/consumer/pom.xml b/maven-core/src/test/resources/projects/tree/consumer/pom.xml
new file mode 100644
index 0000000..c527112
--- /dev/null
+++ b/maven-core/src/test/resources/projects/tree/consumer/pom.xml
@@ -0,0 +1,16 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0">
+
+    <parent>
+        <groupId>org.apache.maven.ut</groupId>
+        <artifactId>parent</artifactId>
+    </parent>
+    <artifactId>consumer</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.maven.ut</groupId>
+            <artifactId>dep</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/maven-core/src/test/resources/projects/tree/dep/pom.xml b/maven-core/src/test/resources/projects/tree/dep/pom.xml
new file mode 100644
index 0000000..09ccb88
--- /dev/null
+++ b/maven-core/src/test/resources/projects/tree/dep/pom.xml
@@ -0,0 +1,9 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0">
+
+    <parent>
+        <groupId>org.apache.maven.ut</groupId>
+        <artifactId>parent</artifactId>
+    </parent>
+    <artifactId>dep</artifactId>
+
+</project>
diff --git a/maven-core/src/test/resources/projects/tree/pom.xml b/maven-core/src/test/resources/projects/tree/pom.xml
new file mode 100644
index 0000000..8534ac4
--- /dev/null
+++ b/maven-core/src/test/resources/projects/tree/pom.xml
@@ -0,0 +1,10 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0">
+    <groupId>org.apache.maven.ut</groupId>
+    <artifactId>parent</artifactId>
+    <version>1.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+    <modules>
+        <module>dep</module>
+        <module>consumer</module>
+    </modules>
+</project>
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index 2013c7b..e26a7f1 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-embedder</artifactId>
@@ -75,22 +73,14 @@
       <artifactId>maven-resolver-util</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.maven.shared</groupId>
-      <artifactId>maven-shared-utils</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-slf4j-wrapper</artifactId>
     </dependency>
     <dependency>
       <groupId>com.google.inject</groupId>
       <artifactId>guice</artifactId>
-      <classifier>no_aop</classifier>
+      <classifier>classes</classifier>
       <exclusions>
-        <exclusion>
-          <groupId>aopalliance</groupId>
-          <artifactId>aopalliance</artifactId>
-        </exclusion>
         <!-- MNG-7068 Active dependency management for Google Guice / Google Guava. Excludes of Guava are managed in parent POM -->
         <exclusion>
           <groupId>com.google.guava</groupId>
@@ -116,10 +106,6 @@
     </dependency>
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-classworlds</artifactId>
     </dependency>
     <dependency>
@@ -158,8 +144,14 @@
       <artifactId>commons-cli</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.commons</groupId>
-      <artifactId>commons-lang3</artifactId>
+      <groupId>org.fusesource.jansi</groupId>
+      <artifactId>jansi</artifactId>
+      <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-params</artifactId>
+      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>org.mockito</groupId>
@@ -167,11 +159,6 @@
       <scope>test</scope>
     </dependency>
     <dependency>
-      <groupId>org.fusesource.jansi</groupId>
-      <artifactId>jansi</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
       <scope>test</scope>
@@ -188,11 +175,30 @@
         <groupId>org.codehaus.modello</groupId>
         <artifactId>modello-maven-plugin</artifactId>
         <configuration>
-          <version>1.1.0</version>
+          <version>1.2.0</version>
           <models>
             <model>src/main/mdo/core-extensions.mdo</model>
           </models>
+          <templates>
+            <template>model.vm</template>
+            <template>reader-stax.vm</template>
+            <template>writer-stax.vm</template>
+          </templates>
+          <params>
+            <param>packageModelV4=org.apache.maven.cli.internal.extension.model</param>
+            <param>packageToolV4=org.apache.maven.cli.internal.extension.io</param>
+          </params>
+          <velocityBasedir>${project.basedir}/../src/mdo</velocityBasedir>
         </configuration>
+        <executions>
+          <execution>
+            <id>modello</id>
+            <goals>
+              <goal>velocity</goal>
+              <goal>xsd</goal>
+            </goals>
+          </execution>
+        </executions>
       </plugin>
     </plugins>
   </build>
diff --git a/maven-embedder/src/examples/simple-project/src/main/java/org/apache/maven/embedder/App.java b/maven-embedder/src/examples/simple-project/src/main/java/org/apache/maven/embedder/App.java
index 06927bf..f05e5d0 100644
--- a/maven-embedder/src/examples/simple-project/src/main/java/org/apache/maven/embedder/App.java
+++ b/maven-embedder/src/examples/simple-project/src/main/java/org/apache/maven/embedder/App.java
@@ -1,20 +1,5 @@
 package org.apache.maven.embedder;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
 /**
  * Hello world!
  *
diff --git a/maven-embedder/src/examples/simple-project/src/test/java/org/apache/maven/embedder/AppTest.java b/maven-embedder/src/examples/simple-project/src/test/java/org/apache/maven/embedder/AppTest.java
index ab1b1a0..f04b7a9 100644
--- a/maven-embedder/src/examples/simple-project/src/test/java/org/apache/maven/embedder/AppTest.java
+++ b/maven-embedder/src/examples/simple-project/src/test/java/org/apache/maven/embedder/AppTest.java
@@ -1,20 +1,5 @@
 package org.apache.maven.embedder;
 
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
- * agreements. See the NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance with the License. You may obtain a
- * copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-
 import junit.framework.Test;
 import junit.framework.TestCase;
 import junit.framework.TestSuite;
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
index 51824ce..3b04b19 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
 
 import java.io.PrintStream;
 import java.io.PrintWriter;
@@ -29,18 +28,26 @@
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.Options;
 import org.apache.commons.cli.ParseException;
-import org.apache.maven.shared.utils.logging.MessageUtils;
+import org.apache.maven.cli.jansi.MessageUtils;
 
 /**
- * @author Jason van Zyl
  */
-public class CLIManager
-{
+public class CLIManager {
     public static final char ALTERNATE_POM_FILE = 'f';
 
     public static final char BATCH_MODE = 'B';
 
-    public static final char SET_SYSTEM_PROPERTY = 'D';
+    public static final String NON_INTERACTIVE = "non-interactive";
+
+    public static final String FORCE_INTERACTIVE = "force-interactive";
+
+    public static final char SET_USER_PROPERTY = 'D';
+
+    /**
+     * @deprecated Use {@link #SET_USER_PROPERTY}
+     */
+    @Deprecated
+    public static final char SET_SYSTEM_PROPERTY = SET_USER_PROPERTY;
 
     public static final char OFFLINE = 'o';
 
@@ -70,6 +77,8 @@
 
     public static final char ALTERNATE_USER_SETTINGS = 's';
 
+    public static final String ALTERNATE_PROJECT_SETTINGS = "ps";
+
     public static final String ALTERNATE_GLOBAL_SETTINGS = "gs";
 
     public static final char ALTERNATE_USER_TOOLCHAINS = 't';
@@ -102,14 +111,16 @@
 
     public static final String THREADS = "T";
 
-    public static final String LEGACY_LOCAL_REPOSITORY = "llr";
-
     public static final String BUILDER = "b";
 
     public static final String NO_TRANSFER_PROGRESS = "ntp";
 
     public static final String COLOR = "color";
 
+    public static final String CACHE_ARTIFACT_NOT_FOUND = "canf";
+
+    public static final String STRICT_ARTIFACT_DESCRIPTOR_POLICY = "sadp";
+
     /** This option is deprecated and may be repurposed as Java debug in a future version.
      * Use {@code -X/--verbose} instead. */
     @Deprecated
@@ -117,81 +128,246 @@
 
     protected Options options;
 
-    @SuppressWarnings( "checkstyle:linelength" )
-    public CLIManager()
-    {
+    @SuppressWarnings("checkstyle:linelength")
+    public CLIManager() {
         options = new Options();
-        options.addOption( Option.builder( Character.toString( HELP ) ).longOpt( "help" ).desc( "Display help information" ).build() );
-        options.addOption( Option.builder( Character.toString( ALTERNATE_POM_FILE ) ).longOpt( "file" ).hasArg().desc( "Force the use of an alternate POM file (or directory with pom.xml)" ).build() );
-        options.addOption( Option.builder( Character.toString( SET_SYSTEM_PROPERTY ) ).numberOfArgs( 2 ).valueSeparator( '=' ).desc( "Define a system property" ).build() );
-        options.addOption( Option.builder( Character.toString( OFFLINE ) ).longOpt( "offline" ).desc( "Work offline" ).build() );
-        options.addOption( Option.builder( Character.toString( VERSION ) ).longOpt( "version" ).desc( "Display version information" ).build() );
-        options.addOption( Option.builder( Character.toString( QUIET ) ).longOpt( "quiet" ).desc( "Quiet output - only show errors" ).build() );
-        options.addOption( Option.builder( Character.toString( VERBOSE ) ).longOpt( "verbose" ).desc( "Produce execution verbose output" ).build() );
-        options.addOption( Option.builder( Character.toString( ERRORS ) ).longOpt( "errors" ).desc( "Produce execution error messages" ).build() );
-        options.addOption( Option.builder( Character.toString( NON_RECURSIVE ) ).longOpt( "non-recursive" ).desc( "Do not recurse into sub-projects. When used together with -pl, do not recurse into sub-projects of selected aggregators" ).build() );
-        options.addOption( Option.builder( Character.toString( UPDATE_SNAPSHOTS ) ).longOpt( "update-snapshots" ).desc( "Forces a check for missing releases and updated snapshots on remote repositories" ).build() );
-        options.addOption( Option.builder( Character.toString( ACTIVATE_PROFILES ) ).longOpt( "activate-profiles" ).desc( "Comma-delimited list of profiles to activate. Prefixing a profile with ! excludes it, and ? marks it as optional" ).hasArg().build() );
-        options.addOption( Option.builder( Character.toString( BATCH_MODE ) ).longOpt( "batch-mode" ).desc( "Run in non-interactive (batch) mode (disables output color)" ).build() );
-        options.addOption( Option.builder( SUPPRESS_SNAPSHOT_UPDATES ).longOpt( "no-snapshot-updates" ).desc( "Suppress SNAPSHOT updates" ).build() );
-        options.addOption( Option.builder( Character.toString( CHECKSUM_FAILURE_POLICY ) ).longOpt( "strict-checksums" ).desc( "Fail the build if checksums don't match" ).build() );
-        options.addOption( Option.builder( Character.toString( CHECKSUM_WARNING_POLICY ) ).longOpt( "lax-checksums" ).desc( "Warn if checksums don't match" ).build() );
-        options.addOption( Option.builder( Character.toString( ALTERNATE_USER_SETTINGS ) ).longOpt( "settings" ).desc( "Alternate path for the user settings file" ).hasArg().build() );
-        options.addOption( Option.builder( ALTERNATE_GLOBAL_SETTINGS ).longOpt( "global-settings" ).desc( "Alternate path for the global settings file" ).hasArg().build() );
-        options.addOption( Option.builder( Character.toString( ALTERNATE_USER_TOOLCHAINS ) ).longOpt( "toolchains" ).desc( "Alternate path for the user toolchains file" ).hasArg().build() );
-        options.addOption( Option.builder( ALTERNATE_GLOBAL_TOOLCHAINS ).longOpt( "global-toolchains" ).desc( "Alternate path for the global toolchains file" ).hasArg().build() );
-        options.addOption( Option.builder( FAIL_ON_SEVERITY ).longOpt( "fail-on-severity" ).desc( "Configure which severity of logging should cause the build to fail" ).hasArg().build() );
-        options.addOption( Option.builder( FAIL_FAST ).longOpt( "fail-fast" ).desc( "Stop at first failure in reactorized builds" ).build() );
-        options.addOption( Option.builder( FAIL_AT_END ).longOpt( "fail-at-end" ).desc( "Only fail the build afterwards; allow all non-impacted builds to continue" ).build() );
-        options.addOption( Option.builder( FAIL_NEVER ).longOpt( "fail-never" ).desc( "NEVER fail the build, regardless of project result" ).build() );
-        options.addOption( Option.builder( RESUME ).longOpt( "resume" ).desc( "Resume reactor from the last failed project, using the resume.properties file in the build directory" ).build() );
-        options.addOption( Option.builder( RESUME_FROM ).longOpt( "resume-from" ).hasArg().desc( "Resume reactor from specified project" ).build() );
-        options.addOption( Option.builder( PROJECT_LIST ).longOpt( "projects" ).desc( "Comma-delimited list of specified reactor projects to build instead of all projects. A project can be specified by [groupId]:artifactId or by its relative path. Prefixing a project with ! excludes it, and ? marks it as optional" ).hasArg().build() );
-        options.addOption( Option.builder( ALSO_MAKE ).longOpt( "also-make" ).desc( "If project list is specified, also build projects required by the list" ).build() );
-        options.addOption( Option.builder( ALSO_MAKE_DEPENDENTS ).longOpt( "also-make-dependents" ).desc( "If project list is specified, also build projects that depend on projects on the list" ).build() );
-        options.addOption( Option.builder( LOG_FILE ).longOpt( "log-file" ).hasArg().desc( "Log file where all build output will go (disables output color)" ).build() );
-        options.addOption( Option.builder( Character.toString( SHOW_VERSION ) ).longOpt( "show-version" ).desc( "Display version information WITHOUT stopping build" ).build() );
-        options.addOption( Option.builder( ENCRYPT_MASTER_PASSWORD ).longOpt( "encrypt-master-password" ).hasArg().optionalArg( true ).desc( "Encrypt master security password" ).build() );
-        options.addOption( Option.builder( ENCRYPT_PASSWORD ).longOpt( "encrypt-password" ).hasArg().optionalArg( true ).desc( "Encrypt server password" ).build() );
-        options.addOption( Option.builder( THREADS ).longOpt( "threads" ).hasArg().desc( "Thread count, for instance 4 (int) or 2C/2.5C (int/float) where C is core multiplied" ).build() );
-        options.addOption( Option.builder( LEGACY_LOCAL_REPOSITORY ).longOpt( "legacy-local-repository" ).desc( "Use Maven 2 Legacy Local Repository behaviour, ie no use of _remote.repositories. Can also be activated by using -Dmaven.legacyLocalRepo=true" ).build() );
-        options.addOption( Option.builder( BUILDER ).longOpt( "builder" ).hasArg().desc( "The id of the build strategy to use" ).build() );
-        options.addOption( Option.builder( NO_TRANSFER_PROGRESS ).longOpt( "no-transfer-progress" ).desc( "Do not display transfer progress when downloading or uploading" ).build() );
-        options.addOption( Option.builder().longOpt( COLOR ).hasArg().optionalArg( true ).desc( "Defines the color mode of the output. Supported are 'auto', 'always', 'never'." ).build() );
+        options.addOption(Option.builder(Character.toString(HELP))
+                .longOpt("help")
+                .desc("Display help information")
+                .build());
+        options.addOption(Option.builder(Character.toString(ALTERNATE_POM_FILE))
+                .longOpt("file")
+                .hasArg()
+                .desc("Force the use of an alternate POM file (or directory with pom.xml)")
+                .build());
+        options.addOption(Option.builder(Character.toString(SET_USER_PROPERTY))
+                .numberOfArgs(2)
+                .valueSeparator('=')
+                .desc("Define a user property")
+                .build());
+        options.addOption(Option.builder(Character.toString(OFFLINE))
+                .longOpt("offline")
+                .desc("Work offline")
+                .build());
+        options.addOption(Option.builder(Character.toString(VERSION))
+                .longOpt("version")
+                .desc("Display version information")
+                .build());
+        options.addOption(Option.builder(Character.toString(QUIET))
+                .longOpt("quiet")
+                .desc("Quiet output - only show errors")
+                .build());
+        options.addOption(Option.builder(Character.toString(VERBOSE))
+                .longOpt("verbose")
+                .desc("Produce execution verbose output")
+                .build());
+        options.addOption(Option.builder(Character.toString(ERRORS))
+                .longOpt("errors")
+                .desc("Produce execution error messages")
+                .build());
+        options.addOption(Option.builder(Character.toString(NON_RECURSIVE))
+                .longOpt("non-recursive")
+                .desc(
+                        "Do not recurse into sub-projects. When used together with -pl, do not recurse into sub-projects of selected aggregators")
+                .build());
+        options.addOption(Option.builder(Character.toString(UPDATE_SNAPSHOTS))
+                .longOpt("update-snapshots")
+                .desc("Forces a check for missing releases and updated snapshots on remote repositories")
+                .build());
+        options.addOption(Option.builder(Character.toString(ACTIVATE_PROFILES))
+                .longOpt("activate-profiles")
+                .desc(
+                        "Comma-delimited list of profiles to activate. Prefixing a profile with ! excludes it, and ? marks it as optional")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(Character.toString(BATCH_MODE))
+                .longOpt("batch-mode")
+                .desc("Run in non-interactive mode. Alias for --non-interactive (kept for backwards compatability)")
+                .build());
+        options.addOption(Option.builder()
+                .longOpt(NON_INTERACTIVE)
+                .desc("Run in non-interactive mode. Alias for --batch-mode")
+                .build());
+        options.addOption(Option.builder()
+                .longOpt(FORCE_INTERACTIVE)
+                .desc(
+                        "Run in interactive mode. Overrides, if applicable, the CI environment variable and --non-interactive/--batch-mode options")
+                .build());
+        options.addOption(Option.builder(SUPPRESS_SNAPSHOT_UPDATES)
+                .longOpt("no-snapshot-updates")
+                .desc("Suppress SNAPSHOT updates")
+                .build());
+        options.addOption(Option.builder(Character.toString(CHECKSUM_FAILURE_POLICY))
+                .longOpt("strict-checksums")
+                .desc("Fail the build if checksums don't match")
+                .build());
+        options.addOption(Option.builder(Character.toString(CHECKSUM_WARNING_POLICY))
+                .longOpt("lax-checksums")
+                .desc("Warn if checksums don't match")
+                .build());
+        options.addOption(Option.builder(Character.toString(ALTERNATE_USER_SETTINGS))
+                .longOpt("settings")
+                .desc("Alternate path for the user settings file")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(ALTERNATE_PROJECT_SETTINGS)
+                .longOpt("project-settings")
+                .desc("Alternate path for the project settings file")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(ALTERNATE_GLOBAL_SETTINGS)
+                .longOpt("global-settings")
+                .desc("Alternate path for the global settings file")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(Character.toString(ALTERNATE_USER_TOOLCHAINS))
+                .longOpt("toolchains")
+                .desc("Alternate path for the user toolchains file")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(ALTERNATE_GLOBAL_TOOLCHAINS)
+                .longOpt("global-toolchains")
+                .desc("Alternate path for the global toolchains file")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(FAIL_ON_SEVERITY)
+                .longOpt("fail-on-severity")
+                .desc("Configure which severity of logging should cause the build to fail")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(FAIL_FAST)
+                .longOpt("fail-fast")
+                .desc("Stop at first failure in reactorized builds")
+                .build());
+        options.addOption(Option.builder(FAIL_AT_END)
+                .longOpt("fail-at-end")
+                .desc("Only fail the build afterwards; allow all non-impacted builds to continue")
+                .build());
+        options.addOption(Option.builder(FAIL_NEVER)
+                .longOpt("fail-never")
+                .desc("NEVER fail the build, regardless of project result")
+                .build());
+        options.addOption(Option.builder(RESUME)
+                .longOpt("resume")
+                .desc(
+                        "Resume reactor from the last failed project, using the resume.properties file in the build directory")
+                .build());
+        options.addOption(Option.builder(RESUME_FROM)
+                .longOpt("resume-from")
+                .hasArg()
+                .desc("Resume reactor from specified project")
+                .build());
+        options.addOption(Option.builder(PROJECT_LIST)
+                .longOpt("projects")
+                .desc(
+                        "Comma-delimited list of specified reactor projects to build instead of all projects. A project can be specified by [groupId]:artifactId or by its relative path. Prefixing a project with ! excludes it, and ? marks it as optional")
+                .hasArg()
+                .build());
+        options.addOption(Option.builder(ALSO_MAKE)
+                .longOpt("also-make")
+                .desc("If project list is specified, also build projects required by the list")
+                .build());
+        options.addOption(Option.builder(ALSO_MAKE_DEPENDENTS)
+                .longOpt("also-make-dependents")
+                .desc("If project list is specified, also build projects that depend on projects on the list")
+                .build());
+        options.addOption(Option.builder(LOG_FILE)
+                .longOpt("log-file")
+                .hasArg()
+                .desc("Log file where all build output will go (disables output color)")
+                .build());
+        options.addOption(Option.builder(Character.toString(SHOW_VERSION))
+                .longOpt("show-version")
+                .desc("Display version information WITHOUT stopping build")
+                .build());
+        options.addOption(Option.builder(ENCRYPT_MASTER_PASSWORD)
+                .longOpt("encrypt-master-password")
+                .hasArg()
+                .optionalArg(true)
+                .desc("Encrypt master security password")
+                .build());
+        options.addOption(Option.builder(ENCRYPT_PASSWORD)
+                .longOpt("encrypt-password")
+                .hasArg()
+                .optionalArg(true)
+                .desc("Encrypt server password")
+                .build());
+        options.addOption(Option.builder(THREADS)
+                .longOpt("threads")
+                .hasArg()
+                .desc("Thread count, for instance 4 (int) or 2C/2.5C (int/float) where C is core multiplied")
+                .build());
+        options.addOption(Option.builder(BUILDER)
+                .longOpt("builder")
+                .hasArg()
+                .desc("The id of the build strategy to use")
+                .build());
+        options.addOption(Option.builder(NO_TRANSFER_PROGRESS)
+                .longOpt("no-transfer-progress")
+                .desc("Do not display transfer progress when downloading or uploading")
+                .build());
+        options.addOption(Option.builder()
+                .longOpt(COLOR)
+                .hasArg()
+                .optionalArg(true)
+                .desc("Defines the color mode of the output. Supported are 'auto', 'always', 'never'.")
+                .build());
+        options.addOption(Option.builder(CACHE_ARTIFACT_NOT_FOUND)
+                .longOpt("cache-artifact-not-found")
+                .hasArg()
+                .desc(
+                        "Defines caching behaviour for 'not found' artifacts. Supported values are 'true' (default), 'false'.")
+                .build());
+        options.addOption(Option.builder(STRICT_ARTIFACT_DESCRIPTOR_POLICY)
+                .longOpt("strict-artifact-descriptor-policy")
+                .hasArg()
+                .desc("Defines 'strict' artifact descriptor policy. Supported values are 'true', 'false' (default).")
+                .build());
+
+        // Adding this back to make Maven fail if used
+        options.addOption(Option.builder("llr")
+                .longOpt("legacy-local-repository")
+                .desc("UNSUPPORTED: Use of this option will make Maven invocation fail.")
+                .build());
 
         // Deprecated
-        options.addOption( Option.builder().longOpt( DEBUG ).desc( "Produce execution verbose output (deprecated; only kept for backward compatibility)" ).build() );
+        options.addOption(Option.builder()
+                .longOpt(DEBUG)
+                .desc("Produce execution verbose output (deprecated; only kept for backward compatibility)")
+                .build());
     }
 
-    public CommandLine parse( String[] args )
-        throws ParseException
-    {
+    public CommandLine parse(String[] args) throws ParseException {
         // We need to eat any quotes surrounding arguments...
-        String[] cleanArgs = CleanArgument.cleanArgs( args );
+        String[] cleanArgs = CleanArgument.cleanArgs(args);
 
         CommandLineParser parser = new DefaultParser();
 
-        return parser.parse( options, cleanArgs );
+        return parser.parse(options, cleanArgs);
     }
 
-    public void displayHelp( PrintStream stdout )
-    {
+    public void displayHelp(PrintStream stdout) {
         stdout.println();
 
-        PrintWriter pw = new PrintWriter( stdout );
+        PrintWriter pw = new PrintWriter(stdout);
 
         HelpFormatter formatter = new HelpFormatter();
 
         int width = MessageUtils.getTerminalWidth();
-        if ( width <= 0 )
-        {
+        if (width <= 0) {
             width = HelpFormatter.DEFAULT_WIDTH;
         }
 
-        formatter.printHelp( pw, width, "mvn [args]",
-                             System.lineSeparator() + "Options:", options,
-                             HelpFormatter.DEFAULT_LEFT_PAD, HelpFormatter.DEFAULT_DESC_PAD,
-                             System.lineSeparator(), false );
+        formatter.printHelp(
+                pw,
+                width,
+                "mvn [args]",
+                System.lineSeparator() + "Options:",
+                options,
+                HelpFormatter.DEFAULT_LEFT_PAD,
+                HelpFormatter.DEFAULT_DESC_PAD,
+                System.lineSeparator(),
+                false);
 
         pw.flush();
     }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java
index 4cdfbfd..5fd3198 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,8 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
+package org.apache.maven.cli;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -28,17 +25,15 @@
 import java.util.Locale;
 import java.util.Properties;
 
-import org.apache.commons.lang3.StringUtils;
-import org.codehaus.plexus.util.Os;
+import org.apache.maven.cli.jansi.MessageUtils;
+import org.apache.maven.utils.Os;
 import org.slf4j.Logger;
 
 /**
  * Utility class used to report errors, statistics, application version info, etc.
  *
- * @author jdcasey
  */
-public final class CLIReportingUtils
-{
+public final class CLIReportingUtils {
     // CHECKSTYLE_OFF: MagicNumber
     public static final long MB = 1024 * 1024;
 
@@ -53,33 +48,43 @@
 
     public static final String BUILD_VERSION_PROPERTY = "version";
 
-    public static String showVersion()
-    {
+    public static String showVersion() {
         final String ls = System.lineSeparator();
         Properties properties = getBuildProperties();
-        StringBuilder version = new StringBuilder( 256 );
-        version.append( buffer().strong( createMavenVersionString( properties ) ) ).append( ls );
-        version.append( reduce(
-            properties.getProperty( "distributionShortName" ) + " home: " + System.getProperty( "maven.home",
-                                                                                                "<unknown Maven "
-                                                                                                    + "home>" ) ) )
-            .append( ls );
-        version.append( "Java version: " ).append(
-            System.getProperty( "java.version", "<unknown Java version>" ) ).append( ", vendor: " ).append(
-            System.getProperty( "java.vendor", "<unknown vendor>" ) ).append( ", runtime: " ).append(
-            System.getProperty( "java.home", "<unknown runtime>" ) ).append( ls );
-        version.append( "Default locale: " ).append( Locale.getDefault() ).append( ", platform encoding: " ).append(
-            System.getProperty( "file.encoding", "<unknown encoding>" ) ).append( ls );
-        version.append( "OS name: \"" ).append( Os.OS_NAME ).append( "\", version: \"" ).append( Os.OS_VERSION ).append(
-            "\", arch: \"" ).append( Os.OS_ARCH ).append( "\", family: \"" ).append( Os.OS_FAMILY ).append( '\"' );
+        StringBuilder version = new StringBuilder(256);
+        version.append(MessageUtils.builder().strong(createMavenVersionString(properties)))
+                .append(ls);
+        version.append(reduce(properties.getProperty("distributionShortName") + " home: "
+                        + System.getProperty("maven.home", "<unknown Maven " + "home>")))
+                .append(ls);
+        version.append("Java version: ")
+                .append(System.getProperty("java.version", "<unknown Java version>"))
+                .append(", vendor: ")
+                .append(System.getProperty("java.vendor", "<unknown vendor>"))
+                .append(", runtime: ")
+                .append(System.getProperty("java.home", "<unknown runtime>"))
+                .append(ls);
+        version.append("Default locale: ")
+                .append(Locale.getDefault())
+                .append(", platform encoding: ")
+                .append(System.getProperty("file.encoding", "<unknown encoding>"))
+                .append(ls);
+        version.append("OS name: \"")
+                .append(Os.OS_NAME)
+                .append("\", version: \"")
+                .append(Os.OS_VERSION)
+                .append("\", arch: \"")
+                .append(Os.OS_ARCH)
+                .append("\", family: \"")
+                .append(Os.OS_FAMILY)
+                .append('\"');
         return version.toString();
     }
 
-    public static String showVersionMinimal()
-    {
+    public static String showVersionMinimal() {
         Properties properties = getBuildProperties();
-        String version = reduce( properties.getProperty( BUILD_VERSION_PROPERTY ) );
-        return ( version != null ? version : "<version unknown>" );
+        String version = reduce(properties.getProperty(BUILD_VERSION_PROPERTY));
+        return (version != null ? version : "<version unknown>");
     }
 
     /**
@@ -88,116 +93,100 @@
      * @param buildProperties The build properties
      * @return Readable build info
      */
-    static String createMavenVersionString( Properties buildProperties )
-    {
-        String timestamp = reduce( buildProperties.getProperty( "timestamp" ) );
-        String version = reduce( buildProperties.getProperty( BUILD_VERSION_PROPERTY ) );
-        String rev = reduce( buildProperties.getProperty( "buildNumber" ) );
-        String distributionName = reduce( buildProperties.getProperty( "distributionName" ) );
+    static String createMavenVersionString(Properties buildProperties) {
+        String timestamp = reduce(buildProperties.getProperty("timestamp"));
+        String version = reduce(buildProperties.getProperty(BUILD_VERSION_PROPERTY));
+        String rev = reduce(buildProperties.getProperty("buildNumber"));
+        String distributionName = reduce(buildProperties.getProperty("distributionName"));
 
         String msg = distributionName + " ";
-        msg += ( version != null ? version : "<version unknown>" );
-        if ( rev != null || timestamp != null )
-        {
+        msg += (version != null ? version : "<version unknown>");
+        if (rev != null || timestamp != null) {
             msg += " (";
-            msg += ( rev != null ? rev : "" );
-            if ( StringUtils.isNotBlank( timestamp ) )
-            {
-                String ts = formatTimestamp( Long.parseLong( timestamp ) );
-                msg += ( rev != null ? "; " : "" ) + ts;
+            msg += (rev != null ? rev : "");
+            if (timestamp != null && !timestamp.isEmpty()) {
+                String ts = formatTimestamp(Long.parseLong(timestamp));
+                msg += (rev != null ? "; " : "") + ts;
             }
             msg += ")";
         }
         return msg;
     }
 
-    private static String reduce( String s )
-    {
-        return ( s != null ? ( s.startsWith( "${" ) && s.endsWith( "}" ) ? null : s ) : null );
+    private static String reduce(String s) {
+        return (s != null ? (s.startsWith("${") && s.endsWith("}") ? null : s) : null);
     }
 
-    static Properties getBuildProperties()
-    {
+    static Properties getBuildProperties() {
         Properties properties = new Properties();
 
-        try ( InputStream resourceAsStream = MavenCli.class.getResourceAsStream(
-            "/org/apache/maven/messages/build.properties" ) )
-        {
+        try (InputStream resourceAsStream =
+                MavenCli.class.getResourceAsStream("/org/apache/maven/messages/build.properties")) {
 
-            if ( resourceAsStream != null )
-            {
-                properties.load( resourceAsStream );
+            if (resourceAsStream != null) {
+                properties.load(resourceAsStream);
             }
-        }
-        catch ( IOException e )
-        {
-            System.err.println( "Unable determine version from JAR file: " + e.getMessage() );
+        } catch (IOException e) {
+            System.err.println("Unable determine version from JAR file: " + e.getMessage());
         }
 
         return properties;
     }
 
-    public static void showError( Logger logger, String message, Throwable e, boolean showStackTrace )
-    {
-        if ( showStackTrace )
-        {
-            logger.error( message, e );
+    public static void showError(Logger logger, String message, Throwable e, boolean showStackTrace) {
+        if (logger == null) {
+            System.err.println(message);
+            if (showStackTrace && e != null) {
+                e.printStackTrace(System.err);
+            }
+            return;
         }
-        else
-        {
-            logger.error( message );
+        if (showStackTrace) {
+            logger.error(message, e);
+        } else {
+            logger.error(message);
 
-            if ( e != null )
-            {
-                logger.error( e.getMessage() );
+            if (e != null) {
+                logger.error(e.getMessage());
 
-                for ( Throwable cause = e.getCause(); cause != null; cause = cause.getCause() )
-                {
-                    logger.error( "Caused by: {}", cause.getMessage() );
+                for (Throwable cause = e.getCause();
+                        cause != null && cause != cause.getCause();
+                        cause = cause.getCause()) {
+                    logger.error("Caused by: {}", cause.getMessage());
                 }
             }
         }
     }
 
-    public static String formatTimestamp( long timestamp )
-    {
-        SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssXXX" );
-        return sdf.format( new Date( timestamp ) );
+    public static String formatTimestamp(long timestamp) {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
+        return sdf.format(new Date(timestamp));
     }
 
-    public static String formatDuration( long duration )
-    {
+    public static String formatDuration(long duration) {
         // CHECKSTYLE_OFF: MagicNumber
         long ms = duration % 1000;
-        long s = ( duration / ONE_SECOND ) % 60;
-        long m = ( duration / ONE_MINUTE ) % 60;
-        long h = ( duration / ONE_HOUR ) % 24;
+        long s = (duration / ONE_SECOND) % 60;
+        long m = (duration / ONE_MINUTE) % 60;
+        long h = (duration / ONE_HOUR) % 24;
         long d = duration / ONE_DAY;
         // CHECKSTYLE_ON: MagicNumber
 
         String format;
-        if ( d > 0 )
-        {
+        if (d > 0) {
             // Length 11+ chars
             format = "%d d %02d:%02d h";
-        }
-        else if ( h > 0 )
-        {
+        } else if (h > 0) {
             // Length 7 chars
             format = "%2$02d:%3$02d h";
-        }
-        else if ( m > 0 )
-        {
+        } else if (m > 0) {
             // Length 9 chars
             format = "%3$02d:%4$02d min";
-        }
-        else
-        {
+        } else {
             // Length 7-8 chars
             format = "%4$d.%5$03d s";
         }
 
-        return String.format( format, d, h, m, s, ms );
+        return String.format(format, d, h, m, s, ms);
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CleanArgument.java b/maven-embedder/src/main/java/org/apache/maven/cli/CleanArgument.java
index 08403b6..c725faa 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/CleanArgument.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/CleanArgument.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -25,57 +24,46 @@
 /**
  * CleanArgument
  */
-public class CleanArgument
-{
-    public static String[] cleanArgs( String[] args )
-    {
+public class CleanArgument {
+    public static String[] cleanArgs(String[] args) {
         List<String> cleaned = new ArrayList<>();
 
         StringBuilder currentArg = null;
 
-        for ( String arg : args )
-        {
+        for (String arg : args) {
             boolean addedToBuffer = false;
 
-            if ( arg.startsWith( "\"" ) )
-            {
+            if (arg.startsWith("\"")) {
                 // if we're in the process of building up another arg, push it and start over.
                 // this is for the case: "-Dfoo=bar "-Dfoo2=bar two" (note the first unterminated quote)
-                if ( currentArg != null )
-                {
-                    cleaned.add( currentArg.toString() );
+                if (currentArg != null) {
+                    cleaned.add(currentArg.toString());
                 }
 
                 // start building an argument here.
-                currentArg = new StringBuilder( arg.substring( 1 ) );
+                currentArg = new StringBuilder(arg.substring(1));
                 addedToBuffer = true;
             }
 
             // this has to be a separate "if" statement, to capture the case of: "-Dfoo=bar"
-            if ( addedToBuffer && arg.endsWith( "\"" ) )
-            {
-                String cleanArgPart = arg.substring( 0, arg.length() - 1 );
+            if (addedToBuffer && arg.endsWith("\"")) {
+                String cleanArgPart = arg.substring(0, arg.length() - 1);
 
                 // if we're building an argument, keep doing so.
-                if ( currentArg != null )
-                {
+                if (currentArg != null) {
                     // if this is the case of "-Dfoo=bar", then we need to adjust the buffer.
-                    if ( addedToBuffer )
-                    {
-                        currentArg.setLength( currentArg.length() - 1 );
+                    if (addedToBuffer) {
+                        currentArg.setLength(currentArg.length() - 1);
                     }
                     // otherwise, we trim the trailing " and append to the buffer.
-                    else
-                    {
+                    else {
                         // TODO introducing a space here...not sure what else to do but collapse whitespace
-                        currentArg.append( ' ' ).append( cleanArgPart );
+                        currentArg.append(' ').append(cleanArgPart);
                     }
 
-                    cleaned.add( currentArg.toString() );
-                }
-                else
-                {
-                    cleaned.add( cleanArgPart );
+                    cleaned.add(currentArg.toString());
+                } else {
+                    cleaned.add(cleanArgPart);
                 }
 
                 currentArg = null;
@@ -87,39 +75,29 @@
             // buffer, then append it with a preceding space...again, not sure what else to
             // do other than collapse whitespace.
             // NOTE: The case of a trailing quote is handled by nullifying the arg buffer.
-            if ( !addedToBuffer )
-            {
-                if ( currentArg != null )
-                {
-                    currentArg.append( ' ' ).append( arg );
-                }
-                else
-                {
-                    cleaned.add( arg );
+            if (!addedToBuffer) {
+                if (currentArg != null) {
+                    currentArg.append(' ').append(arg);
+                } else {
+                    cleaned.add(arg);
                 }
             }
         }
 
-        if ( currentArg != null )
-        {
-            cleaned.add( currentArg.toString() );
+        if (currentArg != null) {
+            cleaned.add(currentArg.toString());
         }
 
         int cleanedSz = cleaned.size();
 
         String[] cleanArgs;
 
-        if ( cleanedSz == 0 )
-        {
+        if (cleanedSz == 0) {
             cleanArgs = args;
-        }
-        else
-        {
-            cleanArgs = cleaned.toArray( new String[0] );
+        } else {
+            cleanArgs = cleaned.toArray(new String[0]);
         }
 
         return cleanArgs;
     }
-
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CliRequest.java b/maven-embedder/src/main/java/org/apache/maven/cli/CliRequest.java
index 166d1a1..1e8a184 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/CliRequest.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/CliRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.Properties;
 
 import org.apache.commons.cli.CommandLine;
@@ -30,8 +30,7 @@
 /**
  * CliRequest
  */
-public class CliRequest
-{
+public class CliRequest {
     String[] args;
 
     CommandLine commandLine;
@@ -42,6 +41,10 @@
 
     File multiModuleProjectDirectory;
 
+    Path rootDirectory;
+
+    Path topDirectory;
+
     boolean verbose;
 
     boolean quiet;
@@ -54,70 +57,65 @@
 
     MavenExecutionRequest request;
 
-    CliRequest( String[] args, ClassWorld classWorld )
-    {
+    CliRequest(String[] args, ClassWorld classWorld) {
         this.args = args;
         this.classWorld = classWorld;
         this.request = new DefaultMavenExecutionRequest();
     }
 
-    public String[] getArgs()
-    {
+    public String[] getArgs() {
         return args;
     }
 
-    public CommandLine getCommandLine()
-    {
+    public CommandLine getCommandLine() {
         return commandLine;
     }
 
-    public ClassWorld getClassWorld()
-    {
+    public ClassWorld getClassWorld() {
         return classWorld;
     }
 
-    public String getWorkingDirectory()
-    {
+    public String getWorkingDirectory() {
         return workingDirectory;
     }
 
-    public File getMultiModuleProjectDirectory()
-    {
+    public File getMultiModuleProjectDirectory() {
         return multiModuleProjectDirectory;
     }
 
-    public boolean isVerbose()
-    {
+    public boolean isVerbose() {
         return verbose;
     }
 
-    public boolean isQuiet()
-    {
+    public boolean isQuiet() {
         return quiet;
     }
 
-    public boolean isShowErrors()
-    {
+    public boolean isShowErrors() {
         return showErrors;
     }
 
-    public Properties getUserProperties()
-    {
+    public Properties getUserProperties() {
         return userProperties;
     }
 
-    public Properties getSystemProperties()
-    {
+    public Properties getSystemProperties() {
         return systemProperties;
     }
 
-    public MavenExecutionRequest getRequest()
-    {
+    public MavenExecutionRequest getRequest() {
         return request;
     }
 
-    public void setUserProperties( Properties properties )
-    {
-        this.userProperties.putAll( properties );
+    public void setUserProperties(Properties properties) {
+        this.userProperties.putAll(properties);
     }
-}
\ No newline at end of file
+
+    public Path getRootDirectory() {
+        return rootDirectory;
+    }
+
+    public Path getTopDirectory() {
+        return topDirectory;
+    }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/ExtensionConfigurationModule.java b/maven-embedder/src/main/java/org/apache/maven/cli/ExtensionConfigurationModule.java
new file mode 100644
index 0000000..21d9cb2
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/ExtensionConfigurationModule.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.cli;
+
+import java.util.Arrays;
+
+import com.google.inject.Binder;
+import com.google.inject.Module;
+import com.google.inject.name.Names;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.extension.internal.CoreExtensionEntry;
+import org.apache.maven.internal.xml.XmlNodeImpl;
+import org.apache.maven.internal.xml.XmlPlexusConfiguration;
+import org.apache.maven.model.v4.MavenTransformer;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+import org.codehaus.plexus.interpolation.InterpolationException;
+import org.codehaus.plexus.interpolation.StringSearchInterpolator;
+import org.codehaus.plexus.interpolation.ValueSource;
+
+public class ExtensionConfigurationModule implements Module {
+
+    private final CoreExtensionEntry extension;
+    private final Iterable<ValueSource> valueSources;
+
+    public ExtensionConfigurationModule(CoreExtensionEntry extension, ValueSource... valueSources) {
+        this.extension = extension;
+        this.valueSources = Arrays.asList(valueSources);
+    }
+
+    @Override
+    public void configure(Binder binder) {
+        if (extension.getKey() != null) {
+            XmlNode configuration = extension.getConfiguration();
+            if (configuration == null) {
+                configuration = new XmlNodeImpl("configuration");
+            }
+            configuration = new Interpolator().transform(configuration);
+
+            binder.bind(XmlNode.class)
+                    .annotatedWith(Names.named(extension.getKey()))
+                    .toInstance(configuration);
+            binder.bind(PlexusConfiguration.class)
+                    .annotatedWith(Names.named(extension.getKey()))
+                    .toInstance(XmlPlexusConfiguration.toPlexusConfiguration(configuration));
+        }
+    }
+
+    class Interpolator extends MavenTransformer {
+        final StringSearchInterpolator interpolator;
+
+        Interpolator() {
+            super(null);
+            interpolator = new StringSearchInterpolator();
+            interpolator.setCacheAnswers(true);
+            valueSources.forEach(interpolator::addValueSource);
+        }
+
+        public XmlNode transform(XmlNode node) {
+            return super.transform(node);
+        }
+
+        protected String transform(String str) {
+            try {
+                return interpolator.interpolate(str);
+            } catch (InterpolationException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 598dcaa..422fe9c 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,38 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Console;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
 
 import com.google.inject.AbstractModule;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.ParseException;
 import org.apache.commons.cli.UnrecognizedOptionException;
-import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.maven.BuildAbort;
 import org.apache.maven.InternalErrorException;
 import org.apache.maven.Maven;
+import org.apache.maven.api.services.MessageBuilder;
+import org.apache.maven.api.services.MessageBuilderFactory;
 import org.apache.maven.building.FileSource;
 import org.apache.maven.building.Problem;
 import org.apache.maven.building.Source;
@@ -36,8 +56,10 @@
 import org.apache.maven.cli.event.DefaultEventSpyContext;
 import org.apache.maven.cli.event.ExecutionEventLogger;
 import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
+import org.apache.maven.cli.internal.extension.io.CoreExtensionsStaxReader;
 import org.apache.maven.cli.internal.extension.model.CoreExtension;
-import org.apache.maven.cli.internal.extension.model.io.xpp3.CoreExtensionsXpp3Reader;
+import org.apache.maven.cli.jansi.JansiMessageBuilderFactory;
+import org.apache.maven.cli.jansi.MessageUtils;
 import org.apache.maven.cli.logging.Slf4jConfiguration;
 import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
 import org.apache.maven.cli.logging.Slf4jLoggerManager;
@@ -64,12 +86,11 @@
 import org.apache.maven.logwrapper.LogLevelRecorder;
 import org.apache.maven.logwrapper.MavenSlf4jWrapperFactory;
 import org.apache.maven.model.building.ModelProcessor;
+import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.properties.internal.EnvironmentUtils;
 import org.apache.maven.properties.internal.SystemProperties;
 import org.apache.maven.session.scope.internal.SessionScopeModule;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.apache.maven.shared.utils.logging.MessageUtils;
 import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
 import org.apache.maven.toolchain.building.ToolchainsBuilder;
 import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
@@ -82,9 +103,10 @@
 import org.codehaus.plexus.classworlds.realm.ClassRealm;
 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
+import org.codehaus.plexus.interpolation.AbstractValueSource;
+import org.codehaus.plexus.interpolation.BasicInterpolator;
+import org.codehaus.plexus.interpolation.StringSearchInterpolator;
 import org.codehaus.plexus.logging.LoggerManager;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 import org.eclipse.aether.DefaultRepositoryCache;
 import org.eclipse.aether.transfer.TransferListener;
 import org.slf4j.ILoggerFactory;
@@ -96,58 +118,36 @@
 import org.sonatype.plexus.components.sec.dispatcher.SecUtil;
 import org.sonatype.plexus.components.sec.dispatcher.model.SettingsSecurity;
 
-import java.io.BufferedInputStream;
-import java.io.Console;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PrintStream;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Properties;
-import java.util.Set;
-import java.util.function.Consumer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 import static java.util.Comparator.comparing;
+import static org.apache.maven.cli.CLIManager.BATCH_MODE;
 import static org.apache.maven.cli.CLIManager.COLOR;
+import static org.apache.maven.cli.CLIManager.FORCE_INTERACTIVE;
+import static org.apache.maven.cli.CLIManager.NON_INTERACTIVE;
 import static org.apache.maven.cli.ResolveFile.resolveFile;
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
 
 // TODO push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs
 
 /**
- * @author Jason van Zyl
  */
-public class MavenCli
-{
+public class MavenCli {
     public static final String LOCAL_REPO_PROPERTY = "maven.repo.local";
 
     public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory";
 
-    public static final String USER_HOME = System.getProperty( "user.home" );
+    public static final String USER_HOME = System.getProperty("user.home");
 
-    public static final File USER_MAVEN_CONFIGURATION_HOME = new File( USER_HOME, ".m2" );
+    public static final File USER_MAVEN_CONFIGURATION_HOME = new File(USER_HOME, ".m2");
 
-    public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File( USER_MAVEN_CONFIGURATION_HOME, "toolchains.xml" );
+    public static final File DEFAULT_USER_TOOLCHAINS_FILE = new File(USER_MAVEN_CONFIGURATION_HOME, "toolchains.xml");
 
     public static final File DEFAULT_GLOBAL_TOOLCHAINS_FILE =
-        new File( System.getProperty( "maven.conf" ), "toolchains.xml" );
+            new File(System.getProperty("maven.conf"), "toolchains.xml");
 
     private static final String EXT_CLASS_PATH = "maven.ext.class.path";
 
-    private static final String EXTENSIONS_FILENAME = ".mvn/extensions.xml";
+    private static final String EXTENSIONS_FILENAME = "extensions.xml";
+
+    private static final String MVN_EXTENSIONS_FILENAME = ".mvn/" + EXTENSIONS_FILENAME;
 
     private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config";
 
@@ -177,41 +177,41 @@
 
     private CLIManager cliManager;
 
-    public MavenCli()
-    {
-        this( null );
+    private MessageBuilderFactory messageBuilderFactory;
+
+    private static final Pattern NEXT_LINE = Pattern.compile("\r?\n");
+
+    public MavenCli() {
+        this(null);
     }
 
     // This supports painless invocation by the Verifier during embedded execution of the core ITs
-    public MavenCli( ClassWorld classWorld )
-    {
+    public MavenCli(ClassWorld classWorld) {
         this.classWorld = classWorld;
+        this.messageBuilderFactory = new JansiMessageBuilderFactory();
     }
 
-    public static void main( String[] args )
-    {
-        int result = main( args, null );
+    public static void main(String[] args) {
+        int result = main(args, null);
 
-        System.exit( result );
+        System.exit(result);
     }
 
-    public static int main( String[] args, ClassWorld classWorld )
-    {
+    public static int main(String[] args, ClassWorld classWorld) {
         MavenCli cli = new MavenCli();
 
         MessageUtils.systemInstall();
         MessageUtils.registerShutdownHook();
-        int result = cli.doMain( new CliRequest( args, classWorld ) );
+        int result = cli.doMain(new CliRequest(args, classWorld));
         MessageUtils.systemUninstall();
 
         return result;
     }
 
     // TODO need to externalize CliRequest
-    public static int doMain( String[] args, ClassWorld classWorld )
-    {
+    public static int doMain(String[] args, ClassWorld classWorld) {
         MavenCli cli = new MavenCli();
-        return cli.doMain( new CliRequest( args, classWorld ) );
+        return cli.doMain(new CliRequest(args, classWorld));
     }
 
     /**
@@ -225,160 +225,157 @@
      * @param stderr stderr
      * @return return code
      */
-    public int doMain( String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr )
-    {
+    public int doMain(String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr) {
         PrintStream oldout = System.out;
         PrintStream olderr = System.err;
 
         final Set<String> realms;
-        if ( classWorld != null )
-        {
+        if (classWorld != null) {
             realms = new HashSet<>();
-            for ( ClassRealm realm : classWorld.getRealms() )
-            {
-                realms.add( realm.getId() );
+            for (ClassRealm realm : classWorld.getRealms()) {
+                realms.add(realm.getId());
             }
-        }
-        else
-        {
+        } else {
             realms = Collections.emptySet();
         }
 
-        try
-        {
-            if ( stdout != null )
-            {
-                System.setOut( stdout );
+        try {
+            if (stdout != null) {
+                System.setOut(stdout);
             }
-            if ( stderr != null )
-            {
-                System.setErr( stderr );
+            if (stderr != null) {
+                System.setErr(stderr);
             }
 
-            CliRequest cliRequest = new CliRequest( args, classWorld );
+            CliRequest cliRequest = new CliRequest(args, classWorld);
             cliRequest.workingDirectory = workingDirectory;
 
-            return doMain( cliRequest );
-        }
-        finally
-        {
-            if ( classWorld != null )
-            {
-                for ( ClassRealm realm : new ArrayList<>( classWorld.getRealms() ) )
-                {
+            return doMain(cliRequest);
+        } finally {
+            if (classWorld != null) {
+                for (ClassRealm realm : new ArrayList<>(classWorld.getRealms())) {
                     String realmId = realm.getId();
-                    if ( !realms.contains( realmId ) )
-                    {
-                        try
-                        {
-                            classWorld.disposeRealm( realmId );
-                        }
-                        catch ( NoSuchRealmException ignored )
-                        {
+                    if (!realms.contains(realmId)) {
+                        try {
+                            classWorld.disposeRealm(realmId);
+                        } catch (NoSuchRealmException ignored) {
                             // can't happen
                         }
                     }
                 }
             }
-            System.setOut( oldout );
-            System.setErr( olderr );
+            System.setOut(oldout);
+            System.setErr(olderr);
         }
     }
 
     // TODO need to externalize CliRequest
-    public int doMain( CliRequest cliRequest )
-    {
+    public int doMain(CliRequest cliRequest) {
         PlexusContainer localContainer = null;
-        try
-        {
-            initialize( cliRequest );
-            cli( cliRequest );
-            properties( cliRequest );
-            logging( cliRequest );
-            informativeCommands( cliRequest );
-            version( cliRequest );
-            localContainer = container( cliRequest );
-            commands( cliRequest );
-            configure( cliRequest );
-            toolchains( cliRequest );
-            populateRequest( cliRequest );
-            encryption( cliRequest );
-            repository( cliRequest );
-            return execute( cliRequest );
-        }
-        catch ( ExitException e )
-        {
+        try {
+            initialize(cliRequest);
+            cli(cliRequest);
+            properties(cliRequest);
+            logging(cliRequest);
+            informativeCommands(cliRequest);
+            version(cliRequest);
+            localContainer = container(cliRequest);
+            commands(cliRequest);
+            configure(cliRequest);
+            toolchains(cliRequest);
+            populateRequest(cliRequest);
+            encryption(cliRequest);
+            return execute(cliRequest);
+        } catch (ExitException e) {
             return e.exitCode;
-        }
-        catch ( UnrecognizedOptionException e )
-        {
+        } catch (UnrecognizedOptionException e) {
             // pure user error, suppress stack trace
             return 1;
-        }
-        catch ( BuildAbort e )
-        {
-            CLIReportingUtils.showError( slf4jLogger, "ABORTED", e, cliRequest.showErrors );
+        } catch (BuildAbort e) {
+            CLIReportingUtils.showError(slf4jLogger, "ABORTED", e, cliRequest.showErrors);
 
             return 2;
-        }
-        catch ( Exception e )
-        {
-            CLIReportingUtils.showError( slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors );
+        } catch (Exception e) {
+            CLIReportingUtils.showError(slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors);
 
             return 1;
-        }
-        finally
-        {
-            if ( localContainer != null )
-            {
+        } finally {
+            if (localContainer != null) {
                 localContainer.dispose();
             }
         }
     }
 
-    void initialize( CliRequest cliRequest )
-        throws ExitException
-    {
-        if ( cliRequest.workingDirectory == null )
-        {
-            cliRequest.workingDirectory = System.getProperty( "user.dir" );
+    void initialize(CliRequest cliRequest) throws ExitException {
+        if (cliRequest.workingDirectory == null) {
+            cliRequest.workingDirectory = System.getProperty("user.dir");
         }
 
-        if ( cliRequest.multiModuleProjectDirectory == null )
-        {
-            String basedirProperty = System.getProperty( MULTIMODULE_PROJECT_DIRECTORY );
-            if ( basedirProperty == null )
-            {
-                System.err.format(
-                    "-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY );
-                throw new ExitException( 1 );
+        if (cliRequest.multiModuleProjectDirectory == null) {
+            String basedirProperty = System.getProperty(MULTIMODULE_PROJECT_DIRECTORY);
+            if (basedirProperty == null) {
+                System.err.format("-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY);
+                throw new ExitException(1);
             }
-            File basedir = new File( basedirProperty );
-            try
-            {
+            File basedir = new File(basedirProperty);
+            try {
                 cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile();
-            }
-            catch ( IOException e )
-            {
+            } catch (IOException e) {
                 cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile();
             }
         }
 
+        // We need to locate the top level project which may be pointed at using
+        // the -f/--file option.  However, the command line isn't parsed yet, so
+        // we need to iterate through the args to find it and act upon it.
+        Path topDirectory = Paths.get(cliRequest.workingDirectory);
+        boolean isAltFile = false;
+        for (String arg : cliRequest.args) {
+            if (isAltFile) {
+                // this is the argument following -f/--file
+                Path path = topDirectory.resolve(stripLeadingAndTrailingQuotes(arg));
+                if (Files.isDirectory(path)) {
+                    topDirectory = path;
+                } else if (Files.isRegularFile(path)) {
+                    topDirectory = path.getParent();
+                    if (!Files.isDirectory(topDirectory)) {
+                        System.err.println("Directory " + topDirectory
+                                + " extracted from the -f/--file command-line argument " + arg + " does not exist");
+                        throw new ExitException(1);
+                    }
+                } else {
+                    System.err.println(
+                            "POM file " + arg + " specified with the -f/--file command line argument does not exist");
+                    throw new ExitException(1);
+                }
+                break;
+            } else {
+                // Check if this is the -f/--file option
+                isAltFile = arg.equals("-f") || arg.equals("--file");
+            }
+        }
+        topDirectory = getCanonicalPath(topDirectory);
+        cliRequest.topDirectory = topDirectory;
+        // We're very early in the process, and we don't have the container set up yet,
+        // so we rely on the JDK services to eventually look up a custom RootLocator.
+        // This is used to compute {@code session.rootDirectory} but all {@code project.rootDirectory}
+        // properties will be computed through the RootLocator found in the container.
+        RootLocator rootLocator =
+                ServiceLoader.load(RootLocator.class).iterator().next();
+        cliRequest.rootDirectory = rootLocator.findRoot(topDirectory);
+
         //
         // Make sure the Maven home directory is an absolute path to save us from confusion with say drive-relative
         // Windows paths.
         //
-        String mavenHome = System.getProperty( "maven.home" );
+        String mavenHome = System.getProperty("maven.home");
 
-        if ( mavenHome != null )
-        {
-            System.setProperty( "maven.home", new File( mavenHome ).getAbsolutePath() );
+        if (mavenHome != null) {
+            System.setProperty("maven.home", new File(mavenHome).getAbsolutePath());
         }
     }
 
-    void cli( CliRequest cliRequest )
-        throws Exception
-    {
+    void cli(CliRequest cliRequest) throws Exception {
         //
         // Parsing errors can happen during the processing of the arguments and we prefer not having to check if
         // the logger is null and construct this so we can use an SLF4J logger everywhere.
@@ -387,113 +384,105 @@
 
         cliManager = new CLIManager();
 
-        List<String> args = new ArrayList<>();
         CommandLine mavenConfig = null;
-        try
-        {
-            File configFile = new File( cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG );
+        try {
+            File configFile = new File(cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG);
 
-            if ( configFile.isFile() )
-            {
-                for ( String arg : Files.readAllLines( configFile.toPath(), Charset.defaultCharset() ) )
-                {
-                    if ( !arg.isEmpty() )
-                    {
-                        args.add( arg );
+            if (configFile.isFile()) {
+                try (Stream<String> lines = Files.lines(configFile.toPath(), Charset.defaultCharset())) {
+                    String[] args = lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#"))
+                            .toArray(String[]::new);
+                    mavenConfig = cliManager.parse(args);
+                    List<?> unrecognized = mavenConfig.getArgList();
+                    if (!unrecognized.isEmpty()) {
+                        // This file can only contain options, not args (goals or phases)
+                        throw new ParseException("Unrecognized maven.config file entries: " + unrecognized);
                     }
                 }
-
-                mavenConfig = cliManager.parse( args.toArray( new String[0] ) );
-                List<?> unrecognized = mavenConfig.getArgList();
-                if ( !unrecognized.isEmpty() )
-                {
-                    throw new ParseException( "Unrecognized maven.config entries: " + unrecognized );
-                }
             }
-        }
-        catch ( ParseException e )
-        {
-            System.err.println( "Unable to parse maven.config: " + e.getMessage() );
-            cliManager.displayHelp( System.out );
+        } catch (ParseException e) {
+            System.err.println("Unable to parse maven.config file options: " + e.getMessage());
+            cliManager.displayHelp(System.out);
             throw e;
         }
 
-        try
-        {
-            if ( mavenConfig == null )
-            {
-                cliRequest.commandLine = cliManager.parse( cliRequest.args );
+        try {
+            CommandLine mavenCli = cliManager.parse(cliRequest.args);
+            if (mavenConfig == null) {
+                cliRequest.commandLine = mavenCli;
+            } else {
+                cliRequest.commandLine = cliMerge(mavenConfig, mavenCli);
             }
-            else
-            {
-                cliRequest.commandLine = cliMerge( cliManager.parse( cliRequest.args ), mavenConfig );
-            }
+        } catch (ParseException e) {
+            System.err.println("Unable to parse command line options: " + e.getMessage());
+            cliManager.displayHelp(System.out);
+            throw e;
         }
-        catch ( ParseException e )
-        {
-            System.err.println( "Unable to parse command line options: " + e.getMessage() );
-            cliManager.displayHelp( System.out );
+
+        // check for presence of unsupported command line options
+        try {
+            if (cliRequest.commandLine.hasOption("llr")) {
+                throw new UnrecognizedOptionException("Option '-llr' is not supported starting with Maven 3.9.1");
+            }
+        } catch (ParseException e) {
+            System.err.println("Unsupported options: " + e.getMessage());
+            cliManager.displayHelp(System.out);
             throw e;
         }
     }
 
-    private void informativeCommands( CliRequest cliRequest ) throws ExitException
-    {
-        if ( cliRequest.commandLine.hasOption( CLIManager.HELP ) )
-        {
-            cliManager.displayHelp( System.out );
-            throw new ExitException( 0 );
+    private void informativeCommands(CliRequest cliRequest) throws ExitException {
+        if (cliRequest.commandLine.hasOption(CLIManager.HELP)) {
+            cliManager.displayHelp(System.out);
+            throw new ExitException(0);
         }
 
-        if ( cliRequest.commandLine.hasOption( CLIManager.VERSION ) )
-        {
-            if ( cliRequest.commandLine.hasOption( CLIManager.QUIET ) )
-            {
-                System.out.println( CLIReportingUtils.showVersionMinimal() );
+        if (cliRequest.commandLine.hasOption(CLIManager.VERSION)) {
+            if (cliRequest.commandLine.hasOption(CLIManager.QUIET)) {
+                System.out.println(CLIReportingUtils.showVersionMinimal());
+            } else {
+                System.out.println(CLIReportingUtils.showVersion());
             }
-            else
-            {
-                System.out.println( CLIReportingUtils.showVersion() );
-            }
-            throw new ExitException( 0 );
+            throw new ExitException(0);
+        }
+
+        if (cliRequest.rootDirectory == null) {
+            slf4jLogger.info(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
         }
     }
 
-    private CommandLine cliMerge( CommandLine mavenArgs, CommandLine mavenConfig )
-    {
+    private CommandLine cliMerge(CommandLine mavenConfig, CommandLine mavenCli) {
         CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
 
-        // the args are easy, cli first then config file
-        for ( String arg : mavenArgs.getArgs() )
-        {
-            commandLineBuilder.addArg( arg );
-        }
-        for ( String arg : mavenConfig.getArgs() )
-        {
-            commandLineBuilder.addArg( arg );
+        // the args are easy, CLI only since maven.config file can only contain options
+        for (String arg : mavenCli.getArgs()) {
+            commandLineBuilder.addArg(arg);
         }
 
-        // now add all options, except for -D with cli first then config file
+        /* Although this looks wrong in terms of order Commons CLI stores the value of options in
+         * an array and when a value is potentionally overriden it is added to the array. The single
+         * arg option value is retrieved and instead of returning values[values.length-1] it returns
+         * values[0] which means that the original value instead of the overridden one is returned
+         * (first wins). With properties values are truely overriden since at the end a map is used
+         * to merge which means last wins.
+         *
+         * TODO Report this behavioral bug with Commons CLI
+         */
+        // now add all options, except for user properties with CLI first then maven.config file
         List<Option> setPropertyOptions = new ArrayList<>();
-        for ( Option opt : mavenArgs.getOptions() )
-        {
-            if ( String.valueOf( CLIManager.SET_SYSTEM_PROPERTY ).equals( opt.getOpt() ) )
-            {
-                setPropertyOptions.add( opt );
-            }
-            else
-            {
-                commandLineBuilder.addOption( opt );
+        for (Option opt : mavenCli.getOptions()) {
+            if (String.valueOf(CLIManager.SET_USER_PROPERTY).equals(opt.getOpt())) {
+                setPropertyOptions.add(opt);
+            } else {
+                commandLineBuilder.addOption(opt);
             }
         }
-        for ( Option opt : mavenConfig.getOptions() )
-        {
-            commandLineBuilder.addOption( opt );
+        for (Option opt : mavenConfig.getOptions()) {
+            commandLineBuilder.addOption(opt);
         }
-        // finally add the CLI system properties
-        for ( Option opt : setPropertyOptions )
-        {
-            commandLineBuilder.addOption( opt );
+        // finally add the CLI user properties
+        for (Option opt : setPropertyOptions) {
+            commandLineBuilder.addOption(opt);
         }
         return commandLineBuilder.build();
     }
@@ -501,67 +490,55 @@
     /**
      * configure logging
      */
-    void logging( CliRequest cliRequest )
-    {
+    void logging(CliRequest cliRequest) {
         // LOG LEVEL
-        cliRequest.verbose = cliRequest.commandLine.hasOption( CLIManager.VERBOSE )
-                             || cliRequest.commandLine.hasOption( CLIManager.DEBUG );
-        cliRequest.quiet = !cliRequest.verbose && cliRequest.commandLine.hasOption( CLIManager.QUIET );
-        cliRequest.showErrors = cliRequest.verbose || cliRequest.commandLine.hasOption( CLIManager.ERRORS );
+        CommandLine commandLine = cliRequest.commandLine;
+        cliRequest.verbose = commandLine.hasOption(CLIManager.VERBOSE) || commandLine.hasOption(CLIManager.DEBUG);
+        cliRequest.quiet = !cliRequest.verbose && commandLine.hasOption(CLIManager.QUIET);
+        cliRequest.showErrors = cliRequest.verbose || commandLine.hasOption(CLIManager.ERRORS);
+
+        // LOG COLOR
+        String styleColor = cliRequest.getUserProperties().getProperty(STYLE_COLOR_PROPERTY, "auto");
+        styleColor = commandLine.getOptionValue(COLOR, styleColor);
+        if ("always".equals(styleColor) || "yes".equals(styleColor) || "force".equals(styleColor)) {
+            MessageUtils.setColorEnabled(true);
+        } else if ("never".equals(styleColor) || "no".equals(styleColor) || "none".equals(styleColor)) {
+            MessageUtils.setColorEnabled(false);
+        } else if (!"auto".equals(styleColor) && !"tty".equals(styleColor) && !"if-tty".equals(styleColor)) {
+            throw new IllegalArgumentException(
+                    "Invalid color configuration value '" + styleColor + "'. Supported are 'auto', 'always', 'never'.");
+        } else {
+            boolean isBatchMode = !commandLine.hasOption(FORCE_INTERACTIVE)
+                    && (commandLine.hasOption(BATCH_MODE) || commandLine.hasOption(NON_INTERACTIVE));
+            if (isBatchMode || commandLine.hasOption(CLIManager.LOG_FILE)) {
+                MessageUtils.setColorEnabled(false);
+            }
+        }
 
         slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
-        Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration( slf4jLoggerFactory );
+        Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory);
 
-        if ( cliRequest.verbose )
-        {
-            cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_DEBUG );
-            slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.DEBUG );
-        }
-        else if ( cliRequest.quiet )
-        {
-            cliRequest.request.setLoggingLevel( MavenExecutionRequest.LOGGING_LEVEL_ERROR );
-            slf4jConfiguration.setRootLoggerLevel( Slf4jConfiguration.Level.ERROR );
+        if (cliRequest.verbose) {
+            cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_DEBUG);
+            slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.DEBUG);
+        } else if (cliRequest.quiet) {
+            cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_ERROR);
+            slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.ERROR);
         }
         // else fall back to default log level specified in conf
         // see https://issues.apache.org/jira/browse/MNG-2570
 
-        // LOG COLOR
-        String styleColor = cliRequest.getUserProperties().getProperty( STYLE_COLOR_PROPERTY, "auto" );
-        styleColor = cliRequest.commandLine.getOptionValue( COLOR, styleColor );
-        if ( "always".equals( styleColor ) || "yes".equals( styleColor ) || "force".equals( styleColor ) )
-        {
-            MessageUtils.setColorEnabled( true );
-        }
-        else if ( "never".equals( styleColor ) || "no".equals( styleColor ) || "none".equals( styleColor ) )
-        {
-            MessageUtils.setColorEnabled( false );
-        }
-        else if ( !"auto".equals( styleColor ) && !"tty".equals( styleColor ) && !"if-tty".equals( styleColor ) )
-        {
-            throw new IllegalArgumentException( "Invalid color configuration value '" + styleColor
-                + "'. Supported are 'auto', 'always', 'never'." );
-        }
-        else if ( cliRequest.commandLine.hasOption( CLIManager.BATCH_MODE )
-            || cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
-        {
-            MessageUtils.setColorEnabled( false );
-        }
-
         // LOG STREAMS
-        if ( cliRequest.commandLine.hasOption( CLIManager.LOG_FILE ) )
-        {
-            File logFile = new File( cliRequest.commandLine.getOptionValue( CLIManager.LOG_FILE ) );
-            logFile = resolveFile( logFile, cliRequest.workingDirectory );
+        if (commandLine.hasOption(CLIManager.LOG_FILE)) {
+            File logFile = new File(commandLine.getOptionValue(CLIManager.LOG_FILE));
+            logFile = resolveFile(logFile, cliRequest.workingDirectory);
 
             // redirect stdout and stderr to file
-            try
-            {
-                PrintStream ps = new PrintStream( new FileOutputStream( logFile ) );
-                System.setOut( ps );
-                System.setErr( ps );
-            }
-            catch ( FileNotFoundException e )
-            {
+            try {
+                PrintStream ps = new PrintStream(new FileOutputStream(logFile));
+                System.setOut(ps);
+                System.setErr(ps);
+            } catch (FileNotFoundException e) {
                 //
                 // Ignore
                 //
@@ -571,294 +548,302 @@
         slf4jConfiguration.activate();
 
         plexusLoggerManager = new Slf4jLoggerManager();
-        slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
+        slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
 
-        if ( cliRequest.commandLine.hasOption( CLIManager.FAIL_ON_SEVERITY ) )
-        {
-            String logLevelThreshold = cliRequest.commandLine.getOptionValue( CLIManager.FAIL_ON_SEVERITY );
+        if (commandLine.hasOption(CLIManager.FAIL_ON_SEVERITY)) {
+            String logLevelThreshold = commandLine.getOptionValue(CLIManager.FAIL_ON_SEVERITY);
 
-            if ( slf4jLoggerFactory instanceof MavenSlf4jWrapperFactory )
-            {
-                LogLevelRecorder logLevelRecorder = new LogLevelRecorder( logLevelThreshold );
-                ( (MavenSlf4jWrapperFactory) slf4jLoggerFactory ).setLogLevelRecorder( logLevelRecorder );
-                slf4jLogger.info( "Enabled to break the build on log level {}.", logLevelThreshold );
-            }
-            else
-            {
-                slf4jLogger.warn( "Expected LoggerFactory to be of type '{}', but found '{}' instead. "
-                        + "The --fail-on-severity flag will not take effect.",
-                        MavenSlf4jWrapperFactory.class.getName(), slf4jLoggerFactory.getClass().getName() );
+            if (slf4jLoggerFactory instanceof MavenSlf4jWrapperFactory) {
+                LogLevelRecorder logLevelRecorder = new LogLevelRecorder(logLevelThreshold);
+                ((MavenSlf4jWrapperFactory) slf4jLoggerFactory).setLogLevelRecorder(logLevelRecorder);
+                slf4jLogger.info("Enabled to break the build on log level {}.", logLevelThreshold);
+            } else {
+                slf4jLogger.warn(
+                        "Expected LoggerFactory to be of type '{}', but found '{}' instead. "
+                                + "The --fail-on-severity flag will not take effect.",
+                        MavenSlf4jWrapperFactory.class.getName(),
+                        slf4jLoggerFactory.getClass().getName());
             }
         }
 
-        if ( cliRequest.commandLine.hasOption( CLIManager.DEBUG ) )
-        {
-            slf4jLogger.warn( "The option '--debug' is deprecated and may be repurposed as Java debug"
-                    + " in a future version. Use -X/--verbose instead." );
+        if (commandLine.hasOption(CLIManager.DEBUG)) {
+            slf4jLogger.warn("The option '--debug' is deprecated and may be repurposed as Java debug"
+                    + " in a future version. Use -X/--verbose instead.");
         }
     }
 
-    private void version( CliRequest cliRequest )
-    {
-        if ( cliRequest.verbose || cliRequest.commandLine.hasOption( CLIManager.SHOW_VERSION ) )
-        {
-            System.out.println( CLIReportingUtils.showVersion() );
+    private void version(CliRequest cliRequest) {
+        if (cliRequest.verbose || cliRequest.commandLine.hasOption(CLIManager.SHOW_VERSION)) {
+            System.out.println(CLIReportingUtils.showVersion());
         }
     }
 
-    private void commands( CliRequest cliRequest )
-    {
-        if ( cliRequest.showErrors )
-        {
-            slf4jLogger.info( "Error stacktraces are turned on." );
+    private void commands(CliRequest cliRequest) {
+        if (cliRequest.showErrors) {
+            slf4jLogger.info("Error stacktraces are turned on.");
         }
 
-        if ( MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
-        {
-            slf4jLogger.info( "Disabling strict checksum verification on all artifact downloads." );
-        }
-        else if ( MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals( cliRequest.request.getGlobalChecksumPolicy() ) )
-        {
-            slf4jLogger.info( "Enabling strict checksum verification on all artifact downloads." );
+        if (MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals(cliRequest.request.getGlobalChecksumPolicy())) {
+            slf4jLogger.info("Disabling strict checksum verification on all artifact downloads.");
+        } else if (MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals(cliRequest.request.getGlobalChecksumPolicy())) {
+            slf4jLogger.info("Enabling strict checksum verification on all artifact downloads.");
         }
 
-        if ( slf4jLogger.isDebugEnabled() )
-        {
-            slf4jLogger.debug( "Message scheme: {}", ( MessageUtils.isColorEnabled() ? "color" : "plain" ) );
-            if ( MessageUtils.isColorEnabled() )
-            {
-                MessageBuilder buff = MessageUtils.buffer();
-                buff.a( "Message styles: " );
-                buff.a( MessageUtils.level().debug( "debug" ) ).a( ' ' );
-                buff.a( MessageUtils.level().info( "info" ) ).a( ' ' );
-                buff.a( MessageUtils.level().warning( "warning" ) ).a( ' ' );
-                buff.a( MessageUtils.level().error( "error" ) ).a( ' ' );
-
-                buff.success( "success" ).a( ' ' );
-                buff.failure( "failure" ).a( ' ' );
-                buff.strong( "strong" ).a( ' ' );
-                buff.mojo( "mojo" ).a( ' ' );
-                buff.project( "project" );
-                slf4jLogger.debug( buff.toString() );
+        if (slf4jLogger.isDebugEnabled()) {
+            slf4jLogger.debug("Message scheme: {}", (MessageUtils.isColorEnabled() ? "color" : "plain"));
+            if (MessageUtils.isColorEnabled()) {
+                MessageBuilder buff = MessageUtils.builder();
+                buff.a("Message styles: ");
+                buff.trace("trace").a(' ');
+                buff.debug("debug").a(' ');
+                buff.info("info").a(' ');
+                buff.warning("warning").a(' ');
+                buff.error("error").a(' ');
+                buff.success("success").a(' ');
+                buff.failure("failure").a(' ');
+                buff.strong("strong").a(' ');
+                buff.mojo("mojo").a(' ');
+                buff.project("project");
+                slf4jLogger.debug(buff.toString());
             }
         }
     }
 
-    //Needed to make this method package visible to make writing a unit test possible
-    //Maybe it's better to move some of those methods to separate class (SoC).
-    void properties( CliRequest cliRequest )
-    {
-        populateProperties( cliRequest.commandLine, cliRequest.systemProperties, cliRequest.userProperties );
-    }
-
-    PlexusContainer container( CliRequest cliRequest )
-        throws Exception
-    {
-        if ( cliRequest.classWorld == null )
-        {
-            cliRequest.classWorld = new ClassWorld( "plexus.core", Thread.currentThread().getContextClassLoader() );
+    // Needed to make this method package visible to make writing a unit test possible
+    // Maybe it's better to move some of those methods to separate class (SoC).
+    void properties(CliRequest cliRequest) throws Exception {
+        Properties paths = new Properties();
+        if (cliRequest.topDirectory != null) {
+            paths.put("session.topDirectory", cliRequest.topDirectory.toString());
+        }
+        if (cliRequest.rootDirectory != null) {
+            paths.put("session.rootDirectory", cliRequest.rootDirectory.toString());
         }
 
-        ClassRealm coreRealm = cliRequest.classWorld.getClassRealm( "plexus.core" );
-        if ( coreRealm == null )
-        {
+        populateProperties(cliRequest.commandLine, paths, cliRequest.systemProperties, cliRequest.userProperties);
+
+        // now that we have properties, interpolate all arguments
+        BasicInterpolator interpolator =
+                createInterpolator(paths, cliRequest.systemProperties, cliRequest.userProperties);
+        CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
+        for (Option option : cliRequest.commandLine.getOptions()) {
+            if (!String.valueOf(CLIManager.SET_USER_PROPERTY).equals(option.getOpt())) {
+                List<String> values = option.getValuesList();
+                for (ListIterator<String> it = values.listIterator(); it.hasNext(); ) {
+                    it.set(interpolator.interpolate(it.next()));
+                }
+            }
+            commandLineBuilder.addOption(option);
+        }
+        for (String arg : cliRequest.commandLine.getArgList()) {
+            commandLineBuilder.addArg(interpolator.interpolate(arg));
+        }
+        cliRequest.commandLine = commandLineBuilder.build();
+    }
+
+    PlexusContainer container(CliRequest cliRequest) throws Exception {
+        if (cliRequest.classWorld == null) {
+            cliRequest.classWorld =
+                    new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader());
+        }
+
+        ClassRealm coreRealm = cliRequest.classWorld.getClassRealm("plexus.core");
+        if (coreRealm == null) {
             coreRealm = cliRequest.classWorld.getRealms().iterator().next();
         }
 
-        List<File> extClassPath = parseExtClasspath( cliRequest );
+        List<File> extClassPath = parseExtClasspath(cliRequest);
 
-        CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom( coreRealm );
+        CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom(coreRealm);
         List<CoreExtensionEntry> extensions =
-            loadCoreExtensions( cliRequest, coreRealm, coreEntry.getExportedArtifacts() );
+                loadCoreExtensions(cliRequest, coreRealm, coreEntry.getExportedArtifacts());
 
-        ClassRealm containerRealm = setupContainerRealm( cliRequest.classWorld, coreRealm, extClassPath, extensions );
+        ClassRealm containerRealm = setupContainerRealm(cliRequest.classWorld, coreRealm, extClassPath, extensions);
 
-        ContainerConfiguration cc = new DefaultContainerConfiguration().setClassWorld( cliRequest.classWorld )
-            .setRealm( containerRealm ).setClassPathScanning( PlexusConstants.SCANNING_INDEX ).setAutoWiring( true )
-            .setJSR250Lifecycle( true ).setName( "maven" );
+        ContainerConfiguration cc = new DefaultContainerConfiguration()
+                .setClassWorld(cliRequest.classWorld)
+                .setRealm(containerRealm)
+                .setClassPathScanning(PlexusConstants.SCANNING_INDEX)
+                .setAutoWiring(true)
+                .setJSR250Lifecycle(true)
+                .setName("maven");
 
-        Set<String> exportedArtifacts = new HashSet<>( coreEntry.getExportedArtifacts() );
-        Set<String> exportedPackages = new HashSet<>( coreEntry.getExportedPackages() );
-        for ( CoreExtensionEntry extension : extensions )
-        {
-            exportedArtifacts.addAll( extension.getExportedArtifacts() );
-            exportedPackages.addAll( extension.getExportedPackages() );
+        Set<String> exportedArtifacts = new HashSet<>(coreEntry.getExportedArtifacts());
+        Set<String> exportedPackages = new HashSet<>(coreEntry.getExportedPackages());
+        for (CoreExtensionEntry extension : extensions) {
+            exportedArtifacts.addAll(extension.getExportedArtifacts());
+            exportedPackages.addAll(extension.getExportedPackages());
         }
 
-        final CoreExports exports = new CoreExports( containerRealm, exportedArtifacts, exportedPackages );
+        final CoreExports exports = new CoreExports(containerRealm, exportedArtifacts, exportedPackages);
 
-        DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
-        {
+        DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
             @Override
-            protected void configure()
-            {
-                bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
-                bind( CoreExports.class ).toInstance( exports );
+            protected void configure() {
+                bind(ILoggerFactory.class).toInstance(slf4jLoggerFactory);
+                bind(CoreExports.class).toInstance(exports);
+                bind(MessageBuilderFactory.class).toInstance(messageBuilderFactory);
             }
-        } );
+        });
 
         // NOTE: To avoid inconsistencies, we'll use the TCCL exclusively for lookups
-        container.setLookupRealm( null );
-        Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
+        container.setLookupRealm(null);
+        Thread.currentThread().setContextClassLoader(container.getContainerRealm());
 
-        container.setLoggerManager( plexusLoggerManager );
+        container.setLoggerManager(plexusLoggerManager);
 
-        for ( CoreExtensionEntry extension : extensions )
-        {
-            container.discoverComponents( extension.getClassRealm(), new SessionScopeModule( container ),
-                                          new MojoExecutionScopeModule( container ) );
+        AbstractValueSource extensionSource = new AbstractValueSource(false) {
+            @Override
+            public Object getValue(String expression) {
+                Object value = cliRequest.userProperties.getProperty(expression);
+                if (value == null) {
+                    value = cliRequest.systemProperties.getProperty(expression);
+                }
+                return value;
+            }
+        };
+        for (CoreExtensionEntry extension : extensions) {
+            container.discoverComponents(
+                    extension.getClassRealm(),
+                    new SessionScopeModule(container),
+                    new MojoExecutionScopeModule(container),
+                    new ExtensionConfigurationModule(extension, extensionSource));
         }
 
-        customizeContainer( container );
+        customizeContainer(container);
 
-        container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
+        container.getLoggerManager().setThresholds(cliRequest.request.getLoggingLevel());
 
-        eventSpyDispatcher = container.lookup( EventSpyDispatcher.class );
+        eventSpyDispatcher = container.lookup(EventSpyDispatcher.class);
 
         DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
         Map<String, Object> data = eventSpyContext.getData();
-        data.put( "plexus", container );
-        data.put( "workingDirectory", cliRequest.workingDirectory );
-        data.put( "systemProperties", cliRequest.systemProperties );
-        data.put( "userProperties", cliRequest.userProperties );
-        data.put( "versionProperties", CLIReportingUtils.getBuildProperties() );
-        eventSpyDispatcher.init( eventSpyContext );
+        data.put("plexus", container);
+        data.put("workingDirectory", cliRequest.workingDirectory);
+        data.put("systemProperties", cliRequest.systemProperties);
+        data.put("userProperties", cliRequest.userProperties);
+        data.put("versionProperties", CLIReportingUtils.getBuildProperties());
+        eventSpyDispatcher.init(eventSpyContext);
 
         // refresh logger in case container got customized by spy
-        slf4jLogger = slf4jLoggerFactory.getLogger( this.getClass().getName() );
+        slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
 
-        maven = container.lookup( Maven.class );
+        maven = container.lookup(Maven.class);
 
-        executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
+        executionRequestPopulator = container.lookup(MavenExecutionRequestPopulator.class);
 
-        modelProcessor = createModelProcessor( container );
+        modelProcessor = createModelProcessor(container);
 
-        configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
+        configurationProcessors = container.lookupMap(ConfigurationProcessor.class);
 
-        toolchainsBuilder = container.lookup( ToolchainsBuilder.class );
+        toolchainsBuilder = container.lookup(ToolchainsBuilder.class);
 
-        dispatcher = (DefaultSecDispatcher) container.lookup( SecDispatcher.class, "maven" );
+        dispatcher = (DefaultSecDispatcher) container.lookup(SecDispatcher.class, "maven");
 
         return container;
     }
 
-    private List<CoreExtensionEntry> loadCoreExtensions( CliRequest cliRequest, ClassRealm containerRealm,
-                                                         Set<String> providedArtifacts )
-            throws Exception
-    {
-        if ( cliRequest.multiModuleProjectDirectory == null )
-        {
+    private List<CoreExtensionEntry> loadCoreExtensions(
+            CliRequest cliRequest, ClassRealm containerRealm, Set<String> providedArtifacts) throws Exception {
+        if (cliRequest.multiModuleProjectDirectory == null) {
             return Collections.emptyList();
         }
 
-        File extensionsFile = new File( cliRequest.multiModuleProjectDirectory, EXTENSIONS_FILENAME );
-        if ( !extensionsFile.isFile() )
-        {
-            return Collections.emptyList();
+        File extensionsFile = new File(cliRequest.multiModuleProjectDirectory, MVN_EXTENSIONS_FILENAME);
+        File userHomeExtensionsFile = new File(USER_MAVEN_CONFIGURATION_HOME, EXTENSIONS_FILENAME);
+
+        List<CoreExtension> extensions = new ArrayList<>();
+        if (extensionsFile.isFile()) {
+            extensions.addAll(readCoreExtensionsDescriptor(extensionsFile));
+        }
+        if (userHomeExtensionsFile.isFile()) {
+            extensions.addAll(readCoreExtensionsDescriptor(userHomeExtensionsFile));
         }
 
-        List<CoreExtension> extensions = readCoreExtensionsDescriptor( extensionsFile );
-        if ( extensions.isEmpty() )
-        {
+        if (extensions.isEmpty()) {
             return Collections.emptyList();
         }
 
         ContainerConfiguration cc = new DefaultContainerConfiguration() //
-            .setClassWorld( cliRequest.classWorld ) //
-            .setRealm( containerRealm ) //
-            .setClassPathScanning( PlexusConstants.SCANNING_INDEX ) //
-            .setAutoWiring( true ) //
-            .setJSR250Lifecycle( true ) //
-            .setName( "maven" );
+                .setClassWorld(cliRequest.classWorld) //
+                .setRealm(containerRealm) //
+                .setClassPathScanning(PlexusConstants.SCANNING_INDEX) //
+                .setAutoWiring(true) //
+                .setJSR250Lifecycle(true) //
+                .setName("maven");
 
-        DefaultPlexusContainer container = new DefaultPlexusContainer( cc, new AbstractModule()
-        {
+        DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
             @Override
-            protected void configure()
-            {
-                bind( ILoggerFactory.class ).toInstance( slf4jLoggerFactory );
+            protected void configure() {
+                bind(ILoggerFactory.class).toInstance(slf4jLoggerFactory);
             }
-        } );
+        });
 
-        try
-        {
-            container.setLookupRealm( null );
+        try {
+            container.setLookupRealm(null);
 
-            container.setLoggerManager( plexusLoggerManager );
+            container.setLoggerManager(plexusLoggerManager);
 
-            container.getLoggerManager().setThresholds( cliRequest.request.getLoggingLevel() );
+            container.getLoggerManager().setThresholds(cliRequest.request.getLoggingLevel());
 
-            Thread.currentThread().setContextClassLoader( container.getContainerRealm() );
+            Thread.currentThread().setContextClassLoader(container.getContainerRealm());
 
-            executionRequestPopulator = container.lookup( MavenExecutionRequestPopulator.class );
+            executionRequestPopulator = container.lookup(MavenExecutionRequestPopulator.class);
 
-            configurationProcessors = container.lookupMap( ConfigurationProcessor.class );
+            configurationProcessors = container.lookupMap(ConfigurationProcessor.class);
 
-            configure( cliRequest );
+            configure(cliRequest);
 
-            MavenExecutionRequest request = DefaultMavenExecutionRequest.copy( cliRequest.request );
+            MavenExecutionRequest request = DefaultMavenExecutionRequest.copy(cliRequest.request);
 
-            populateRequest( cliRequest, request );
+            populateRequest(cliRequest, request);
 
-            request = executionRequestPopulator.populateDefaults( request );
+            request = executionRequestPopulator.populateDefaults(request);
 
-            BootstrapCoreExtensionManager resolver = container.lookup( BootstrapCoreExtensionManager.class );
+            BootstrapCoreExtensionManager resolver = container.lookup(BootstrapCoreExtensionManager.class);
 
-            return Collections.unmodifiableList( resolver.loadCoreExtensions( request, providedArtifacts,
-                                                                              extensions ) );
+            return Collections.unmodifiableList(resolver.loadCoreExtensions(request, providedArtifacts, extensions));
 
-        }
-        finally
-        {
+        } finally {
             executionRequestPopulator = null;
             container.dispose();
         }
     }
 
-    private List<CoreExtension> readCoreExtensionsDescriptor( File extensionsFile )
-        throws IOException, XmlPullParserException
-    {
-        CoreExtensionsXpp3Reader parser = new CoreExtensionsXpp3Reader();
+    private List<CoreExtension> readCoreExtensionsDescriptor(File extensionsFile)
+            throws IOException, XMLStreamException {
+        CoreExtensionsStaxReader parser = new CoreExtensionsStaxReader();
 
-        try ( InputStream is = new BufferedInputStream( new FileInputStream( extensionsFile ) ) )
-        {
-
-            return parser.read( is ).getExtensions();
+        try (InputStream is = Files.newInputStream(extensionsFile.toPath())) {
+            return parser.read(is, true).getExtensions();
         }
-
     }
 
-    private ClassRealm setupContainerRealm( ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath,
-                                            List<CoreExtensionEntry> extensions )
-        throws Exception
-    {
-        if ( !extClassPath.isEmpty() || !extensions.isEmpty() )
-        {
-            ClassRealm extRealm = classWorld.newRealm( "maven.ext", null );
+    private ClassRealm setupContainerRealm(
+            ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath, List<CoreExtensionEntry> extensions)
+            throws Exception {
+        if (!extClassPath.isEmpty() || !extensions.isEmpty()) {
+            ClassRealm extRealm = classWorld.newRealm("maven.ext", null);
 
-            extRealm.setParentRealm( coreRealm );
+            extRealm.setParentRealm(coreRealm);
 
-            slf4jLogger.debug( "Populating class realm '{}'", extRealm.getId() );
+            slf4jLogger.debug("Populating class realm '{}'", extRealm.getId());
 
-            for ( File file : extClassPath )
-            {
-                slf4jLogger.debug( "  included '{}'", file );
+            for (File file : extClassPath) {
+                slf4jLogger.debug("  included '{}'", file);
 
-                extRealm.addURL( file.toURI().toURL() );
+                extRealm.addURL(file.toURI().toURL());
             }
 
-            for ( CoreExtensionEntry entry : reverse( extensions ) )
-            {
+            for (CoreExtensionEntry entry : reverse(extensions)) {
                 Set<String> exportedPackages = entry.getExportedPackages();
                 ClassRealm realm = entry.getClassRealm();
-                for ( String exportedPackage : exportedPackages )
-                {
-                    extRealm.importFrom( realm, exportedPackage );
+                for (String exportedPackage : exportedPackages) {
+                    extRealm.importFrom(realm, exportedPackage);
                 }
-                if ( exportedPackages.isEmpty() )
-                {
+                if (exportedPackages.isEmpty()) {
                     // sisu uses realm imports to establish component visibility
-                    extRealm.importFrom( realm, realm.getId() );
+                    extRealm.importFrom(realm, realm.getId());
                 }
             }
 
@@ -868,32 +853,27 @@
         return coreRealm;
     }
 
-    private static <T> List<T> reverse( List<T> list )
-    {
-        List<T> copy = new ArrayList<>( list );
-        Collections.reverse( copy );
+    private static <T> List<T> reverse(List<T> list) {
+        List<T> copy = new ArrayList<>(list);
+        Collections.reverse(copy);
         return copy;
     }
 
-    private List<File> parseExtClasspath( CliRequest cliRequest )
-    {
-        String extClassPath = cliRequest.userProperties.getProperty( EXT_CLASS_PATH );
-        if ( extClassPath == null )
-        {
-            extClassPath = cliRequest.systemProperties.getProperty( EXT_CLASS_PATH );
+    private List<File> parseExtClasspath(CliRequest cliRequest) {
+        String extClassPath = cliRequest.userProperties.getProperty(EXT_CLASS_PATH);
+        if (extClassPath == null) {
+            extClassPath = cliRequest.systemProperties.getProperty(EXT_CLASS_PATH);
         }
 
         List<File> jars = new ArrayList<>();
 
-        if ( StringUtils.isNotEmpty( extClassPath ) )
-        {
-            for ( String jar : StringUtils.split( extClassPath, File.pathSeparator ) )
-            {
-                File file = resolveFile( new File( jar ), cliRequest.workingDirectory );
+        if (extClassPath != null && !extClassPath.isEmpty()) {
+            for (String jar : extClassPath.split(File.pathSeparator)) {
+                File file = resolveFile(new File(jar), cliRequest.workingDirectory);
 
-                slf4jLogger.debug( "  included '{}'", file );
+                slf4jLogger.debug("  included '{}'", file);
 
-                jars.add( file );
+                jars.add(file);
             }
         }
 
@@ -903,196 +883,155 @@
     //
     // This should probably be a separate tool and not be baked into Maven.
     //
-    private void encryption( CliRequest cliRequest )
-        throws Exception
-    {
-        if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_MASTER_PASSWORD ) )
-        {
-            String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_MASTER_PASSWORD );
+    private void encryption(CliRequest cliRequest) throws Exception {
+        if (cliRequest.commandLine.hasOption(CLIManager.ENCRYPT_MASTER_PASSWORD)) {
+            String passwd = cliRequest.commandLine.getOptionValue(CLIManager.ENCRYPT_MASTER_PASSWORD);
 
-            if ( passwd == null )
-            {
+            if (passwd == null) {
                 Console cons = System.console();
-                char[] password = ( cons == null ) ? null : cons.readPassword( "Master password: " );
-                if ( password != null )
-                {
+                char[] password = (cons == null) ? null : cons.readPassword("Master password: ");
+                if (password != null) {
                     // Cipher uses Strings
-                    passwd = String.copyValueOf( password );
+                    passwd = String.copyValueOf(password);
 
                     // Sun/Oracle advises to empty the char array
-                    java.util.Arrays.fill( password, ' ' );
+                    java.util.Arrays.fill(password, ' ');
                 }
             }
 
             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
 
-            System.out.println(
-                cipher.encryptAndDecorate( passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION ) );
+            System.out.println(cipher.encryptAndDecorate(passwd, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION));
 
-            throw new ExitException( 0 );
-        }
-        else if ( cliRequest.commandLine.hasOption( CLIManager.ENCRYPT_PASSWORD ) )
-        {
-            String passwd = cliRequest.commandLine.getOptionValue( CLIManager.ENCRYPT_PASSWORD );
+            throw new ExitException(0);
+        } else if (cliRequest.commandLine.hasOption(CLIManager.ENCRYPT_PASSWORD)) {
+            String passwd = cliRequest.commandLine.getOptionValue(CLIManager.ENCRYPT_PASSWORD);
 
-            if ( passwd == null )
-            {
+            if (passwd == null) {
                 Console cons = System.console();
-                char[] password = ( cons == null ) ? null : cons.readPassword( "Password: " );
-                if ( password != null )
-                {
+                char[] password = (cons == null) ? null : cons.readPassword("Password: ");
+                if (password != null) {
                     // Cipher uses Strings
-                    passwd = String.copyValueOf( password );
+                    passwd = String.copyValueOf(password);
 
                     // Sun/Oracle advises to empty the char array
-                    java.util.Arrays.fill( password, ' ' );
+                    java.util.Arrays.fill(password, ' ');
                 }
             }
 
             String configurationFile = dispatcher.getConfigurationFile();
 
-            if ( configurationFile.startsWith( "~" ) )
-            {
-                configurationFile = System.getProperty( "user.home" ) + configurationFile.substring( 1 );
+            if (configurationFile.startsWith("~")) {
+                configurationFile = System.getProperty("user.home") + configurationFile.substring(1);
             }
 
-            String file = System.getProperty( DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile );
+            String file = System.getProperty(DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION, configurationFile);
 
             String master = null;
 
-            SettingsSecurity sec = SecUtil.read( file, true );
-            if ( sec != null )
-            {
+            SettingsSecurity sec = SecUtil.read(file, true);
+            if (sec != null) {
                 master = sec.getMaster();
             }
 
-            if ( master == null )
-            {
-                throw new IllegalStateException( "Master password is not set in the setting security file: " + file );
+            if (master == null) {
+                throw new IllegalStateException("Master password is not set in the setting security file: " + file);
             }
 
             DefaultPlexusCipher cipher = new DefaultPlexusCipher();
-            String masterPasswd = cipher.decryptDecorated( master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION );
-            System.out.println( cipher.encryptAndDecorate( passwd, masterPasswd ) );
+            String masterPasswd = cipher.decryptDecorated(master, DefaultSecDispatcher.SYSTEM_PROPERTY_SEC_LOCATION);
+            System.out.println(cipher.encryptAndDecorate(passwd, masterPasswd));
 
-            throw new ExitException( 0 );
+            throw new ExitException(0);
         }
     }
 
-    private void repository( CliRequest cliRequest )
-        throws Exception
-    {
-        if ( cliRequest.commandLine.hasOption( CLIManager.LEGACY_LOCAL_REPOSITORY ) || Boolean.getBoolean(
-            "maven.legacyLocalRepo" ) )
-        {
-            cliRequest.request.setUseLegacyLocalRepository( true );
-        }
-    }
+    private int execute(CliRequest cliRequest) throws MavenExecutionRequestPopulationException {
+        MavenExecutionRequest request = executionRequestPopulator.populateDefaults(cliRequest.request);
 
-    private int execute( CliRequest cliRequest )
-        throws MavenExecutionRequestPopulationException
-    {
-        MavenExecutionRequest request = executionRequestPopulator.populateDefaults( cliRequest.request );
-
-        if ( cliRequest.request.getRepositoryCache() == null )
-        {
-            cliRequest.request.setRepositoryCache( new DefaultRepositoryCache() );
+        if (cliRequest.request.getRepositoryCache() == null) {
+            cliRequest.request.setRepositoryCache(new DefaultRepositoryCache());
         }
 
-        eventSpyDispatcher.onEvent( request );
+        eventSpyDispatcher.onEvent(request);
 
-        MavenExecutionResult result = maven.execute( request );
+        MavenExecutionResult result = maven.execute(request);
 
-        eventSpyDispatcher.onEvent( result );
+        eventSpyDispatcher.onEvent(result);
 
         eventSpyDispatcher.close();
 
-        if ( result.hasExceptions() )
-        {
+        if (result.hasExceptions()) {
             ExceptionHandler handler = new DefaultExceptionHandler();
 
             Map<String, String> references = new LinkedHashMap<>();
 
             List<MavenProject> failedProjects = new ArrayList<>();
 
-            for ( Throwable exception : result.getExceptions() )
-            {
-                ExceptionSummary summary = handler.handleException( exception );
+            for (Throwable exception : result.getExceptions()) {
+                ExceptionSummary summary = handler.handleException(exception);
 
-                logSummary( summary, references, "", cliRequest.showErrors );
+                logSummary(summary, references, "", cliRequest.showErrors);
 
-                if ( exception instanceof LifecycleExecutionException )
-                {
-                    failedProjects.add ( ( (LifecycleExecutionException) exception ).getProject() );
+                if (exception instanceof LifecycleExecutionException) {
+                    failedProjects.add(((LifecycleExecutionException) exception).getProject());
                 }
             }
 
-            slf4jLogger.error( "" );
+            slf4jLogger.error("");
 
-            if ( !cliRequest.showErrors )
-            {
-                slf4jLogger.error( "To see the full stack trace of the errors, re-run Maven with the '{}' switch",
-                        buffer().strong( "-e" ) );
+            if (!cliRequest.showErrors) {
+                slf4jLogger.error(
+                        "To see the full stack trace of the errors, re-run Maven with the '{}' switch",
+                        MessageUtils.builder().strong("-e"));
             }
-            if ( !slf4jLogger.isDebugEnabled() )
-            {
-                slf4jLogger.error( "Re-run Maven using the '{}' switch to enable verbose output",
-                        buffer().strong( "-X" ) );
+            if (!slf4jLogger.isDebugEnabled()) {
+                slf4jLogger.error(
+                        "Re-run Maven using the '{}' switch to enable verbose output",
+                        MessageUtils.builder().strong("-X"));
             }
 
-            if ( !references.isEmpty() )
-            {
-                slf4jLogger.error( "" );
-                slf4jLogger.error( "For more information about the errors and possible solutions"
-                                       + ", please read the following articles:" );
+            if (!references.isEmpty()) {
+                slf4jLogger.error("");
+                slf4jLogger.error("For more information about the errors and possible solutions"
+                        + ", please read the following articles:");
 
-                for ( Map.Entry<String, String> entry : references.entrySet() )
-                {
-                    slf4jLogger.error( "{} {}", buffer().strong( entry.getValue() ), entry.getKey() );
+                for (Map.Entry<String, String> entry : references.entrySet()) {
+                    slf4jLogger.error("{} {}", MessageUtils.builder().strong(entry.getValue()), entry.getKey());
                 }
             }
 
-            if ( result.canResume() )
-            {
-                logBuildResumeHint( "mvn [args] -r" );
-            }
-            else if ( !failedProjects.isEmpty() )
-            {
+            if (result.canResume()) {
+                logBuildResumeHint("mvn [args] -r");
+            } else if (!failedProjects.isEmpty()) {
                 List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
 
                 // Sort the failedProjects list in the topologically sorted order.
-                failedProjects.sort( comparing( sortedProjects::indexOf ) );
+                failedProjects.sort(comparing(sortedProjects::indexOf));
 
-                MavenProject firstFailedProject = failedProjects.get( 0 );
-                if ( !firstFailedProject.equals( sortedProjects.get( 0 ) ) )
-                {
-                    String resumeFromSelector = getResumeFromSelector( sortedProjects, firstFailedProject );
-                    logBuildResumeHint( "mvn [args] -rf " + resumeFromSelector );
+                MavenProject firstFailedProject = failedProjects.get(0);
+                if (!firstFailedProject.equals(sortedProjects.get(0))) {
+                    String resumeFromSelector = getResumeFromSelector(sortedProjects, firstFailedProject);
+                    logBuildResumeHint("mvn [args] -rf " + resumeFromSelector);
                 }
             }
 
-            if ( MavenExecutionRequest.REACTOR_FAIL_NEVER.equals( cliRequest.request.getReactorFailureBehavior() ) )
-            {
-                slf4jLogger.info( "Build failures were ignored." );
+            if (MavenExecutionRequest.REACTOR_FAIL_NEVER.equals(cliRequest.request.getReactorFailureBehavior())) {
+                slf4jLogger.info("Build failures were ignored.");
 
                 return 0;
-            }
-            else
-            {
+            } else {
                 return 1;
             }
-        }
-        else
-        {
+        } else {
             return 0;
         }
     }
 
-    private void logBuildResumeHint( String resumeBuildHint )
-    {
-        slf4jLogger.error( "" );
-        slf4jLogger.error( "After correcting the problems, you can resume the build with the command" );
-        slf4jLogger.error( buffer().a( "  " ).strong( resumeBuildHint ).toString() );
+    private void logBuildResumeHint(String resumeBuildHint) {
+        slf4jLogger.error("");
+        slf4jLogger.error("After correcting the problems, you can resume the build with the command");
+        slf4jLogger.error(MessageUtils.builder().a("  ").strong(resumeBuildHint).toString());
     }
 
     /**
@@ -1112,81 +1051,63 @@
      * @return Value for -rf flag to resume build exactly from place where it failed ({@code :artifactId} in general
      * and {@code groupId:artifactId} when there is a name clash).
      */
-    String getResumeFromSelector( List<MavenProject> mavenProjects, MavenProject firstFailedProject )
-    {
+    String getResumeFromSelector(List<MavenProject> mavenProjects, MavenProject firstFailedProject) {
         boolean hasOverlappingArtifactId = mavenProjects.stream()
-                .filter( project -> firstFailedProject.getArtifactId().equals( project.getArtifactId() ) )
-                .count() > 1;
+                        .filter(project -> firstFailedProject.getArtifactId().equals(project.getArtifactId()))
+                        .count()
+                > 1;
 
-        if ( hasOverlappingArtifactId )
-        {
+        if (hasOverlappingArtifactId) {
             return firstFailedProject.getGroupId() + ":" + firstFailedProject.getArtifactId();
         }
 
         return ":" + firstFailedProject.getArtifactId();
     }
 
-    private void logSummary( ExceptionSummary summary, Map<String, String> references, String indent,
-                             boolean showErrors )
-    {
+    private void logSummary(
+            ExceptionSummary summary, Map<String, String> references, String indent, boolean showErrors) {
         String referenceKey = "";
 
-        if ( StringUtils.isNotEmpty( summary.getReference() ) )
-        {
-            referenceKey = references.get( summary.getReference() );
-            if ( referenceKey == null )
-            {
-                referenceKey = "[Help " + ( references.size() + 1 ) + "]";
-                references.put( summary.getReference(), referenceKey );
-            }
+        if (summary.getReference() != null && !summary.getReference().isEmpty()) {
+            referenceKey =
+                    references.computeIfAbsent(summary.getReference(), k -> "[Help " + (references.size() + 1) + "]");
         }
 
         String msg = summary.getMessage();
 
-        if ( StringUtils.isNotEmpty( referenceKey ) )
-        {
-            if ( msg.indexOf( '\n' ) < 0 )
-            {
-                msg += " -> " + buffer().strong( referenceKey );
-            }
-            else
-            {
-                msg += "\n-> " + buffer().strong( referenceKey );
+        if (referenceKey != null && !referenceKey.isEmpty()) {
+            if (msg.indexOf('\n') < 0) {
+                msg += " -> " + MessageUtils.builder().strong(referenceKey);
+            } else {
+                msg += "\n-> " + MessageUtils.builder().strong(referenceKey);
             }
         }
 
-        String[] lines = msg.split( "(\r\n)|(\r)|(\n)" );
+        String[] lines = NEXT_LINE.split(msg);
         String currentColor = "";
 
-        for ( int i = 0; i < lines.length; i++ )
-        {
+        for (int i = 0; i < lines.length; i++) {
             // add eventual current color inherited from previous line
             String line = currentColor + lines[i];
 
             // look for last ANSI escape sequence to check if nextColor
-            Matcher matcher = LAST_ANSI_SEQUENCE.matcher( line );
+            Matcher matcher = LAST_ANSI_SEQUENCE.matcher(line);
             String nextColor = "";
-            if ( matcher.find() )
-            {
-                nextColor = matcher.group( 1 );
-                if ( ANSI_RESET.equals( nextColor ) )
-                {
+            if (matcher.find()) {
+                nextColor = matcher.group(1);
+                if (ANSI_RESET.equals(nextColor)) {
                     // last ANSI escape code is reset: no next color
                     nextColor = "";
                 }
             }
 
             // effective line, with indent and reset if end is colored
-            line = indent + line + ( "".equals( nextColor ) ? "" : ANSI_RESET );
+            line = indent + line + ("".equals(nextColor) ? "" : ANSI_RESET);
 
-            if ( ( i == lines.length - 1 ) && ( showErrors
-                || ( summary.getException() instanceof InternalErrorException ) ) )
-            {
-                slf4jLogger.error( line, summary.getException() );
-            }
-            else
-            {
-                slf4jLogger.error( line );
+            if ((i == lines.length - 1) && (showErrors || (summary.getException() instanceof InternalErrorException))) {
+                slf4jLogger.error(line, summary.getException());
+            } else {
+                slf4jLogger.error(line);
             }
 
             currentColor = nextColor;
@@ -1194,26 +1115,23 @@
 
         indent += "  ";
 
-        for ( ExceptionSummary child : summary.getChildren() )
-        {
-            logSummary( child, references, indent, showErrors );
+        for (ExceptionSummary child : summary.getChildren()) {
+            logSummary(child, references, indent, showErrors);
         }
     }
 
-    private static final Pattern LAST_ANSI_SEQUENCE = Pattern.compile( "(\u001B\\[[;\\d]*[ -/]*[@-~])[^\u001B]*$" );
+    private static final Pattern LAST_ANSI_SEQUENCE = Pattern.compile("(\u001B\\[[;\\d]*[ -/]*[@-~])[^\u001B]*$");
 
     private static final String ANSI_RESET = "\u001B\u005Bm";
 
-    private void configure( CliRequest cliRequest )
-        throws Exception
-    {
+    private void configure(CliRequest cliRequest) throws Exception {
         //
         // This is not ideal but there are events specifically for configuration from the CLI which I don't
         // believe are really valid but there are ITs which assert the right events are published so this
         // needs to be supported so the EventSpyDispatcher needs to be put in the CliRequest so that
         // it can be accessed by configuration processors.
         //
-        cliRequest.request.setEventSpyDispatcher( eventSpyDispatcher );
+        cliRequest.request.setEventSpyDispatcher(eventSpyDispatcher);
 
         //
         // We expect at most 2 implementations to be available. The SettingsXmlConfigurationProcessor implementation
@@ -1224,190 +1142,175 @@
         //
         int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1;
 
-        if ( userSuppliedConfigurationProcessorCount == 0 )
-        {
+        if (userSuppliedConfigurationProcessorCount == 0) {
             //
             // Our settings.xml source is historically how we have configured Maven from the CLI so we are going to
             // have to honour its existence forever. So let's run it.
             //
-            configurationProcessors.get( SettingsXmlConfigurationProcessor.HINT ).process( cliRequest );
-        }
-        else if ( userSuppliedConfigurationProcessorCount == 1 )
-        {
+            configurationProcessors.get(SettingsXmlConfigurationProcessor.HINT).process(cliRequest);
+        } else if (userSuppliedConfigurationProcessorCount == 1) {
             //
             // Run the user supplied ConfigurationProcessor
             //
-            for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
-            {
+            for (Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet()) {
                 String hint = entry.getKey();
-                if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
-                {
+                if (!hint.equals(SettingsXmlConfigurationProcessor.HINT)) {
                     ConfigurationProcessor configurationProcessor = entry.getValue();
-                    configurationProcessor.process( cliRequest );
+                    configurationProcessor.process(cliRequest);
                 }
             }
-        }
-        else if ( userSuppliedConfigurationProcessorCount > 1 )
-        {
+        } else if (userSuppliedConfigurationProcessorCount > 1) {
             //
             // There are too many ConfigurationProcessors so we don't know which one to run so report the error.
             //
-            StringBuilder sb = new StringBuilder(
-                String.format( "%nThere can only be one user supplied ConfigurationProcessor, there are %s:%n%n",
-                               userSuppliedConfigurationProcessorCount ) );
-            for ( Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet() )
-            {
+            StringBuilder sb = new StringBuilder(String.format(
+                    "%nThere can only be one user supplied ConfigurationProcessor, there are %s:%n%n",
+                    userSuppliedConfigurationProcessorCount));
+            for (Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet()) {
                 String hint = entry.getKey();
-                if ( !hint.equals( SettingsXmlConfigurationProcessor.HINT ) )
-                {
+                if (!hint.equals(SettingsXmlConfigurationProcessor.HINT)) {
                     ConfigurationProcessor configurationProcessor = entry.getValue();
-                    sb.append( String.format( "%s%n", configurationProcessor.getClass().getName() ) );
+                    sb.append(String.format(
+                            "%s%n", configurationProcessor.getClass().getName()));
                 }
             }
-            throw new Exception( sb.toString() );
+            throw new Exception(sb.toString());
         }
     }
 
-    void toolchains( CliRequest cliRequest )
-        throws Exception
-    {
+    void toolchains(CliRequest cliRequest) throws Exception {
         File userToolchainsFile;
 
-        if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_USER_TOOLCHAINS ) )
-        {
-            userToolchainsFile =
-                new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_USER_TOOLCHAINS ) );
-            userToolchainsFile = resolveFile( userToolchainsFile, cliRequest.workingDirectory );
+        if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_USER_TOOLCHAINS)) {
+            userToolchainsFile = new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_USER_TOOLCHAINS));
+            userToolchainsFile = resolveFile(userToolchainsFile, cliRequest.workingDirectory);
 
-            if ( !userToolchainsFile.isFile() )
-            {
+            if (!userToolchainsFile.isFile()) {
                 throw new FileNotFoundException(
-                    "The specified user toolchains file does not exist: " + userToolchainsFile );
+                        "The specified user toolchains file does not exist: " + userToolchainsFile);
             }
-        }
-        else
-        {
+        } else {
             userToolchainsFile = DEFAULT_USER_TOOLCHAINS_FILE;
         }
 
         File globalToolchainsFile;
 
-        if ( cliRequest.commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) )
-        {
+        if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS)) {
             globalToolchainsFile =
-                new File( cliRequest.commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS ) );
-            globalToolchainsFile = resolveFile( globalToolchainsFile, cliRequest.workingDirectory );
+                    new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS));
+            globalToolchainsFile = resolveFile(globalToolchainsFile, cliRequest.workingDirectory);
 
-            if ( !globalToolchainsFile.isFile() )
-            {
+            if (!globalToolchainsFile.isFile()) {
                 throw new FileNotFoundException(
-                    "The specified global toolchains file does not exist: " + globalToolchainsFile );
+                        "The specified global toolchains file does not exist: " + globalToolchainsFile);
             }
-        }
-        else
-        {
+        } else {
             globalToolchainsFile = DEFAULT_GLOBAL_TOOLCHAINS_FILE;
         }
 
-        cliRequest.request.setGlobalToolchainsFile( globalToolchainsFile );
-        cliRequest.request.setUserToolchainsFile( userToolchainsFile );
+        cliRequest.request.setGlobalToolchainsFile(globalToolchainsFile);
+        cliRequest.request.setUserToolchainsFile(userToolchainsFile);
 
         DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest();
-        if ( globalToolchainsFile.isFile() )
-        {
-            toolchainsRequest.setGlobalToolchainsSource( new FileSource( globalToolchainsFile ) );
+        if (globalToolchainsFile.isFile()) {
+            toolchainsRequest.setGlobalToolchainsSource(new FileSource(globalToolchainsFile));
         }
-        if ( userToolchainsFile.isFile() )
-        {
-            toolchainsRequest.setUserToolchainsSource( new FileSource( userToolchainsFile ) );
+        if (userToolchainsFile.isFile()) {
+            toolchainsRequest.setUserToolchainsSource(new FileSource(userToolchainsFile));
         }
 
-        eventSpyDispatcher.onEvent( toolchainsRequest );
+        eventSpyDispatcher.onEvent(toolchainsRequest);
 
-        slf4jLogger.debug( "Reading global toolchains from '{}'",
-                getLocation( toolchainsRequest.getGlobalToolchainsSource(), globalToolchainsFile ) );
-        slf4jLogger.debug( "Reading user toolchains from '{}'",
-                getLocation( toolchainsRequest.getUserToolchainsSource(), userToolchainsFile ) );
+        slf4jLogger.debug(
+                "Reading global toolchains from '{}'",
+                getLocation(toolchainsRequest.getGlobalToolchainsSource(), globalToolchainsFile));
+        slf4jLogger.debug(
+                "Reading user toolchains from '{}'",
+                getLocation(toolchainsRequest.getUserToolchainsSource(), userToolchainsFile));
 
-        ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build( toolchainsRequest );
+        ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build(toolchainsRequest);
 
-        eventSpyDispatcher.onEvent( toolchainsResult );
+        eventSpyDispatcher.onEvent(toolchainsResult);
 
-        executionRequestPopulator.populateFromToolchains( cliRequest.request,
-                                                          toolchainsResult.getEffectiveToolchains() );
+        executionRequestPopulator.populateFromToolchains(cliRequest.request, toolchainsResult.getEffectiveToolchains());
 
-        if ( !toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled() )
-        {
-            slf4jLogger.warn( "" );
-            slf4jLogger.warn( "Some problems were encountered while building the effective toolchains" );
+        if (!toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled()) {
+            slf4jLogger.warn("");
+            slf4jLogger.warn("Some problems were encountered while building the effective toolchains");
 
-            for ( Problem problem : toolchainsResult.getProblems() )
-            {
-                slf4jLogger.warn( "{} @ {}", problem.getMessage(), problem.getLocation() );
+            for (Problem problem : toolchainsResult.getProblems()) {
+                slf4jLogger.warn("{} @ {}", problem.getMessage(), problem.getLocation());
             }
 
-            slf4jLogger.warn( "" );
+            slf4jLogger.warn("");
         }
     }
 
-    private Object getLocation( Source source, File defaultLocation )
-    {
-        if ( source != null )
-        {
+    private Object getLocation(Source source, File defaultLocation) {
+        if (source != null) {
             return source.getLocation();
         }
         return defaultLocation;
     }
 
-    protected MavenExecutionRequest populateRequest( CliRequest cliRequest )
-    {
-        return populateRequest( cliRequest, cliRequest.request );
+    protected MavenExecutionRequest populateRequest(CliRequest cliRequest) {
+        return populateRequest(cliRequest, cliRequest.request);
     }
 
-    private MavenExecutionRequest populateRequest( CliRequest cliRequest, MavenExecutionRequest request )
-    {
+    private MavenExecutionRequest populateRequest(CliRequest cliRequest, MavenExecutionRequest request) {
         slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
         CommandLine commandLine = cliRequest.commandLine;
         String workingDirectory = cliRequest.workingDirectory;
         boolean quiet = cliRequest.quiet;
         boolean verbose = cliRequest.verbose;
-        request.setShowErrors( cliRequest.showErrors ); // default: false
-        File baseDirectory = new File( workingDirectory, "" ).getAbsoluteFile();
+        request.setShowErrors(cliRequest.showErrors); // default: false
+        File baseDirectory = new File(workingDirectory, "").getAbsoluteFile();
 
-        disableOnPresentOption( commandLine, CLIManager.BATCH_MODE, request::setInteractiveMode );
-        enableOnPresentOption( commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates );
-        request.setGoals( commandLine.getArgList() );
-        request.setReactorFailureBehavior( determineReactorFailureBehaviour ( commandLine ) );
-        disableOnPresentOption( commandLine, CLIManager.NON_RECURSIVE, request::setRecursive );
-        enableOnPresentOption( commandLine, CLIManager.OFFLINE, request::setOffline );
-        enableOnPresentOption( commandLine, CLIManager.UPDATE_SNAPSHOTS, request::setUpdateSnapshots );
-        request.setGlobalChecksumPolicy( determineGlobalCheckPolicy( commandLine ) );
-        request.setBaseDirectory( baseDirectory );
-        request.setSystemProperties( cliRequest.systemProperties );
-        request.setUserProperties( cliRequest.userProperties );
-        request.setMultiModuleProjectDirectory( cliRequest.multiModuleProjectDirectory );
-        request.setPom( determinePom( commandLine, workingDirectory, baseDirectory ) );
-        request.setTransferListener( determineTransferListener( quiet, verbose, commandLine, request ) );
-        request.setExecutionListener( determineExecutionListener() );
+        disableInteractiveModeIfNeeded(cliRequest, request);
+        enableOnPresentOption(commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates);
+        request.setGoals(commandLine.getArgList());
+        request.setReactorFailureBehavior(determineReactorFailureBehaviour(commandLine));
+        disableOnPresentOption(commandLine, CLIManager.NON_RECURSIVE, request::setRecursive);
+        enableOnPresentOption(commandLine, CLIManager.OFFLINE, request::setOffline);
+        enableOnPresentOption(commandLine, CLIManager.UPDATE_SNAPSHOTS, request::setUpdateSnapshots);
+        request.setGlobalChecksumPolicy(determineGlobalCheckPolicy(commandLine));
+        request.setBaseDirectory(baseDirectory);
+        request.setSystemProperties(cliRequest.systemProperties);
+        request.setUserProperties(cliRequest.userProperties);
+        request.setMultiModuleProjectDirectory(cliRequest.multiModuleProjectDirectory);
+        request.setRootDirectory(cliRequest.rootDirectory);
+        request.setTopDirectory(cliRequest.topDirectory);
+        request.setPom(determinePom(commandLine, workingDirectory, baseDirectory));
+        request.setTransferListener(determineTransferListener(quiet, verbose, commandLine, request));
+        request.setExecutionListener(determineExecutionListener());
 
-        if ( ( request.getPom() != null ) && ( request.getPom().getParentFile() != null ) )
-        {
-            request.setBaseDirectory( request.getPom().getParentFile() );
+        if ((request.getPom() != null) && (request.getPom().getParentFile() != null)) {
+            request.setBaseDirectory(request.getPom().getParentFile());
         }
 
-        request.setResumeFrom( commandLine.getOptionValue( CLIManager.RESUME_FROM ) );
-        enableOnPresentOption( commandLine, CLIManager.RESUME, request::setResume );
-        request.setMakeBehavior( determineMakeBehavior( commandLine ) );
-        request.setCacheNotFound( true );
-        request.setCacheTransferError( false );
+        request.setResumeFrom(commandLine.getOptionValue(CLIManager.RESUME_FROM));
+        enableOnPresentOption(commandLine, CLIManager.RESUME, request::setResume);
+        request.setMakeBehavior(determineMakeBehavior(commandLine));
+        boolean cacheNotFound = !commandLine.hasOption(CLIManager.CACHE_ARTIFACT_NOT_FOUND)
+                || Boolean.parseBoolean(commandLine.getOptionValue(CLIManager.CACHE_ARTIFACT_NOT_FOUND));
+        request.setCacheNotFound(cacheNotFound);
+        request.setCacheTransferError(false);
+        boolean strictArtifactDescriptorPolicy = commandLine.hasOption(CLIManager.STRICT_ARTIFACT_DESCRIPTOR_POLICY)
+                && Boolean.parseBoolean(commandLine.getOptionValue(CLIManager.STRICT_ARTIFACT_DESCRIPTOR_POLICY));
+        if (strictArtifactDescriptorPolicy) {
+            request.setIgnoreMissingArtifactDescriptor(false);
+            request.setIgnoreInvalidArtifactDescriptor(false);
+        } else {
+            request.setIgnoreMissingArtifactDescriptor(true);
+            request.setIgnoreInvalidArtifactDescriptor(true);
+        }
 
-        performProjectActivation( commandLine, request.getProjectActivation() );
-        performProfileActivation( commandLine, request.getProfileActivation() );
+        performProjectActivation(commandLine, request.getProjectActivation());
+        performProfileActivation(commandLine, request.getProfileActivation());
 
-        final String localRepositoryPath = determineLocalRepositoryPath( request );
-        if ( localRepositoryPath != null )
-        {
-            request.setLocalRepositoryPath( localRepositoryPath );
+        final String localRepositoryPath = determineLocalRepositoryPath(request);
+        if (localRepositoryPath != null) {
+            request.setLocalRepositoryPath(localRepositoryPath);
         }
 
         //
@@ -1418,339 +1321,265 @@
         // parameters but this is sufficient for now. Ultimately we want components like Builders to provide a way to
         // extend the command line to accept its own configuration parameters.
         //
-        final String threadConfiguration = commandLine.getOptionValue( CLIManager.THREADS );
+        final String threadConfiguration = commandLine.getOptionValue(CLIManager.THREADS);
 
-        if ( threadConfiguration != null )
-        {
-            int degreeOfConcurrency = calculateDegreeOfConcurrency( threadConfiguration );
-            if ( degreeOfConcurrency > 1 )
-            {
-                request.setBuilderId( "multithreaded" );
-                request.setDegreeOfConcurrency( degreeOfConcurrency );
+        if (threadConfiguration != null) {
+            int degreeOfConcurrency = calculateDegreeOfConcurrency(threadConfiguration);
+            if (degreeOfConcurrency > 1) {
+                request.setBuilderId("multithreaded");
+                request.setDegreeOfConcurrency(degreeOfConcurrency);
             }
         }
 
         //
         // Allow the builder to be overridden by the user if requested. The builders are now pluggable.
         //
-        request.setBuilderId( commandLine.getOptionValue( CLIManager.BUILDER, request.getBuilderId() ) );
+        request.setBuilderId(commandLine.getOptionValue(CLIManager.BUILDER, request.getBuilderId()));
 
         return request;
     }
 
-    private String determineLocalRepositoryPath( final MavenExecutionRequest request )
-    {
-        String userDefinedLocalRepo = request.getUserProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
-        if ( userDefinedLocalRepo != null )
-        {
+    private void disableInteractiveModeIfNeeded(final CliRequest cliRequest, final MavenExecutionRequest request) {
+        CommandLine commandLine = cliRequest.getCommandLine();
+        if (commandLine.hasOption(FORCE_INTERACTIVE)) {
+            return;
+        }
+
+        boolean runningOnCI = isRunningOnCI(cliRequest.getSystemProperties());
+        if (runningOnCI) {
+            slf4jLogger.info("Making this build non-interactive, because the environment variable CI equals \"true\"."
+                    + " Disable this detection by removing that variable or adding --force-interactive.");
+            request.setInteractiveMode(false);
+        } else if (commandLine.hasOption(BATCH_MODE) || commandLine.hasOption(NON_INTERACTIVE)) {
+            request.setInteractiveMode(false);
+        }
+    }
+
+    private static boolean isRunningOnCI(Properties systemProperties) {
+        String ciEnv = systemProperties.getProperty("env.CI");
+        return ciEnv != null && !"false".equals(ciEnv);
+    }
+
+    private String determineLocalRepositoryPath(final MavenExecutionRequest request) {
+        String userDefinedLocalRepo = request.getUserProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY);
+        if (userDefinedLocalRepo != null) {
             return userDefinedLocalRepo;
         }
 
-        return request.getSystemProperties().getProperty( MavenCli.LOCAL_REPO_PROPERTY );
+        // TODO Investigate why this can also be a Java system property and not just a Maven user property like
+        // other properties
+        return request.getSystemProperties().getProperty(MavenCli.LOCAL_REPO_PROPERTY);
     }
 
-    private File determinePom( final CommandLine commandLine, final String workingDirectory, final File baseDirectory )
-    {
+    private File determinePom(final CommandLine commandLine, final String workingDirectory, final File baseDirectory) {
         String alternatePomFile = null;
-        if ( commandLine.hasOption( CLIManager.ALTERNATE_POM_FILE ) )
-        {
-            alternatePomFile = commandLine.getOptionValue( CLIManager.ALTERNATE_POM_FILE );
+        if (commandLine.hasOption(CLIManager.ALTERNATE_POM_FILE)) {
+            alternatePomFile = commandLine.getOptionValue(CLIManager.ALTERNATE_POM_FILE);
         }
 
-        if ( alternatePomFile != null )
-        {
-            File pom = resolveFile( new File( alternatePomFile ), workingDirectory );
-            if ( pom.isDirectory() )
-            {
-                pom = new File( pom, "pom.xml" );
-            }
-
-            return pom;
-        }
-        else if ( modelProcessor != null )
-        {
-            File pom = modelProcessor.locatePom( baseDirectory );
-
-            if ( pom.isFile() )
-            {
-                return pom;
-            }
+        File current = baseDirectory;
+        if (alternatePomFile != null) {
+            current = resolveFile(new File(alternatePomFile), workingDirectory);
         }
 
-        return null;
+        if (modelProcessor != null) {
+            return modelProcessor.locateExistingPom(current);
+        } else {
+            return current.isFile() ? current : null;
+        }
     }
 
     // Visible for testing
-    static void performProjectActivation( final CommandLine commandLine, final ProjectActivation projectActivation )
-    {
-        if ( commandLine.hasOption( CLIManager.PROJECT_LIST ) )
-        {
-            final String[] optionValues = commandLine.getOptionValues( CLIManager.PROJECT_LIST );
+    static void performProjectActivation(final CommandLine commandLine, final ProjectActivation projectActivation) {
+        if (commandLine.hasOption(CLIManager.PROJECT_LIST)) {
+            final String[] optionValues = commandLine.getOptionValues(CLIManager.PROJECT_LIST);
 
-            if ( optionValues == null || optionValues.length == 0 )
-            {
+            if (optionValues == null || optionValues.length == 0) {
                 return;
             }
 
-            for ( final String optionValue : optionValues )
-            {
-                for ( String token : optionValue.split( "," ) )
-                {
+            for (final String optionValue : optionValues) {
+                for (String token : optionValue.split(",")) {
                     String selector = token.trim();
                     boolean active = true;
-                    if ( selector.charAt( 0 ) == '-' || selector.charAt( 0 ) == '!' )
-                    {
+                    if (selector.charAt(0) == '-' || selector.charAt(0) == '!') {
                         active = false;
-                        selector = selector.substring( 1 );
-                    }
-                    else if ( token.charAt( 0 ) == '+' )
-                    {
-                        selector = selector.substring( 1 );
+                        selector = selector.substring(1);
+                    } else if (token.charAt(0) == '+') {
+                        selector = selector.substring(1);
                     }
 
-                    boolean optional = selector.charAt( 0 ) == '?';
-                    selector = selector.substring( optional ? 1 : 0 );
+                    boolean optional = selector.charAt(0) == '?';
+                    selector = selector.substring(optional ? 1 : 0);
 
-                    projectActivation.addProjectActivation( selector, active, optional );
+                    projectActivation.addProjectActivation(selector, active, optional);
                 }
             }
         }
     }
 
     // Visible for testing
-    static void performProfileActivation( final CommandLine commandLine, final ProfileActivation profileActivation )
-    {
-        if ( commandLine.hasOption( CLIManager.ACTIVATE_PROFILES ) )
-        {
-            final String[] optionValues = commandLine.getOptionValues( CLIManager.ACTIVATE_PROFILES );
+    static void performProfileActivation(final CommandLine commandLine, final ProfileActivation profileActivation) {
+        if (commandLine.hasOption(CLIManager.ACTIVATE_PROFILES)) {
+            final String[] optionValues = commandLine.getOptionValues(CLIManager.ACTIVATE_PROFILES);
 
-            if ( optionValues == null || optionValues.length == 0 )
-            {
+            if (optionValues == null || optionValues.length == 0) {
                 return;
             }
 
-            for ( final String optionValue : optionValues )
-            {
-                for ( String token : optionValue.split( "," ) )
-                {
+            for (final String optionValue : optionValues) {
+                for (String token : optionValue.split(",")) {
                     String profileId = token.trim();
                     boolean active = true;
-                    if ( profileId.charAt( 0 ) == '-' || profileId.charAt( 0 ) == '!' )
-                    {
+                    if (profileId.charAt(0) == '-' || profileId.charAt(0) == '!') {
                         active = false;
-                        profileId = profileId.substring( 1 );
-                    }
-                    else if ( token.charAt( 0 ) == '+' )
-                    {
-                        profileId = profileId.substring( 1 );
+                        profileId = profileId.substring(1);
+                    } else if (token.charAt(0) == '+') {
+                        profileId = profileId.substring(1);
                     }
 
-                    boolean optional = profileId.charAt( 0 ) == '?';
-                    profileId = profileId.substring( optional ? 1 : 0 );
+                    boolean optional = profileId.charAt(0) == '?';
+                    profileId = profileId.substring(optional ? 1 : 0);
 
-                    profileActivation.addProfileActivation( profileId, active, optional );
+                    profileActivation.addProfileActivation(profileId, active, optional);
                 }
             }
         }
     }
 
-    private ExecutionListener determineExecutionListener()
-    {
-        ExecutionListener executionListener = new ExecutionEventLogger();
-        if ( eventSpyDispatcher != null )
-        {
-            return eventSpyDispatcher.chainListener( executionListener );
-        }
-        else
-        {
+    private ExecutionListener determineExecutionListener() {
+        ExecutionListener executionListener = new ExecutionEventLogger(messageBuilderFactory);
+        if (eventSpyDispatcher != null) {
+            return eventSpyDispatcher.chainListener(executionListener);
+        } else {
             return executionListener;
         }
     }
 
-    private String determineReactorFailureBehaviour( final CommandLine commandLine )
-    {
-        if ( commandLine.hasOption( CLIManager.FAIL_FAST ) )
-        {
+    private String determineReactorFailureBehaviour(final CommandLine commandLine) {
+        if (commandLine.hasOption(CLIManager.FAIL_FAST)) {
             return MavenExecutionRequest.REACTOR_FAIL_FAST;
-        }
-        else if ( commandLine.hasOption( CLIManager.FAIL_AT_END ) )
-        {
+        } else if (commandLine.hasOption(CLIManager.FAIL_AT_END)) {
             return MavenExecutionRequest.REACTOR_FAIL_AT_END;
-        }
-        else if ( commandLine.hasOption( CLIManager.FAIL_NEVER ) )
-        {
+        } else if (commandLine.hasOption(CLIManager.FAIL_NEVER)) {
             return MavenExecutionRequest.REACTOR_FAIL_NEVER;
-        }
-        else
-        {
+        } else {
             // this is the default behavior.
             return MavenExecutionRequest.REACTOR_FAIL_FAST;
         }
     }
 
-    private TransferListener determineTransferListener( final boolean quiet,
-                                                        final boolean verbose,
-                                                        final CommandLine commandLine,
-                                                        final MavenExecutionRequest request )
-    {
-        if ( quiet || commandLine.hasOption( CLIManager.NO_TRANSFER_PROGRESS ) )
-        {
+    private TransferListener determineTransferListener(
+            final boolean quiet,
+            final boolean verbose,
+            final CommandLine commandLine,
+            final MavenExecutionRequest request) {
+        boolean runningOnCI = isRunningOnCI(request.getSystemProperties());
+        boolean quietCI = runningOnCI && !commandLine.hasOption(FORCE_INTERACTIVE);
+
+        if (quiet || commandLine.hasOption(CLIManager.NO_TRANSFER_PROGRESS) || quietCI) {
             return new QuietMavenTransferListener();
-        }
-        else if ( request.isInteractiveMode() && !commandLine.hasOption( CLIManager.LOG_FILE ) )
-        {
+        } else if (request.isInteractiveMode() && !commandLine.hasOption(CLIManager.LOG_FILE)) {
             //
             // If we're logging to a file then we don't want the console transfer listener as it will spew
             // download progress all over the place
             //
-            return getConsoleTransferListener( verbose );
-        }
-        else
-        {
+            return getConsoleTransferListener(verbose);
+        } else {
             // default: batch mode which goes along with interactive
             return getBatchTransferListener();
         }
     }
 
-    private String determineMakeBehavior( final CommandLine cl )
-    {
-        if ( cl.hasOption( CLIManager.ALSO_MAKE ) && !cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
-        {
+    private String determineMakeBehavior(final CommandLine cl) {
+        if (cl.hasOption(CLIManager.ALSO_MAKE) && !cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
             return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM;
-        }
-        else if ( !cl.hasOption( CLIManager.ALSO_MAKE ) && cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
-        {
+        } else if (!cl.hasOption(CLIManager.ALSO_MAKE) && cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
             return MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM;
-        }
-        else if ( cl.hasOption( CLIManager.ALSO_MAKE ) && cl.hasOption( CLIManager.ALSO_MAKE_DEPENDENTS ) )
-        {
+        } else if (cl.hasOption(CLIManager.ALSO_MAKE) && cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
             return MavenExecutionRequest.REACTOR_MAKE_BOTH;
-        }
-        else
-        {
+        } else {
             return null;
         }
     }
 
-    private String determineGlobalCheckPolicy( final CommandLine commandLine )
-    {
-        if ( commandLine.hasOption( CLIManager.CHECKSUM_FAILURE_POLICY ) )
-        {
+    private String determineGlobalCheckPolicy(final CommandLine commandLine) {
+        if (commandLine.hasOption(CLIManager.CHECKSUM_FAILURE_POLICY)) {
             return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
-        }
-        else if ( commandLine.hasOption( CLIManager.CHECKSUM_WARNING_POLICY ) )
-        {
+        } else if (commandLine.hasOption(CLIManager.CHECKSUM_WARNING_POLICY)) {
             return MavenExecutionRequest.CHECKSUM_POLICY_WARN;
-        }
-        else
-        {
+        } else {
             return null;
         }
     }
 
-    private void disableOnPresentOption( final CommandLine commandLine,
-                                         final String option,
-                                         final Consumer<Boolean> setting )
-    {
-        if ( commandLine.hasOption( option ) )
-        {
-            setting.accept( false );
+    private void disableOnPresentOption(
+            final CommandLine commandLine, final String option, final Consumer<Boolean> setting) {
+        if (commandLine.hasOption(option)) {
+            setting.accept(false);
         }
     }
 
-    private void disableOnPresentOption( final CommandLine commandLine,
-                                         final char option,
-                                         final Consumer<Boolean> setting )
-    {
-        disableOnPresentOption( commandLine, String.valueOf( option ), setting );
+    private void disableOnPresentOption(
+            final CommandLine commandLine, final char option, final Consumer<Boolean> setting) {
+        disableOnPresentOption(commandLine, String.valueOf(option), setting);
     }
 
-    private void enableOnPresentOption( final CommandLine commandLine,
-                                        final String option,
-                                        final Consumer<Boolean> setting )
-    {
-        if ( commandLine.hasOption( option ) )
-        {
-            setting.accept( true );
+    private void enableOnPresentOption(
+            final CommandLine commandLine, final String option, final Consumer<Boolean> setting) {
+        if (commandLine.hasOption(option)) {
+            setting.accept(true);
         }
     }
 
-    private void enableOnPresentOption( final CommandLine commandLine,
-                                        final char option,
-                                        final Consumer<Boolean> setting )
-    {
-        enableOnPresentOption( commandLine, String.valueOf( option ), setting );
+    private void enableOnPresentOption(
+            final CommandLine commandLine, final char option, final Consumer<Boolean> setting) {
+        enableOnPresentOption(commandLine, String.valueOf(option), setting);
     }
 
-    private void enableOnAbsentOption( final CommandLine commandLine,
-                                       final char option,
-                                       final Consumer<Boolean> setting )
-    {
-        if ( !commandLine.hasOption( option ) )
-        {
-            setting.accept( true );
+    private void enableOnAbsentOption(
+            final CommandLine commandLine, final char option, final Consumer<Boolean> setting) {
+        if (!commandLine.hasOption(option)) {
+            setting.accept(true);
         }
     }
 
-    int calculateDegreeOfConcurrency( String threadConfiguration )
-    {
-        if ( threadConfiguration.endsWith( "C" ) )
-        {
-            threadConfiguration = threadConfiguration.substring( 0, threadConfiguration.length() - 1 );
+    int calculateDegreeOfConcurrency(String threadConfiguration) {
+        try {
+            if (threadConfiguration.endsWith("C")) {
+                String str = threadConfiguration.substring(0, threadConfiguration.length() - 1);
+                float coreMultiplier = Float.parseFloat(str);
 
-            if ( !NumberUtils.isParsable( threadConfiguration ) )
-            {
-                throw new IllegalArgumentException( "Invalid threads core multiplier value: '" + threadConfiguration
-                        + "C'. Supported are int and float values ending with C." );
-            }
-
-            float coreMultiplier = Float.parseFloat( threadConfiguration );
-
-            if ( coreMultiplier <= 0.0f )
-            {
-                throw new IllegalArgumentException( "Invalid threads core multiplier value: '" + threadConfiguration
-                        + "C'. Value must be positive." );
-            }
-
-            int procs = Runtime.getRuntime().availableProcessors();
-            int threads = (int) ( coreMultiplier * procs );
-            return threads == 0 ? 1 : threads;
-        }
-        else
-        {
-            if ( !NumberUtils.isParsable( threadConfiguration ) )
-            {
-                throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration
-                        + "'. Supported are int values." );
-            }
-
-            try
-            {
-                int threads = Integer.parseInt( threadConfiguration );
-
-                if ( threads <= 0 )
-                {
-                    throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration
-                            + "'. Value must be positive." );
+                if (coreMultiplier <= 0.0f) {
+                    throw new IllegalArgumentException("Invalid threads core multiplier value: '" + threadConfiguration
+                            + "'. Value must be positive.");
                 }
 
+                int procs = Runtime.getRuntime().availableProcessors();
+                int threads = (int) (coreMultiplier * procs);
+                return threads == 0 ? 1 : threads;
+            } else {
+                int threads = Integer.parseInt(threadConfiguration);
+                if (threads <= 0) {
+                    throw new IllegalArgumentException(
+                            "Invalid threads value: '" + threadConfiguration + "'. Value must be positive.");
+                }
                 return threads;
             }
-            catch ( NumberFormatException e )
-            {
-                throw new IllegalArgumentException( "Invalid threads value: '" + threadConfiguration
-                        + "'. Supported are integer values." );
-            }
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException("Invalid threads value: '" + threadConfiguration
+                    + "'. Supported are int and float values ending with C.");
         }
     }
 
     // ----------------------------------------------------------------------
-    // System properties handling
+    // Properties handling
     // ----------------------------------------------------------------------
 
-    static void populateProperties( CommandLine commandLine, Properties systemProperties, Properties userProperties )
-    {
-        EnvironmentUtils.addEnvVars( systemProperties );
+    static void populateProperties(
+            CommandLine commandLine, Properties paths, Properties systemProperties, Properties userProperties)
+            throws Exception {
+        EnvironmentUtils.addEnvVars(systemProperties);
 
         // ----------------------------------------------------------------------
         // Options that are set on the command line become system properties
@@ -1758,13 +1587,10 @@
         // are most dominant.
         // ----------------------------------------------------------------------
 
-        final Properties userSpecifiedProperties = commandLine.getOptionProperties(
-                String.valueOf( CLIManager.SET_SYSTEM_PROPERTY ) );
-        userSpecifiedProperties.forEach(
-                ( prop, value ) -> setCliProperty( (String) prop, (String) value, userProperties )
-        );
+        final Properties userSpecifiedProperties =
+                commandLine.getOptionProperties(String.valueOf(CLIManager.SET_USER_PROPERTY));
 
-        SystemProperties.addSystemProperties( systemProperties );
+        SystemProperties.addSystemProperties(systemProperties);
 
         // ----------------------------------------------------------------------
         // Properties containing info about the currently running version of Maven
@@ -1773,32 +1599,69 @@
 
         Properties buildProperties = CLIReportingUtils.getBuildProperties();
 
-        String mavenVersion = buildProperties.getProperty( CLIReportingUtils.BUILD_VERSION_PROPERTY );
-        systemProperties.setProperty( "maven.version", mavenVersion );
+        String mavenVersion = buildProperties.getProperty(CLIReportingUtils.BUILD_VERSION_PROPERTY);
+        systemProperties.setProperty("maven.version", mavenVersion);
 
-        String mavenBuildVersion = CLIReportingUtils.createMavenVersionString( buildProperties );
-        systemProperties.setProperty( "maven.build.version", mavenBuildVersion );
+        String mavenBuildVersion = CLIReportingUtils.createMavenVersionString(buildProperties);
+        systemProperties.setProperty("maven.build.version", mavenBuildVersion);
+
+        BasicInterpolator interpolator =
+                createInterpolator(paths, systemProperties, userProperties, userSpecifiedProperties);
+        for (Map.Entry<Object, Object> e : userSpecifiedProperties.entrySet()) {
+            String name = (String) e.getKey();
+            String value = interpolator.interpolate((String) e.getValue());
+            userProperties.setProperty(name, value);
+            // ----------------------------------------------------------------------
+            // I'm leaving the setting of system properties here as not to break
+            // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
+            // ----------------------------------------------------------------------
+            if (System.getProperty(name) == null) {
+                System.setProperty(name, value);
+            }
+        }
     }
 
-    private static void setCliProperty( String name, String value, Properties properties )
-    {
-        properties.setProperty( name, value );
-
-        // ----------------------------------------------------------------------
-        // I'm leaving the setting of system properties here as not to break
-        // the SystemPropertyProfileActivator. This won't harm embedding. jvz.
-        // ----------------------------------------------------------------------
-
-        System.setProperty( name, value );
+    private static BasicInterpolator createInterpolator(Properties... properties) {
+        StringSearchInterpolator interpolator = new StringSearchInterpolator();
+        interpolator.addValueSource(new AbstractValueSource(false) {
+            @Override
+            public Object getValue(String expression) {
+                for (Properties props : properties) {
+                    Object val = props.getProperty(expression);
+                    if (val != null) {
+                        return val;
+                    }
+                }
+                return null;
+            }
+        });
+        return interpolator;
     }
 
-    static class ExitException
-        extends Exception
-    {
+    private static String stripLeadingAndTrailingQuotes(String str) {
+        final int length = str.length();
+        if (length > 1
+                && str.startsWith("\"")
+                && str.endsWith("\"")
+                && str.substring(1, length - 1).indexOf('"') == -1) {
+            str = str.substring(1, length - 1);
+        }
+
+        return str;
+    }
+
+    private static Path getCanonicalPath(Path path) {
+        try {
+            return path.toRealPath();
+        } catch (IOException e) {
+            return getCanonicalPath(path.getParent()).resolve(path.getFileName());
+        }
+    }
+
+    static class ExitException extends Exception {
         int exitCode;
 
-        ExitException( int exitCode )
-        {
+        ExitException(int exitCode) {
             this.exitCode = exitCode;
         }
     }
@@ -1807,23 +1670,17 @@
     // Customizations available via the CLI
     //
 
-    protected TransferListener getConsoleTransferListener( boolean printResourceNames )
-    {
-        return new ConsoleMavenTransferListener( System.out, printResourceNames );
+    protected TransferListener getConsoleTransferListener(boolean printResourceNames) {
+        return new ConsoleMavenTransferListener(System.out, printResourceNames);
     }
 
-    protected TransferListener getBatchTransferListener()
-    {
+    protected TransferListener getBatchTransferListener() {
         return new Slf4jMavenTransferListener();
     }
 
-    protected void customizeContainer( PlexusContainer container )
-    {
-    }
+    protected void customizeContainer(PlexusContainer container) {}
 
-    protected ModelProcessor createModelProcessor( PlexusContainer container )
-        throws ComponentLookupException
-    {
-        return container.lookup( ModelProcessor.class );
+    protected ModelProcessor createModelProcessor(PlexusContainer container) throws ComponentLookupException {
+        return container.lookup(ModelProcessor.class);
     }
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java b/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java
index 7a1652e..d4d496f 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/ResolveFile.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
 
 import java.io.File;
 import java.nio.file.Paths;
@@ -25,26 +24,17 @@
 /**
  * Resolve relative file path against the given base directory
  */
-public class ResolveFile
-{
-    public static File resolveFile( File file, String baseDirectory )
-    {
-        if ( file == null )
-        {
+public class ResolveFile {
+    public static File resolveFile(File file, String baseDirectory) {
+        if (file == null) {
             return null;
-        }
-        else if ( file.isAbsolute() )
-        {
+        } else if (file.isAbsolute()) {
             return file;
-        }
-        else if ( file.getPath().startsWith( File.separator ) )
-        {
+        } else if (file.getPath().startsWith(File.separator)) {
             // drive-relative Windows path
             return file.getAbsoluteFile();
-        }
-        else
-        {
-            return Paths.get( baseDirectory, file.getPath() ).normalize().toFile();
+        } else {
+            return Paths.get(baseDirectory, file.getPath()).normalize().toFile();
         }
     }
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/configuration/ConfigurationProcessor.java b/maven-embedder/src/main/java/org/apache/maven/cli/configuration/ConfigurationProcessor.java
index 50a5854..6e9f064 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/configuration/ConfigurationProcessor.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/configuration/ConfigurationProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.configuration;
 
 import org.apache.maven.cli.CliRequest;
 
 /**
  * ConfigurationProcessor
  */
-public interface ConfigurationProcessor
-{
-    void process( CliRequest request )
-        throws Exception;
+public interface ConfigurationProcessor {
+    void process(CliRequest request) throws Exception;
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java b/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java
index ef0c553..902d0c1 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/configuration/SettingsXmlConfigurationProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.configuration;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.util.List;
+package org.apache.maven.cli.configuration;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.List;
+import java.util.Properties;
+
 import org.apache.commons.cli.CommandLine;
 import org.apache.maven.artifact.InvalidRepositoryException;
 import org.apache.maven.bridge.MavenRepositorySystem;
@@ -36,6 +36,7 @@
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.execution.MavenExecutionRequestPopulationException;
 import org.apache.maven.settings.Mirror;
+import org.apache.maven.settings.Profile;
 import org.apache.maven.settings.Proxy;
 import org.apache.maven.settings.Repository;
 import org.apache.maven.settings.Server;
@@ -55,142 +56,149 @@
 /**
  * SettingsXmlConfigurationProcessor
  */
-@Named ( SettingsXmlConfigurationProcessor.HINT )
+@Named(SettingsXmlConfigurationProcessor.HINT)
 @Singleton
-public class SettingsXmlConfigurationProcessor
-    implements ConfigurationProcessor
-{
+public class SettingsXmlConfigurationProcessor implements ConfigurationProcessor {
     public static final String HINT = "settings";
 
-    public static final String USER_HOME = System.getProperty( "user.home" );
+    public static final String USER_HOME = System.getProperty("user.home");
 
-    public static final File USER_MAVEN_CONFIGURATION_HOME = new File( USER_HOME, ".m2" );
+    public static final File USER_MAVEN_CONFIGURATION_HOME = new File(USER_HOME, ".m2");
 
-    public static final File DEFAULT_USER_SETTINGS_FILE = new File( USER_MAVEN_CONFIGURATION_HOME, "settings.xml" );
+    public static final File DEFAULT_USER_SETTINGS_FILE = new File(USER_MAVEN_CONFIGURATION_HOME, "settings.xml");
 
-    public static final File DEFAULT_GLOBAL_SETTINGS_FILE =
-        new File( System.getProperty( "maven.conf" ), "settings.xml" );
+    public static final File DEFAULT_PROJECT_SETTINGS_FILE = new File(".mvn", "settings.xml");
 
-    private static final Logger LOGGER = LoggerFactory.getLogger( SettingsXmlConfigurationProcessor.class );
+    public static final File DEFAULT_GLOBAL_SETTINGS_FILE = new File(System.getProperty("maven.conf"), "settings.xml");
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(SettingsXmlConfigurationProcessor.class);
 
     private final SettingsBuilder settingsBuilder;
     private final SettingsDecrypter settingsDecrypter;
 
     @Inject
-    public SettingsXmlConfigurationProcessor(
-            SettingsBuilder settingsBuilder,
-            SettingsDecrypter settingsDecrypter )
-    {
+    public SettingsXmlConfigurationProcessor(SettingsBuilder settingsBuilder, SettingsDecrypter settingsDecrypter) {
         this.settingsBuilder = settingsBuilder;
         this.settingsDecrypter = settingsDecrypter;
     }
 
     @Override
-    public void process( CliRequest cliRequest )
-        throws Exception
-    {
+    public void process(CliRequest cliRequest) throws Exception {
         CommandLine commandLine = cliRequest.getCommandLine();
         String workingDirectory = cliRequest.getWorkingDirectory();
         MavenExecutionRequest request = cliRequest.getRequest();
 
         File userSettingsFile;
 
-        if ( commandLine.hasOption( CLIManager.ALTERNATE_USER_SETTINGS ) )
-        {
-            userSettingsFile = new File( commandLine.getOptionValue( CLIManager.ALTERNATE_USER_SETTINGS ) );
-            userSettingsFile = resolveFile( userSettingsFile, workingDirectory );
+        if (commandLine.hasOption(CLIManager.ALTERNATE_USER_SETTINGS)) {
+            userSettingsFile = new File(commandLine.getOptionValue(CLIManager.ALTERNATE_USER_SETTINGS));
+            userSettingsFile = resolveFile(userSettingsFile, workingDirectory);
 
-            if ( !userSettingsFile.isFile() )
-            {
-                throw new FileNotFoundException( "The specified user settings file does not exist: "
-                    + userSettingsFile );
+            if (!userSettingsFile.isFile()) {
+                throw new FileNotFoundException("The specified user settings file does not exist: " + userSettingsFile);
             }
-        }
-        else
-        {
+        } else {
             userSettingsFile = DEFAULT_USER_SETTINGS_FILE;
         }
 
+        File projectSettingsFile;
+
+        if (commandLine.hasOption(CLIManager.ALTERNATE_PROJECT_SETTINGS)) {
+            projectSettingsFile = new File(commandLine.getOptionValue(CLIManager.ALTERNATE_PROJECT_SETTINGS));
+            projectSettingsFile = resolveFile(projectSettingsFile, workingDirectory);
+
+            if (!projectSettingsFile.isFile()) {
+                throw new FileNotFoundException(
+                        "The specified project settings file does not exist: " + projectSettingsFile);
+            }
+        } else if (cliRequest.getRootDirectory() != null) {
+            projectSettingsFile = DEFAULT_PROJECT_SETTINGS_FILE;
+            projectSettingsFile = resolveFile(
+                    projectSettingsFile, cliRequest.getRootDirectory().toString());
+        } else {
+            projectSettingsFile = null;
+        }
+
         File globalSettingsFile;
 
-        if ( commandLine.hasOption( CLIManager.ALTERNATE_GLOBAL_SETTINGS ) )
-        {
-            globalSettingsFile = new File( commandLine.getOptionValue( CLIManager.ALTERNATE_GLOBAL_SETTINGS ) );
-            globalSettingsFile = resolveFile( globalSettingsFile, workingDirectory );
+        if (commandLine.hasOption(CLIManager.ALTERNATE_GLOBAL_SETTINGS)) {
+            globalSettingsFile = new File(commandLine.getOptionValue(CLIManager.ALTERNATE_GLOBAL_SETTINGS));
+            globalSettingsFile = resolveFile(globalSettingsFile, workingDirectory);
 
-            if ( !globalSettingsFile.isFile() )
-            {
-                throw new FileNotFoundException( "The specified global settings file does not exist: "
-                    + globalSettingsFile );
+            if (!globalSettingsFile.isFile()) {
+                throw new FileNotFoundException(
+                        "The specified global settings file does not exist: " + globalSettingsFile);
             }
-        }
-        else
-        {
+        } else {
             globalSettingsFile = DEFAULT_GLOBAL_SETTINGS_FILE;
         }
 
-        request.setGlobalSettingsFile( globalSettingsFile );
-        request.setUserSettingsFile( userSettingsFile );
+        request.setGlobalSettingsFile(globalSettingsFile);
+        request.setProjectSettingsFile(projectSettingsFile);
+        request.setUserSettingsFile(userSettingsFile);
 
         SettingsBuildingRequest settingsRequest = new DefaultSettingsBuildingRequest();
-        settingsRequest.setGlobalSettingsFile( globalSettingsFile );
-        settingsRequest.setUserSettingsFile( userSettingsFile );
-        settingsRequest.setSystemProperties( cliRequest.getSystemProperties() );
-        settingsRequest.setUserProperties( cliRequest.getUserProperties() );
+        settingsRequest.setGlobalSettingsFile(globalSettingsFile);
+        settingsRequest.setProjectSettingsFile(projectSettingsFile);
+        settingsRequest.setUserSettingsFile(userSettingsFile);
+        settingsRequest.setSystemProperties(cliRequest.getSystemProperties());
+        Properties props = cliRequest.getUserProperties();
+        if (cliRequest.getRootDirectory() != null) {
+            props = new Properties();
+            props.putAll(cliRequest.getUserProperties());
+            props.put("session.rootDirectory", cliRequest.getRootDirectory().toString());
+        }
+        settingsRequest.setUserProperties(props);
 
-        if ( request.getEventSpyDispatcher() != null )
-        {
-            request.getEventSpyDispatcher().onEvent( settingsRequest );
+        if (request.getEventSpyDispatcher() != null) {
+            request.getEventSpyDispatcher().onEvent(settingsRequest);
         }
 
-        LOGGER.debug( "Reading global settings from '{}'",
-            getLocation( settingsRequest.getGlobalSettingsSource(), settingsRequest.getGlobalSettingsFile() ) );
-        LOGGER.debug( "Reading user settings from '{}'",
-            getLocation( settingsRequest.getUserSettingsSource(), settingsRequest.getUserSettingsFile() ) );
+        LOGGER.debug(
+                "Reading global settings from '{}'",
+                getLocation(settingsRequest.getGlobalSettingsSource(), settingsRequest.getGlobalSettingsFile()));
+        LOGGER.debug(
+                "Reading project settings from '{}'",
+                getLocation(settingsRequest.getProjectSettingsSource(), settingsRequest.getProjectSettingsFile()));
+        LOGGER.debug(
+                "Reading user settings from '{}'",
+                getLocation(settingsRequest.getUserSettingsSource(), settingsRequest.getUserSettingsFile()));
 
-        SettingsBuildingResult settingsResult = settingsBuilder.build( settingsRequest );
+        SettingsBuildingResult settingsResult = settingsBuilder.build(settingsRequest);
 
-        if ( request.getEventSpyDispatcher() != null )
-        {
-            request.getEventSpyDispatcher().onEvent( settingsResult );
+        if (request.getEventSpyDispatcher() != null) {
+            request.getEventSpyDispatcher().onEvent(settingsResult);
         }
 
-        populateFromSettings( request, settingsResult.getEffectiveSettings() );
+        populateFromSettings(request, settingsResult.getEffectiveSettings());
 
-        if ( !settingsResult.getProblems().isEmpty() && LOGGER.isWarnEnabled() )
-        {
-            LOGGER.warn( "" );
-            LOGGER.warn( "Some problems were encountered while building the effective settings" );
+        if (!settingsResult.getProblems().isEmpty() && LOGGER.isWarnEnabled()) {
+            LOGGER.warn("");
+            LOGGER.warn("Some problems were encountered while building the effective settings");
 
-            for ( SettingsProblem problem : settingsResult.getProblems() )
-            {
-                LOGGER.warn( "{} @ {}", problem.getMessage(), problem.getLocation() );
+            for (SettingsProblem problem : settingsResult.getProblems()) {
+                LOGGER.warn("{} @ {}", problem.getMessage(), problem.getLocation());
             }
-            LOGGER.warn( "" );
+            LOGGER.warn("");
         }
     }
 
-    private MavenExecutionRequest populateFromSettings( MavenExecutionRequest request, Settings settings )
-        throws MavenExecutionRequestPopulationException
-    {
-        if ( settings == null )
-        {
+    private MavenExecutionRequest populateFromSettings(MavenExecutionRequest request, Settings settings)
+            throws MavenExecutionRequestPopulationException {
+        if (settings == null) {
             return request;
         }
 
-        request.setOffline( settings.isOffline() );
+        request.setOffline(settings.isOffline());
 
-        request.setInteractiveMode( settings.isInteractiveMode() );
+        request.setInteractiveMode(settings.isInteractiveMode());
 
-        request.setPluginGroups( settings.getPluginGroups() );
+        request.setPluginGroups(settings.getPluginGroups());
 
-        request.setLocalRepositoryPath( settings.getLocalRepository() );
+        request.setLocalRepositoryPath(settings.getLocalRepository());
 
-        for ( Server server : settings.getServers() )
-        {
-            server = server.clone();
-
-            request.addServer( server );
+        for (Server server : settings.getServers()) {
+            request.addServer(server);
         }
 
         //  <proxies>
@@ -205,16 +213,12 @@
         //    </proxy>
         //  </proxies>
 
-        for ( Proxy proxy : settings.getProxies() )
-        {
-            if ( !proxy.isActive() )
-            {
+        for (Proxy proxy : settings.getProxies()) {
+            if (!proxy.isActive()) {
                 continue;
             }
 
-            proxy = proxy.clone();
-
-            request.addProxy( proxy );
+            request.addProxy(proxy);
         }
 
         // <mirrors>
@@ -225,45 +229,47 @@
         //   </mirror>
         // </mirrors>
 
-        for ( Mirror mirror : settings.getMirrors() )
-        {
-            mirror = mirror.clone();
-
-            request.addMirror( mirror );
+        for (Mirror mirror : settings.getMirrors()) {
+            request.addMirror(mirror);
         }
 
-        request.setActiveProfiles( settings.getActiveProfiles() );
+        for (Repository remoteRepository : settings.getRepositories()) {
+            try {
+                request.addRemoteRepository(MavenRepositorySystem.buildArtifactRepository(remoteRepository));
+            } catch (InvalidRepositoryException e) {
+                // do nothing for now
+            }
+        }
 
-        for ( org.apache.maven.settings.Profile rawProfile : settings.getProfiles() )
-        {
-            request.addProfile( SettingsUtils.convertFromSettingsProfile( rawProfile ) );
+        for (Repository pluginRepository : settings.getPluginRepositories()) {
+            try {
+                request.addPluginArtifactRepository(MavenRepositorySystem.buildArtifactRepository(pluginRepository));
+            } catch (InvalidRepositoryException e) {
+                // do nothing for now
+            }
+        }
 
-            if ( settings.getActiveProfiles().contains( rawProfile.getId() ) )
-            {
+        request.setActiveProfiles(settings.getActiveProfiles());
+
+        for (Profile rawProfile : settings.getProfiles()) {
+            request.addProfile(SettingsUtils.convertFromSettingsProfile(rawProfile));
+
+            if (settings.getActiveProfiles().contains(rawProfile.getId())) {
                 List<Repository> remoteRepositories = rawProfile.getRepositories();
-                for ( Repository remoteRepository : remoteRepositories )
-                {
-                    try
-                    {
-                        request.addRemoteRepository(
-                            MavenRepositorySystem.buildArtifactRepository( remoteRepository ) );
-                    }
-                    catch ( InvalidRepositoryException e )
-                    {
+                for (Repository remoteRepository : remoteRepositories) {
+                    try {
+                        request.addRemoteRepository(MavenRepositorySystem.buildArtifactRepository(remoteRepository));
+                    } catch (InvalidRepositoryException e) {
                         // do nothing for now
                     }
                 }
 
                 List<Repository> pluginRepositories = rawProfile.getPluginRepositories();
-                for ( Repository pluginRepository : pluginRepositories )
-                {
-                    try
-                    {
+                for (Repository pluginRepository : pluginRepositories) {
+                    try {
                         request.addPluginArtifactRepository(
-                            MavenRepositorySystem.buildArtifactRepository( pluginRepository ) );
-                    }
-                    catch ( InvalidRepositoryException e )
-                    {
+                                MavenRepositorySystem.buildArtifactRepository(pluginRepository));
+                    } catch (InvalidRepositoryException e) {
                         // do nothing for now
                     }
                 }
@@ -272,10 +278,8 @@
         return request;
     }
 
-    private Object getLocation( Source source, File defaultLocation )
-    {
-        if ( source != null )
-        {
+    private Object getLocation(Source source, File defaultLocation) {
+        if (source != null) {
             return source.getLocation();
         }
         return defaultLocation;
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/event/DefaultEventSpyContext.java b/maven-embedder/src/main/java/org/apache/maven/cli/event/DefaultEventSpyContext.java
index 55b1155..b3c7671 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/event/DefaultEventSpyContext.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/event/DefaultEventSpyContext.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.event;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.event;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -27,15 +26,11 @@
 /**
  * DefaultEventSpyContext
  */
-public class DefaultEventSpyContext
-    implements EventSpy.Context
-{
+public class DefaultEventSpyContext implements EventSpy.Context {
 
     private final Map<String, Object> data = new HashMap<>();
 
-    public Map<String, Object> getData()
-    {
+    public Map<String, Object> getData() {
         return data;
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java b/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java
index 7d33f11..7567e54 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.event;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.apache.maven.cli.CLIReportingUtils.formatDuration;
-import static org.apache.maven.cli.CLIReportingUtils.formatTimestamp;
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
+package org.apache.maven.cli.event;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.List;
 import java.util.Objects;
 
+import org.apache.maven.api.services.MessageBuilder;
+import org.apache.maven.api.services.MessageBuilderFactory;
 import org.apache.maven.execution.AbstractExecutionListener;
 import org.apache.maven.execution.BuildFailure;
 import org.apache.maven.execution.BuildSuccess;
@@ -39,22 +37,18 @@
 import org.apache.maven.plugin.MojoExecution;
 import org.apache.maven.plugin.descriptor.MojoDescriptor;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.apache.maven.shared.utils.logging.MessageUtils;
-import org.codehaus.plexus.util.StringUtils;
 import org.slf4j.ILoggerFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import static org.apache.maven.cli.CLIReportingUtils.formatDuration;
+import static org.apache.maven.cli.CLIReportingUtils.formatTimestamp;
+
 /**
  * Logs execution events to logger, eventually user-supplied.
  *
- * @author Benjamin Bentmann
  */
-public class ExecutionEventLogger extends AbstractExecutionListener
-{
-    private final Logger logger;
-
+public class ExecutionEventLogger extends AbstractExecutionListener {
     private static final int MAX_LOG_PREFIX_SIZE = 8; // "[ERROR] "
     private static final int PROJECT_STATUS_SUFFIX_SIZE = 20; // "SUCCESS [  0.000 s]"
     private static final int MIN_TERMINAL_WIDTH = 60;
@@ -62,133 +56,119 @@
     private static final int MAX_TERMINAL_WIDTH = 130;
     private static final int MAX_PADDED_BUILD_TIME_DURATION_LENGTH = 9;
 
+    private final MessageBuilderFactory messageBuilderFactory;
+    private final Logger logger;
     private final int terminalWidth;
     private final int lineLength;
     private final int maxProjectNameLength;
     private int totalProjects;
     private volatile int currentVisitedProjectCount;
 
-    public ExecutionEventLogger()
-    {
-        this( LoggerFactory.getLogger( ExecutionEventLogger.class ) );
+    public ExecutionEventLogger(MessageBuilderFactory messageBuilderFactory) {
+        this(messageBuilderFactory, LoggerFactory.getLogger(ExecutionEventLogger.class));
     }
 
-    public ExecutionEventLogger( int terminalWidth )
-    {
-        this( LoggerFactory.getLogger( ExecutionEventLogger.class ), terminalWidth );
+    public ExecutionEventLogger(MessageBuilderFactory messageBuilderFactory, Logger logger) {
+        this(messageBuilderFactory, logger, messageBuilderFactory.getTerminalWidth());
     }
 
-    public ExecutionEventLogger( Logger logger )
-    {
-        this( logger, MessageUtils.getTerminalWidth() );
-    }
-
-    public ExecutionEventLogger( Logger logger, int terminalWidth )
-    {
-        this.logger = Objects.requireNonNull( logger, "logger cannot be null" );
-        this.terminalWidth = Math.min( MAX_TERMINAL_WIDTH,
-                                       Math.max( terminalWidth < 0 ? DEFAULT_TERMINAL_WIDTH : terminalWidth,
-                                                 MIN_TERMINAL_WIDTH ) );
+    public ExecutionEventLogger(MessageBuilderFactory messageBuilderFactory, Logger logger, int terminalWidth) {
+        this.logger = Objects.requireNonNull(logger, "logger cannot be null");
+        this.messageBuilderFactory = messageBuilderFactory;
+        this.terminalWidth = Math.min(
+                MAX_TERMINAL_WIDTH,
+                Math.max(terminalWidth < 0 ? DEFAULT_TERMINAL_WIDTH : terminalWidth, MIN_TERMINAL_WIDTH));
         this.lineLength = this.terminalWidth - MAX_LOG_PREFIX_SIZE;
         this.maxProjectNameLength = this.lineLength - PROJECT_STATUS_SUFFIX_SIZE;
     }
 
-    private static String chars( char c, int count )
-    {
-        StringBuilder buffer = new StringBuilder( count );
+    private static String chars(char c, int count) {
+        StringBuilder buffer = new StringBuilder(count);
 
-        for ( int i = count; i > 0; i-- )
-        {
-            buffer.append( c );
+        for (int i = count; i > 0; i--) {
+            buffer.append(c);
         }
 
         return buffer.toString();
     }
 
-    private void infoLine( char c )
-    {
-        infoMain( chars( c, lineLength ) );
+    private void infoLine(char c) {
+        infoMain(chars(c, lineLength));
     }
 
-    private void infoMain( String msg )
-    {
-        logger.info( buffer().strong( msg ).toString() );
+    private void infoMain(String msg) {
+        logger.info(builder().strong(msg).toString());
     }
 
     @Override
-    public void projectDiscoveryStarted( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() )
-        {
-            logger.info( "Scanning for projects..." );
+    public void projectDiscoveryStarted(ExecutionEvent event) {
+        if (logger.isInfoEnabled()) {
+            logger.info("Scanning for projects...");
         }
     }
 
     @Override
-    public void sessionStarted( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() && event.getSession().getProjects().size() > 1 )
-        {
-            infoLine( '-' );
+    public void sessionStarted(ExecutionEvent event) {
+        if (logger.isInfoEnabled() && event.getSession().getProjects().size() > 1) {
+            infoLine('-');
 
-            infoMain( "Reactor Build Order:" );
+            infoMain("Reactor Build Order:");
 
-            logger.info( "" );
+            logger.info("");
 
             final List<MavenProject> projects = event.getSession().getProjects();
-            for ( MavenProject project : projects )
-            {
-                int len = lineLength - project.getName().length() - project.getPackaging().length() - 2;
-                logger.info( "{}{}[{}]",
-                        project.getName(), chars( ' ', ( len > 0 ) ? len : 1 ), project.getPackaging() );
+            for (MavenProject project : projects) {
+                int len = lineLength
+                        - project.getName().length()
+                        - project.getPackaging().length()
+                        - 2;
+                logger.info("{}{}[{}]", project.getName(), chars(' ', (len > 0) ? len : 1), project.getPackaging());
             }
 
-            totalProjects = projects.size();
+            final List<MavenProject> allProjects = event.getSession().getAllProjects();
+            final int projectsSkipped = allProjects.size() - projects.size();
+
+            currentVisitedProjectCount = projectsSkipped;
+            totalProjects = allProjects.size();
         }
     }
 
     @Override
-    public void sessionEnded( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() )
-        {
-            if ( event.getSession().getProjects().size() > 1 )
-            {
-                logReactorSummary( event.getSession() );
+    public void sessionEnded(ExecutionEvent event) {
+        if (logger.isInfoEnabled()) {
+            if (event.getSession().getProjects().size() > 1) {
+                logReactorSummary(event.getSession());
             }
 
             ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();
 
-            if ( iLoggerFactory instanceof MavenSlf4jWrapperFactory )
-            {
+            if (iLoggerFactory instanceof MavenSlf4jWrapperFactory) {
                 MavenSlf4jWrapperFactory loggerFactory = (MavenSlf4jWrapperFactory) iLoggerFactory;
-                loggerFactory.getLogLevelRecorder()
-                        .filter( LogLevelRecorder::metThreshold )
-                        .ifPresent( recorder ->
-                                event.getSession().getResult().addException( new Exception(
+                loggerFactory
+                        .getLogLevelRecorder()
+                        .filter(LogLevelRecorder::metThreshold)
+                        .ifPresent(recorder -> event.getSession()
+                                .getResult()
+                                .addException(new Exception(
                                         "Build failed due to log statements with a higher severity than allowed. "
-                                        + "Fix the logged issues or remove flag --fail-on-severity (-fos)." ) )
-                );
+                                                + "Fix the logged issues or remove flag --fail-on-severity (-fos).")));
             }
 
-            logResult( event.getSession() );
+            logResult(event.getSession());
 
-            logStats( event.getSession() );
+            logStats(event.getSession());
 
-            infoLine( '-' );
+            infoLine('-');
         }
     }
 
-    private boolean isSingleVersionedReactor( MavenSession session )
-    {
+    private boolean isSingleVersionedReactor(MavenSession session) {
         boolean result = true;
 
         MavenProject topProject = session.getTopLevelProject();
         List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
-        for ( MavenProject mavenProject : sortedProjects )
-        {
-            if ( !topProject.getVersion().equals( mavenProject.getVersion() ) )
-            {
+        for (MavenProject mavenProject : sortedProjects) {
+            if (!topProject.getVersion().equals(mavenProject.getVersion())) {
                 result = false;
                 break;
             }
@@ -197,107 +177,94 @@
         return result;
     }
 
-    private void logReactorSummary( MavenSession session )
-    {
-        boolean isSingleVersion = isSingleVersionedReactor( session );
+    private void logReactorSummary(MavenSession session) {
+        boolean isSingleVersion = isSingleVersionedReactor(session);
 
-        infoLine( '-' );
+        infoLine('-');
 
-        StringBuilder summary = new StringBuilder( "Reactor Summary" );
-        if ( isSingleVersion )
-        {
-            summary.append( " for " );
-            summary.append( session.getTopLevelProject().getName() );
-            summary.append( " " );
-            summary.append( session.getTopLevelProject().getVersion() );
+        StringBuilder summary = new StringBuilder("Reactor Summary");
+        if (isSingleVersion) {
+            summary.append(" for ");
+            summary.append(session.getTopLevelProject().getName());
+            summary.append(" ");
+            summary.append(session.getTopLevelProject().getVersion());
         }
-        summary.append( ":" );
-        infoMain( summary.toString() );
+        summary.append(":");
+        infoMain(summary.toString());
 
-        logger.info( "" );
+        logger.info("");
 
         MavenExecutionResult result = session.getResult();
 
         List<MavenProject> projects = session.getProjects();
 
-        for ( MavenProject project : projects )
-        {
-            StringBuilder buffer = new StringBuilder( 128 );
+        StringBuilder buffer = new StringBuilder(128);
 
-            buffer.append( project.getName() );
-            buffer.append( ' ' );
+        for (MavenProject project : projects) {
+            buffer.append(project.getName());
+            buffer.append(' ');
 
-            if ( !isSingleVersion )
-            {
-                buffer.append( project.getVersion() );
-                buffer.append( ' ' );
+            if (!isSingleVersion) {
+                buffer.append(project.getVersion());
+                buffer.append(' ');
             }
 
-            if ( buffer.length() <= maxProjectNameLength )
-            {
-                while ( buffer.length() < maxProjectNameLength )
-                {
-                    buffer.append( '.' );
+            if (buffer.length() <= maxProjectNameLength) {
+                while (buffer.length() < maxProjectNameLength) {
+                    buffer.append('.');
                 }
-                buffer.append( ' ' );
+                buffer.append(' ');
             }
 
-            BuildSummary buildSummary = result.getBuildSummary( project );
+            BuildSummary buildSummary = result.getBuildSummary(project);
 
-            if ( buildSummary == null )
-            {
-                buffer.append( buffer().warning( "SKIPPED" ) );
-            }
-            else if ( buildSummary instanceof BuildSuccess )
-            {
-                buffer.append( buffer().success( "SUCCESS" ) );
-                buffer.append( " [" );
-                String buildTimeDuration = formatDuration( buildSummary.getTime() );
+            if (buildSummary == null) {
+                buffer.append(builder().warning("SKIPPED"));
+            } else if (buildSummary instanceof BuildSuccess) {
+                buffer.append(builder().success("SUCCESS"));
+                buffer.append(" [");
+                String buildTimeDuration = formatDuration(buildSummary.getTime());
                 int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
-                if ( padSize > 0 )
-                {
-                    buffer.append( chars( ' ', padSize ) );
+                if (padSize > 0) {
+                    buffer.append(chars(' ', padSize));
                 }
-                buffer.append( buildTimeDuration );
-                buffer.append( ']' );
-            }
-            else if ( buildSummary instanceof BuildFailure )
-            {
-                buffer.append( buffer().failure( "FAILURE" ) );
-                buffer.append( " [" );
-                String buildTimeDuration = formatDuration( buildSummary.getTime() );
+                buffer.append(buildTimeDuration);
+                buffer.append(']');
+            } else if (buildSummary instanceof BuildFailure) {
+                buffer.append(builder().failure("FAILURE"));
+                buffer.append(" [");
+                String buildTimeDuration = formatDuration(buildSummary.getTime());
                 int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
-                if ( padSize > 0 )
-                {
-                    buffer.append( chars( ' ', padSize ) );
+                if (padSize > 0) {
+                    buffer.append(chars(' ', padSize));
                 }
-                buffer.append( buildTimeDuration );
-                buffer.append( ']' );
+                buffer.append(buildTimeDuration);
+                buffer.append(']');
             }
 
-            logger.info( buffer.toString() );
+            logger.info(buffer.toString());
+            buffer.setLength(0);
         }
     }
 
-    private void logResult( MavenSession session )
-    {
-        infoLine( '-' );
-        MessageBuilder buffer = buffer();
+    private void logResult(MavenSession session) {
+        infoLine('-');
+        MessageBuilder buffer = builder();
 
-        if ( session.getResult().hasExceptions() )
-        {
-            buffer.failure( "BUILD FAILURE" );
+        if (session.getResult().hasExceptions()) {
+            buffer.failure("BUILD FAILURE");
+        } else {
+            buffer.success("BUILD SUCCESS");
         }
-        else
-        {
-            buffer.success( "BUILD SUCCESS" );
-        }
-        logger.info( buffer.toString() );
+        logger.info(buffer.toString());
     }
 
-    private void logStats( MavenSession session )
-    {
-        infoLine( '-' );
+    private MessageBuilder builder() {
+        return messageBuilderFactory.builder();
+    }
+
+    private void logStats(MavenSession session) {
+        infoLine('-');
 
         long finish = System.currentTimeMillis();
 
@@ -305,34 +272,30 @@
 
         String wallClock = session.getRequest().getDegreeOfConcurrency() > 1 ? " (Wall Clock)" : "";
 
-        logger.info( "Total time:  {}{}", formatDuration( time ), wallClock );
+        logger.info("Total time:  {}{}", formatDuration(time), wallClock);
 
-        logger.info( "Finished at: {}", formatTimestamp( finish ) );
+        logger.info("Finished at: {}", formatTimestamp(finish));
     }
 
     @Override
-    public void projectSkipped( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() )
-        {
-            logger.info( "" );
-            infoLine( '-' );
+    public void projectSkipped(ExecutionEvent event) {
+        if (logger.isInfoEnabled()) {
+            logger.info("");
+            infoLine('-');
 
-            infoMain( "Skipping " + event.getProject().getName() );
-            logger.info( "This project has been banned from the build due to previous failures." );
+            infoMain("Skipping " + event.getProject().getName());
+            logger.info("This project has been banned from the build due to previous failures.");
 
-            infoLine( '-' );
+            infoLine('-');
         }
     }
 
     @Override
-    public void projectStarted( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() )
-        {
+    public void projectStarted(ExecutionEvent event) {
+        if (logger.isInfoEnabled()) {
             MavenProject project = event.getProject();
 
-            logger.info( "" );
+            logger.info("");
 
             // -------< groupId:artifactId >-------
             String projectKey = project.getGroupId() + ':' + project.getArtifactId();
@@ -342,58 +305,58 @@
 
             final int headerLen = preHeader.length() + projectKey.length() + postHeader.length();
 
-            String prefix = chars( '-', Math.max( 0, ( lineLength - headerLen ) / 2 ) ) + preHeader;
+            String prefix = chars('-', Math.max(0, (lineLength - headerLen) / 2)) + preHeader;
 
-            String suffix = postHeader + chars( '-',
-                    Math.max( 0, lineLength - headerLen - prefix.length() + preHeader.length() ) );
+            String suffix =
+                    postHeader + chars('-', Math.max(0, lineLength - headerLen - prefix.length() + preHeader.length()));
 
-            logger.info( buffer().strong( prefix ).project( projectKey ).strong( suffix ).toString() );
+            logger.info(
+                    builder().strong(prefix).project(projectKey).strong(suffix).toString());
 
             // Building Project Name Version    [i/n]
-            String building = "Building " + event.getProject().getName() + " " + event.getProject().getVersion();
+            String building = "Building " + event.getProject().getName() + " "
+                    + event.getProject().getVersion();
 
-            if ( totalProjects <= 1 )
-            {
-                infoMain( building );
-            }
-            else
-            {
+            if (totalProjects <= 1) {
+                infoMain(building);
+            } else {
                 // display progress [i/n]
                 int number;
-                synchronized ( this )
-                {
+                synchronized (this) {
                     number = ++currentVisitedProjectCount;
                 }
                 String progress = " [" + number + '/' + totalProjects + ']';
 
                 int pad = lineLength - building.length() - progress.length();
 
-                infoMain( building + ( ( pad > 0 ) ? chars( ' ', pad ) : "" ) + progress );
+                infoMain(building + ((pad > 0) ? chars(' ', pad) : "") + progress);
             }
 
             // path to pom.xml
             File currentPom = project.getFile();
-            if ( currentPom != null )
-            {
+            if (currentPom != null) {
                 MavenSession session = event.getSession();
-                File rootBasedir = session.getTopLevelProject().getBasedir();
-                logger.info( "  from " + rootBasedir.toPath().relativize( currentPom.toPath() ) );
+                Path current = currentPom.toPath().toAbsolutePath().normalize();
+                Path topDirectory = session.getTopDirectory();
+                if (topDirectory != null && current.startsWith(topDirectory)) {
+                    current = topDirectory.relativize(current);
+                }
+                logger.info("  from " + current);
             }
 
             // ----------[ packaging ]----------
-            prefix = chars( '-', Math.max( 0, ( lineLength - project.getPackaging().length() - 4 ) / 2 ) );
-            suffix = chars( '-', Math.max( 0, lineLength - project.getPackaging().length() - 4 - prefix.length() ) );
-            infoMain( prefix + "[ " + project.getPackaging() + " ]" + suffix );
+            prefix = chars('-', Math.max(0, (lineLength - project.getPackaging().length() - 4) / 2));
+            suffix = chars('-', Math.max(0, lineLength - project.getPackaging().length() - 4 - prefix.length()));
+            infoMain(prefix + "[ " + project.getPackaging() + " ]" + suffix);
         }
     }
 
     @Override
-    public void mojoSkipped( ExecutionEvent event )
-    {
-        if ( logger.isWarnEnabled() )
-        {
-            logger.warn( "Goal '{}' requires online mode for execution but Maven is currently offline, skipping",
-                    event.getMojoExecution().getGoal() );
+    public void mojoSkipped(ExecutionEvent event) {
+        if (logger.isWarnEnabled()) {
+            logger.warn(
+                    "Goal '{}' requires online mode for execution but Maven is currently offline, skipping",
+                    event.getMojoExecution().getGoal());
         }
     }
 
@@ -401,18 +364,16 @@
      * <pre>--- mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId ---</pre>
      */
     @Override
-    public void mojoStarted( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() )
-        {
-            logger.info( "" );
+    public void mojoStarted(ExecutionEvent event) {
+        if (logger.isInfoEnabled()) {
+            logger.info("");
 
-            MessageBuilder buffer = buffer().strong( "--- " );
-            append( buffer, event.getMojoExecution() );
-            append( buffer, event.getProject() );
-            buffer.strong( " ---" );
+            MessageBuilder buffer = builder().strong("--- ");
+            append(buffer, event.getMojoExecution());
+            append(buffer, event.getProject());
+            buffer.strong(" ---");
 
-            logger.info( buffer.toString() );
+            logger.info(buffer.toString());
         }
     }
 
@@ -423,20 +384,18 @@
      */
     // CHECKSTYLE_ON: LineLength
     @Override
-    public void forkStarted( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() )
-        {
-            logger.info( "" );
+    public void forkStarted(ExecutionEvent event) {
+        if (logger.isInfoEnabled()) {
+            logger.info("");
 
-            MessageBuilder buffer = buffer().strong( ">>> " );
-            append( buffer, event.getMojoExecution() );
-            buffer.strong( " > " );
-            appendForkInfo( buffer, event.getMojoExecution().getMojoDescriptor() );
-            append( buffer, event.getProject() );
-            buffer.strong( " >>>" );
+            MessageBuilder buffer = builder().strong(">>> ");
+            append(buffer, event.getMojoExecution());
+            buffer.strong(" > ");
+            appendForkInfo(buffer, event.getMojoExecution().getMojoDescriptor());
+            append(buffer, event.getProject());
+            buffer.strong(" >>>");
 
-            logger.info( buffer.toString() );
+            logger.info(buffer.toString());
         }
     }
 
@@ -447,73 +406,67 @@
      */
     // CHECKSTYLE_ON: LineLength
     @Override
-    public void forkSucceeded( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() )
-        {
-            logger.info( "" );
+    public void forkSucceeded(ExecutionEvent event) {
+        if (logger.isInfoEnabled()) {
+            logger.info("");
 
-            MessageBuilder buffer = buffer().strong( "<<< " );
-            append( buffer, event.getMojoExecution() );
-            buffer.strong( " < " );
-            appendForkInfo( buffer, event.getMojoExecution().getMojoDescriptor() );
-            append( buffer, event.getProject() );
-            buffer.strong( " <<<" );
+            MessageBuilder buffer = builder().strong("<<< ");
+            append(buffer, event.getMojoExecution());
+            buffer.strong(" < ");
+            appendForkInfo(buffer, event.getMojoExecution().getMojoDescriptor());
+            append(buffer, event.getProject());
+            buffer.strong(" <<<");
 
-            logger.info( buffer.toString() );
+            logger.info(buffer.toString());
 
-            logger.info( "" );
+            logger.info("");
         }
     }
 
-    private void append( MessageBuilder buffer, MojoExecution me )
-    {
-        buffer.mojo( me.getArtifactId() + ':' + me.getVersion() + ':' + me.getGoal() );
-        if ( me.getExecutionId() != null )
-        {
-            buffer.a( ' ' ).strong( '(' + me.getExecutionId() + ')' );
+    private void append(MessageBuilder buffer, MojoExecution me) {
+        String prefix = me.getMojoDescriptor().getPluginDescriptor().getGoalPrefix();
+        if (prefix == null || prefix.isEmpty()) {
+            prefix = me.getGroupId() + ":" + me.getArtifactId();
+        }
+        buffer.mojo(prefix + ':' + me.getVersion() + ':' + me.getGoal());
+        if (me.getExecutionId() != null) {
+            buffer.a(' ').strong('(' + me.getExecutionId() + ')');
         }
     }
 
-    private void appendForkInfo( MessageBuilder buffer, MojoDescriptor md )
-    {
+    private void appendForkInfo(MessageBuilder buffer, MojoDescriptor md) {
         StringBuilder buff = new StringBuilder();
-        if ( StringUtils.isNotEmpty( md.getExecutePhase() ) )
-        {
+        if (md.getExecutePhase() != null && !md.getExecutePhase().isEmpty()) {
             // forked phase
-            if ( StringUtils.isNotEmpty( md.getExecuteLifecycle() ) )
-            {
-                buff.append( '[' );
-                buff.append( md.getExecuteLifecycle() );
-                buff.append( ']' );
+            if (md.getExecuteLifecycle() != null && !md.getExecuteLifecycle().isEmpty()) {
+                buff.append('[');
+                buff.append(md.getExecuteLifecycle());
+                buff.append(']');
             }
-            buff.append( md.getExecutePhase() );
-        }
-        else
-        {
+            buff.append(md.getExecutePhase());
+        } else {
             // forked goal
-            buff.append( ':' );
-            buff.append( md.getExecuteGoal() );
+            buff.append(':');
+            buff.append(md.getExecuteGoal());
         }
-        buffer.strong( buff.toString() );
+        buffer.strong(buff.toString());
     }
 
-    private void append( MessageBuilder buffer, MavenProject project )
-    {
-        buffer.a( " @ " ).project( project.getArtifactId() );
+    private void append(MessageBuilder buffer, MavenProject project) {
+        buffer.a(" @ ").project(project.getArtifactId());
     }
 
     @Override
-    public void forkedProjectStarted( ExecutionEvent event )
-    {
-        if ( logger.isInfoEnabled() && event.getMojoExecution().getForkedExecutions().size() > 1 )
-        {
-            logger.info( "" );
-            infoLine( '>' );
+    public void forkedProjectStarted(ExecutionEvent event) {
+        if (logger.isInfoEnabled()
+                && event.getMojoExecution().getForkedExecutions().size() > 1) {
+            logger.info("");
+            infoLine('>');
 
-            infoMain( "Forking " + event.getProject().getName() + " " + event.getProject().getVersion() );
+            infoMain("Forking " + event.getProject().getName() + " "
+                    + event.getProject().getVersion());
 
-            infoLine( '>' );
+            infoLine('>');
         }
     }
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
index f3583e2..c613513 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/BootstrapCoreExtensionManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -25,16 +27,13 @@
 import java.util.List;
 import java.util.Set;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-
 import org.apache.maven.RepositoryUtils;
+import org.apache.maven.api.model.Plugin;
 import org.apache.maven.cli.internal.extension.model.CoreExtension;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.extension.internal.CoreExports;
 import org.apache.maven.extension.internal.CoreExtensionEntry;
 import org.apache.maven.internal.aether.DefaultRepositorySystemSessionFactory;
-import org.apache.maven.model.Plugin;
 import org.apache.maven.plugin.PluginResolutionException;
 import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
 import org.codehaus.plexus.DefaultPlexusContainer;
@@ -46,6 +45,7 @@
 import org.codehaus.plexus.interpolation.MapBasedValueSource;
 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
 import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.CloseableSession;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.graph.DependencyFilter;
 import org.eclipse.aether.graph.DependencyNode;
@@ -59,13 +59,12 @@
  * BootstrapCoreExtensionManager
  */
 @Named
-public class BootstrapCoreExtensionManager
-{
+public class BootstrapCoreExtensionManager {
     public static final String STRATEGY_PARENT_FIRST = "parent-first";
     public static final String STRATEGY_PLUGIN = "plugin";
     public static final String STRATEGY_SELF_FIRST = "self-first";
 
-    private final Logger log = LoggerFactory.getLogger( getClass() );
+    private final Logger log = LoggerFactory.getLogger(getClass());
 
     private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
 
@@ -78,137 +77,124 @@
     private final ClassRealm parentRealm;
 
     @Inject
-    public BootstrapCoreExtensionManager( DefaultPluginDependenciesResolver pluginDependenciesResolver,
-                                          DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
-                                          CoreExports coreExports,
-                                          PlexusContainer container )
-    {
+    public BootstrapCoreExtensionManager(
+            DefaultPluginDependenciesResolver pluginDependenciesResolver,
+            DefaultRepositorySystemSessionFactory repositorySystemSessionFactory,
+            CoreExports coreExports,
+            PlexusContainer container) {
         this.pluginDependenciesResolver = pluginDependenciesResolver;
         this.repositorySystemSessionFactory = repositorySystemSessionFactory;
         this.coreExports = coreExports;
-        this.classWorld = ( (DefaultPlexusContainer) container ).getClassWorld();
+        this.classWorld = ((DefaultPlexusContainer) container).getClassWorld();
         this.parentRealm = container.getContainerRealm();
     }
 
-    public List<CoreExtensionEntry> loadCoreExtensions( MavenExecutionRequest request, Set<String> providedArtifacts,
-                                                        List<CoreExtension> extensions )
-        throws Exception
-    {
-        RepositorySystemSession repoSession = repositorySystemSessionFactory.newRepositorySession( request );
-        List<RemoteRepository> repositories = RepositoryUtils.toRepos( request.getPluginArtifactRepositories() );
-        Interpolator interpolator = createInterpolator( request );
+    public List<CoreExtensionEntry> loadCoreExtensions(
+            MavenExecutionRequest request, Set<String> providedArtifacts, List<CoreExtension> extensions)
+            throws Exception {
+        try (CloseableSession repoSession = repositorySystemSessionFactory
+                .newRepositorySessionBuilder(request)
+                .build()) {
+            List<RemoteRepository> repositories = RepositoryUtils.toRepos(request.getPluginArtifactRepositories());
+            Interpolator interpolator = createInterpolator(request);
 
-        return resolveCoreExtensions( repoSession, repositories, providedArtifacts, extensions, interpolator );
+            return resolveCoreExtensions(repoSession, repositories, providedArtifacts, extensions, interpolator);
+        }
     }
 
-    private List<CoreExtensionEntry> resolveCoreExtensions( RepositorySystemSession repoSession,
-                                                            List<RemoteRepository> repositories,
-                                                            Set<String> providedArtifacts,
-                                                            List<CoreExtension> configuration,
-                                                            Interpolator interpolator )
-        throws Exception
-    {
+    private List<CoreExtensionEntry> resolveCoreExtensions(
+            RepositorySystemSession repoSession,
+            List<RemoteRepository> repositories,
+            Set<String> providedArtifacts,
+            List<CoreExtension> configuration,
+            Interpolator interpolator)
+            throws Exception {
         List<CoreExtensionEntry> extensions = new ArrayList<>();
 
-        DependencyFilter dependencyFilter = new ExclusionsDependencyFilter( providedArtifacts );
+        DependencyFilter dependencyFilter = new ExclusionsDependencyFilter(providedArtifacts);
 
-        for ( CoreExtension extension : configuration )
-        {
-            List<Artifact> artifacts = resolveExtension( extension, repoSession, repositories,
-                                                         dependencyFilter, interpolator );
-            if ( !artifacts.isEmpty() )
-            {
-                extensions.add( createExtension( extension, artifacts ) );
+        for (CoreExtension extension : configuration) {
+            List<Artifact> artifacts =
+                    resolveExtension(extension, repoSession, repositories, dependencyFilter, interpolator);
+            if (!artifacts.isEmpty()) {
+                extensions.add(createExtension(extension, artifacts));
             }
         }
 
-        return Collections.unmodifiableList( extensions );
+        return Collections.unmodifiableList(extensions);
     }
 
-    private CoreExtensionEntry createExtension( CoreExtension extension, List<Artifact> artifacts )
-        throws Exception
-    {
-        String realmId =
-            "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":" + extension.getVersion();
-        final ClassRealm realm = classWorld.newRealm( realmId, null );
+    private CoreExtensionEntry createExtension(CoreExtension extension, List<Artifact> artifacts) throws Exception {
+        String realmId = "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":"
+                + extension.getVersion();
+        final ClassRealm realm = classWorld.newRealm(realmId, null);
         Set<String> providedArtifacts = Collections.emptySet();
         String classLoadingStrategy = extension.getClassLoadingStrategy();
-        if ( STRATEGY_PARENT_FIRST.equals( classLoadingStrategy ) )
-        {
-            realm.importFrom( parentRealm, "" );
-        }
-        else if ( STRATEGY_PLUGIN.equals( classLoadingStrategy ) )
-        {
-            coreExports.getExportedPackages().forEach( ( p, cl ) -> realm.importFrom( cl, p ) );
+        if (STRATEGY_PARENT_FIRST.equals(classLoadingStrategy)) {
+            realm.importFrom(parentRealm, "");
+        } else if (STRATEGY_PLUGIN.equals(classLoadingStrategy)) {
+            coreExports.getExportedPackages().forEach((p, cl) -> realm.importFrom(cl, p));
             providedArtifacts = coreExports.getExportedArtifacts();
-        }
-        else if ( STRATEGY_SELF_FIRST.equals( classLoadingStrategy ) )
-        {
-            realm.setParentRealm( parentRealm );
-        }
-        else
-        {
-            throw new IllegalArgumentException( "Unsupported class-loading strategy '"
+        } else if (STRATEGY_SELF_FIRST.equals(classLoadingStrategy)) {
+            realm.setParentRealm(parentRealm);
+        } else {
+            throw new IllegalArgumentException("Unsupported class-loading strategy '"
                     + classLoadingStrategy + "'. Supported values are: " + STRATEGY_PARENT_FIRST
-                    + ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST );
+                    + ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST);
         }
-        log.debug( "Populating class realm {}", realm.getId() );
-        for ( Artifact artifact : artifacts )
-        {
+        log.debug("Populating class realm {}", realm.getId());
+        for (Artifact artifact : artifacts) {
             String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
-            if ( providedArtifacts.contains( id ) )
-            {
-                log.debug( "  Excluded {}", id );
-            }
-            else
-            {
+            if (providedArtifacts.contains(id)) {
+                log.debug("  Excluded {}", id);
+            } else {
                 File file = artifact.getFile();
-                log.debug( "  Included {} located at {}", id, file );
-                realm.addURL( file.toURI().toURL() );
+                log.debug("  Included {} located at {}", id, file);
+                realm.addURL(file.toURI().toURL());
             }
         }
-        return CoreExtensionEntry.discoverFrom( realm, Collections.singleton( artifacts.get( 0 ).getFile() ) );
+        return CoreExtensionEntry.discoverFrom(
+                realm,
+                Collections.singleton(artifacts.get(0).getFile()),
+                extension.getGroupId() + ":" + extension.getArtifactId(),
+                extension.getConfiguration());
     }
 
-    private List<Artifact> resolveExtension( CoreExtension extension, RepositorySystemSession repoSession,
-                                             List<RemoteRepository> repositories, DependencyFilter dependencyFilter,
-                                             Interpolator interpolator )
-        throws ExtensionResolutionException
-    {
-        try
-        {
+    private List<Artifact> resolveExtension(
+            CoreExtension extension,
+            RepositorySystemSession repoSession,
+            List<RemoteRepository> repositories,
+            DependencyFilter dependencyFilter,
+            Interpolator interpolator)
+            throws ExtensionResolutionException {
+        try {
             /* TODO: Enhance the PluginDependenciesResolver to provide a
              * resolveCoreExtension method which uses a CoreExtension
              * object instead of a Plugin as this makes no sense.
              */
-            Plugin plugin = new Plugin();
-            plugin.setGroupId( interpolator.interpolate( extension.getGroupId() ) );
-            plugin.setArtifactId( interpolator.interpolate( extension.getArtifactId() ) );
-            plugin.setVersion( interpolator.interpolate( extension.getVersion() ) );
+            Plugin plugin = Plugin.newBuilder()
+                    .groupId(interpolator.interpolate(extension.getGroupId()))
+                    .artifactId(interpolator.interpolate(extension.getArtifactId()))
+                    .version(interpolator.interpolate(extension.getVersion()))
+                    .build();
 
-            DependencyNode root = pluginDependenciesResolver
-                    .resolveCoreExtension( plugin, dependencyFilter, repositories, repoSession );
+            DependencyNode root = pluginDependenciesResolver.resolveCoreExtension(
+                    new org.apache.maven.model.Plugin(plugin), dependencyFilter, repositories, repoSession);
             PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
-            root.accept( nlg );
+            root.accept(nlg);
 
-            return nlg.getArtifacts( false );
-        }
-        catch ( PluginResolutionException e )
-        {
-            throw new ExtensionResolutionException( extension, e.getCause() );
-        }
-        catch ( InterpolationException e )
-        {
-            throw new ExtensionResolutionException( extension, e );
+            return nlg.getArtifacts(false);
+        } catch (PluginResolutionException e) {
+            throw new ExtensionResolutionException(extension, e.getCause());
+        } catch (InterpolationException e) {
+            throw new ExtensionResolutionException(extension, e);
         }
     }
 
-    private static Interpolator createInterpolator( MavenExecutionRequest request )
-    {
+    private static Interpolator createInterpolator(MavenExecutionRequest request) {
         StringSearchInterpolator interpolator = new StringSearchInterpolator();
-        interpolator.addValueSource( new MapBasedValueSource( request.getUserProperties() ) );
-        interpolator.addValueSource( new MapBasedValueSource( request.getSystemProperties() ) );
+        interpolator.addValueSource(new MapBasedValueSource(request.getUserProperties()));
+        interpolator.addValueSource(new MapBasedValueSource(request.getSystemProperties()));
         return interpolator;
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java b/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java
index 4f8cff9..5245113 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/internal/ExtensionResolutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,30 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.internal;
 
 import org.apache.maven.cli.internal.extension.model.CoreExtension;
 
 /**
  * Exception occurring trying to resolve a plugin.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class ExtensionResolutionException
-    extends Exception
-{
+public class ExtensionResolutionException extends Exception {
 
     private final CoreExtension extension;
 
-    public ExtensionResolutionException( CoreExtension extension, Throwable cause )
-    {
-        super( "Extension " + extension.getId() + " or one of its dependencies could not be resolved: "
-                        + cause.getMessage(), cause );
+    public ExtensionResolutionException(CoreExtension extension, Throwable cause) {
+        super(
+                "Extension " + extension.getId() + " or one of its dependencies could not be resolved: "
+                        + cause.getMessage(),
+                cause);
         this.extension = extension;
     }
 
-    public CoreExtension getExtension()
-    {
+    public CoreExtension getExtension() {
         return extension;
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/jansi/JansiMessageBuilder.java b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/JansiMessageBuilder.java
new file mode 100644
index 0000000..be51f30
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/JansiMessageBuilder.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.cli.jansi;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.MessageBuilder;
+import org.fusesource.jansi.Ansi;
+
+@Experimental
+public class JansiMessageBuilder implements MessageBuilder {
+    private final Ansi ansi;
+    private StringBuilder sb;
+
+    @SuppressWarnings("magicnumber")
+    public JansiMessageBuilder() {
+        this.sb = new StringBuilder(80);
+        this.ansi = Ansi.ansi();
+    }
+
+    public JansiMessageBuilder(StringBuilder sb) {
+        this.sb = sb;
+        this.ansi = Ansi.ansi(sb);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder trace(Object o) {
+        return style(Style.TRACE, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder debug(Object o) {
+        return style(Style.DEBUG, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder info(Object o) {
+        return style(Style.INFO, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder warning(Object o) {
+        return style(Style.WARNING, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder error(Object o) {
+        return style(Style.ERROR, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder success(Object o) {
+        return style(Style.SUCCESS, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder failure(Object o) {
+        return style(Style.FAILURE, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder strong(Object o) {
+        return style(Style.STRONG, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder mojo(Object o) {
+        return style(Style.MOJO, o);
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder project(Object o) {
+        return style(Style.PROJECT, o);
+    }
+
+    private MessageBuilder style(Style style, Object o) {
+        style.apply(ansi).a(o).reset();
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(char[] chars, int i, int i1) {
+        ansi.a(chars, i, i1);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(char[] chars) {
+        ansi.a(chars);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(CharSequence charSequence, int i, int i1) {
+        ansi.a(charSequence, i, i1);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(CharSequence charSequence) {
+        ansi.a(charSequence);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder a(Object o) {
+        ansi.a(o);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder newline() {
+        ansi.newline();
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder format(String s, Object... objects) {
+        ansi.format(s, objects);
+        return this;
+    }
+
+    @Override
+    @Nonnull
+    public String build() {
+        return ansi.toString();
+    }
+
+    @Override
+    public String toString() {
+        return build();
+    }
+
+    @Override
+    public void setLength(int length) {
+        sb.setLength(length);
+    }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/jansi/JansiMessageBuilderFactory.java b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/JansiMessageBuilderFactory.java
new file mode 100644
index 0000000..c7d3225
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/JansiMessageBuilderFactory.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.cli.jansi;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.api.annotations.Experimental;
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.services.MessageBuilder;
+import org.apache.maven.api.services.MessageBuilderFactory;
+
+@Experimental
+@Named
+@Singleton
+public class JansiMessageBuilderFactory implements MessageBuilderFactory {
+
+    @Override
+    public boolean isColorEnabled() {
+        return MessageUtils.isColorEnabled();
+    }
+
+    @Override
+    public int getTerminalWidth() {
+        return MessageUtils.getTerminalWidth();
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder builder() {
+        return builder(new StringBuilder());
+    }
+
+    @Override
+    @Nonnull
+    public MessageBuilder builder(@Nonnull StringBuilder stringBuilder) {
+        return MessageUtils.builder(stringBuilder);
+    }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/jansi/MessageUtils.java b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/MessageUtils.java
new file mode 100644
index 0000000..3d0a5d4
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/MessageUtils.java
@@ -0,0 +1,201 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.cli.jansi;
+
+import org.apache.maven.api.services.MessageBuilder;
+import org.apache.maven.internal.impl.DefaultMessageBuilder;
+import org.fusesource.jansi.Ansi;
+import org.fusesource.jansi.AnsiConsole;
+import org.fusesource.jansi.AnsiMode;
+
+/**
+ * Colored message utils, to manage colors.  This is the core implementation of the
+ * {@link JansiMessageBuilderFactory} and {@link JansiMessageBuilder} classes.
+ * This class should not be used outside of maven-embedder and the public
+ * {@link org.apache.maven.api.services.MessageBuilderFactory} should be used instead.
+ * <p>
+ * Internally, <a href="http://fusesource.github.io/jansi/">Jansi</a> is used to render
+ * <a href="https://en.wikipedia.org/wiki/ANSI_escape_code#Colors">ANSI colors</a> on any platform.
+ * <p>
+ *
+ * @see MessageBuilder
+ * @see org.apache.maven.api.services.MessageBuilderFactory
+ * @see JansiMessageBuilderFactory
+ * @see JansiMessageBuilder
+ * @since 4.0.0
+ */
+public class MessageUtils {
+    private static final boolean JANSI;
+
+    /** Reference to the JVM shutdown hook, if registered */
+    private static Thread shutdownHook;
+
+    /** Synchronization monitor for the "uninstall" */
+    private static final Object STARTUP_SHUTDOWN_MONITOR = new Object();
+
+    static {
+        boolean jansi = true;
+        try {
+            // Jansi is provided by Maven core since 3.5.0
+            Class.forName("org.fusesource.jansi.Ansi");
+        } catch (ClassNotFoundException cnfe) {
+            jansi = false;
+        }
+        JANSI = jansi;
+    }
+
+    /**
+     * Install color support.
+     * This method is called by Maven core, and calling it is not necessary in plugins.
+     */
+    public static void systemInstall() {
+        if (JANSI) {
+            AnsiConsole.systemInstall();
+        }
+    }
+
+    /**
+     * Undo a previous {@link #systemInstall()}.  If {@link #systemInstall()} was called
+     * multiple times, {@link #systemUninstall()} must be called call the same number of times before
+     * it is actually uninstalled.
+     */
+    public static void systemUninstall() {
+        synchronized (STARTUP_SHUTDOWN_MONITOR) {
+            doSystemUninstall();
+
+            // hook can only set when Jansi is true
+            if (shutdownHook != null) {
+                try {
+                    Runtime.getRuntime().removeShutdownHook(shutdownHook);
+                } catch (IllegalStateException ex) {
+                    // ignore - VM is already shutting down
+                }
+            }
+        }
+    }
+
+    private static void doSystemUninstall() {
+        if (JANSI) {
+            AnsiConsole.systemUninstall();
+        }
+    }
+
+    /**
+     * Enables message color (if Jansi is available).
+     * @param flag to enable Jansi
+     */
+    public static void setColorEnabled(boolean flag) {
+        if (JANSI) {
+            AnsiConsole.out().setMode(flag ? AnsiMode.Force : AnsiMode.Strip);
+            Ansi.setEnabled(flag);
+            System.setProperty(
+                    AnsiConsole.JANSI_MODE, flag ? AnsiConsole.JANSI_MODE_FORCE : AnsiConsole.JANSI_MODE_STRIP);
+            boolean installed = AnsiConsole.isInstalled();
+            while (AnsiConsole.isInstalled()) {
+                AnsiConsole.systemUninstall();
+            }
+            if (installed) {
+                AnsiConsole.systemInstall();
+            }
+        }
+    }
+
+    /**
+     * Is message color enabled: requires Jansi available (through Maven) and the color has not been disabled.
+     * @return whether colored messages are enabled
+     */
+    public static boolean isColorEnabled() {
+        return JANSI ? Ansi.isEnabled() : false;
+    }
+
+    /**
+     * Create a default message buffer.
+     * @return a new buffer
+     */
+    public static MessageBuilder builder() {
+        return builder(new StringBuilder());
+    }
+
+    /**
+     * Create a message buffer with an internal buffer of defined size.
+     * @param size size of the buffer
+     * @return a new buffer
+     */
+    public static MessageBuilder builder(int size) {
+        return builder(new StringBuilder(size));
+    }
+
+    /**
+     * Create a message buffer with defined String builder.
+     * @param builder initial content of the message buffer
+     * @return a new buffer
+     */
+    public static MessageBuilder builder(StringBuilder builder) {
+        return JANSI && isColorEnabled() ? new JansiMessageBuilder(builder) : new DefaultMessageBuilder(builder);
+    }
+
+    /**
+     * Remove any ANSI code from a message (colors or other escape sequences).
+     * @param msg message eventually containing ANSI codes
+     * @return the message with ANSI codes removed
+     */
+    public static String stripAnsiCodes(String msg) {
+        return msg.replaceAll("\u001B\\[[;\\d]*[ -/]*[@-~]", "");
+    }
+
+    /**
+     * Register a shutdown hook with the JVM runtime, uninstalling Ansi support on
+     * JVM shutdown unless is has already been uninstalled at that time.
+     * <p>Delegates to {@link #doSystemUninstall()} for the actual uninstall procedure
+     *
+     * @see Runtime#addShutdownHook(Thread)
+     * @see MessageUtils#systemUninstall()
+     * @see #doSystemUninstall()
+     */
+    public static void registerShutdownHook() {
+        if (JANSI && shutdownHook == null) {
+            // No shutdown hook registered yet.
+            shutdownHook = new Thread() {
+                @Override
+                public void run() {
+                    synchronized (STARTUP_SHUTDOWN_MONITOR) {
+                        while (AnsiConsole.isInstalled()) {
+                            doSystemUninstall();
+                        }
+                    }
+                }
+            };
+            Runtime.getRuntime().addShutdownHook(shutdownHook);
+        }
+    }
+
+    /**
+     * Get the terminal width or -1 if the width cannot be determined.
+     *
+     * @return the terminal width
+     */
+    public static int getTerminalWidth() {
+        if (JANSI) {
+            int width = AnsiConsole.getTerminalWidth();
+            return width > 0 ? width : -1;
+        } else {
+            return -1;
+        }
+    }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/jansi/Style.java b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/Style.java
new file mode 100644
index 0000000..16ae2ad
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/jansi/Style.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.cli.jansi;
+
+import java.util.Locale;
+
+import org.fusesource.jansi.Ansi;
+import org.fusesource.jansi.Ansi.Color;
+
+/**
+ * Configurable message styles.
+ * @since 4.0.0
+ */
+enum Style {
+    TRACE("bold,magenta"),
+    DEBUG("bold,cyan"),
+    INFO("bold,blue"),
+    WARNING("bold,yellow"),
+    ERROR("bold,red"),
+    SUCCESS("bold,green"),
+    FAILURE("bold,red"),
+    STRONG("bold"),
+    MOJO("green"),
+    PROJECT("cyan");
+
+    private final boolean bold;
+
+    private final boolean bright;
+
+    private final Color color;
+
+    private final boolean bgBright;
+
+    private final Color bgColor;
+
+    Style(String defaultValue) {
+        boolean currentBold = false;
+        boolean currentBright = false;
+        Color currentColor = null;
+        boolean currentBgBright = false;
+        Color currentBgColor = null;
+
+        String value = System.getProperty("style." + name().toLowerCase(Locale.ENGLISH), defaultValue)
+                .toLowerCase(Locale.ENGLISH);
+
+        for (String token : value.split(",")) {
+            if ("bold".equals(token)) {
+                currentBold = true;
+            } else if (token.startsWith("bg")) {
+                token = token.substring(2);
+                if (token.startsWith("bright")) {
+                    currentBgBright = true;
+                    token = token.substring(6);
+                }
+                currentBgColor = toColor(token);
+            } else {
+                if (token.startsWith("bright")) {
+                    currentBright = true;
+                    token = token.substring(6);
+                }
+                currentColor = toColor(token);
+            }
+        }
+
+        this.bold = currentBold;
+        this.bright = currentBright;
+        this.color = currentColor;
+        this.bgBright = currentBgBright;
+        this.bgColor = currentBgColor;
+    }
+
+    private static Color toColor(String token) {
+        for (Color color : Color.values()) {
+            if (color.toString().equalsIgnoreCase(token)) {
+                return color;
+            }
+        }
+        return null;
+    }
+
+    Ansi apply(Ansi ansi) {
+        if (bold) {
+            ansi.bold();
+        }
+        if (color != null) {
+            if (bright) {
+                ansi.fgBright(color);
+            } else {
+                ansi.fg(color);
+            }
+        }
+        if (bgColor != null) {
+            if (bgBright) {
+                ansi.bgBright(bgColor);
+            } else {
+                ansi.bg(bgColor);
+            }
+        }
+        return ansi;
+    }
+
+    @Override
+    public String toString() {
+        if (!bold && color == null && bgColor == null) {
+            return name();
+        }
+        StringBuilder sb = new StringBuilder(name() + '=');
+        if (bold) {
+            sb.append("bold");
+        }
+        if (color != null) {
+            if (sb.length() > 0) {
+                sb.append(',');
+            }
+            if (bright) {
+                sb.append("bright");
+            }
+            sb.append(color.name());
+        }
+        if (bgColor != null) {
+            if (sb.length() > 0) {
+                sb.append(',');
+            }
+            sb.append("bg");
+            if (bgBright) {
+                sb.append("bright");
+            }
+            sb.append(bgColor.name());
+        }
+        return sb.toString();
+    }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/BaseSlf4jConfiguration.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/BaseSlf4jConfiguration.java
index 33c47c2..fe29c71 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/BaseSlf4jConfiguration.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/BaseSlf4jConfiguration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,21 +24,16 @@
 /**
  * Abstract implementation.
  *
- * @author Hervé Boutemy
  * @since 3.1.0
  */
-public class BaseSlf4jConfiguration
-    implements Slf4jConfiguration
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( BaseSlf4jConfiguration.class );
+public class BaseSlf4jConfiguration implements Slf4jConfiguration {
+    private static final Logger LOGGER = LoggerFactory.getLogger(BaseSlf4jConfiguration.class);
 
-    public void setRootLoggerLevel( Level level )
-    {
-        LOGGER.warn( "setRootLoggerLevel: operation not supported" );
+    public void setRootLoggerLevel(Level level) {
+        LOGGER.warn("setRootLoggerLevel: operation not supported");
     }
 
-    public void activate()
-    {
-        LOGGER.warn( "reset(): operation not supported" );
+    public void activate() {
+        LOGGER.warn("reset(): operation not supported");
     }
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfiguration.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfiguration.java
index 8dc81c7..7a162fa 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfiguration.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfiguration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,22 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging;
 
 /**
  * Interface for configuration operations on loggers, which are not available in slf4j, then require per-slf4f-binding
  * implementation.
  *
- * @author Hervé Boutemy
  * @since 3.1.0
  */
-public interface Slf4jConfiguration
-{
+public interface Slf4jConfiguration {
     /**
      * Level
      */
-    enum Level
-    {
-        DEBUG, INFO, ERROR
+    enum Level {
+        DEBUG,
+        INFO,
+        ERROR
     }
 
     /**
@@ -41,7 +39,7 @@
      *
      * @param level the level
      */
-    void setRootLoggerLevel( Level level );
+    void setRootLoggerLevel(Level level);
 
     /**
      * Activate logging implementation configuration (if necessary).
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfigurationFactory.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfigurationFactory.java
index 1a68d76..2d65fe8 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfigurationFactory.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jConfigurationFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.URL;
 import java.util.Enumeration;
-import java.util.LinkedHashMap;
-import java.util.Map;
 import java.util.Properties;
-import java.util.Set;
 
 import org.apache.maven.cli.logging.impl.UnsupportedSlf4jBindingConfiguration;
-import org.codehaus.plexus.util.PropertyUtils;
 import org.slf4j.ILoggerFactory;
 
 /**
@@ -36,44 +32,40 @@
  * configuration files in class loader: key is the class name of the ILoggerFactory, value is the class name of
  * the corresponding Slf4jConfiguration.
  *
- * @author Hervé Boutemy
  * @since 3.1.0
  */
-public class Slf4jConfigurationFactory
-{
+public class Slf4jConfigurationFactory {
     public static final String RESOURCE = "META-INF/maven/slf4j-configuration.properties";
 
-    public static Slf4jConfiguration getConfiguration( ILoggerFactory loggerFactory )
-    {
-        Map<URL, Set<Object>> supported = new LinkedHashMap<>();
-
+    public static Slf4jConfiguration getConfiguration(ILoggerFactory loggerFactory) {
         String slf4jBinding = loggerFactory.getClass().getCanonicalName();
 
-        try
-        {
-            Enumeration<URL> resources = Slf4jConfigurationFactory.class.getClassLoader().getResources( RESOURCE );
+        try {
+            Enumeration<URL> resources =
+                    Slf4jConfigurationFactory.class.getClassLoader().getResources(RESOURCE);
 
-            while ( resources.hasMoreElements() )
-            {
+            while (resources.hasMoreElements()) {
                 URL resource = resources.nextElement();
-
-                Properties conf = PropertyUtils.loadProperties( resource.openStream() );
-
-                String impl = conf.getProperty( slf4jBinding );
-
-                if ( impl != null )
-                {
-                    return (Slf4jConfiguration) Class.forName( impl ).newInstance();
+                try {
+                    InputStream is = resource.openStream();
+                    final Properties properties = new Properties();
+                    if (is != null) {
+                        try (InputStream in = is) {
+                            properties.load(in);
+                        }
+                    }
+                    String impl = properties.getProperty(slf4jBinding);
+                    if (impl != null) {
+                        return (Slf4jConfiguration) Class.forName(impl).newInstance();
+                    }
+                } catch (IOException | ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
+                    // ignore and move on to the next
                 }
-
-                supported.put( resource, conf.keySet() );
             }
-        }
-        catch ( IOException | ClassNotFoundException | IllegalAccessException | InstantiationException e )
-        {
-            e.printStackTrace();
+        } catch (IOException ex) {
+            // ignore
         }
 
-        return new UnsupportedSlf4jBindingConfiguration( slf4jBinding, supported );
+        return new UnsupportedSlf4jBindingConfiguration();
     }
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLogger.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLogger.java
index 3957464..9cca0a9 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLogger.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLogger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging;
 
 import org.codehaus.plexus.logging.Logger;
 
@@ -25,121 +24,96 @@
  * Adapt an SLF4J logger to a Plexus logger, ignoring Plexus logger API parts that are not classical and
  * probably not really used.
  *
- * @author Jason van Zyl
  * @since 3.1.0
  */
-public class Slf4jLogger
-    implements Logger
-{
+public class Slf4jLogger implements Logger {
 
     private org.slf4j.Logger logger;
 
-    public Slf4jLogger( org.slf4j.Logger logger )
-    {
+    public Slf4jLogger(org.slf4j.Logger logger) {
         this.logger = logger;
     }
 
-    public void debug( String message )
-    {
-        logger.debug( message );
+    public void debug(String message) {
+        logger.debug(message);
     }
 
-    public void debug( String message, Throwable throwable )
-    {
-        logger.debug( message, throwable );
+    public void debug(String message, Throwable throwable) {
+        logger.debug(message, throwable);
     }
 
-    public boolean isDebugEnabled()
-    {
+    public boolean isDebugEnabled() {
         return logger.isDebugEnabled();
     }
 
-    public void info( String message )
-    {
-        logger.info( message );
+    public void info(String message) {
+        logger.info(message);
     }
 
-    public void info( String message, Throwable throwable )
-    {
-        logger.info( message, throwable );
+    public void info(String message, Throwable throwable) {
+        logger.info(message, throwable);
     }
 
-    public boolean isInfoEnabled()
-    {
+    public boolean isInfoEnabled() {
         return logger.isInfoEnabled();
     }
 
-    public void warn( String message )
-    {
-        logger.warn( message );
+    public void warn(String message) {
+        logger.warn(message);
     }
 
-    public void warn( String message, Throwable throwable )
-    {
-        logger.warn( message, throwable );
+    public void warn(String message, Throwable throwable) {
+        logger.warn(message, throwable);
     }
 
-    public boolean isWarnEnabled()
-    {
+    public boolean isWarnEnabled() {
         return logger.isWarnEnabled();
     }
 
-    public void error( String message )
-    {
-        logger.error( message );
+    public void error(String message) {
+        logger.error(message);
     }
 
-    public void error( String message, Throwable throwable )
-    {
-        logger.error( message, throwable );
+    public void error(String message, Throwable throwable) {
+        logger.error(message, throwable);
     }
 
-    public boolean isErrorEnabled()
-    {
+    public boolean isErrorEnabled() {
         return logger.isErrorEnabled();
     }
 
-    public void fatalError( String message )
-    {
-        logger.error( message );
+    public void fatalError(String message) {
+        logger.error(message);
     }
 
-    public void fatalError( String message, Throwable throwable )
-    {
-        logger.error( message, throwable );
+    public void fatalError(String message, Throwable throwable) {
+        logger.error(message, throwable);
     }
 
-    public boolean isFatalErrorEnabled()
-    {
+    public boolean isFatalErrorEnabled() {
         return logger.isErrorEnabled();
     }
 
     /**
      * <b>Warning</b>: ignored (always return <code>0 == Logger.LEVEL_DEBUG</code>).
      */
-    public int getThreshold()
-    {
+    public int getThreshold() {
         return 0;
     }
 
     /**
      * <b>Warning</b>: ignored.
      */
-    public void setThreshold( int threshold )
-    {
-    }
+    public void setThreshold(int threshold) {}
 
     /**
      * <b>Warning</b>: ignored (always return <code>null</code>).
      */
-    public Logger getChildLogger( String name )
-    {
+    public Logger getChildLogger(String name) {
         return null;
     }
 
-    public String getName()
-    {
+    public String getName() {
         return logger.getName();
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLoggerManager.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLoggerManager.java
index 529f19e..4342390 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLoggerManager.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jLoggerManager.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging;
 
 import org.codehaus.plexus.logging.Logger;
 import org.codehaus.plexus.logging.LoggerManager;
@@ -29,23 +28,18 @@
  * {@link org.codehaus.plexus.logging.LoggerManager},
  * ignoring Plexus logger API parts that are not classical and probably not really used.
  *
- * @author Jason van Zyl
  * @since 3.1
  */
-public class Slf4jLoggerManager
-    implements LoggerManager
-{
+public class Slf4jLoggerManager implements LoggerManager {
 
     private ILoggerFactory loggerFactory;
 
-    public Slf4jLoggerManager()
-    {
+    public Slf4jLoggerManager() {
         loggerFactory = LoggerFactory.getILoggerFactory();
     }
 
-    public Logger getLoggerForComponent( String role )
-    {
-        return new Slf4jLogger( loggerFactory.getLogger( role ) );
+    public Logger getLoggerForComponent(String role) {
+        return new Slf4jLogger(loggerFactory.getLogger(role));
     }
 
     /**
@@ -53,11 +47,10 @@
      * <b>Warning</b>: this does not conform to logger name as class name convention.
      * (and what about <code>null</code> and <code>default</code> hint equivalence?)
      */
-    public Logger getLoggerForComponent( String role, String hint )
-    {
-        return ( null == hint
-            ? getLoggerForComponent( role )
-            : new Slf4jLogger( loggerFactory.getLogger( role + '.' + hint ) ) );
+    public Logger getLoggerForComponent(String role, String hint) {
+        return (null == hint
+                ? getLoggerForComponent(role)
+                : new Slf4jLogger(loggerFactory.getLogger(role + '.' + hint)));
     }
 
     //
@@ -67,45 +60,34 @@
     /**
      * <b>Warning</b>: ignored.
      */
-    public void returnComponentLogger( String role )
-    {
-    }
+    public void returnComponentLogger(String role) {}
 
     /**
      * <b>Warning</b>: ignored.
      */
-    public void returnComponentLogger( String role, String hint )
-    {
-    }
+    public void returnComponentLogger(String role, String hint) {}
 
     /**
      * <b>Warning</b>: ignored (always return <code>0</code>).
      */
-    public int getThreshold()
-    {
+    public int getThreshold() {
         return 0;
     }
 
     /**
      * <b>Warning</b>: ignored.
      */
-    public void setThreshold( int threshold )
-    {
-    }
+    public void setThreshold(int threshold) {}
 
     /**
      * <b>Warning</b>: ignored.
      */
-    public void setThresholds( int threshold )
-    {
-    }
+    public void setThresholds(int threshold) {}
 
     /**
      * <b>Warning</b>: ignored (always return <code>0</code>).
      */
-    public int getActiveLoggerCount()
-    {
+    public int getActiveLoggerCount() {
         return 0;
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jStdoutLogger.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jStdoutLogger.java
index 64b9bfd..5052adc 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jStdoutLogger.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/Slf4jStdoutLogger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging;
 
 import java.io.PrintStream;
 
@@ -27,9 +26,7 @@
 /**
  * @since 3.1.0
  */
-public class Slf4jStdoutLogger
-    implements Logger
-{
+public class Slf4jStdoutLogger implements Logger {
     private static final String ERROR = "[ERROR] ";
 
     private PrintStream out = System.out;
@@ -37,270 +34,159 @@
     //
     // These are the only methods we need in our primordial logger
     //
-    public void error( String msg )
-    {
-        out.print( ERROR );
-        out.println( msg );
+    public void error(String msg) {
+        out.print(ERROR);
+        out.println(msg);
     }
 
-    public void error( String msg, Throwable t )
-    {
-        error( msg );
+    public void error(String msg, Throwable t) {
+        error(msg);
 
-        if ( null != t )
-        {
-            t.printStackTrace( out );
+        if (null != t) {
+            t.printStackTrace(out);
         }
     }
 
     //
     // Don't need any of this
     //
-    public String getName()
-    {
+    public String getName() {
         return null;
     }
 
-    public boolean isTraceEnabled()
-    {
+    public boolean isTraceEnabled() {
         return false;
     }
 
-    public void trace( String msg )
-    {
-    }
+    public void trace(String msg) {}
 
-    public void trace( String format, Object arg )
-    {
-    }
+    public void trace(String format, Object arg) {}
 
-    public void trace( String format, Object arg1, Object arg2 )
-    {
-    }
+    public void trace(String format, Object arg1, Object arg2) {}
 
-    public void trace( String format, Object... arguments )
-    {
-    }
+    public void trace(String format, Object... arguments) {}
 
-    public void trace( String msg, Throwable t )
-    {
-    }
+    public void trace(String msg, Throwable t) {}
 
-    public boolean isTraceEnabled( Marker marker )
-    {
+    public boolean isTraceEnabled(Marker marker) {
         return false;
     }
 
-    public void trace( Marker marker, String msg )
-    {
-    }
+    public void trace(Marker marker, String msg) {}
 
-    public void trace( Marker marker, String format, Object arg )
-    {
-    }
+    public void trace(Marker marker, String format, Object arg) {}
 
-    public void trace( Marker marker, String format, Object arg1, Object arg2 )
-    {
-    }
+    public void trace(Marker marker, String format, Object arg1, Object arg2) {}
 
-    public void trace( Marker marker, String format, Object... argArray )
-    {
-    }
+    public void trace(Marker marker, String format, Object... argArray) {}
 
-    public void trace( Marker marker, String msg, Throwable t )
-    {
-    }
+    public void trace(Marker marker, String msg, Throwable t) {}
 
-    public boolean isDebugEnabled()
-    {
+    public boolean isDebugEnabled() {
         return false;
     }
 
-    public void debug( String msg )
-    {
-    }
+    public void debug(String msg) {}
 
-    public void debug( String format, Object arg )
-    {
-    }
+    public void debug(String format, Object arg) {}
 
-    public void debug( String format, Object arg1, Object arg2 )
-    {
-    }
+    public void debug(String format, Object arg1, Object arg2) {}
 
-    public void debug( String format, Object... arguments )
-    {
-    }
+    public void debug(String format, Object... arguments) {}
 
-    public void debug( String msg, Throwable t )
-    {
-    }
+    public void debug(String msg, Throwable t) {}
 
-    public boolean isDebugEnabled( Marker marker )
-    {
+    public boolean isDebugEnabled(Marker marker) {
         return false;
     }
 
-    public void debug( Marker marker, String msg )
-    {
-    }
+    public void debug(Marker marker, String msg) {}
 
-    public void debug( Marker marker, String format, Object arg )
-    {
-    }
+    public void debug(Marker marker, String format, Object arg) {}
 
-    public void debug( Marker marker, String format, Object arg1, Object arg2 )
-    {
-    }
+    public void debug(Marker marker, String format, Object arg1, Object arg2) {}
 
-    public void debug( Marker marker, String format, Object... arguments )
-    {
-    }
+    public void debug(Marker marker, String format, Object... arguments) {}
 
-    public void debug( Marker marker, String msg, Throwable t )
-    {
-    }
+    public void debug(Marker marker, String msg, Throwable t) {}
 
-    public boolean isInfoEnabled()
-    {
+    public boolean isInfoEnabled() {
         return false;
     }
 
-    public void info( String msg )
-    {
-    }
+    public void info(String msg) {}
 
-    public void info( String format, Object arg )
-    {
-    }
+    public void info(String format, Object arg) {}
 
-    public void info( String format, Object arg1, Object arg2 )
-    {
-    }
+    public void info(String format, Object arg1, Object arg2) {}
 
-    public void info( String format, Object... arguments )
-    {
-    }
+    public void info(String format, Object... arguments) {}
 
-    public void info( String msg, Throwable t )
-    {
-    }
+    public void info(String msg, Throwable t) {}
 
-    public boolean isInfoEnabled( Marker marker )
-    {
+    public boolean isInfoEnabled(Marker marker) {
         return false;
     }
 
-    public void info( Marker marker, String msg )
-    {
-    }
+    public void info(Marker marker, String msg) {}
 
-    public void info( Marker marker, String format, Object arg )
-    {
-    }
+    public void info(Marker marker, String format, Object arg) {}
 
-    public void info( Marker marker, String format, Object arg1, Object arg2 )
-    {
-    }
+    public void info(Marker marker, String format, Object arg1, Object arg2) {}
 
-    public void info( Marker marker, String format, Object... arguments )
-    {
-    }
+    public void info(Marker marker, String format, Object... arguments) {}
 
-    public void info( Marker marker, String msg, Throwable t )
-    {
-    }
+    public void info(Marker marker, String msg, Throwable t) {}
 
-    public boolean isWarnEnabled()
-    {
+    public boolean isWarnEnabled() {
         return false;
     }
 
-    public void warn( String msg )
-    {
-    }
+    public void warn(String msg) {}
 
-    public void warn( String format, Object arg )
-    {
-    }
+    public void warn(String format, Object arg) {}
 
-    public void warn( String format, Object... arguments )
-    {
-    }
+    public void warn(String format, Object... arguments) {}
 
-    public void warn( String format, Object arg1, Object arg2 )
-    {
-    }
+    public void warn(String format, Object arg1, Object arg2) {}
 
-    public void warn( String msg, Throwable t )
-    {
-    }
+    public void warn(String msg, Throwable t) {}
 
-    public boolean isWarnEnabled( Marker marker )
-    {
+    public boolean isWarnEnabled(Marker marker) {
         return false;
     }
 
-    public void warn( Marker marker, String msg )
-    {
-    }
+    public void warn(Marker marker, String msg) {}
 
-    public void warn( Marker marker, String format, Object arg )
-    {
-    }
+    public void warn(Marker marker, String format, Object arg) {}
 
-    public void warn( Marker marker, String format, Object arg1, Object arg2 )
-    {
-    }
+    public void warn(Marker marker, String format, Object arg1, Object arg2) {}
 
-    public void warn( Marker marker, String format, Object... arguments )
-    {
-    }
+    public void warn(Marker marker, String format, Object... arguments) {}
 
-    public void warn( Marker marker, String msg, Throwable t )
-    {
-    }
+    public void warn(Marker marker, String msg, Throwable t) {}
 
-    public boolean isErrorEnabled()
-    {
+    public boolean isErrorEnabled() {
         return false;
     }
 
-    public void error( String format, Object arg )
-    {
-    }
+    public void error(String format, Object arg) {}
 
-    public void error( String format, Object arg1, Object arg2 )
-    {
-    }
+    public void error(String format, Object arg1, Object arg2) {}
 
-    public void error( String format, Object... arguments )
-    {
-    }
+    public void error(String format, Object... arguments) {}
 
-    public boolean isErrorEnabled( Marker marker )
-    {
+    public boolean isErrorEnabled(Marker marker) {
         return false;
     }
 
-    public void error( Marker marker, String msg )
-    {
-    }
+    public void error(Marker marker, String msg) {}
 
-    public void error( Marker marker, String format, Object arg )
-    {
-    }
+    public void error(Marker marker, String format, Object arg) {}
 
-    public void error( Marker marker, String format, Object arg1, Object arg2 )
-    {
-    }
+    public void error(Marker marker, String format, Object arg1, Object arg2) {}
 
-    public void error( Marker marker, String format, Object... arguments )
-    {
-    }
+    public void error(Marker marker, String format, Object... arguments) {}
 
-    public void error( Marker marker, String msg, Throwable t )
-    {
-    }
-
+    public void error(Marker marker, String msg, Throwable t) {}
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Log4j2Configuration.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Log4j2Configuration.java
index b24ea9c..d6171f7 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Log4j2Configuration.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Log4j2Configuration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,24 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging.impl;
 
 import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
 
 /**
  * Configuration for slf4j-log4j2.
  *
- * @author Hervé Boutemy
  * @since 3.1.0
  */
-public class Log4j2Configuration
-    extends BaseSlf4jConfiguration
-{
+public class Log4j2Configuration extends BaseSlf4jConfiguration {
     @Override
-    public void setRootLoggerLevel( Level level )
-    {
+    public void setRootLoggerLevel(Level level) {
         String value;
-        switch ( level )
-        {
+        switch (level) {
             case DEBUG:
                 value = "debug";
                 break;
@@ -48,12 +42,11 @@
                 value = "error";
                 break;
         }
-        System.setProperty( "maven.logging.root.level", value );
+        System.setProperty("maven.logging.root.level", value);
     }
 
     @Override
-    public void activate()
-    {
+    public void activate() {
         // no op
     }
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/LogbackConfiguration.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/LogbackConfiguration.java
index 5d9fab7..e2f0cb6 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/LogbackConfiguration.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/LogbackConfiguration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging.impl;
 
 import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
 import org.slf4j.Logger;
@@ -26,18 +25,13 @@
 /**
  * Configuration for slf4j-logback.
  *
- * @author Hervé Boutemy
  * @since 3.1.0
  */
-public class LogbackConfiguration
-    extends BaseSlf4jConfiguration
-{
+public class LogbackConfiguration extends BaseSlf4jConfiguration {
     @Override
-    public void setRootLoggerLevel( Level level )
-    {
+    public void setRootLoggerLevel(Level level) {
         ch.qos.logback.classic.Level value;
-        switch ( level )
-        {
+        switch (level) {
             case DEBUG:
                 value = ch.qos.logback.classic.Level.DEBUG;
                 break;
@@ -50,12 +44,11 @@
                 value = ch.qos.logback.classic.Level.ERROR;
                 break;
         }
-        ( (ch.qos.logback.classic.Logger) LoggerFactory.getLogger( Logger.ROOT_LOGGER_NAME ) ).setLevel( value );
+        ((ch.qos.logback.classic.Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME)).setLevel(value);
     }
 
     @Override
-    public void activate()
-    {
+    public void activate() {
         // no op
     }
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Slf4jSimpleConfiguration.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Slf4jSimpleConfiguration.java
index 3961059..5325250 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Slf4jSimpleConfiguration.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/Slf4jSimpleConfiguration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging.impl;
 
 import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
 import org.slf4j.MavenSlf4jFriend;
@@ -26,18 +25,13 @@
 /**
  * Configuration for slf4j-simple.
  *
- * @author Hervé Boutemy
  * @since 3.1.0
  */
-public class Slf4jSimpleConfiguration
-    extends BaseSlf4jConfiguration
-{
+public class Slf4jSimpleConfiguration extends BaseSlf4jConfiguration {
     @Override
-    public void setRootLoggerLevel( Level level )
-    {
+    public void setRootLoggerLevel(Level level) {
         String value;
-        switch ( level )
-        {
+        switch (level) {
             case DEBUG:
                 value = "debug";
                 break;
@@ -50,12 +44,11 @@
                 value = "error";
                 break;
         }
-        System.setProperty( "org.slf4j.simpleLogger.defaultLogLevel", value );
+        System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", value);
     }
 
     @Override
-    public void activate()
-    {
+    public void activate() {
         // property for root logger level or System.out redirection need to be taken into account
         MavenSlf4jFriend.reset();
         MavenSlf4jSimpleFriend.init();
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java
index 077c674..8c29235 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/logging/impl/UnsupportedSlf4jBindingConfiguration.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.logging.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,55 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.logging.impl;
 
 import java.net.URL;
 import java.util.Map;
 import java.util.Set;
 
 import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
- * Pseudo-configuration for unsupported slf4j binding.
+ * Pseudo-configuration for unsupported SLF4J binding.
  *
- * @author Hervé Boutemy
  * @since 3.2.4
  */
-public class UnsupportedSlf4jBindingConfiguration
-    extends BaseSlf4jConfiguration
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( UnsupportedSlf4jBindingConfiguration.class );
+public class UnsupportedSlf4jBindingConfiguration extends BaseSlf4jConfiguration {
 
-    private String slf4jBinding;
+    /**
+     * @deprecated the arguments are ignored. Use the no-args constructor.
+     */
+    @Deprecated
+    public UnsupportedSlf4jBindingConfiguration(String slf4jBinding, Map<URL, Set<Object>> supported) {}
 
-    private Map<URL, Set<Object>> supported;
-
-    public UnsupportedSlf4jBindingConfiguration( String slf4jBinding, Map<URL, Set<Object>> supported )
-    {
-        this.slf4jBinding = slf4jBinding;
-        this.supported = supported;
-    }
+    public UnsupportedSlf4jBindingConfiguration() {}
 
     @Override
-    public void activate()
-    {
-        LOGGER.warn( "The SLF4J binding actually used is not supported by Maven: {}", slf4jBinding );
-        LOGGER.warn( "Maven supported bindings are:" );
-
-        String ls = System.lineSeparator();
-
-        for ( Map.Entry<URL, Set<Object>> entry : supported.entrySet() )
-        {
-            StringBuilder sb = new StringBuilder();
-            sb.append( "(from " ).append( entry.getKey().toExternalForm() ).append( ')' );
-
-            for ( Object binding : entry.getValue() )
-            {
-                sb.append( ls ).append( "- " ).append( binding );
-            }
-
-            LOGGER.warn( sb.toString() );
-        }
-    }
+    public void activate() {}
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
index 72bffc3..bc65268 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.transfer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.transfer;
 
 import java.io.PrintStream;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
 import java.util.Locale;
 
-import org.apache.commons.lang3.Validate;
+import org.apache.maven.cli.jansi.MessageUtils;
 import org.eclipse.aether.transfer.AbstractTransferListener;
 import org.eclipse.aether.transfer.TransferCancelledException;
 import org.eclipse.aether.transfer.TransferEvent;
@@ -33,240 +30,73 @@
 /**
  * AbstractMavenTransferListener
  */
-public abstract class AbstractMavenTransferListener
-    extends AbstractTransferListener
-{
+public abstract class AbstractMavenTransferListener extends AbstractTransferListener {
 
-    // CHECKSTYLE_OFF: LineLength
-    /**
-     * Formats file size with the associated <a href="https://en.wikipedia.org/wiki/Metric_prefix">SI</a> prefix
-     * (GB, MB, kB) and using the patterns <code>#0.0</code> for numbers between 1 and 10
-     * and <code>###0</code> for numbers between 10 and 1000+ by default.
-     *
-     * @see <a href="https://en.wikipedia.org/wiki/Metric_prefix">https://en.wikipedia.org/wiki/Metric_prefix</a>
-     * @see <a href="https://en.wikipedia.org/wiki/Binary_prefix">https://en.wikipedia.org/wiki/Binary_prefix</a>
-     * @see <a
-     *      href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
-     */
-    // CHECKSTYLE_ON: LineLength
-    // TODO Move me to Maven Shared Utils
-    static class FileSizeFormat
-    {
-        enum ScaleUnit
-        {
-            BYTE
-            {
-                @Override
-                public long bytes()
-                {
-                    return 1L;
-                }
-
-                @Override
-                public String symbol()
-                {
-                    return "B";
-                }
-            },
-            KILOBYTE
-            {
-                @Override
-                public long bytes()
-                {
-                    return 1000L;
-                }
-
-                @Override
-                public String symbol()
-                {
-                    return "kB";
-                }
-            },
-            MEGABYTE
-            {
-                @Override
-                public long bytes()
-                {
-                    return KILOBYTE.bytes() * KILOBYTE.bytes();
-                }
-
-                @Override
-                public String symbol()
-                {
-                    return "MB";
-                }
-            },
-            GIGABYTE
-            {
-                @Override
-                public long bytes()
-                {
-                    return MEGABYTE.bytes() * KILOBYTE.bytes();
-                };
-
-                @Override
-                public String symbol()
-                {
-                    return "GB";
-                }
-            };
-
-            public abstract long bytes();
-            public abstract String symbol();
-
-            public static ScaleUnit getScaleUnit( long size )
-            {
-                Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
-
-                if ( size >= GIGABYTE.bytes() )
-                {
-                    return GIGABYTE;
-                }
-                else if ( size >= MEGABYTE.bytes() )
-                {
-                    return MEGABYTE;
-                }
-                else if ( size >= KILOBYTE.bytes() )
-                {
-                    return KILOBYTE;
-                }
-                else
-                {
-                    return BYTE;
-                }
-            }
-        }
-
-        private DecimalFormat smallFormat;
-        private DecimalFormat largeFormat;
-
-        FileSizeFormat( Locale locale )
-        {
-            smallFormat = new DecimalFormat( "#0.0", new DecimalFormatSymbols( locale ) );
-            largeFormat = new DecimalFormat( "###0", new DecimalFormatSymbols( locale ) );
-        }
-
-        public String format( long size )
-        {
-            return format( size, null );
-        }
-
-        public String format( long size, ScaleUnit unit )
-        {
-            return format( size, unit, false );
-        }
-
-        @SuppressWarnings( "checkstyle:magicnumber" )
-        public String format( long size, ScaleUnit unit, boolean omitSymbol )
-        {
-            Validate.isTrue( size >= 0L, "file size cannot be negative: %s", size );
-
-            if ( unit == null )
-            {
-                unit = ScaleUnit.getScaleUnit( size );
-            }
-
-            double scaledSize = (double) size / unit.bytes();
-            String scaledSymbol = " " + unit.symbol();
-
-            if ( omitSymbol )
-            {
-                scaledSymbol = "";
-            }
-
-            if ( unit == ScaleUnit.BYTE )
-            {
-                return largeFormat.format( size ) + scaledSymbol;
-            }
-
-            if ( scaledSize < 0.05 || scaledSize >= 10.0 )
-            {
-                return largeFormat.format( scaledSize ) + scaledSymbol;
-            }
-            else
-            {
-                return smallFormat.format( scaledSize ) + scaledSymbol;
-            }
-        }
-
-        public String formatProgress( long progressedSize, long size )
-        {
-            Validate.isTrue( progressedSize >= 0L, "progressed file size cannot be negative: %s", progressedSize );
-            Validate.isTrue( size < 0L || progressedSize <= size,
-                "progressed file size cannot be greater than size: %s > %s", progressedSize, size );
-
-            if ( size >= 0L && progressedSize != size )
-            {
-                ScaleUnit unit = ScaleUnit.getScaleUnit( size );
-                String formattedProgressedSize = format( progressedSize, unit, true );
-                String formattedSize = format( size, unit );
-
-                return formattedProgressedSize + "/" + formattedSize;
-            }
-            else
-            {
-                return format( progressedSize );
-            }
-        }
-    }
+    private static final String ESC = "\u001B";
+    private static final String ANSI_DARK_SET = ESC + "[90m";
+    private static final String ANSI_DARK_RESET = ESC + "[0m";
 
     protected PrintStream out;
 
-    protected AbstractMavenTransferListener( PrintStream out )
-    {
+    protected AbstractMavenTransferListener(PrintStream out) {
         this.out = out;
     }
 
     @Override
-    public void transferInitiated( TransferEvent event )
-    {
+    public void transferInitiated(TransferEvent event) {
+        String darkOn = MessageUtils.isColorEnabled() ? ANSI_DARK_SET : "";
+        String darkOff = MessageUtils.isColorEnabled() ? ANSI_DARK_RESET : "";
+
         String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
 
         TransferResource resource = event.getResource();
         StringBuilder message = new StringBuilder();
-        message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
-        message.append( ": " );
-        message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
+        message.append(darkOn).append(action).append(' ').append(direction).append(' ');
+        message.append(darkOff).append(resource.getRepositoryId());
+        message.append(darkOn).append(": ").append(resource.getRepositoryUrl());
+        message.append(darkOff).append(resource.getResourceName());
 
-        out.println( message.toString() );
+        out.println(message.toString());
     }
 
     @Override
-    public void transferCorrupted( TransferEvent event )
-        throws TransferCancelledException
-    {
+    public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
         TransferResource resource = event.getResource();
         // TODO This needs to be colorized
-        out.println( "[WARNING] " + event.getException().getMessage() + " from " + resource.getRepositoryId() + " for "
-            + resource.getRepositoryUrl() + resource.getResourceName() );
+        out.println("[WARNING] " + event.getException().getMessage() + " from " + resource.getRepositoryId() + " for "
+                + resource.getRepositoryUrl() + resource.getResourceName());
     }
 
     @Override
-    public void transferSucceeded( TransferEvent event )
-    {
-        String action = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
+    public void transferSucceeded(TransferEvent event) {
+        String darkOn = MessageUtils.isColorEnabled() ? ANSI_DARK_SET : "";
+        String darkOff = MessageUtils.isColorEnabled() ? ANSI_DARK_RESET : "";
+
+        String action = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded");
         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
 
         TransferResource resource = event.getResource();
         long contentLength = event.getTransferredBytes();
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
         StringBuilder message = new StringBuilder();
-        message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
-        message.append( ": " );
-        message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
-        message.append( " (" ).append( format.format( contentLength ) );
+        message.append(action).append(darkOn).append(' ').append(direction).append(' ');
+        message.append(darkOff).append(resource.getRepositoryId());
+        message.append(darkOn).append(": ").append(resource.getRepositoryUrl());
+        message.append(darkOff).append(resource.getResourceName());
+        message.append(darkOn).append(" (");
+        format.format(message, contentLength);
 
         long duration = System.currentTimeMillis() - resource.getTransferStartTime();
-        if ( duration > 0L )
-        {
-            double bytesPerSecond = contentLength / ( duration / 1000.0 );
-            message.append( " at " ).append( format.format( (long) bytesPerSecond ) ).append( "/s" );
+        if (duration > 0L) {
+            double bytesPerSecond = contentLength / (duration / 1000.0);
+            message.append(" at ");
+            format.format(message, (long) bytesPerSecond);
+            message.append("/s");
         }
 
-        message.append( ')' );
-        out.println( message.toString() );
+        message.append(')').append(darkOff);
+        out.println(message.toString());
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/BatchModeMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/BatchModeMavenTransferListener.java
deleted file mode 100644
index 2eee8f6..0000000
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/BatchModeMavenTransferListener.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package org.apache.maven.cli.transfer;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.PrintStream;
-
-/**
- * BatchModeMavenTransferListener
- */
-public class BatchModeMavenTransferListener
-    extends AbstractMavenTransferListener
-{
-    public BatchModeMavenTransferListener( PrintStream out )
-    {
-        super( out );
-    }
-
-}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java
index 950b5d0..78addd1 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.transfer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.transfer;
 
 import java.io.PrintStream;
-import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Locale;
 import java.util.Map;
 
-import org.apache.commons.lang3.StringUtils;
 import org.eclipse.aether.transfer.TransferCancelledException;
 import org.eclipse.aether.transfer.TransferEvent;
 import org.eclipse.aether.transfer.TransferResource;
@@ -34,136 +31,115 @@
 /**
  * Console download progress meter.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class ConsoleMavenTransferListener
-    extends AbstractMavenTransferListener
-{
+public class ConsoleMavenTransferListener extends AbstractMavenTransferListener {
 
-    private Map<TransferResource, Long> transfers = Collections.synchronizedMap(
-            new LinkedHashMap<>() );
+    private Map<TransferResource, Long> transfers = new LinkedHashMap<>();
+    private FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH); // use in a synchronized fashion
+    private StringBuilder buffer = new StringBuilder(128); // use in a synchronized fashion
 
     private boolean printResourceNames;
     private int lastLength;
 
-    public ConsoleMavenTransferListener( PrintStream out, boolean printResourceNames )
-    {
-        super( out );
+    public ConsoleMavenTransferListener(PrintStream out, boolean printResourceNames) {
+        super(out);
         this.printResourceNames = printResourceNames;
     }
 
     @Override
-    public synchronized void transferInitiated( TransferEvent event )
-    {
-        overridePreviousTransfer( event );
+    public synchronized void transferInitiated(TransferEvent event) {
+        overridePreviousTransfer(event);
 
-        super.transferInitiated( event );
+        super.transferInitiated(event);
     }
 
     @Override
-    public synchronized void transferCorrupted( TransferEvent event )
-        throws TransferCancelledException
-    {
-        overridePreviousTransfer( event );
+    public synchronized void transferCorrupted(TransferEvent event) throws TransferCancelledException {
+        overridePreviousTransfer(event);
 
-        super.transferCorrupted( event );
+        super.transferCorrupted(event);
     }
 
     @Override
-    public synchronized void transferProgressed( TransferEvent event )
-        throws TransferCancelledException
-    {
+    public synchronized void transferProgressed(TransferEvent event) throws TransferCancelledException {
         TransferResource resource = event.getResource();
-        transfers.put( resource, event.getTransferredBytes() );
+        transfers.put(resource, event.getTransferredBytes());
 
-        StringBuilder buffer = new StringBuilder( 128 );
-        buffer.append( "Progress (" ).append(  transfers.size() ).append( "): " );
+        buffer.append("Progress (").append(transfers.size()).append("): ");
 
-        synchronized ( transfers )
-        {
-            Iterator<Map.Entry<TransferResource, Long>> entries = transfers.entrySet().iterator();
-            while ( entries.hasNext() )
-            {
-                Map.Entry<TransferResource, Long> entry = entries.next();
-                long total = entry.getKey().getContentLength();
-                Long complete = entry.getValue();
-                buffer.append( getStatus( entry.getKey().getResourceName(), complete, total ) );
-                if ( entries.hasNext() )
-                {
-                    buffer.append( " | " );
+        Iterator<Map.Entry<TransferResource, Long>> entries =
+                transfers.entrySet().iterator();
+        while (entries.hasNext()) {
+            Map.Entry<TransferResource, Long> entry = entries.next();
+            long total = entry.getKey().getContentLength();
+            Long complete = entry.getValue();
+
+            String resourceName = entry.getKey().getResourceName();
+
+            if (printResourceNames) {
+                int idx = resourceName.lastIndexOf('/');
+
+                if (idx < 0) {
+                    buffer.append(resourceName);
+                } else {
+                    buffer.append(resourceName, idx + 1, resourceName.length());
                 }
+                buffer.append(" (");
+            }
+
+            format.formatProgress(buffer, complete, total);
+
+            if (printResourceNames) {
+                buffer.append(")");
+            }
+
+            if (entries.hasNext()) {
+                buffer.append(" | ");
             }
         }
 
         int pad = lastLength - buffer.length();
         lastLength = buffer.length();
-        pad( buffer, pad );
-        buffer.append( '\r' );
-        out.print( buffer );
+        pad(buffer, pad);
+        buffer.append('\r');
+        out.print(buffer);
         out.flush();
+        buffer.setLength(0);
     }
 
-    private String getStatus( String resourceName, long complete, long total )
-    {
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
-        StringBuilder status = new StringBuilder();
-
-        if ( printResourceNames )
-        {
-            status.append( StringUtils.substringAfterLast( resourceName,  "/" ) );
-            status.append( " (" );
-        }
-
-        status.append( format.formatProgress( complete, total ) );
-
-        if ( printResourceNames )
-        {
-            status.append( ")" );
-        }
-
-        return status.toString();
-    }
-
-    private void pad( StringBuilder buffer, int spaces )
-    {
+    private void pad(StringBuilder buffer, int spaces) {
         String block = "                                        ";
-        while ( spaces > 0 )
-        {
-            int n = Math.min( spaces, block.length() );
-            buffer.append( block, 0, n );
+        while (spaces > 0) {
+            int n = Math.min(spaces, block.length());
+            buffer.append(block, 0, n);
             spaces -= n;
         }
     }
 
     @Override
-    public synchronized void transferSucceeded( TransferEvent event )
-    {
-        transfers.remove( event.getResource() );
-        overridePreviousTransfer( event );
+    public synchronized void transferSucceeded(TransferEvent event) {
+        transfers.remove(event.getResource());
+        overridePreviousTransfer(event);
 
-        super.transferSucceeded( event );
+        super.transferSucceeded(event);
     }
 
     @Override
-    public synchronized void transferFailed( TransferEvent event )
-    {
-        transfers.remove( event.getResource() );
-        overridePreviousTransfer( event );
+    public synchronized void transferFailed(TransferEvent event) {
+        transfers.remove(event.getResource());
+        overridePreviousTransfer(event);
 
-        super.transferFailed( event );
+        super.transferFailed(event);
     }
 
-    private void overridePreviousTransfer( TransferEvent event )
-    {
-        if ( lastLength > 0 )
-        {
-            StringBuilder buffer = new StringBuilder( 128 );
-            pad( buffer, lastLength );
-            buffer.append( '\r' );
-            out.print( buffer );
+    private void overridePreviousTransfer(TransferEvent event) {
+        if (lastLength > 0) {
+            pad(buffer, lastLength);
+            buffer.append('\r');
+            out.print(buffer);
             out.flush();
             lastLength = 0;
+            buffer.setLength(0);
         }
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/FileSizeFormat.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/FileSizeFormat.java
new file mode 100644
index 0000000..6ae2054
--- /dev/null
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/FileSizeFormat.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.cli.transfer;
+
+import java.util.Locale;
+
+/**
+ * Formats file size with the associated <a href="https://en.wikipedia.org/wiki/Metric_prefix">SI</a> prefix
+ * (GB, MB, kB) and using the patterns <code>#0.0</code> for numbers between 1 and 10
+ * and <code>###0</code> for numbers between 10 and 1000+ by default.
+ *
+ * @see <a href="https://en.wikipedia.org/wiki/Metric_prefix">https://en.wikipedia.org/wiki/Metric_prefix</a>
+ * @see <a href="https://en.wikipedia.org/wiki/Binary_prefix">https://en.wikipedia.org/wiki/Binary_prefix</a>
+ * @see <a
+ *      href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
+ */
+public class FileSizeFormat {
+    public enum ScaleUnit {
+        BYTE {
+            @Override
+            public long bytes() {
+                return 1L;
+            }
+
+            @Override
+            public String symbol() {
+                return "B";
+            }
+        },
+        KILOBYTE {
+            @Override
+            public long bytes() {
+                return 1000L;
+            }
+
+            @Override
+            public String symbol() {
+                return "kB";
+            }
+        },
+        MEGABYTE {
+            @Override
+            public long bytes() {
+                return KILOBYTE.bytes() * KILOBYTE.bytes();
+            }
+
+            @Override
+            public String symbol() {
+                return "MB";
+            }
+        },
+        GIGABYTE {
+            @Override
+            public long bytes() {
+                return MEGABYTE.bytes() * KILOBYTE.bytes();
+            }
+            ;
+
+            @Override
+            public String symbol() {
+                return "GB";
+            }
+        };
+
+        public abstract long bytes();
+
+        public abstract String symbol();
+
+        public static ScaleUnit getScaleUnit(long size) {
+            if (size < 0L) {
+                throw new IllegalArgumentException("file size cannot be negative: " + size);
+            }
+
+            if (size >= GIGABYTE.bytes()) {
+                return GIGABYTE;
+            } else if (size >= MEGABYTE.bytes()) {
+                return MEGABYTE;
+            } else if (size >= KILOBYTE.bytes()) {
+                return KILOBYTE;
+            } else {
+                return BYTE;
+            }
+        }
+    }
+
+    public FileSizeFormat(Locale locale) {}
+
+    public String format(long size) {
+        return format(size, null);
+    }
+
+    public String format(long size, ScaleUnit unit) {
+        return format(size, unit, false);
+    }
+
+    public String format(long size, ScaleUnit unit, boolean omitSymbol) {
+        StringBuilder sb = new StringBuilder();
+        format(sb, size, unit, omitSymbol);
+        return sb.toString();
+    }
+
+    public void format(StringBuilder builder, long size) {
+        format(builder, size, null, false);
+    }
+
+    public void format(StringBuilder builder, long size, ScaleUnit unit) {
+        format(builder, size, unit, false);
+    }
+
+    @SuppressWarnings("checkstyle:magicnumber")
+    private void format(StringBuilder builder, long size, ScaleUnit unit, boolean omitSymbol) {
+        if (size < 0L) {
+            throw new IllegalArgumentException("file size cannot be negative: " + size);
+        }
+        if (unit == null) {
+            unit = ScaleUnit.getScaleUnit(size);
+        }
+
+        double scaledSize = (double) size / unit.bytes();
+
+        if (unit == ScaleUnit.BYTE) {
+            builder.append(size);
+        } else if (scaledSize < 0.05d || scaledSize >= 10.0d) {
+            builder.append(Math.round(scaledSize));
+        } else {
+            builder.append(Math.round(scaledSize * 10d) / 10d);
+        }
+
+        if (!omitSymbol) {
+            builder.append(" ").append(unit.symbol());
+        }
+    }
+
+    public String formatProgress(long progressedSize, long size) {
+        StringBuilder sb = new StringBuilder();
+        formatProgress(sb, progressedSize, size);
+        return sb.toString();
+    }
+
+    public void formatProgress(StringBuilder builder, long progressedSize, long size) {
+        if (progressedSize < 0L) {
+            throw new IllegalArgumentException("progressed file size cannot be negative: " + size);
+        }
+        if (size >= 0 && progressedSize > size) {
+            throw new IllegalArgumentException(
+                    "progressed file size cannot be greater than size: " + progressedSize + " > " + size);
+        }
+
+        if (size >= 0L && progressedSize != size) {
+            ScaleUnit unit = ScaleUnit.getScaleUnit(size);
+            format(builder, progressedSize, unit, true);
+            builder.append("/");
+            format(builder, size, unit, false);
+        } else {
+            ScaleUnit unit = ScaleUnit.getScaleUnit(progressedSize);
+
+            format(builder, progressedSize, unit, false);
+        }
+    }
+}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/QuietMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/QuietMavenTransferListener.java
index fd9f52c..400ad13 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/QuietMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/QuietMavenTransferListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.transfer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,14 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.transfer;
 
 import org.eclipse.aether.transfer.AbstractTransferListener;
 
 /**
- * @author Benjamin Bentmann
  */
-public class QuietMavenTransferListener
-    extends AbstractTransferListener
-{
-
-}
+public class QuietMavenTransferListener extends AbstractTransferListener {}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java
index 57e69ba..573b6ea 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/Slf4jMavenTransferListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.transfer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,10 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.transfer;
 
 import java.util.Locale;
 
-import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat;
 import org.eclipse.aether.transfer.AbstractTransferListener;
 import org.eclipse.aether.transfer.TransferCancelledException;
 import org.eclipse.aether.transfer.TransferEvent;
@@ -32,72 +30,70 @@
 /**
  * Slf4jMavenTransferListener
  */
-public class Slf4jMavenTransferListener
-    extends AbstractTransferListener
-{
+public class Slf4jMavenTransferListener extends AbstractTransferListener {
 
     protected final Logger out;
 
-    public Slf4jMavenTransferListener()
-    {
-        this.out = LoggerFactory.getLogger( Slf4jMavenTransferListener.class );
+    public Slf4jMavenTransferListener() {
+        this.out = LoggerFactory.getLogger(Slf4jMavenTransferListener.class);
     }
 
     // TODO should we deprecate?
-    public Slf4jMavenTransferListener( Logger out )
-    {
+    public Slf4jMavenTransferListener(Logger out) {
         this.out = out;
     }
 
     @Override
-    public void transferInitiated( TransferEvent event )
-    {
+    public void transferInitiated(TransferEvent event) {
         String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
 
         TransferResource resource = event.getResource();
         StringBuilder message = new StringBuilder();
-        message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
-        message.append( ": " );
-        message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
+        message.append(action).append(' ').append(direction).append(' ').append(resource.getRepositoryId());
+        message.append(": ");
+        message.append(resource.getRepositoryUrl()).append(resource.getResourceName());
 
-        out.info( message.toString() );
+        out.info(message.toString());
     }
 
     @Override
-    public void transferCorrupted( TransferEvent event )
-        throws TransferCancelledException
-    {
+    public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
         TransferResource resource = event.getResource();
-        out.warn( "{} from {} for {}{}", event.getException().getMessage(), resource.getRepositoryId(),
-            resource.getRepositoryUrl(), resource.getResourceName() );
+        out.warn(
+                "{} from {} for {}{}",
+                event.getException().getMessage(),
+                resource.getRepositoryId(),
+                resource.getRepositoryUrl(),
+                resource.getResourceName());
     }
 
     @Override
-    public void transferSucceeded( TransferEvent event )
-    {
-        String action = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
+    public void transferSucceeded(TransferEvent event) {
+        String action = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded");
         String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
 
         TransferResource resource = event.getResource();
         long contentLength = event.getTransferredBytes();
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
         StringBuilder message = new StringBuilder();
-        message.append( action ).append( ' ' ).append( direction ).append( ' ' ).append( resource.getRepositoryId() );
-        message.append( ": " );
-        message.append( resource.getRepositoryUrl() ).append( resource.getResourceName() );
-        message.append( " (" ).append( format.format( contentLength ) );
+        message.append(action).append(' ').append(direction).append(' ').append(resource.getRepositoryId());
+        message.append(": ");
+        message.append(resource.getRepositoryUrl())
+                .append(resource.getResourceName())
+                .append(" (");
+        format.format(message, contentLength);
 
         long duration = System.currentTimeMillis() - resource.getTransferStartTime();
-        if ( duration > 0L )
-        {
-            double bytesPerSecond = contentLength / ( duration / 1000.0 );
-            message.append( " at " ).append( format.format( (long) bytesPerSecond ) ).append( "/s" );
+        if (duration > 0L) {
+            double bytesPerSecond = contentLength / (duration / 1000.0);
+            message.append(" at ");
+            format.format(message, (long) bytesPerSecond);
+            message.append("/s");
         }
 
-        message.append( ')' );
-        out.info( message.toString() );
+        message.append(')');
+        out.info(message.toString());
     }
-
 }
diff --git a/maven-embedder/src/main/java/org/eclipse/sisu/plexus/PlexusXmlBeanConverter.java b/maven-embedder/src/main/java/org/eclipse/sisu/plexus/PlexusXmlBeanConverter.java
new file mode 100644
index 0000000..7ed8d31
--- /dev/null
+++ b/maven-embedder/src/main/java/org/eclipse/sisu/plexus/PlexusXmlBeanConverter.java
@@ -0,0 +1,395 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.eclipse.sisu.plexus;
+
+import javax.annotation.Priority;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+
+import java.io.StringReader;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.TypeConverter;
+import com.google.inject.spi.TypeConverterBinding;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.pull.MXParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.eclipse.sisu.bean.BeanProperties;
+import org.eclipse.sisu.bean.BeanProperty;
+import org.eclipse.sisu.inject.Logs;
+import org.eclipse.sisu.inject.TypeArguments;
+
+/**
+ * {@link PlexusBeanConverter} {@link Module} that converts Plexus XML configuration into beans.
+ */
+@Singleton
+@Priority(10)
+public final class PlexusXmlBeanConverter implements PlexusBeanConverter {
+    // ----------------------------------------------------------------------
+    // Constants
+    // ----------------------------------------------------------------------
+
+    private static final String CONVERSION_ERROR = "Cannot convert: \"%s\" to: %s";
+
+    // ----------------------------------------------------------------------
+    // Implementation fields
+    // ----------------------------------------------------------------------
+
+    private final Collection<TypeConverterBinding> typeConverterBindings;
+
+    // ----------------------------------------------------------------------
+    // Constructors
+    // ----------------------------------------------------------------------
+
+    @Inject
+    PlexusXmlBeanConverter(final Injector injector) {
+        typeConverterBindings = injector.getTypeConverterBindings();
+    }
+
+    // ----------------------------------------------------------------------
+    // Public methods
+    // ----------------------------------------------------------------------
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public Object convert(final TypeLiteral role, final String value) {
+        if (value.trim().startsWith("<")) {
+            try {
+                final MXParser parser = new MXParser();
+                parser.setInput(new StringReader(value));
+                parser.nextTag();
+
+                return parse(parser, role);
+            } catch (final Exception e) {
+                throw new IllegalArgumentException(String.format(CONVERSION_ERROR, value, role), e);
+            }
+        }
+
+        return convertText(value, role);
+    }
+
+    // ----------------------------------------------------------------------
+    // Implementation methods
+    // ----------------------------------------------------------------------
+
+    /**
+     * Parses a sequence of XML elements and converts them to the given target type.
+     *
+     * @param parser The XML parser
+     * @param toType The target type
+     * @return Converted instance of the target type
+     */
+    private Object parse(final MXParser parser, final TypeLiteral<?> toType) throws Exception {
+        parser.require(XmlPullParser.START_TAG, null, null);
+
+        final Class<?> rawType = toType.getRawType();
+        if (XmlNode.class.isAssignableFrom(rawType)) {
+            return XmlNodeBuilder.build(parser);
+        }
+        if (Xpp3Dom.class.isAssignableFrom(rawType)) {
+            return new Xpp3Dom(XmlNodeBuilder.build(parser));
+        }
+        if (Properties.class.isAssignableFrom(rawType)) {
+            return parseProperties(parser);
+        }
+        if (Map.class.isAssignableFrom(rawType)) {
+            return parseMap(parser, TypeArguments.get(toType.getSupertype(Map.class), 1));
+        }
+        if (Collection.class.isAssignableFrom(rawType)) {
+            return parseCollection(parser, TypeArguments.get(toType.getSupertype(Collection.class), 0));
+        }
+        if (rawType.isArray()) {
+            return parseArray(parser, TypeArguments.get(toType, 0));
+        }
+        return parseBean(parser, toType, rawType);
+    }
+
+    /**
+     * Parses a sequence of XML elements and converts them to the appropriate {@link Properties} type.
+     *
+     * @param parser The XML parser
+     * @return Converted Properties instance
+     */
+    private static Properties parseProperties(final XmlPullParser parser) throws Exception {
+        final Properties properties = newImplementation(parser, Properties.class);
+        while (parser.nextTag() == XmlPullParser.START_TAG) {
+            parser.nextTag();
+            // 'name-then-value' or 'value-then-name'
+            if ("name".equals(parser.getName())) {
+                final String name = parser.nextText();
+                parser.nextTag();
+                properties.put(name, parser.nextText());
+            } else {
+                final String value = parser.nextText();
+                parser.nextTag();
+                properties.put(parser.nextText(), value);
+            }
+            parser.nextTag();
+        }
+        return properties;
+    }
+
+    /**
+     * Parses a sequence of XML elements and converts them to the appropriate {@link Map} type.
+     *
+     * @param parser The XML parser
+     * @return Converted Map instance
+     */
+    private Map<String, Object> parseMap(final MXParser parser, final TypeLiteral<?> toType) throws Exception {
+        @SuppressWarnings("unchecked")
+        final Map<String, Object> map = newImplementation(parser, HashMap.class);
+        while (parser.nextTag() == XmlPullParser.START_TAG) {
+            map.put(parser.getName(), parse(parser, toType));
+        }
+        return map;
+    }
+
+    /**
+     * Parses a sequence of XML elements and converts them to the appropriate {@link Collection} type.
+     *
+     * @param parser The XML parser
+     * @return Converted Collection instance
+     */
+    private Collection<Object> parseCollection(final MXParser parser, final TypeLiteral<?> toType) throws Exception {
+        @SuppressWarnings("unchecked")
+        final Collection<Object> collection = newImplementation(parser, ArrayList.class);
+        while (parser.nextTag() == XmlPullParser.START_TAG) {
+            collection.add(parse(parser, toType));
+        }
+        return collection;
+    }
+
+    /**
+     * Parses a sequence of XML elements and converts them to the appropriate array type.
+     *
+     * @param parser The XML parser
+     * @return Converted array instance
+     */
+    private Object parseArray(final MXParser parser, final TypeLiteral<?> toType) throws Exception {
+        // convert to a collection first then convert that into an array
+        final Collection<?> collection = parseCollection(parser, toType);
+        final Object array = Array.newInstance(toType.getRawType(), collection.size());
+
+        int i = 0;
+        for (final Object element : collection) {
+            Array.set(array, i++, element);
+        }
+
+        return array;
+    }
+
+    /**
+     * Parses a sequence of XML elements and converts them to the appropriate bean type.
+     *
+     * @param parser The XML parser
+     * @return Converted bean instance
+     */
+    private Object parseBean(final MXParser parser, final TypeLiteral<?> toType, final Class<?> rawType)
+            throws Exception {
+        final Class<?> clazz = loadImplementation(parseImplementation(parser), rawType);
+
+        // simple bean? assumes string constructor
+        if (parser.next() == XmlPullParser.TEXT) {
+            final String text = parser.getText();
+
+            // confirm element doesn't contain nested XML
+            if (parser.next() != XmlPullParser.START_TAG) {
+                return convertText(text, clazz == rawType ? toType : TypeLiteral.get(clazz));
+            }
+        }
+
+        if (String.class == clazz) {
+            // mimic plexus: discard any strings containing nested XML
+            while (parser.getEventType() == XmlPullParser.START_TAG) {
+                final String pos = parser.getPositionDescription();
+                Logs.warn("Expected TEXT, not XML: {}", pos, new Throwable());
+                parser.skipSubTree();
+                parser.nextTag();
+            }
+            return "";
+        }
+
+        final Object bean = newImplementation(clazz);
+
+        // build map of all known bean properties belonging to the chosen implementation
+        final Map<String, BeanProperty<Object>> propertyMap = new HashMap<>();
+        for (final BeanProperty<Object> property : new BeanProperties(clazz)) {
+            final String name = property.getName();
+            if (!propertyMap.containsKey(name)) {
+                propertyMap.put(name, property);
+            }
+        }
+
+        while (parser.getEventType() == XmlPullParser.START_TAG) {
+            // update properties inside the bean, guided by the cached property map
+            final BeanProperty<Object> property = propertyMap.get(Roles.camelizeName(parser.getName()));
+            if (property != null) {
+                property.set(bean, parse(parser, property.getType()));
+                parser.nextTag();
+            } else {
+                throw new XmlPullParserException("Unknown bean property: " + parser.getName(), parser, null);
+            }
+        }
+
+        return bean;
+    }
+
+    /**
+     * Parses an XML element looking for the name of a custom implementation.
+     *
+     * @param parser The XML parser
+     * @return Name of the custom implementation; otherwise {@code null}
+     */
+    private static String parseImplementation(final XmlPullParser parser) {
+        return parser.getAttributeValue(null, "implementation");
+    }
+
+    /**
+     * Attempts to load the named implementation, uses default implementation if no name is given.
+     *
+     * @param name The optional implementation name
+     * @param defaultClazz The default implementation type
+     * @return Custom implementation type if one was given; otherwise default implementation type
+     */
+    private static Class<?> loadImplementation(final String name, final Class<?> defaultClazz) {
+        if (null == name) {
+            return defaultClazz; // just use the default type
+        }
+
+        // TCCL allows surrounding container to influence class loading policy
+        final ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+        if (tccl != null) {
+            try {
+                return tccl.loadClass(name);
+            } catch (final Exception e) {
+                // drop through...
+            } catch (final LinkageError e) {
+                // drop through...
+            }
+        }
+
+        // assume custom type is in same class space as default
+        final ClassLoader peer = defaultClazz.getClassLoader();
+        if (peer != null) {
+            try {
+                return peer.loadClass(name);
+            } catch (final Exception e) {
+                // drop through...
+            } catch (final LinkageError e) {
+                // drop through...
+            }
+        }
+
+        try {
+            // last chance - classic model
+            return Class.forName(name);
+        } catch (final Exception e) {
+            throw new TypeNotPresentException(name, e);
+        } catch (final LinkageError e) {
+            throw new TypeNotPresentException(name, e);
+        }
+    }
+
+    /**
+     * Creates an instance of the given implementation using the default constructor.
+     *
+     * @param clazz The implementation type
+     * @return Instance of given implementation
+     */
+    private static <T> T newImplementation(final Class<T> clazz) {
+        try {
+            return clazz.newInstance();
+        } catch (final Exception e) {
+            throw new IllegalArgumentException("Cannot create instance of: " + clazz, e);
+        } catch (final LinkageError e) {
+            throw new IllegalArgumentException("Cannot create instance of: " + clazz, e);
+        }
+    }
+
+    /**
+     * Creates an instance of the given implementation using the given string, assumes a public string constructor.
+     *
+     * @param clazz The implementation type
+     * @param value The string argument
+     * @return Instance of given implementation, constructed using the the given string
+     */
+    private static <T> T newImplementation(final Class<T> clazz, final String value) {
+        try {
+            return clazz.getConstructor(String.class).newInstance(value);
+        } catch (final Exception e) {
+            final Throwable cause = e instanceof InvocationTargetException ? e.getCause() : e;
+            throw new IllegalArgumentException(String.format(CONVERSION_ERROR, value, clazz), cause);
+        } catch (final LinkageError e) {
+            throw new IllegalArgumentException(String.format(CONVERSION_ERROR, value, clazz), e);
+        }
+    }
+
+    /**
+     * Creates an instance of the implementation named in the current XML element, or the default if no name is given.
+     *
+     * @param parser The XML parser
+     * @param defaultClazz The default implementation type
+     * @return Instance of custom implementation if one was given; otherwise instance of default type
+     */
+    @SuppressWarnings("unchecked")
+    private static <T> T newImplementation(final XmlPullParser parser, final Class<T> defaultClazz) {
+        return (T) newImplementation(loadImplementation(parseImplementation(parser), defaultClazz));
+    }
+
+    /**
+     * Converts the given string to the target type, using {@link TypeConverter}s registered with the {@link Injector}.
+     *
+     * @param value The string value
+     * @param toType The target type
+     * @return Converted instance of the target type
+     */
+    private Object convertText(final String value, final TypeLiteral<?> toType) {
+        final String text = value.trim();
+
+        final Class<?> rawType = toType.getRawType();
+        if (rawType.isAssignableFrom(String.class)) {
+            return text; // compatible type => no conversion needed
+        }
+
+        // use temporary Key as quick way to auto-box primitive types into their equivalent object types
+        final TypeLiteral<?> boxedType =
+                rawType.isPrimitive() ? Key.get(rawType).getTypeLiteral() : toType;
+
+        for (final TypeConverterBinding b : typeConverterBindings) {
+            if (b.getTypeMatcher().matches(boxedType)) {
+                return b.getTypeConverter().convert(text, toType);
+            }
+        }
+
+        // last chance => attempt to create an instance of the expected type: use the string if non-empty
+        return text.length() == 0 ? newImplementation(rawType) : newImplementation(rawType, text);
+    }
+}
diff --git a/maven-embedder/src/main/java/org/slf4j/MavenSlf4jFriend.java b/maven-embedder/src/main/java/org/slf4j/MavenSlf4jFriend.java
index 8a43053..b729879 100644
--- a/maven-embedder/src/main/java/org/slf4j/MavenSlf4jFriend.java
+++ b/maven-embedder/src/main/java/org/slf4j/MavenSlf4jFriend.java
@@ -1,5 +1,3 @@
-package org.slf4j;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.slf4j;
 
 /**
  * Utility for Maven to access Slf4j internals through package access.
  * Use with precaution, since this is not normally intended for production use.
  */
-public class MavenSlf4jFriend
-{
+public class MavenSlf4jFriend {
     /**
      * Reset Slf4j internal state.
      */
-    public static void reset()
-    {
+    public static void reset() {
         LoggerFactory.reset();
     }
 }
diff --git a/maven-embedder/src/main/java/org/slf4j/impl/MavenSlf4jSimpleFriend.java b/maven-embedder/src/main/java/org/slf4j/impl/MavenSlf4jSimpleFriend.java
index bffd18c..b511094 100644
--- a/maven-embedder/src/main/java/org/slf4j/impl/MavenSlf4jSimpleFriend.java
+++ b/maven-embedder/src/main/java/org/slf4j/impl/MavenSlf4jSimpleFriend.java
@@ -1,5 +1,3 @@
-package org.slf4j.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.slf4j.impl;
 
 import org.slf4j.ILoggerFactory;
 import org.slf4j.LoggerFactory;
@@ -26,15 +25,12 @@
  * Utility for Maven to access Slf4j-Simple internals through package access.
  * Use with precaution, since this is not normally intended for production use.
  */
-public class MavenSlf4jSimpleFriend
-{
-    public static void init()
-    {
+public class MavenSlf4jSimpleFriend {
+    public static void init() {
         SimpleLogger.init();
         ILoggerFactory loggerFactory = LoggerFactory.getILoggerFactory();
-        if ( loggerFactory instanceof SimpleLoggerFactory )
-        {
-            ( (SimpleLoggerFactory) loggerFactory ).reset();
+        if (loggerFactory instanceof SimpleLoggerFactory) {
+            ((SimpleLoggerFactory) loggerFactory).reset();
         }
     }
 }
diff --git a/maven-embedder/src/main/mdo/core-extensions.mdo b/maven-embedder/src/main/mdo/core-extensions.mdo
index 968258d..f0d5088 100644
--- a/maven-embedder/src/main/mdo/core-extensions.mdo
+++ b/maven-embedder/src/main/mdo/core-extensions.mdo
@@ -90,6 +90,12 @@
           <required>false</required>
           <type>String</type>
         </field>
+        <field>
+          <name>configuration</name>
+          <version>1.2.0+</version>
+          <required>false</required>
+          <type>DOM</type>
+        </field>
       </fields>
       <codeSegments>
         <codeSegment>
@@ -101,17 +107,10 @@
      *
      * @return The extension id in the form {@code <groupId>:<artifactId>:<version>}, never {@code null}.
      */
-    public String getId()
-    {
-        StringBuilder id = new StringBuilder( 128 );
-
-        id.append( ( getGroupId() == null ) ? "[unknown-group-id]" : getGroupId() );
-        id.append( ":" );
-        id.append( ( getArtifactId() == null ) ? "[unknown-artifact-id]" : getArtifactId() );
-        id.append( ":" );
-        id.append( ( getVersion() == null ) ? "[unknown-version]" : getVersion() );
-
-        return id.toString();
+    public String getId() {
+        return (getGroupId() == null ? "[unknown-group-id]" : getGroupId())
+            + ":" + (getArtifactId() == null ? "[unknown-artifact-id]" : getArtifactId())
+            + ":" + (getVersion() == null ? "[unknown-version]" : getVersion());
     }
             ]]>
           </code>
diff --git a/maven-embedder/src/site/apt/logging.apt b/maven-embedder/src/site/apt/logging.apt
index 7ff3129..3793ba7 100644
--- a/maven-embedder/src/site/apt/logging.apt
+++ b/maven-embedder/src/site/apt/logging.apt
@@ -25,7 +25,7 @@
 
 Maven Logging
 
- End-user logging documentation is available {{{/maven-logging.html}in Maven site}}.
+ {{{/maven-logging.html}End-user logging documentation}} is available {{{/maven-logging.html}in Maven site}}.
  This documentation is focused on internal implementation details.
 
 * Logging API
@@ -48,7 +48,7 @@
 
 * Logging Implementation
 
- Maven 3.1.0 ships bundled with {{{http://www.slf4j.org/apidocs/org/slf4j/impl/SimpleLogger.html}SLF4J simple logger}},
+ Maven 3.1.0 ships bundled with {{{https://www.slf4j.org/api/org/slf4j/simple/SimpleLogger.html}SLF4J simple logger}} and since 3.5.0 {{{../maven-slf4j-provider/}Maven-customized <<<maven-slf4j-provider>>>}},
  but is ready to use other logging implementations: SLF4J is responsible for loading the implementation, referred to as
  {{{http://www.slf4j.org/manual.html#swapping}"SLF4J bindings"}}.
 
@@ -62,6 +62,8 @@
  {{{./apidocs/org/apache/maven/cli/logging/Slf4jConfigurationFactory.html}Slf4jConfigurationFactory}} /
  {{{./apidocs/org/apache/maven/cli/logging/Slf4jConfiguration.html}Slf4jConfiguration}}.
 
+~~ TODO document META-INF/maven/slf4j-configuration.properties
+
 * Getting Logger Instance
 
  Starting with Maven 3.1.0, SLF4J Logger can be used directly. This technique can be used safely in Maven core
@@ -79,14 +81,7 @@
 
 * Logger Name
 
- Before Maven 3.1.0, with logging implementation done in Maven, logger name wasn't used by basic console logging implementation:
- they are as-is, without clear convention on when to pass logger from class to class or when to create a new logger.
+ Logger name is basically the classical fully qualified class name: it's not visible by default, but can be activated (see {{{/maven-logging.html}user documentation}}).
 
- Starting with Maven 3.1.0, logging implementation can be of greatest use if logger names are well defined. This definition still
- needs to be defined and implemented:
-
- * classical "class name" pattern?
-
- * Maven-specific name hierarchy?
-
- * a mix (some with class name, some with Maven-specific hierarchy)?
+ Notice that before Maven 3.1.0, with logger created by Maven, some code used to pass logger from class to class because it could not create a new logger:
+ discrepencies between logger name and actual class may happen.
diff --git a/maven-embedder/src/site/site.xml b/maven-embedder/src/site/site.xml
index 908e741..c1bd4a7 100644
--- a/maven-embedder/src/site/site.xml
+++ b/maven-embedder/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java
index a652eda..bae804f 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/CLIManagerDocumentationTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,92 +16,102 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
 import org.apache.commons.cli.Option;
-import org.codehaus.plexus.util.FileUtils;
+import org.apache.commons.io.FileUtils;
 import org.junit.jupiter.api.Test;
 
+import static java.util.Objects.nonNull;
+
 /**
  * Pseudo test to generate documentation fragment about supported CLI options. TODO such documentation generation code
  * should not be necessary as unit test but should be run during site generation (Velocity? Doxia macro?)
  */
-public class CLIManagerDocumentationTest
-{
-    private final static String LS = System.lineSeparator();
+class CLIManagerDocumentationTest {
+    private static final String LS = System.lineSeparator();
 
-    private static class OptionComparator
-        implements Comparator<Option>
-    {
-        public int compare( Option opt1, Option opt2 )
-        {
+    private static class OptionComparator implements Comparator<Option> {
+        public int compare(Option opt1, Option opt2) {
             String s1 = opt1.getOpt() != null ? opt1.getOpt() : opt1.getLongOpt();
             String s2 = opt2.getOpt() != null ? opt2.getOpt() : opt2.getLongOpt();
-            return s1.compareToIgnoreCase( s2 );
+            return s1.compareToIgnoreCase(s2);
         }
     }
 
-    private static class CLIManagerExtension
-        extends CLIManager
-    {
-        public Collection<Option> getOptions()
-        {
-            List<Option> optList = new ArrayList<>( options.getOptions() );
-            Collections.sort( optList, new OptionComparator() );
+    private static class CLIManagerExtension extends CLIManager {
+        public Collection<Option> getOptions() {
+            List<Option> optList = new ArrayList<>(options.getOptions());
+            optList.sort(new OptionComparator());
             return optList;
         }
     }
 
-    public String getOptionsAsHtml()
-    {
-        StringBuilder sb = new StringBuilder( 512 );
-        boolean a = true;
-        sb.append( "<table border='1' class='zebra-striped'><tr class='a'><th><b>Options</b></th><th><b>Description</b></th></tr>" );
-        for ( Option option : new CLIManagerExtension().getOptions() )
-        {
-            a = !a;
-            sb.append( "<tr class='" ).append( a ? 'a' : 'b' ).append( "'><td><code>-<a name='" );
-            sb.append( option.getOpt() );
-            sb.append( "'>" );
-            sb.append( option.getOpt() );
-            sb.append( "</a>,--<a name='" );
-            sb.append( option.getLongOpt() );
-            sb.append( "'>" );
-            sb.append( option.getLongOpt() );
-            sb.append( "</a>" );
-            if ( option.hasArg() )
-            {
-                if ( option.hasArgName() )
-                {
-                    sb.append( " &lt;" ).append( option.getArgName() ).append( "&gt;" );
+    String getOptionsAsHtml() {
+        StringBuilder sb = new StringBuilder(512);
+        boolean odd = true;
+        sb.append(
+                "<table border='1' class='zebra-striped'><tr class='a'><th><b>Options</b></th><th><b>Description</b></th></tr>");
+        for (Option option : new CLIManagerExtension().getOptions()) {
+            odd = !odd;
+            sb.append("<tr class='");
+            sb.append(odd ? 'a' : 'b');
+            sb.append("'>");
+
+            sb.append("<td>");
+
+            sb.append("<code>");
+
+            if (nonNull(option.getOpt())) {
+                sb.append("-<a name='");
+                sb.append(option.getOpt());
+                sb.append("'>");
+                sb.append(option.getOpt());
+                sb.append("</a>");
+            }
+
+            if (nonNull(option.getLongOpt())) {
+                if (nonNull(option.getOpt())) {
+                    sb.append(", ");
                 }
-                else
-                {
-                    sb.append( ' ' );
+                sb.append("--<a name='");
+                sb.append(option.getLongOpt());
+                sb.append("'>");
+                sb.append(option.getLongOpt());
+                sb.append("</a>");
+            }
+
+            if (option.hasArg()) {
+                if (option.hasArgName()) {
+                    sb.append(" &lt;").append(option.getArgName()).append("&gt;");
+                } else {
+                    sb.append(' ');
                 }
             }
-            sb.append( "</code></td><td>" );
-            sb.append( option.getDescription() );
-            sb.append( "</td></tr>" );
-            sb.append( LS );
+            sb.append("</code>");
+
+            sb.append("</td>");
+            sb.append("<td>");
+            sb.append(option.getDescription());
+            sb.append("</td>");
+
+            sb.append("</tr>");
+            sb.append(LS);
         }
-        sb.append( "</table>" );
+        sb.append("</table>");
         return sb.toString();
     }
 
     @Test
-    public void testOptionsAsHtml()
-        throws IOException
-    {
-        File options = new File( "target/test-classes/options.html" );
-        FileUtils.fileWrite( options, "UTF-8", getOptionsAsHtml() );
+    void testOptionsAsHtml() throws IOException {
+        File options = new File("target/test-classes/options.html");
+        FileUtils.write(options, getOptionsAsHtml(), "UTF-8");
     }
-
 }
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/CLIReportingUtilsTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/CLIReportingUtilsTest.java
index ac0cb30..f9c0aac 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/CLIReportingUtilsTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/CLIReportingUtilsTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,25 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
 
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class CLIReportingUtilsTest
-{
+class CLIReportingUtilsTest {
 
     @Test
-    public void testFormatDuration()
-    {
-        assertEquals( "0.001 s", CLIReportingUtils.formatDuration( 1 ) );
-        assertEquals( "0.999 s", CLIReportingUtils.formatDuration( 1000 - 1 ) );
-        assertEquals( "1.000 s", CLIReportingUtils.formatDuration( 1000 ) );
-        assertEquals( "59.999 s", CLIReportingUtils.formatDuration( 60 * 1000 - 1 ) );
-        assertEquals( "01:00 min", CLIReportingUtils.formatDuration( 60 * 1000 ) );
-        assertEquals( "59:59 min", CLIReportingUtils.formatDuration( 60 * 60 * 1000 - 1 ) );
-        assertEquals( "01:00 h", CLIReportingUtils.formatDuration( 60 * 60 * 1000 ) );
-        assertEquals( "23:59 h", CLIReportingUtils.formatDuration( 24 * 60 * 60 * 1000 - 1 ) );
-        assertEquals( "1 d 00:00 h", CLIReportingUtils.formatDuration( 24 * 60 * 60 * 1000 ) );
+    void testFormatDuration() {
+        assertEquals("0.001 s", CLIReportingUtils.formatDuration(1));
+        assertEquals("0.999 s", CLIReportingUtils.formatDuration(1000 - 1));
+        assertEquals("1.000 s", CLIReportingUtils.formatDuration(1000));
+        assertEquals("59.999 s", CLIReportingUtils.formatDuration(60 * 1000 - 1));
+        assertEquals("01:00 min", CLIReportingUtils.formatDuration(60 * 1000));
+        assertEquals("59:59 min", CLIReportingUtils.formatDuration(60 * 60 * 1000 - 1));
+        assertEquals("01:00 h", CLIReportingUtils.formatDuration(60 * 60 * 1000));
+        assertEquals("23:59 h", CLIReportingUtils.formatDuration(24 * 60 * 60 * 1000 - 1));
+        assertEquals("1 d 00:00 h", CLIReportingUtils.formatDuration(24 * 60 * 60 * 1000));
     }
 }
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/CleanArgumentTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/CleanArgumentTest.java
index 1624be1..fb4bcd2 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/CleanArgumentTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/CleanArgumentTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,44 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
+package org.apache.maven.cli;
 
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
 /**
- * @author Karl Heinz Marbaise
  */
-public class CleanArgumentTest
-{
+class CleanArgumentTest {
     @Test
-    public void cleanArgsShouldRemoveWrongSurroundingQuotes()
-    {
-        String[] args = { "\"-Dfoo=bar", "\"-Dfoo2=bar two\"" };
-        String[] cleanArgs = CleanArgument.cleanArgs( args );
-        assertEquals( args.length, cleanArgs.length );
-        assertEquals( "-Dfoo=bar", cleanArgs[0] );
-        assertEquals( "-Dfoo2=bar two", cleanArgs[1] );
+    void cleanArgsShouldRemoveWrongSurroundingQuotes() {
+        String[] args = {"\"-Dfoo=bar", "\"-Dfoo2=bar two\""};
+        String[] cleanArgs = CleanArgument.cleanArgs(args);
+        assertEquals(args.length, cleanArgs.length);
+        assertEquals("-Dfoo=bar", cleanArgs[0]);
+        assertEquals("-Dfoo2=bar two", cleanArgs[1]);
     }
 
     @Test
-    public void testCleanArgsShouldNotTouchCorrectlyQuotedArgumentsUsingDoubleQuotes()
-    {
+    void testCleanArgsShouldNotTouchCorrectlyQuotedArgumentsUsingDoubleQuotes() {
         String information = "-Dinformation=\"The Information is important.\"";
-        String[] args = { information };
-        String[] cleanArgs = CleanArgument.cleanArgs( args );
-        assertEquals( args.length, cleanArgs.length );
-        assertEquals( information, cleanArgs[0] );
+        String[] args = {information};
+        String[] cleanArgs = CleanArgument.cleanArgs(args);
+        assertEquals(args.length, cleanArgs.length);
+        assertEquals(information, cleanArgs[0]);
     }
 
     @Test
-    public void testCleanArgsShouldNotTouchCorrectlyQuotedArgumentsUsingSingleQuotes()
-    {
+    void testCleanArgsShouldNotTouchCorrectlyQuotedArgumentsUsingSingleQuotes() {
         String information = "-Dinformation='The Information is important.'";
-        String[] args = { information };
-        String[] cleanArgs = CleanArgument.cleanArgs( args );
-        assertEquals( args.length, cleanArgs.length );
-        assertEquals( information, cleanArgs[0] );
+        String[] args = {information};
+        String[] cleanArgs = CleanArgument.cleanArgs(args);
+        assertEquals(args.length, cleanArgs.length);
+        assertEquals(information, cleanArgs[0]);
     }
-
 }
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
index c4ddcb8..a68976b 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,55 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Stream;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+import org.apache.maven.Maven;
+import org.apache.maven.cli.jansi.MessageUtils;
+import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
+import org.apache.maven.cli.transfer.QuietMavenTransferListener;
+import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
+import org.apache.maven.eventspy.internal.EventSpyDispatcher;
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.execution.ProfileActivation;
+import org.apache.maven.execution.ProjectActivation;
+import org.apache.maven.model.root.DefaultRootLocator;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.toolchain.building.ToolchainsBuildingRequest;
+import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
+import org.codehaus.plexus.DefaultPlexusContainer;
+import org.codehaus.plexus.PlexusContainer;
+import org.eclipse.aether.transfer.TransferListener;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+import org.mockito.InOrder;
 
 import static java.util.Arrays.asList;
 import static org.apache.maven.cli.MavenCli.performProfileActivation;
 import static org.apache.maven.cli.MavenCli.performProjectActivation;
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -37,184 +77,130 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.PrintStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.Option;
-import org.apache.commons.cli.Options;
-import org.apache.commons.cli.ParseException;
-import org.apache.maven.Maven;
-import org.apache.maven.eventspy.internal.EventSpyDispatcher;
-import org.apache.maven.execution.MavenExecutionRequest;
-import org.apache.maven.execution.ProfileActivation;
-import org.apache.maven.execution.ProjectActivation;
-import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageUtils;
-import org.apache.maven.toolchain.building.ToolchainsBuildingRequest;
-import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
-import org.codehaus.plexus.DefaultPlexusContainer;
-import org.codehaus.plexus.PlexusContainer;
-import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.InOrder;
-
-public class MavenCliTest
-{
+class MavenCliTest {
     private MavenCli cli;
 
     private String origBasedir;
 
     @BeforeEach
-    public void setUp()
-    {
+    void setUp() {
         cli = new MavenCli();
-        origBasedir = System.getProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY );
+        origBasedir = System.getProperty(MavenCli.MULTIMODULE_PROJECT_DIRECTORY);
     }
 
     @AfterEach
-    public void tearDown()
-        throws Exception
-    {
-        if ( origBasedir != null )
-        {
-            System.setProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY, origBasedir );
-        }
-        else
-        {
-            System.getProperties().remove( MavenCli.MULTIMODULE_PROJECT_DIRECTORY );
+    void tearDown() throws Exception {
+        if (origBasedir != null) {
+            System.setProperty(MavenCli.MULTIMODULE_PROJECT_DIRECTORY, origBasedir);
+        } else {
+            System.getProperties().remove(MavenCli.MULTIMODULE_PROJECT_DIRECTORY);
         }
     }
 
     @Test
-    public void testPerformProfileActivation() throws ParseException
-    {
+    void testPerformProfileActivation() throws ParseException {
         final CommandLineParser parser = new DefaultParser();
 
         final Options options = new Options();
-        options.addOption( Option.builder( Character.toString( CLIManager.ACTIVATE_PROFILES ) ).hasArg().build() );
+        options.addOption(Option.builder(Character.toString(CLIManager.ACTIVATE_PROFILES))
+                .hasArg()
+                .build());
 
         ProfileActivation activation;
 
         activation = new ProfileActivation();
-        performProfileActivation( parser.parse( options, new String[]{ "-P", "test1,+test2,?test3,+?test4" } ), activation );
-        assertThat( activation.getRequiredActiveProfileIds(), containsInAnyOrder( "test1", "test2" ) );
-        assertThat( activation.getOptionalActiveProfileIds(), containsInAnyOrder( "test3", "test4" ) );
+        performProfileActivation(parser.parse(options, new String[] {"-P", "test1,+test2,?test3,+?test4"}), activation);
+        assertThat(activation.getRequiredActiveProfileIds(), containsInAnyOrder("test1", "test2"));
+        assertThat(activation.getOptionalActiveProfileIds(), containsInAnyOrder("test3", "test4"));
 
         activation = new ProfileActivation();
-        performProfileActivation( parser.parse( options, new String[]{ "-P", "!test1,-test2,-?test3,!?test4" } ), activation );
-        assertThat( activation.getRequiredInactiveProfileIds(), containsInAnyOrder( "test1", "test2" ) );
-        assertThat( activation.getOptionalInactiveProfileIds(), containsInAnyOrder( "test3", "test4" ) );
+        performProfileActivation(
+                parser.parse(options, new String[] {"-P", "!test1,-test2,-?test3,!?test4"}), activation);
+        assertThat(activation.getRequiredInactiveProfileIds(), containsInAnyOrder("test1", "test2"));
+        assertThat(activation.getOptionalInactiveProfileIds(), containsInAnyOrder("test3", "test4"));
 
         activation = new ProfileActivation();
-        performProfileActivation( parser.parse( options, new String[]{ "-P", "-test1,+test2" } ), activation );
-        assertThat( activation.getRequiredActiveProfileIds(), containsInAnyOrder( "test2" ) );
-        assertThat( activation.getRequiredInactiveProfileIds(), containsInAnyOrder( "test1" ) );
+        performProfileActivation(parser.parse(options, new String[] {"-P", "-test1,+test2"}), activation);
+        assertThat(activation.getRequiredActiveProfileIds(), containsInAnyOrder("test2"));
+        assertThat(activation.getRequiredInactiveProfileIds(), containsInAnyOrder("test1"));
     }
 
     @Test
-    public void testDetermineProjectActivation() throws ParseException
-    {
+    void testDetermineProjectActivation() throws ParseException {
         final CommandLineParser parser = new DefaultParser();
 
         final Options options = new Options();
-        options.addOption( Option.builder( CLIManager.PROJECT_LIST ).hasArg().build() );
+        options.addOption(Option.builder(CLIManager.PROJECT_LIST).hasArg().build());
 
         ProjectActivation activation;
 
         activation = new ProjectActivation();
-        performProjectActivation( parser.parse( options, new String[]{ "-pl", "test1,+test2,?test3,+?test4" } ), activation );
-        assertThat( activation.getRequiredActiveProjectSelectors(), containsInAnyOrder( "test1", "test2" ) );
-        assertThat( activation.getOptionalActiveProjectSelectors(), containsInAnyOrder( "test3", "test4" ) );
+        performProjectActivation(
+                parser.parse(options, new String[] {"-pl", "test1,+test2,?test3,+?test4"}), activation);
+        assertThat(activation.getRequiredActiveProjectSelectors(), containsInAnyOrder("test1", "test2"));
+        assertThat(activation.getOptionalActiveProjectSelectors(), containsInAnyOrder("test3", "test4"));
 
         activation = new ProjectActivation();
-        performProjectActivation( parser.parse( options, new String[]{ "-pl", "!test1,-test2,-?test3,!?test4" } ), activation );
-        assertThat( activation.getRequiredInactiveProjectSelectors(), containsInAnyOrder( "test1", "test2" ) );
-        assertThat( activation.getOptionalInactiveProjectSelectors(), containsInAnyOrder( "test3", "test4" ) );
+        performProjectActivation(
+                parser.parse(options, new String[] {"-pl", "!test1,-test2,-?test3,!?test4"}), activation);
+        assertThat(activation.getRequiredInactiveProjectSelectors(), containsInAnyOrder("test1", "test2"));
+        assertThat(activation.getOptionalInactiveProjectSelectors(), containsInAnyOrder("test3", "test4"));
 
         activation = new ProjectActivation();
-        performProjectActivation( parser.parse( options, new String[]{ "-pl", "-test1,+test2" } ), activation );
-        assertThat( activation.getRequiredActiveProjectSelectors(), containsInAnyOrder( "test2" ) );
-        assertThat( activation.getRequiredInactiveProjectSelectors(), containsInAnyOrder( "test1" ) );
+        performProjectActivation(parser.parse(options, new String[] {"-pl", "-test1,+test2"}), activation);
+        assertThat(activation.getRequiredActiveProjectSelectors(), containsInAnyOrder("test2"));
+        assertThat(activation.getRequiredInactiveProjectSelectors(), containsInAnyOrder("test1"));
     }
 
     @Test
-    public void testCalculateDegreeOfConcurrency()
-    {
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "0" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "-1" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "0x4" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "1.0" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "1." ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "AA" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "C" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "C2.2C" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "C2.2" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "2C2" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "CXXX" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "XXXC" ) );
+    void testCalculateDegreeOfConcurrency() {
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("0"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("-1"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("0x4"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("1.0"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("1."));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("AA"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("C"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("C2.2C"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("C2.2"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("2C2"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("CXXX"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("XXXC"));
 
         int cpus = Runtime.getRuntime().availableProcessors();
-        assertEquals( (int) ( cpus * 2.2 ), cli.calculateDegreeOfConcurrency( "2.2C" ) );
-        assertEquals( 1, cli.calculateDegreeOfConcurrency( "0.0001C" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "2.C" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "-2.2C" ) );
-        assertThrows( IllegalArgumentException.class,
-                () -> cli.calculateDegreeOfConcurrency( "0C" ) );
-
+        assertEquals((int) (cpus * 2.2), cli.calculateDegreeOfConcurrency("2.2C"));
+        assertEquals(1, cli.calculateDegreeOfConcurrency("0.0001C"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("-2.2C"));
+        assertThrows(IllegalArgumentException.class, () -> cli.calculateDegreeOfConcurrency("0C"));
     }
 
     @Test
-    public void testMavenConfig()
-        throws Exception
-    {
-        System.setProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
-                            new File( "src/test/projects/config" ).getCanonicalPath() );
-        CliRequest request = new CliRequest( new String[0], null );
+    void testMavenConfig() throws Exception {
+        System.setProperty(
+                MavenCli.MULTIMODULE_PROJECT_DIRECTORY, new File("src/test/projects/config").getCanonicalPath());
+        CliRequest request = new CliRequest(new String[0], null);
 
         // read .mvn/maven.config
-        cli.initialize( request );
-        cli.cli( request );
-        assertEquals( "multithreaded", request.commandLine.getOptionValue( CLIManager.BUILDER ) );
-        assertEquals( "8", request.commandLine.getOptionValue( CLIManager.THREADS ) );
+        cli.initialize(request);
+        cli.cli(request);
+        assertEquals("multithreaded", request.commandLine.getOptionValue(CLIManager.BUILDER));
+        assertEquals("8", request.commandLine.getOptionValue(CLIManager.THREADS));
 
         // override from command line
-        request = new CliRequest( new String[]{ "--builder", "foobar" }, null );
-        cli.cli( request );
-        assertEquals( "foobar", request.commandLine.getOptionValue( "builder" ) );
+        request = new CliRequest(new String[] {"--builder", "foobar"}, null);
+        cli.cli(request);
+        assertEquals("foobar", request.commandLine.getOptionValue("builder"));
     }
 
     @Test
-    public void testMavenConfigInvalid()
-        throws Exception
-    {
-        System.setProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
-                            new File( "src/test/projects/config-illegal" ).getCanonicalPath() );
-        CliRequest request = new CliRequest( new String[0], null );
+    void testMavenConfigInvalid() throws Exception {
+        System.setProperty(
+                MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
+                new File("src/test/projects/config-illegal").getCanonicalPath());
+        CliRequest request = new CliRequest(new String[0], null);
 
-        cli.initialize( request );
-        assertThrows( ParseException.class, () -> cli.cli( request ) );
+        cli.initialize(request);
+        assertThrows(ParseException.class, () -> cli.cli(request));
     }
 
     /**
@@ -231,18 +217,17 @@
      * @throws Exception in case of failure.
      */
     @Test
-    public void testMVNConfigurationThreadCanBeOverwrittenViaCommandLine()
-        throws Exception
-    {
-        System.setProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
-                            new File( "src/test/projects/mavenConfigProperties" ).getCanonicalPath() );
-        CliRequest request = new CliRequest( new String[]{ "-T", "5" }, null );
+    void testMVNConfigurationThreadCanBeOverwrittenViaCommandLine() throws Exception {
+        System.setProperty(
+                MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
+                new File("src/test/projects/mavenConfigProperties").getCanonicalPath());
+        CliRequest request = new CliRequest(new String[] {"-T", "5"}, null);
 
-        cli.initialize( request );
+        cli.initialize(request);
         // read .mvn/maven.config
-        cli.cli( request );
+        cli.cli(request);
 
-        assertEquals( "5", request.commandLine.getOptionValue( CLIManager.THREADS ) );
+        assertEquals("5", request.commandLine.getOptionValue(CLIManager.THREADS));
     }
 
     /**
@@ -259,20 +244,19 @@
      * @throws Exception
      */
     @Test
-    public void testMVNConfigurationDefinedPropertiesCanBeOverwrittenViaCommandLine()
-        throws Exception
-    {
-        System.setProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
-                            new File( "src/test/projects/mavenConfigProperties" ).getCanonicalPath() );
-        CliRequest request = new CliRequest( new String[]{ "-Drevision=8.1.0" }, null );
+    void testMVNConfigurationDefinedPropertiesCanBeOverwrittenViaCommandLine() throws Exception {
+        System.setProperty(
+                MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
+                new File("src/test/projects/mavenConfigProperties").getCanonicalPath());
+        CliRequest request = new CliRequest(new String[] {"-Drevision=8.1.0"}, null);
 
-        cli.initialize( request );
+        cli.initialize(request);
         // read .mvn/maven.config
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
-        String revision = System.getProperty( "revision" );
-        assertEquals( "8.1.0", revision );
+        String revision = request.getUserProperties().getProperty("revision");
+        assertEquals("8.1.0", revision);
     }
 
     /**
@@ -289,20 +273,19 @@
      * @throws Exception
      */
     @Test
-    public void testMVNConfigurationCLIRepeatedPropertiesLastWins()
-        throws Exception
-    {
-        System.setProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
-                            new File( "src/test/projects/mavenConfigProperties" ).getCanonicalPath() );
-        CliRequest request = new CliRequest( new String[]{ "-Drevision=8.1.0", "-Drevision=8.2.0" }, null );
+    void testMVNConfigurationCLIRepeatedPropertiesLastWins() throws Exception {
+        System.setProperty(
+                MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
+                new File("src/test/projects/mavenConfigProperties").getCanonicalPath());
+        CliRequest request = new CliRequest(new String[] {"-Drevision=8.1.0", "-Drevision=8.2.0"}, null);
 
-        cli.initialize( request );
+        cli.initialize(request);
         // read .mvn/maven.config
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
-        String revision = System.getProperty( "revision" );
-        assertEquals( "8.2.0", revision );
+        String revision = request.getUserProperties().getProperty("revision");
+        assertEquals("8.2.0", revision);
     }
 
     /**
@@ -319,92 +302,104 @@
      * @throws Exception
      */
     @Test
-    public void testMVNConfigurationFunkyArguments()
-        throws Exception
-    {
-        System.setProperty( MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
-                            new File( "src/test/projects/mavenConfigProperties" ).getCanonicalPath() );
+    void testMVNConfigurationFunkyArguments() throws Exception {
+        System.setProperty(
+                MavenCli.MULTIMODULE_PROJECT_DIRECTORY,
+                new File("src/test/projects/mavenConfigProperties").getCanonicalPath());
         CliRequest request = new CliRequest(
-            new String[]{ "-Drevision=8.1.0", "--file=-Dpom.xml", "\"-Dfoo=bar ", "\"-Dfoo2=bar two\"",
-                "-Drevision=8.2.0" }, null );
+                new String[] {
+                    "-Drevision=8.1.0", "--file=-Dpom.xml", "\"-Dfoo=bar ", "\"-Dfoo2=bar two\"", "-Drevision=8.2.0"
+                },
+                null);
 
-        cli.initialize( request );
+        cli.initialize(request);
         // read .mvn/maven.config
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
-        assertEquals( "3", request.commandLine.getOptionValue( CLIManager.THREADS ) );
+        assertEquals("3", request.commandLine.getOptionValue(CLIManager.THREADS));
 
-        String revision = System.getProperty( "revision" );
-        assertEquals( "8.2.0", revision );
+        String revision = request.getUserProperties().getProperty("revision");
+        assertEquals("8.2.0", revision);
 
-        assertEquals( "bar ", request.getSystemProperties().getProperty( "foo" ) );
-        assertEquals( "bar two", request.getSystemProperties().getProperty( "foo2" ) );
-        assertEquals( "Apache Maven", request.getSystemProperties().getProperty( "label" ) );
+        assertEquals("bar ", request.getUserProperties().getProperty("foo"));
+        assertEquals("bar two", request.getUserProperties().getProperty("foo2"));
+        assertEquals("Apache Maven", request.getUserProperties().getProperty("label"));
 
-        assertEquals( "-Dpom.xml", request.getCommandLine().getOptionValue( CLIManager.ALTERNATE_POM_FILE ) );
+        assertEquals("-Dpom.xml", request.getCommandLine().getOptionValue(CLIManager.ALTERNATE_POM_FILE));
     }
 
     @Test
-    public void testStyleColors()
-        throws Exception
-    {
-        assumeTrue( MessageUtils.isColorEnabled(), "ANSI not supported" );
+    void testStyleColors() throws Exception {
+        assumeTrue(MessageUtils.isColorEnabled(), "ANSI not supported");
         CliRequest request;
 
-        MessageUtils.setColorEnabled( true );
-        request = new CliRequest( new String[] { "-B" }, null );
-        cli.cli( request );
-        cli.properties( request );
-        cli.logging( request );
-        assertFalse( MessageUtils.isColorEnabled() );
+        MessageUtils.setColorEnabled(true);
+        request = new CliRequest(new String[] {"-B"}, null);
+        cli.cli(request);
+        cli.properties(request);
+        cli.logging(request);
+        assertFalse(MessageUtils.isColorEnabled());
 
-        MessageUtils.setColorEnabled( true );
-        request = new CliRequest( new String[] { "-l", "target/temp/mvn.log" }, null );
+        MessageUtils.setColorEnabled(true);
+        request = new CliRequest(new String[] {"--non-interactive"}, null);
+        cli.cli(request);
+        cli.properties(request);
+        cli.logging(request);
+        assertFalse(MessageUtils.isColorEnabled());
+
+        MessageUtils.setColorEnabled(true);
+        request = new CliRequest(new String[] {"--force-interactive", "--non-interactive"}, null);
+        cli.cli(request);
+        cli.properties(request);
+        cli.logging(request);
+        assertTrue(MessageUtils.isColorEnabled());
+
+        MessageUtils.setColorEnabled(true);
+        request = new CliRequest(new String[] {"-l", "target/temp/mvn.log"}, null);
         request.workingDirectory = "target/temp";
-        cli.cli( request );
-        cli.properties( request );
-        cli.logging( request );
-        assertFalse( MessageUtils.isColorEnabled() );
+        cli.cli(request);
+        cli.properties(request);
+        cli.logging(request);
+        assertFalse(MessageUtils.isColorEnabled());
 
-        MessageUtils.setColorEnabled( false );
-        request = new CliRequest( new String[] { "-Dstyle.color=always" }, null );
-        cli.cli( request );
-        cli.properties( request );
-        cli.logging( request );
-        assertTrue( MessageUtils.isColorEnabled() );
+        MessageUtils.setColorEnabled(false);
+        request = new CliRequest(new String[] {"-Dstyle.color=always"}, null);
+        cli.cli(request);
+        cli.properties(request);
+        cli.logging(request);
+        assertTrue(MessageUtils.isColorEnabled());
 
-        MessageUtils.setColorEnabled( true );
-        request = new CliRequest( new String[] { "-Dstyle.color=never" }, null );
-        cli.cli( request );
-        cli.properties( request );
-        cli.logging( request );
-        assertFalse( MessageUtils.isColorEnabled() );
+        MessageUtils.setColorEnabled(true);
+        request = new CliRequest(new String[] {"-Dstyle.color=never"}, null);
+        cli.cli(request);
+        cli.properties(request);
+        cli.logging(request);
+        assertFalse(MessageUtils.isColorEnabled());
 
-        MessageUtils.setColorEnabled( false );
-        request = new CliRequest( new String[] { "-Dstyle.color=always", "-B", "-l", "target/temp/mvn.log" }, null );
+        MessageUtils.setColorEnabled(false);
+        request = new CliRequest(new String[] {"-Dstyle.color=always", "-B", "-l", "target/temp/mvn.log"}, null);
         request.workingDirectory = "target/temp";
-        cli.cli( request );
-        cli.properties( request );
-        cli.logging( request );
-        assertTrue( MessageUtils.isColorEnabled() );
+        cli.cli(request);
+        cli.properties(request);
+        cli.logging(request);
+        assertTrue(MessageUtils.isColorEnabled());
 
-        MessageUtils.setColorEnabled( false );
-        CliRequest maybeColorRequest = new CliRequest( new String[] { "-Dstyle.color=maybe", "-B", "-l", "target/temp/mvn.log" }, null );
+        MessageUtils.setColorEnabled(false);
+        CliRequest maybeColorRequest =
+                new CliRequest(new String[] {"-Dstyle.color=maybe", "-B", "-l", "target/temp/mvn.log"}, null);
         request.workingDirectory = "target/temp";
-        cli.cli( maybeColorRequest );
-        cli.properties( maybeColorRequest );
+        cli.cli(maybeColorRequest);
+        cli.properties(maybeColorRequest);
         assertThrows(
-                IllegalArgumentException.class,
-                () -> cli.logging( maybeColorRequest ),
-                "maybe is not a valid option" );
+                IllegalArgumentException.class, () -> cli.logging(maybeColorRequest), "maybe is not a valid option");
     }
 
     /**
      * Verifies MNG-6558
      */
     @Test
-    public void testToolchainsBuildingEvents() throws Exception {
+    void testToolchainsBuildingEvents() throws Exception {
         final EventSpyDispatcher eventSpyDispatcherMock = mock(EventSpyDispatcher.class);
         MavenCli customizedMavenCli = new MavenCli() {
             @Override
@@ -412,12 +407,13 @@
                 super.customizeContainer(container);
                 container.addComponent(mock(Maven.class), "org.apache.maven.Maven");
 
-                ( (DefaultPlexusContainer) container ).addPlexusInjector( Collections.emptyList(),
-                        binder -> binder.bind( EventSpyDispatcher.class ).toInstance( eventSpyDispatcherMock ) );
+                ((DefaultPlexusContainer) container)
+                        .addPlexusInjector(Collections.emptyList(), binder -> binder.bind(EventSpyDispatcher.class)
+                                .toInstance(eventSpyDispatcherMock));
             }
         };
 
-        CliRequest cliRequest = new CliRequest(new String[]{}, null);
+        CliRequest cliRequest = new CliRequest(new String[] {}, null);
 
         customizedMavenCli.cli(cliRequest);
         customizedMavenCli.logging(cliRequest);
@@ -425,64 +421,58 @@
         customizedMavenCli.toolchains(cliRequest);
 
         InOrder orderedEventSpyDispatcherMock = inOrder(eventSpyDispatcherMock);
-        orderedEventSpyDispatcherMock.verify(eventSpyDispatcherMock, times(1)).onEvent(any(ToolchainsBuildingRequest.class));
-        orderedEventSpyDispatcherMock.verify(eventSpyDispatcherMock, times(1)).onEvent(any(ToolchainsBuildingResult.class));
+        orderedEventSpyDispatcherMock
+                .verify(eventSpyDispatcherMock, times(1))
+                .onEvent(any(ToolchainsBuildingRequest.class));
+        orderedEventSpyDispatcherMock
+                .verify(eventSpyDispatcherMock, times(1))
+                .onEvent(any(ToolchainsBuildingResult.class));
     }
 
     @Test
-    public void resumeFromSelectorIsSuggestedWithoutGroupId()
-    {
-        List<MavenProject> allProjects = asList(
-                createMavenProject( "group", "module-a" ),
-                createMavenProject( "group", "module-b" ) );
-        MavenProject failedProject = allProjects.get( 0 );
+    void resumeFromSelectorIsSuggestedWithoutGroupId() {
+        List<MavenProject> allProjects =
+                asList(createMavenProject("group", "module-a"), createMavenProject("group", "module-b"));
+        MavenProject failedProject = allProjects.get(0);
 
-        String selector = cli.getResumeFromSelector( allProjects, failedProject );
+        String selector = cli.getResumeFromSelector(allProjects, failedProject);
 
-        assertThat( selector, is( ":module-a" ) );
+        assertThat(selector, is(":module-a"));
     }
 
     @Test
-    public void resumeFromSelectorContainsGroupIdWhenArtifactIdIsNotUnique()
-    {
-        List<MavenProject> allProjects = asList(
-                createMavenProject( "group-a", "module" ),
-                createMavenProject( "group-b", "module" ) );
-        MavenProject failedProject = allProjects.get( 0 );
+    void resumeFromSelectorContainsGroupIdWhenArtifactIdIsNotUnique() {
+        List<MavenProject> allProjects =
+                asList(createMavenProject("group-a", "module"), createMavenProject("group-b", "module"));
+        MavenProject failedProject = allProjects.get(0);
 
-        String selector = cli.getResumeFromSelector( allProjects, failedProject );
+        String selector = cli.getResumeFromSelector(allProjects, failedProject);
 
-        assertThat( selector, is( "group-a:module" ) );
+        assertThat(selector, is("group-a:module"));
     }
 
     @Test
-    public void verifyLocalRepositoryPath()
-    {
+    void verifyLocalRepositoryPath() {
         MavenCli cli = new MavenCli();
-        CliRequest request = new CliRequest( new String[] { }, null );
+        CliRequest request = new CliRequest(new String[] {}, null);
         request.commandLine = new CommandLine.Builder().build();
         MavenExecutionRequest executionRequest;
 
         // Use default
-        executionRequest = cli.populateRequest( request );
-        assertThat( executionRequest.getLocalRepositoryPath(),
-                is( nullValue() ) );
+        executionRequest = cli.populateRequest(request);
+        assertThat(executionRequest.getLocalRepositoryPath(), is(nullValue()));
 
         // System-properties override default
-        request.getSystemProperties().setProperty( MavenCli.LOCAL_REPO_PROPERTY, "." + File.separatorChar + "custom1" );
-        executionRequest = cli.populateRequest( request );
-        assertThat( executionRequest.getLocalRepositoryPath(),
-                is( notNullValue() ) );
-        assertThat( executionRequest.getLocalRepositoryPath().toString(),
-                is( "." + File.separatorChar + "custom1" ) );
+        request.getSystemProperties().setProperty(MavenCli.LOCAL_REPO_PROPERTY, "." + File.separatorChar + "custom1");
+        executionRequest = cli.populateRequest(request);
+        assertThat(executionRequest.getLocalRepositoryPath(), is(notNullValue()));
+        assertThat(executionRequest.getLocalRepositoryPath().toString(), is("." + File.separatorChar + "custom1"));
 
         // User-properties override system properties
-        request.getUserProperties().setProperty( MavenCli.LOCAL_REPO_PROPERTY, "." + File.separatorChar + "custom2" );
-        executionRequest = cli.populateRequest( request );
-        assertThat( executionRequest.getLocalRepositoryPath(),
-                is( notNullValue() ) );
-        assertThat( executionRequest.getLocalRepositoryPath().toString(),
-                is( "." + File.separatorChar + "custom2" ) );
+        request.getUserProperties().setProperty(MavenCli.LOCAL_REPO_PROPERTY, "." + File.separatorChar + "custom2");
+        executionRequest = cli.populateRequest(request);
+        assertThat(executionRequest.getLocalRepositoryPath(), is(notNullValue()));
+        assertThat(executionRequest.getLocalRepositoryPath().toString(), is("." + File.separatorChar + "custom2"));
     }
 
     /**
@@ -490,109 +480,199 @@
      * @throws Exception cli invocation.
      */
     @Test
-    public void testVersionStringWithoutAnsi() throws Exception
-    {
+    void testVersionStringWithoutAnsi() throws Exception {
         // given
         // - request with version and batch mode
-        CliRequest cliRequest = new CliRequest( new String[] {
-                "--version",
-                "--batch-mode"
-        }, null );
+        CliRequest cliRequest = new CliRequest(new String[] {"--version", "--batch-mode"}, null);
         ByteArrayOutputStream systemOut = new ByteArrayOutputStream();
         PrintStream oldOut = System.out;
-        System.setOut( new PrintStream( systemOut ) );
+        System.setOut(new PrintStream(systemOut));
 
         // when
         try {
-            cli.cli( cliRequest );
-        } catch ( MavenCli.ExitException exitException ) {
+            cli.cli(cliRequest);
+        } catch (MavenCli.ExitException exitException) {
             // expected
         } finally {
             // restore sysout
-            System.setOut( oldOut );
+            System.setOut(oldOut);
         }
-        String versionOut = new String( systemOut.toByteArray(), StandardCharsets.UTF_8 );
+        String versionOut = new String(systemOut.toByteArray(), StandardCharsets.UTF_8);
 
         // then
-        assertEquals( MessageUtils.stripAnsiCodes( versionOut ), versionOut );
+        assertEquals(MessageUtils.stripAnsiCodes(versionOut), versionOut);
     }
 
     @Test
-    public void populatePropertiesCanContainEqualsSign() throws Exception
-    {
+    void populatePropertiesCanContainEqualsSign() throws Exception {
         // Arrange
-        CliRequest request = new CliRequest( new String[] { "-Dw=x=y", "validate" }, null );
+        CliRequest request = new CliRequest(new String[] {"-Dw=x=y", "validate"}, null);
 
         // Act
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
         // Assert
-        assertThat( request.getUserProperties().getProperty( "w" ), is( "x=y" ) );
+        assertThat(request.getUserProperties().getProperty("w"), is("x=y"));
     }
 
     @Test
-    public void populatePropertiesSpace() throws Exception
-    {
+    void populatePropertiesSpace() throws Exception {
         // Arrange
-        CliRequest request = new CliRequest( new String[] { "-D", "z=2", "validate" }, null );
+        CliRequest request = new CliRequest(new String[] {"-D", "z=2", "validate"}, null);
 
         // Act
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
         // Assert
-        assertThat( request.getUserProperties().getProperty( "z" ), is( "2" ) );
+        assertThat(request.getUserProperties().getProperty("z"), is("2"));
     }
 
     @Test
-    public void populatePropertiesShorthand() throws Exception
-    {
+    void populatePropertiesShorthand() throws Exception {
         // Arrange
-        CliRequest request = new CliRequest( new String[] { "-Dx", "validate" }, null );
+        CliRequest request = new CliRequest(new String[] {"-Dx", "validate"}, null);
 
         // Act
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
         // Assert
-        assertThat( request.getUserProperties().getProperty( "x" ), is( "true" ) );
+        assertThat(request.getUserProperties().getProperty("x"), is("true"));
     }
 
     @Test
-    public void populatePropertiesMultiple() throws Exception
-    {
+    void populatePropertiesMultiple() throws Exception {
         // Arrange
-        CliRequest request = new CliRequest( new String[] { "-Dx=1", "-Dy", "validate" }, null );
+        CliRequest request = new CliRequest(new String[] {"-Dx=1", "-Dy", "validate"}, null);
 
         // Act
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
         // Assert
-        assertThat( request.getUserProperties().getProperty( "x" ), is( "1" ) );
-        assertThat( request.getUserProperties().getProperty( "y" ), is( "true" ) );
+        assertThat(request.getUserProperties().getProperty("x"), is("1"));
+        assertThat(request.getUserProperties().getProperty("y"), is("true"));
     }
 
     @Test
-    public void populatePropertiesOverwrite() throws Exception
-    {
+    void populatePropertiesOverwrite() throws Exception {
         // Arrange
-        CliRequest request = new CliRequest( new String[] { "-Dx", "-Dx=false", "validate" }, null );
+        CliRequest request = new CliRequest(new String[] {"-Dx", "-Dx=false", "validate"}, null);
 
         // Act
-        cli.cli( request );
-        cli.properties( request );
+        cli.cli(request);
+        cli.properties(request);
 
         // Assert
-        assertThat( request.getUserProperties().getProperty( "x" ), is( "false" ) );
+        assertThat(request.getUserProperties().getProperty("x"), is("false"));
     }
 
-    private MavenProject createMavenProject( String groupId, String artifactId )
-    {
+    @Test
+    public void findRootProjectWithAttribute() {
+        Path test = Paths.get("src/test/projects/root-attribute");
+        assertEquals(test, new DefaultRootLocator().findRoot(test.resolve("child")));
+    }
+
+    @Test
+    public void testPropertiesInterpolation() throws Exception {
+        // Arrange
+        CliRequest request = new CliRequest(
+                new String[] {
+                    "-Dfoo=bar",
+                    "-DvalFound=s${foo}i",
+                    "-DvalNotFound=s${foz}i",
+                    "-DvalRootDirectory=${session.rootDirectory}/.mvn/foo",
+                    "-DvalTopDirectory=${session.topDirectory}/pom.xml",
+                    "-f",
+                    "${session.rootDirectory}/my-child",
+                    "prefix:3.0.0:${foo}",
+                    "validate"
+                },
+                null);
+        request.rootDirectory = Paths.get("myRootDirectory");
+        request.topDirectory = Paths.get("myTopDirectory");
+
+        // Act
+        cli.cli(request);
+        cli.properties(request);
+
+        // Assert
+        assertThat(request.getUserProperties().getProperty("valFound"), is("sbari"));
+        assertThat(request.getUserProperties().getProperty("valNotFound"), is("s${foz}i"));
+        assertThat(request.getUserProperties().getProperty("valRootDirectory"), is("myRootDirectory/.mvn/foo"));
+        assertThat(request.getUserProperties().getProperty("valTopDirectory"), is("myTopDirectory/pom.xml"));
+        assertThat(request.getCommandLine().getOptionValue('f'), is("myRootDirectory/my-child"));
+        assertThat(request.getCommandLine().getArgs(), equalTo(new String[] {"prefix:3.0.0:bar", "validate"}));
+    }
+
+    @ParameterizedTest
+    @MethodSource("activateBatchModeArguments")
+    public void activateBatchMode(boolean ciEnv, String[] cliArgs, boolean isBatchMode) throws Exception {
+        CliRequest request = new CliRequest(cliArgs, null);
+        if (ciEnv) request.getSystemProperties().put("env.CI", "true");
+        cli.cli(request);
+
+        boolean batchMode = !cli.populateRequest(request).isInteractiveMode();
+
+        assertThat(batchMode, is(isBatchMode));
+    }
+
+    public static Stream<Arguments> activateBatchModeArguments() {
+        return Stream.of(
+                Arguments.of(false, new String[] {}, false),
+                Arguments.of(true, new String[] {}, true),
+                Arguments.of(true, new String[] {"--force-interactive"}, false),
+                Arguments.of(true, new String[] {"--force-interactive", "--non-interactive"}, false),
+                Arguments.of(true, new String[] {"--force-interactive", "--batch-mode"}, false),
+                Arguments.of(true, new String[] {"--force-interactive", "--non-interactive", "--batch-mode"}, false),
+                Arguments.of(false, new String[] {"--non-interactive"}, true),
+                Arguments.of(false, new String[] {"--batch-mode"}, true),
+                Arguments.of(false, new String[] {"--non-interactive", "--batch-mode"}, true));
+    }
+
+    @ParameterizedTest
+    @MethodSource("calculateTransferListenerArguments")
+    public void calculateTransferListener(boolean ciEnv, String[] cliArgs, Class<TransferListener> expectedSubClass)
+            throws Exception {
+        CliRequest request = new CliRequest(cliArgs, null);
+        if (ciEnv) request.getSystemProperties().put("env.CI", "true");
+        cli.cli(request);
+        cli.logging(request);
+
+        TransferListener transferListener = cli.populateRequest(request).getTransferListener();
+
+        assertThat(transferListener.getClass(), is(expectedSubClass));
+    }
+
+    public static Stream<Arguments> calculateTransferListenerArguments() {
+        return Stream.of(
+                Arguments.of(false, new String[] {}, ConsoleMavenTransferListener.class),
+                Arguments.of(true, new String[] {}, QuietMavenTransferListener.class),
+                Arguments.of(false, new String[] {"-ntp"}, QuietMavenTransferListener.class),
+                Arguments.of(false, new String[] {"--quiet"}, QuietMavenTransferListener.class),
+                Arguments.of(true, new String[] {"--force-interactive"}, ConsoleMavenTransferListener.class),
+                Arguments.of(
+                        true,
+                        new String[] {"--force-interactive", "--non-interactive"},
+                        ConsoleMavenTransferListener.class),
+                Arguments.of(
+                        true, new String[] {"--force-interactive", "--batch-mode"}, ConsoleMavenTransferListener.class),
+                Arguments.of(
+                        true,
+                        new String[] {"--force-interactive", "--non-interactive", "--batch-mode"},
+                        ConsoleMavenTransferListener.class),
+                Arguments.of(false, new String[] {"--non-interactive"}, Slf4jMavenTransferListener.class),
+                Arguments.of(false, new String[] {"--batch-mode"}, Slf4jMavenTransferListener.class),
+                Arguments.of(
+                        false, new String[] {"--non-interactive", "--batch-mode"}, Slf4jMavenTransferListener.class));
+    }
+
+    private MavenProject createMavenProject(String groupId, String artifactId) {
         MavenProject project = new MavenProject();
-        project.setGroupId( groupId );
-        project.setArtifactId( artifactId );
+        project.setGroupId(groupId);
+        project.setArtifactId(artifactId);
         return project;
     }
 }
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java
index 6f5b8e2..3e26012 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.event;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,181 +16,257 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.mockito.Mockito.inOrder;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+package org.apache.maven.cli.event;
 
 import java.io.File;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.commons.io.FilenameUtils;
+import org.apache.maven.cli.jansi.JansiMessageBuilderFactory;
+import org.apache.maven.cli.jansi.MessageUtils;
 import org.apache.maven.execution.ExecutionEvent;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageUtils;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.mockito.InOrder;
 import org.mockito.Mockito;
 import org.slf4j.Logger;
 
-class ExecutionEventLoggerTest
-{
+import static org.mockito.ArgumentMatchers.matches;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.when;
+
+class ExecutionEventLoggerTest {
+
+    private Logger logger;
+    private ExecutionEventLogger executionEventLogger;
+    private JansiMessageBuilderFactory messageBuilderFactory = new JansiMessageBuilderFactory();
+
     @BeforeAll
-    public static void setUp()
-    {
-        MessageUtils.setColorEnabled( false );
+    static void setUp() {
+        MessageUtils.setColorEnabled(false);
     }
 
     @AfterAll
-    public static void tearDown()
-    {
-        MessageUtils.setColorEnabled( true );
+    static void tearDown() {
+        MessageUtils.setColorEnabled(true);
+    }
+
+    @BeforeEach
+    void beforeEach() {
+        logger = mock(Logger.class);
+        when(logger.isInfoEnabled()).thenReturn(true);
+        executionEventLogger = new ExecutionEventLogger(messageBuilderFactory, logger);
     }
 
     @Test
-    void testProjectStarted()
-    {
+    void testProjectStarted() {
         // prepare
-        Logger logger = mock( Logger.class );
-        when( logger.isInfoEnabled() ).thenReturn( true );
-        ExecutionEventLogger executionEventLogger = new ExecutionEventLogger( logger );
+        File basedir = new File("").getAbsoluteFile();
+        ExecutionEvent event = mock(ExecutionEvent.class);
+        MavenProject project = mock(MavenProject.class);
+        when(project.getGroupId()).thenReturn("org.apache.maven");
+        when(project.getArtifactId()).thenReturn("maven-embedder");
+        when(project.getPackaging()).thenReturn("jar");
+        when(project.getName()).thenReturn("Apache Maven Embedder");
+        when(project.getVersion()).thenReturn("3.5.4-SNAPSHOT");
+        when(project.getFile()).thenReturn(new File(basedir, "maven-embedder/pom.xml"));
+        when(event.getProject()).thenReturn(project);
 
-        File basedir = new File( "" ).getAbsoluteFile();
-        ExecutionEvent event = mock( ExecutionEvent.class );
-        MavenProject project = mock( MavenProject.class );
-        when( project.getGroupId() ).thenReturn( "org.apache.maven" );
-        when( project.getArtifactId() ).thenReturn( "maven-embedder" );
-        when( project.getPackaging() ).thenReturn( "jar" );
-        when( project.getName() ).thenReturn( "Apache Maven Embedder" );
-        when( project.getVersion() ).thenReturn( "3.5.4-SNAPSHOT" );
-        when( project.getFile() ).thenReturn( new File( basedir, "maven-embedder/pom.xml" ) );
-        when( event.getProject() ).thenReturn( project );
-
-        MavenProject rootProject = mock( MavenProject.class );
-        when( rootProject.getBasedir() ).thenReturn( basedir );
-        MavenSession session = mock( MavenSession.class );
-        when( session.getTopLevelProject() ).thenReturn( rootProject );
-        when( event.getSession() ).thenReturn( session );
+        MavenProject rootProject = mock(MavenProject.class);
+        when(rootProject.getBasedir()).thenReturn(basedir);
+        MavenSession session = mock(MavenSession.class);
+        when(session.getTopLevelProject()).thenReturn(rootProject);
+        when(session.getTopDirectory()).thenReturn(basedir.toPath());
+        when(event.getSession()).thenReturn(session);
 
         // execute
-        executionEventLogger.projectStarted( event );
+        executionEventLogger.projectStarted(event);
 
         // verify
-        InOrder inOrder = inOrder( logger );
-        inOrder.verify( logger ).info( "" );
-        inOrder.verify( logger ).info( "------------------< org.apache.maven:maven-embedder >-------------------" );
-        inOrder.verify( logger ).info( "Building Apache Maven Embedder 3.5.4-SNAPSHOT" );
-        inOrder.verify( logger ).info( adaptDirSeparator( "  from maven-embedder/pom.xml" ) );
-        inOrder.verify( logger ).info( "--------------------------------[ jar ]---------------------------------" );
+        InOrder inOrder = inOrder(logger);
+        inOrder.verify(logger).info("");
+        inOrder.verify(logger).info("------------------< org.apache.maven:maven-embedder >-------------------");
+        inOrder.verify(logger).info("Building Apache Maven Embedder 3.5.4-SNAPSHOT");
+        inOrder.verify(logger).info(adaptDirSeparator("  from maven-embedder/pom.xml"));
+        inOrder.verify(logger).info("--------------------------------[ jar ]---------------------------------");
     }
 
     @Test
-    void testProjectStartedOverflow()
-    {
+    void testProjectStartedOverflow() {
         // prepare
-        Logger logger = mock( Logger.class );
-        when( logger.isInfoEnabled() ).thenReturn( true );
-        ExecutionEventLogger executionEventLogger = new ExecutionEventLogger( logger );
+        File basedir = new File("").getAbsoluteFile();
+        ExecutionEvent event = mock(ExecutionEvent.class);
+        MavenProject project = mock(MavenProject.class);
+        when(project.getGroupId()).thenReturn("org.apache.maven.plugins.overflow");
+        when(project.getArtifactId()).thenReturn("maven-project-info-reports-plugin");
+        when(project.getPackaging()).thenReturn("maven-plugin");
+        when(project.getName()).thenReturn("Apache Maven Project Info Reports Plugin");
+        when(project.getVersion()).thenReturn("3.0.0-SNAPSHOT");
+        when(event.getProject()).thenReturn(project);
+        when(project.getFile()).thenReturn(new File(basedir, "pom.xml"));
+        when(project.getBasedir()).thenReturn(basedir);
 
-        File basedir = new File( "" ).getAbsoluteFile();
-        ExecutionEvent event = mock( ExecutionEvent.class );
-        MavenProject project = mock( MavenProject.class );
-        when( project.getGroupId() ).thenReturn( "org.apache.maven.plugins.overflow" );
-        when( project.getArtifactId() ).thenReturn( "maven-project-info-reports-plugin" );
-        when( project.getPackaging() ).thenReturn( "maven-plugin" );
-        when( project.getName() ).thenReturn( "Apache Maven Project Info Reports Plugin" );
-        when( project.getVersion() ).thenReturn( "3.0.0-SNAPSHOT" );
-        when( event.getProject() ).thenReturn( project );
-        when( project.getFile() ).thenReturn( new File( basedir, "pom.xml" ) );
-        when( project.getBasedir() ).thenReturn( basedir );
-
-        MavenSession session = mock( MavenSession.class );
-        when( session.getTopLevelProject() ).thenReturn( project );
-        when( event.getSession() ).thenReturn( session );
+        MavenSession session = mock(MavenSession.class);
+        when(session.getTopLevelProject()).thenReturn(project);
+        when(event.getSession()).thenReturn(session);
+        when(session.getTopDirectory()).thenReturn(basedir.toPath());
 
         // execute
-        executionEventLogger.projectStarted( event );
+        executionEventLogger.projectStarted(event);
 
         // verify
-        InOrder inOrder = inOrder( logger );
-        inOrder.verify( logger ).info( "" );
-        inOrder.verify( logger ).info( "--< org.apache.maven.plugins.overflow:maven-project-info-reports-plugin >--" );
-        inOrder.verify( logger ).info( "Building Apache Maven Project Info Reports Plugin 3.0.0-SNAPSHOT" );
-        inOrder.verify( logger ).info( adaptDirSeparator( "  from pom.xml" ) );
-        inOrder.verify( logger ).info( "----------------------------[ maven-plugin ]----------------------------" );
+        InOrder inOrder = inOrder(logger);
+        inOrder.verify(logger).info("");
+        inOrder.verify(logger).info("--< org.apache.maven.plugins.overflow:maven-project-info-reports-plugin >--");
+        inOrder.verify(logger).info("Building Apache Maven Project Info Reports Plugin 3.0.0-SNAPSHOT");
+        inOrder.verify(logger).info(adaptDirSeparator("  from pom.xml"));
+        inOrder.verify(logger).info("----------------------------[ maven-plugin ]----------------------------");
     }
 
     @Test
-    void testTerminalWidth()
-    {
+    void testTerminalWidth() {
         // prepare
-        Logger logger = mock( Logger.class );
-        when( logger.isInfoEnabled() ).thenReturn( true );
+        Logger logger = mock(Logger.class);
+        when(logger.isInfoEnabled()).thenReturn(true);
 
-        ExecutionEvent event = mock( ExecutionEvent.class );
-        MavenProject project = mock( MavenProject.class );
-        when( project.getGroupId() ).thenReturn( "org.apache.maven.plugins.overflow" );
-        when( project.getArtifactId() ).thenReturn( "maven-project-info-reports-plugin" );
-        when( project.getPackaging() ).thenReturn( "maven-plugin" );
-        when( project.getName() ).thenReturn( "Apache Maven Project Info Reports Plugin" );
-        when( project.getVersion() ).thenReturn( "3.0.0-SNAPSHOT" );
-        when( event.getProject() ).thenReturn( project );
+        ExecutionEvent event = mock(ExecutionEvent.class);
+        MavenProject project = mock(MavenProject.class);
+        when(project.getGroupId()).thenReturn("org.apache.maven.plugins.overflow");
+        when(project.getArtifactId()).thenReturn("maven-project-info-reports-plugin");
+        when(project.getPackaging()).thenReturn("maven-plugin");
+        when(project.getName()).thenReturn("Apache Maven Project Info Reports Plugin");
+        when(project.getVersion()).thenReturn("3.0.0-SNAPSHOT");
+        when(event.getProject()).thenReturn(project);
 
         // default width
-        new ExecutionEventLogger( logger, -1 ).projectStarted( event );
-        Mockito.verify( logger ).info( "----------------------------[ maven-plugin ]----------------------------" );
+        new ExecutionEventLogger(messageBuilderFactory, logger, -1).projectStarted(event);
+        Mockito.verify(logger).info("----------------------------[ maven-plugin ]----------------------------");
 
         // terminal width: 30
-        new ExecutionEventLogger( logger, 30 ).projectStarted( event );
-        Mockito.verify( logger ).info( "------------------[ maven-plugin ]------------------" );
+        new ExecutionEventLogger(messageBuilderFactory, logger, 30).projectStarted(event);
+        Mockito.verify(logger).info("------------------[ maven-plugin ]------------------");
 
         // terminal width: 70
-        new ExecutionEventLogger( logger, 70 ).projectStarted( event );
-        Mockito.verify( logger ).info( "-----------------------[ maven-plugin ]-----------------------" );
+        new ExecutionEventLogger(messageBuilderFactory, logger, 70).projectStarted(event);
+        Mockito.verify(logger).info("-----------------------[ maven-plugin ]-----------------------");
 
         // terminal width: 110
-        new ExecutionEventLogger( logger, 110 ).projectStarted( event );
-        Mockito.verify( logger ).info( "-------------------------------------------[ maven-plugin ]-------------------------------------------" );
+        new ExecutionEventLogger(messageBuilderFactory, logger, 110).projectStarted(event);
+        Mockito.verify(logger)
+                .info(
+                        "-------------------------------------------[ maven-plugin ]-------------------------------------------");
 
         // terminal width: 200
-        new ExecutionEventLogger( logger, 200 ).projectStarted( event );
-        Mockito.verify( logger ).info( "-----------------------------------------------------[ maven-plugin ]-----------------------------------------------------" );
+        new ExecutionEventLogger(messageBuilderFactory, logger, 200).projectStarted(event);
+        Mockito.verify(logger)
+                .info(
+                        "-----------------------------------------------------[ maven-plugin ]-----------------------------------------------------");
     }
 
-    public void testProjectStartedNoPom()
-    {
+    @Test
+    void testProjectStartedNoPom() {
         // prepare
-        Logger logger = mock( Logger.class );
-        when( logger.isInfoEnabled() ).thenReturn( true );
-        ExecutionEventLogger executionEventLogger = new ExecutionEventLogger( logger );
-
-        File basedir = new File( "" ).getAbsoluteFile();
-        ExecutionEvent event = mock( ExecutionEvent.class );
-        MavenProject project = mock( MavenProject.class );
-        when( project.getGroupId() ).thenReturn( "org.apache.maven" );
-        when( project.getArtifactId() ).thenReturn( "standalone-pom" );
-        when( project.getPackaging() ).thenReturn( "pom" );
-        when( project.getName() ).thenReturn( "Maven Stub Project (No POM)" );
-        when( project.getVersion() ).thenReturn( "1" );
-        when( event.getProject() ).thenReturn( project );
-        when( project.getFile() ).thenReturn( null );
-        when( project.getBasedir() ).thenReturn( basedir );
+        File basedir = new File("").getAbsoluteFile();
+        ExecutionEvent event = mock(ExecutionEvent.class);
+        MavenProject project = mock(MavenProject.class);
+        when(project.getGroupId()).thenReturn("org.apache.maven");
+        when(project.getArtifactId()).thenReturn("standalone-pom");
+        when(project.getPackaging()).thenReturn("pom");
+        when(project.getName()).thenReturn("Maven Stub Project (No POM)");
+        when(project.getVersion()).thenReturn("1");
+        when(event.getProject()).thenReturn(project);
+        when(project.getFile()).thenReturn(null);
+        when(project.getBasedir()).thenReturn(basedir);
 
         // execute
-        executionEventLogger.projectStarted( event );
+        executionEventLogger.projectStarted(event);
 
         // verify
-        InOrder inOrder = inOrder( logger );
-        inOrder.verify( logger ).info( "" );
-        inOrder.verify( logger ).info( "------------------< org.apache.maven:standalone-pom >-------------------" );
-        inOrder.verify( logger ).info( "Building Maven Stub Project (No POM) 1" );
-        inOrder.verify( logger ).info( "--------------------------------[ pom ]---------------------------------" );
+        InOrder inOrder = inOrder(logger);
+        inOrder.verify(logger).info("");
+        inOrder.verify(logger).info("------------------< org.apache.maven:standalone-pom >-------------------");
+        inOrder.verify(logger).info("Building Maven Stub Project (No POM) 1");
+        inOrder.verify(logger).info("--------------------------------[ pom ]---------------------------------");
     }
 
-    private static String adaptDirSeparator( String path )
-    {
-        return FilenameUtils.separatorsToSystem( path );
+    @Test
+    void testMultiModuleProjectProgress() {
+        // prepare
+        MavenProject project1 = generateMavenProject("Apache Maven Embedder 1");
+        MavenProject project2 = generateMavenProject("Apache Maven Embedder 2");
+        MavenProject project3 = generateMavenProject("Apache Maven Embedder 3");
+
+        MavenSession session = mock(MavenSession.class);
+        when(session.getProjects()).thenReturn(ImmutableList.of(project1, project2, project3));
+        when(session.getAllProjects()).thenReturn(ImmutableList.of(project1, project2, project3));
+
+        ExecutionEvent sessionStartedEvent = mock(ExecutionEvent.class);
+        when(sessionStartedEvent.getSession()).thenReturn(session);
+        ExecutionEvent projectStartedEvent1 = mock(ExecutionEvent.class);
+        when(projectStartedEvent1.getProject()).thenReturn(project1);
+        ExecutionEvent projectStartedEvent2 = mock(ExecutionEvent.class);
+        when(projectStartedEvent2.getProject()).thenReturn(project2);
+        ExecutionEvent projectStartedEvent3 = mock(ExecutionEvent.class);
+        when(projectStartedEvent3.getProject()).thenReturn(project3);
+
+        // execute
+        executionEventLogger.sessionStarted(sessionStartedEvent);
+        executionEventLogger.projectStarted(projectStartedEvent1);
+        executionEventLogger.projectStarted(projectStartedEvent2);
+        executionEventLogger.projectStarted(projectStartedEvent3);
+
+        // verify
+        InOrder inOrder = inOrder(logger);
+        inOrder.verify(logger).info(matches(".*Apache Maven Embedder 1.*\\[1\\/3\\]"));
+        inOrder.verify(logger).info(matches(".*Apache Maven Embedder 2.*\\[2\\/3\\]"));
+        inOrder.verify(logger).info(matches(".*Apache Maven Embedder 3.*\\[3\\/3\\]"));
+    }
+
+    @Test
+    void testMultiModuleProjectResumeFromProgress() {
+        // prepare
+        MavenProject project1 = generateMavenProject("Apache Maven Embedder 1");
+        MavenProject project2 = generateMavenProject("Apache Maven Embedder 2");
+        MavenProject project3 = generateMavenProject("Apache Maven Embedder 3");
+
+        MavenSession session = mock(MavenSession.class);
+        when(session.getProjects()).thenReturn(ImmutableList.of(project2, project3));
+        when(session.getAllProjects()).thenReturn(ImmutableList.of(project1, project2, project3));
+
+        ExecutionEvent sessionStartedEvent = mock(ExecutionEvent.class);
+        when(sessionStartedEvent.getSession()).thenReturn(session);
+        ExecutionEvent projectStartedEvent2 = mock(ExecutionEvent.class);
+        when(projectStartedEvent2.getProject()).thenReturn(project2);
+        ExecutionEvent projectStartedEvent3 = mock(ExecutionEvent.class);
+        when(projectStartedEvent3.getProject()).thenReturn(project3);
+
+        // execute
+        executionEventLogger.sessionStarted(sessionStartedEvent);
+        executionEventLogger.projectStarted(projectStartedEvent2);
+        executionEventLogger.projectStarted(projectStartedEvent3);
+
+        // verify
+        InOrder inOrder = inOrder(logger);
+        inOrder.verify(logger, never()).info(matches(".*Apache Maven Embedder 1.*\\[1\\/3\\]"));
+        inOrder.verify(logger).info(matches(".*Apache Maven Embedder 2.*\\[2\\/3\\]"));
+        inOrder.verify(logger).info(matches(".*Apache Maven Embedder 3.*\\[3\\/3\\]"));
+    }
+
+    private static MavenProject generateMavenProject(String projectName) {
+        MavenProject project = mock(MavenProject.class);
+        when(project.getPackaging()).thenReturn("jar");
+        when(project.getVersion()).thenReturn("3.5.4-SNAPSHOT");
+        when(project.getName()).thenReturn(projectName);
+        return project;
+    }
+
+    private static String adaptDirSeparator(String path) {
+        return FilenameUtils.separatorsToSystem(path);
     }
 }
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListenerTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListenerTest.java
new file mode 100644
index 0000000..0951240
--- /dev/null
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/ConsoleMavenTransferListenerTest.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.cli.transfer;
+
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.transfer.TransferCancelledException;
+import org.eclipse.aether.transfer.TransferEvent;
+import org.eclipse.aether.transfer.TransferResource;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class ConsoleMavenTransferListenerTest {
+
+    private CountDownLatch startLatch;
+    private CountDownLatch endLatch;
+
+    @Test
+    void testTransferProgressedWithPrintResourceNames() throws FileNotFoundException, InterruptedException {
+        int size = 1000;
+        ExecutorService service = Executors.newFixedThreadPool(size * 2);
+        startLatch = new CountDownLatch(size);
+        endLatch = new CountDownLatch(size);
+        Map<String, String> output = new ConcurrentHashMap<String, String>();
+
+        ConsoleMavenTransferListener listener = new ConsoleMavenTransferListener(
+                new PrintStream(System.out) {
+
+                    @Override
+                    public void print(Object o) {
+
+                        String string = o.toString();
+                        int i = string.length() - 1;
+                        while (i >= 0) {
+                            char c = string.charAt(i);
+                            if (c == '\n' || c == '\r' || c == ' ') i--;
+                            else break;
+                        }
+
+                        string = string.substring(0, i + 1).trim();
+                        output.put(string, string);
+                        System.out.print(o);
+                    }
+                },
+                true);
+        TransferResource resource = new TransferResource(null, null, "http://maven.org/test/test-resource", null, null);
+        resource.setContentLength(size - 1);
+
+        DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
+
+        // warm up
+        test(listener, session, resource, 0);
+
+        for (int i = 1; i < size; i++) {
+            final int bytes = i;
+
+            service.execute(() -> {
+                test(listener, session, resource, bytes);
+            });
+        }
+
+        // start all threads at once
+        try {
+            startLatch.await();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        // wait for all thread to end
+        try {
+            endLatch.await();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        StringBuilder message = new StringBuilder("Messages [");
+        boolean test = true;
+        for (int i = 0; i < 999; i++) {
+            boolean ok = output.containsKey("Progress (1): test-resource (" + i + "/999 B)");
+            if (!ok) {
+                System.out.println("false : " + i);
+                message.append(i + ",");
+            }
+            test = test & ok;
+        }
+        assertTrue(test, message.toString() + "] are missiong in " + output);
+    }
+
+    private void test(
+            ConsoleMavenTransferListener listener,
+            DefaultRepositorySystemSession session,
+            TransferResource resource,
+            final int bytes) {
+        TransferEvent event = new TransferEvent.Builder(session, resource)
+                .setTransferredBytes(bytes)
+                .build();
+        startLatch.countDown();
+        try {
+            listener.transferProgressed(event);
+        } catch (TransferCancelledException e) {
+        }
+        endLatch.countDown();
+    }
+}
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java
index 5090fac..6f96a59 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/transfer/FileSizeFormatTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.cli.transfer;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,286 +16,276 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.cli.transfer;
 
 import java.util.Locale;
 
-import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat;
-import org.apache.maven.cli.transfer.AbstractMavenTransferListener.FileSizeFormat.ScaleUnit;
+import org.apache.maven.cli.transfer.FileSizeFormat.ScaleUnit;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-public class FileSizeFormatTest {
+class FileSizeFormatTest {
 
     @Test
-    public void testNegativeSize()
-    {
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testNegativeSize() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
         long negativeSize = -100L;
-        assertThrows( IllegalArgumentException.class, () -> format.format( negativeSize ) );
+        assertThrows(IllegalArgumentException.class, () -> format.format(negativeSize));
     }
 
     @Test
-    public void testSize()
-    {
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testSize() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
         long _0_bytes = 0L;
-        assertEquals( "0 B", format.format( _0_bytes ) );
+        assertEquals("0 B", format.format(_0_bytes));
 
         long _5_bytes = 5L;
-        assertEquals( "5 B", format.format( _5_bytes ) );
+        assertEquals("5 B", format.format(_5_bytes));
 
         long _10_bytes = 10L;
-        assertEquals( "10 B", format.format( _10_bytes ) );
+        assertEquals("10 B", format.format(_10_bytes));
 
         long _15_bytes = 15L;
-        assertEquals( "15 B", format.format( _15_bytes ) );
+        assertEquals("15 B", format.format(_15_bytes));
 
         long _999_bytes = 999L;
-        assertEquals( "999 B", format.format( _999_bytes ) );
+        assertEquals("999 B", format.format(_999_bytes));
 
         long _1000_bytes = 1000L;
-        assertEquals( "1.0 kB", format.format( _1000_bytes ) );
+        assertEquals("1.0 kB", format.format(_1000_bytes));
 
         long _5500_bytes = 5500L;
-        assertEquals( "5.5 kB", format.format( _5500_bytes ) );
+        assertEquals("5.5 kB", format.format(_5500_bytes));
 
         long _10_kilobytes = 10L * 1000L;
-        assertEquals( "10 kB", format.format( _10_kilobytes ) );
+        assertEquals("10 kB", format.format(_10_kilobytes));
 
         long _15_kilobytes = 15L * 1000L;
-        assertEquals( "15 kB", format.format( _15_kilobytes ) );
+        assertEquals("15 kB", format.format(_15_kilobytes));
 
         long _999_kilobytes = 999L * 1000L;
-        assertEquals( "999 kB", format.format( _999_kilobytes ) );
+        assertEquals("999 kB", format.format(_999_kilobytes));
 
         long _1000_kilobytes = 1000L * 1000L;
-        assertEquals( "1.0 MB", format.format( _1000_kilobytes ) );
+        assertEquals("1.0 MB", format.format(_1000_kilobytes));
 
         long _5500_kilobytes = 5500L * 1000L;
-        assertEquals( "5.5 MB", format.format( _5500_kilobytes ) );
+        assertEquals("5.5 MB", format.format(_5500_kilobytes));
 
         long _10_megabytes = 10L * 1000L * 1000L;
-        assertEquals( "10 MB", format.format( _10_megabytes ) );
+        assertEquals("10 MB", format.format(_10_megabytes));
 
         long _15_megabytes = 15L * 1000L * 1000L;
-        assertEquals( "15 MB", format.format( _15_megabytes ) );
+        assertEquals("15 MB", format.format(_15_megabytes));
 
         long _999_megabytes = 999L * 1000L * 1000L;
-        assertEquals( "999 MB", format.format( _999_megabytes ) );
+        assertEquals("999 MB", format.format(_999_megabytes));
 
         long _1000_megabytes = 1000L * 1000L * 1000L;
-        assertEquals( "1.0 GB", format.format( _1000_megabytes ) );
+        assertEquals("1.0 GB", format.format(_1000_megabytes));
 
         long _5500_megabytes = 5500L * 1000L * 1000L;
-        assertEquals( "5.5 GB", format.format( _5500_megabytes ) );
+        assertEquals("5.5 GB", format.format(_5500_megabytes));
 
         long _10_gigabytes = 10L * 1000L * 1000L * 1000L;
-        assertEquals( "10 GB", format.format( _10_gigabytes ) );
+        assertEquals("10 GB", format.format(_10_gigabytes));
 
         long _15_gigabytes = 15L * 1000L * 1000L * 1000L;
-        assertEquals( "15 GB", format.format( _15_gigabytes ) );
+        assertEquals("15 GB", format.format(_15_gigabytes));
 
         long _1000_gigabytes = 1000L * 1000L * 1000L * 1000L;
-        assertEquals( "1000 GB", format.format( _1000_gigabytes ) );
+        assertEquals("1000 GB", format.format(_1000_gigabytes));
     }
 
     @Test
-    public void testSizeWithSelectedScaleUnit()
-    {
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testSizeWithSelectedScaleUnit() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
         long _0_bytes = 0L;
-        assertEquals( "0 B", format.format( _0_bytes ) );
-        assertEquals( "0 B", format.format( _0_bytes, ScaleUnit.BYTE ) );
-        assertEquals( "0 kB", format.format( _0_bytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0 MB", format.format( _0_bytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _0_bytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("0 B", format.format(_0_bytes));
+        assertEquals("0 B", format.format(_0_bytes, ScaleUnit.BYTE));
+        assertEquals("0 kB", format.format(_0_bytes, ScaleUnit.KILOBYTE));
+        assertEquals("0 MB", format.format(_0_bytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_0_bytes, ScaleUnit.GIGABYTE));
 
         long _5_bytes = 5L;
-        assertEquals( "5 B", format.format( _5_bytes ) );
-        assertEquals( "5 B", format.format( _5_bytes, ScaleUnit.BYTE ) );
-        assertEquals( "0 kB", format.format( _5_bytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0 MB", format.format( _5_bytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _5_bytes, ScaleUnit.GIGABYTE ) );
-
+        assertEquals("5 B", format.format(_5_bytes));
+        assertEquals("5 B", format.format(_5_bytes, ScaleUnit.BYTE));
+        assertEquals("0 kB", format.format(_5_bytes, ScaleUnit.KILOBYTE));
+        assertEquals("0 MB", format.format(_5_bytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_5_bytes, ScaleUnit.GIGABYTE));
 
         long _49_bytes = 49L;
-        assertEquals( "49 B", format.format( _49_bytes ) );
-        assertEquals( "49 B", format.format( _49_bytes, ScaleUnit.BYTE ) );
-        assertEquals( "0 kB", format.format( _49_bytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0 MB", format.format( _49_bytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _49_bytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("49 B", format.format(_49_bytes));
+        assertEquals("49 B", format.format(_49_bytes, ScaleUnit.BYTE));
+        assertEquals("0 kB", format.format(_49_bytes, ScaleUnit.KILOBYTE));
+        assertEquals("0 MB", format.format(_49_bytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_49_bytes, ScaleUnit.GIGABYTE));
 
         long _50_bytes = 50L;
-        assertEquals( "50 B", format.format( _50_bytes ) );
-        assertEquals( "50 B", format.format( _50_bytes, ScaleUnit.BYTE ) );
-        assertEquals( "0.1 kB", format.format( _50_bytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0 MB", format.format( _50_bytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _50_bytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("50 B", format.format(_50_bytes));
+        assertEquals("50 B", format.format(_50_bytes, ScaleUnit.BYTE));
+        assertEquals("0.1 kB", format.format(_50_bytes, ScaleUnit.KILOBYTE));
+        assertEquals("0 MB", format.format(_50_bytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_50_bytes, ScaleUnit.GIGABYTE));
 
         long _999_bytes = 999L;
-        assertEquals( "999 B", format.format( _999_bytes ) );
-        assertEquals( "999 B", format.format( _999_bytes, ScaleUnit.BYTE ) );
-        assertEquals( "1.0 kB", format.format( _999_bytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0 MB", format.format( _999_bytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _999_bytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("999 B", format.format(_999_bytes));
+        assertEquals("999 B", format.format(_999_bytes, ScaleUnit.BYTE));
+        assertEquals("1.0 kB", format.format(_999_bytes, ScaleUnit.KILOBYTE));
+        assertEquals("0 MB", format.format(_999_bytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_999_bytes, ScaleUnit.GIGABYTE));
 
         long _1000_bytes = 1000L;
-        assertEquals( "1.0 kB", format.format( _1000_bytes ) );
-        assertEquals( "1000 B", format.format( _1000_bytes, ScaleUnit.BYTE ) );
-        assertEquals( "1.0 kB", format.format( _1000_bytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0 MB", format.format( _1000_bytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _1000_bytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("1.0 kB", format.format(_1000_bytes));
+        assertEquals("1000 B", format.format(_1000_bytes, ScaleUnit.BYTE));
+        assertEquals("1.0 kB", format.format(_1000_bytes, ScaleUnit.KILOBYTE));
+        assertEquals("0 MB", format.format(_1000_bytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_1000_bytes, ScaleUnit.GIGABYTE));
 
         long _49_kilobytes = 49L * 1000L;
-        assertEquals( "49 kB", format.format( _49_kilobytes ) );
-        assertEquals( "49000 B", format.format( _49_kilobytes, ScaleUnit.BYTE ) );
-        assertEquals( "49 kB", format.format( _49_kilobytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0 MB", format.format( _49_kilobytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _49_kilobytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("49 kB", format.format(_49_kilobytes));
+        assertEquals("49000 B", format.format(_49_kilobytes, ScaleUnit.BYTE));
+        assertEquals("49 kB", format.format(_49_kilobytes, ScaleUnit.KILOBYTE));
+        assertEquals("0 MB", format.format(_49_kilobytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_49_kilobytes, ScaleUnit.GIGABYTE));
 
         long _50_kilobytes = 50L * 1000L;
-        assertEquals( "50 kB", format.format( _50_kilobytes ) );
-        assertEquals( "50000 B", format.format( _50_kilobytes, ScaleUnit.BYTE ) );
-        assertEquals( "50 kB", format.format( _50_kilobytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "0.1 MB", format.format( _50_kilobytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _50_kilobytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("50 kB", format.format(_50_kilobytes));
+        assertEquals("50000 B", format.format(_50_kilobytes, ScaleUnit.BYTE));
+        assertEquals("50 kB", format.format(_50_kilobytes, ScaleUnit.KILOBYTE));
+        assertEquals("0.1 MB", format.format(_50_kilobytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_50_kilobytes, ScaleUnit.GIGABYTE));
 
         long _999_kilobytes = 999L * 1000L;
-        assertEquals( "999 kB", format.format( _999_kilobytes ) );
-        assertEquals( "999000 B", format.format( _999_kilobytes, ScaleUnit.BYTE ) );
-        assertEquals( "999 kB", format.format( _999_kilobytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "1.0 MB", format.format( _999_kilobytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _999_kilobytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("999 kB", format.format(_999_kilobytes));
+        assertEquals("999000 B", format.format(_999_kilobytes, ScaleUnit.BYTE));
+        assertEquals("999 kB", format.format(_999_kilobytes, ScaleUnit.KILOBYTE));
+        assertEquals("1.0 MB", format.format(_999_kilobytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_999_kilobytes, ScaleUnit.GIGABYTE));
 
         long _1000_kilobytes = 1000L * 1000L;
-        assertEquals( "1.0 MB", format.format( _1000_kilobytes ) );
-        assertEquals( "1000000 B", format.format( _1000_kilobytes, ScaleUnit.BYTE ) );
-        assertEquals( "1000 kB", format.format( _1000_kilobytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "1.0 MB", format.format( _1000_kilobytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _1000_kilobytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("1.0 MB", format.format(_1000_kilobytes));
+        assertEquals("1000000 B", format.format(_1000_kilobytes, ScaleUnit.BYTE));
+        assertEquals("1000 kB", format.format(_1000_kilobytes, ScaleUnit.KILOBYTE));
+        assertEquals("1.0 MB", format.format(_1000_kilobytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_1000_kilobytes, ScaleUnit.GIGABYTE));
 
         long _49_megabytes = 49L * 1000L * 1000L;
-        assertEquals( "49 MB", format.format( _49_megabytes ) );
-        assertEquals( "49000000 B", format.format( _49_megabytes, ScaleUnit.BYTE ) );
-        assertEquals( "49000 kB", format.format( _49_megabytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "49 MB", format.format( _49_megabytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0 GB", format.format( _49_megabytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("49 MB", format.format(_49_megabytes));
+        assertEquals("49000000 B", format.format(_49_megabytes, ScaleUnit.BYTE));
+        assertEquals("49000 kB", format.format(_49_megabytes, ScaleUnit.KILOBYTE));
+        assertEquals("49 MB", format.format(_49_megabytes, ScaleUnit.MEGABYTE));
+        assertEquals("0 GB", format.format(_49_megabytes, ScaleUnit.GIGABYTE));
 
         long _50_megabytes = 50L * 1000L * 1000L;
-        assertEquals( "50 MB", format.format( _50_megabytes ) );
-        assertEquals( "50000000 B", format.format( _50_megabytes, ScaleUnit.BYTE ) );
-        assertEquals( "50000 kB", format.format( _50_megabytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "50 MB", format.format( _50_megabytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "0.1 GB", format.format( _50_megabytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("50 MB", format.format(_50_megabytes));
+        assertEquals("50000000 B", format.format(_50_megabytes, ScaleUnit.BYTE));
+        assertEquals("50000 kB", format.format(_50_megabytes, ScaleUnit.KILOBYTE));
+        assertEquals("50 MB", format.format(_50_megabytes, ScaleUnit.MEGABYTE));
+        assertEquals("0.1 GB", format.format(_50_megabytes, ScaleUnit.GIGABYTE));
 
         long _999_megabytes = 999L * 1000L * 1000L;
-        assertEquals( "999 MB", format.format( _999_megabytes ) );
-        assertEquals( "999000000 B", format.format( _999_megabytes, ScaleUnit.BYTE ) );
-        assertEquals( "999000 kB", format.format( _999_megabytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "999 MB", format.format( _999_megabytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "1.0 GB", format.format( _999_megabytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("999 MB", format.format(_999_megabytes));
+        assertEquals("999000000 B", format.format(_999_megabytes, ScaleUnit.BYTE));
+        assertEquals("999000 kB", format.format(_999_megabytes, ScaleUnit.KILOBYTE));
+        assertEquals("999 MB", format.format(_999_megabytes, ScaleUnit.MEGABYTE));
+        assertEquals("1.0 GB", format.format(_999_megabytes, ScaleUnit.GIGABYTE));
 
         long _1000_megabytes = 1000L * 1000L * 1000L;
-        assertEquals( "1.0 GB", format.format( _1000_megabytes ) );
-        assertEquals( "1000000000 B", format.format( _1000_megabytes, ScaleUnit.BYTE ) );
-        assertEquals( "1000000 kB", format.format( _1000_megabytes, ScaleUnit.KILOBYTE ) );
-        assertEquals( "1000 MB", format.format( _1000_megabytes, ScaleUnit.MEGABYTE ) );
-        assertEquals( "1.0 GB", format.format( _1000_megabytes, ScaleUnit.GIGABYTE ) );
+        assertEquals("1.0 GB", format.format(_1000_megabytes));
+        assertEquals("1000000000 B", format.format(_1000_megabytes, ScaleUnit.BYTE));
+        assertEquals("1000000 kB", format.format(_1000_megabytes, ScaleUnit.KILOBYTE));
+        assertEquals("1000 MB", format.format(_1000_megabytes, ScaleUnit.MEGABYTE));
+        assertEquals("1.0 GB", format.format(_1000_megabytes, ScaleUnit.GIGABYTE));
     }
 
     @Test
-    public void testNegativeProgressedSize()
-    {
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testNegativeProgressedSize() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
         long negativeProgressedSize = -100L;
-        assertThrows( IllegalArgumentException.class, () -> format.formatProgress( negativeProgressedSize, 10L ) );
+        assertThrows(IllegalArgumentException.class, () -> format.formatProgress(negativeProgressedSize, 10L));
     }
 
     @Test
-    public void testNegativeProgressedSizeBiggerThanSize()
-    {
-        FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testNegativeProgressedSizeBiggerThanSize() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
-        assertThrows( IllegalArgumentException.class, () -> format.formatProgress( 100L, 10L ) );
+        assertThrows(IllegalArgumentException.class, () -> format.formatProgress(100L, 10L));
     }
 
     @Test
-    public void testProgressedSizeWithoutSize()
-    {
-         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testProgressedSizeWithoutSize() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
-         long _0_bytes = 0L;
-         assertEquals( "0 B", format.formatProgress( _0_bytes, -1L ) );
+        long _0_bytes = 0L;
+        assertEquals("0 B", format.formatProgress(_0_bytes, -1L));
 
-         long _1000_bytes = 1000L;
-         assertEquals( "1.0 kB", format.formatProgress( _1000_bytes, -1L ) );
+        long _1000_bytes = 1000L;
+        assertEquals("1.0 kB", format.formatProgress(_1000_bytes, -1L));
 
-         long _1000_kilobytes = 1000L * 1000L;
-         assertEquals( "1.0 MB", format.formatProgress( _1000_kilobytes, -1L ) );
+        long _1000_kilobytes = 1000L * 1000L;
+        assertEquals("1.0 MB", format.formatProgress(_1000_kilobytes, -1L));
 
-         long _1000_megabytes = 1000L * 1000L * 1000L;
-         assertEquals( "1.0 GB", format.formatProgress( _1000_megabytes, -1L ) );
-
+        long _1000_megabytes = 1000L * 1000L * 1000L;
+        assertEquals("1.0 GB", format.formatProgress(_1000_megabytes, -1L));
     }
 
     @Test
-    public void testProgressedBothZero()
-    {
-         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testProgressedBothZero() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
-         long _0_bytes = 0L;
-         assertEquals( "0 B", format.formatProgress( _0_bytes, _0_bytes ) );
+        long _0_bytes = 0L;
+        assertEquals("0 B", format.formatProgress(_0_bytes, _0_bytes));
     }
 
     @Test
-    public void testProgressedSizeWithSize()
-    {
-         FileSizeFormat format = new FileSizeFormat( Locale.ENGLISH );
+    void testProgressedSizeWithSize() {
+        FileSizeFormat format = new FileSizeFormat(Locale.ENGLISH);
 
-         long _0_bytes = 0L;
-         long _400_bytes = 400L;
-         long _800_bytes = 2L * _400_bytes;
-         assertEquals( "0/800 B", format.formatProgress( _0_bytes, _800_bytes ) );
-         assertEquals( "400/800 B", format.formatProgress( _400_bytes, _800_bytes ) );
-         assertEquals( "800 B", format.formatProgress( _800_bytes, _800_bytes ) );
+        long _0_bytes = 0L;
+        long _400_bytes = 400L;
+        long _800_bytes = 2L * _400_bytes;
+        assertEquals("0/800 B", format.formatProgress(_0_bytes, _800_bytes));
+        assertEquals("400/800 B", format.formatProgress(_400_bytes, _800_bytes));
+        assertEquals("800 B", format.formatProgress(_800_bytes, _800_bytes));
 
-         long _4000_bytes = 4000L;
-         long _8000_bytes = 2L * _4000_bytes;
-         long _50_kilobytes = 50000L;
-         assertEquals( "0/8.0 kB", format.formatProgress( _0_bytes, _8000_bytes ) );
-         assertEquals( "0.4/8.0 kB", format.formatProgress( _400_bytes, _8000_bytes ) );
-         assertEquals( "4.0/8.0 kB", format.formatProgress( _4000_bytes, _8000_bytes ) );
-         assertEquals( "8.0 kB", format.formatProgress( _8000_bytes, _8000_bytes ) );
-         assertEquals( "8.0/50 kB", format.formatProgress( _8000_bytes, _50_kilobytes ) );
-         assertEquals( "16/50 kB", format.formatProgress( 2L * _8000_bytes, _50_kilobytes ) );
-         assertEquals( "50 kB", format.formatProgress( _50_kilobytes, _50_kilobytes ) );
+        long _4000_bytes = 4000L;
+        long _8000_bytes = 2L * _4000_bytes;
+        long _50_kilobytes = 50000L;
+        assertEquals("0/8.0 kB", format.formatProgress(_0_bytes, _8000_bytes));
+        assertEquals("0.4/8.0 kB", format.formatProgress(_400_bytes, _8000_bytes));
+        assertEquals("4.0/8.0 kB", format.formatProgress(_4000_bytes, _8000_bytes));
+        assertEquals("8.0 kB", format.formatProgress(_8000_bytes, _8000_bytes));
+        assertEquals("8.0/50 kB", format.formatProgress(_8000_bytes, _50_kilobytes));
+        assertEquals("16/50 kB", format.formatProgress(2L * _8000_bytes, _50_kilobytes));
+        assertEquals("50 kB", format.formatProgress(_50_kilobytes, _50_kilobytes));
 
-         long _500_kilobytes = 500000L;
-         long _1000_kilobytes = 2L * _500_kilobytes;;
-         long _5000_kilobytes = 5L * _1000_kilobytes;
-         long _15_megabytes = 3L * _5000_kilobytes;
-         assertEquals( "0/5.0 MB", format.formatProgress( _0_bytes, _5000_kilobytes ) );
-         assertEquals( "0.5/5.0 MB", format.formatProgress( _500_kilobytes, _5000_kilobytes ) );
-         assertEquals( "1.0/5.0 MB", format.formatProgress( _1000_kilobytes, _5000_kilobytes ) );
-         assertEquals( "5.0 MB", format.formatProgress( _5000_kilobytes, _5000_kilobytes ) );
-         assertEquals( "5.0/15 MB", format.formatProgress( _5000_kilobytes, _15_megabytes ) );
-         assertEquals( "15 MB", format.formatProgress( _15_megabytes, _15_megabytes ) );
+        long _500_kilobytes = 500000L;
+        long _1000_kilobytes = 2L * _500_kilobytes;
+        ;
+        long _5000_kilobytes = 5L * _1000_kilobytes;
+        long _15_megabytes = 3L * _5000_kilobytes;
+        assertEquals("0/5.0 MB", format.formatProgress(_0_bytes, _5000_kilobytes));
+        assertEquals("0.5/5.0 MB", format.formatProgress(_500_kilobytes, _5000_kilobytes));
+        assertEquals("1.0/5.0 MB", format.formatProgress(_1000_kilobytes, _5000_kilobytes));
+        assertEquals("5.0 MB", format.formatProgress(_5000_kilobytes, _5000_kilobytes));
+        assertEquals("5.0/15 MB", format.formatProgress(_5000_kilobytes, _15_megabytes));
+        assertEquals("15 MB", format.formatProgress(_15_megabytes, _15_megabytes));
 
-         long _500_megabytes = 500000000L;
-         long _1000_megabytes = 2L * _500_megabytes;
-         long _5000_megabytes = 5L * _1000_megabytes;
-         long _15_gigabytes = 3L * _5000_megabytes;
-         assertEquals( "0/500 MB", format.formatProgress( _0_bytes, _500_megabytes ) );
-         assertEquals( "1.0/5.0 GB", format.formatProgress( _1000_megabytes, _5000_megabytes ) );
-         assertEquals( "5.0 GB", format.formatProgress( _5000_megabytes, _5000_megabytes ) );
-         assertEquals( "5.0/15 GB", format.formatProgress( _5000_megabytes, _15_gigabytes ) );
-         assertEquals( "15 GB", format.formatProgress( _15_gigabytes, _15_gigabytes ) );
+        long _500_megabytes = 500000000L;
+        long _1000_megabytes = 2L * _500_megabytes;
+        long _5000_megabytes = 5L * _1000_megabytes;
+        long _15_gigabytes = 3L * _5000_megabytes;
+        assertEquals("0/500 MB", format.formatProgress(_0_bytes, _500_megabytes));
+        assertEquals("1.0/5.0 GB", format.formatProgress(_1000_megabytes, _5000_megabytes));
+        assertEquals("5.0 GB", format.formatProgress(_5000_megabytes, _5000_megabytes));
+        assertEquals("5.0/15 GB", format.formatProgress(_5000_megabytes, _15_gigabytes));
+        assertEquals("15 GB", format.formatProgress(_15_gigabytes, _15_gigabytes));
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-embedder/src/test/projects/mavenConfigProperties/.mvn/maven.config b/maven-embedder/src/test/projects/mavenConfigProperties/.mvn/maven.config
index 8257023..7f7a687 100644
--- a/maven-embedder/src/test/projects/mavenConfigProperties/.mvn/maven.config
+++ b/maven-embedder/src/test/projects/mavenConfigProperties/.mvn/maven.config
@@ -1,3 +1,4 @@
+# a comment
 -T
 3
 -Drevision=1.3.0
diff --git a/maven-embedder/src/test/projects/root-attribute/child/pom.xml b/maven-embedder/src/test/projects/root-attribute/child/pom.xml
new file mode 100644
index 0000000..7e5b53c
--- /dev/null
+++ b/maven-embedder/src/test/projects/root-attribute/child/pom.xml
@@ -0,0 +1,3 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0">
+
+</project>
\ No newline at end of file
diff --git a/maven-embedder/src/test/projects/root-attribute/pom.xml b/maven-embedder/src/test/projects/root-attribute/pom.xml
new file mode 100644
index 0000000..c44d4f0
--- /dev/null
+++ b/maven-embedder/src/test/projects/root-attribute/pom.xml
@@ -0,0 +1,3 @@
+<project root="true" xmlns="http://maven.apache.org/POM/4.0.0">
+
+</project>
\ No newline at end of file
diff --git a/maven-model-builder/pom.xml b/maven-model-builder/pom.xml
index 27ec86f..23c8c35 100644
--- a/maven-model-builder/pom.xml
+++ b/maven-model-builder/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-model-builder</artifactId>
@@ -35,8 +33,16 @@
 
   <dependencies>
     <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-spi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-xml-impl</artifactId>
     </dependency>
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
@@ -58,14 +64,11 @@
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-builder-support</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
-      <artifactId>maven-model-transform</artifactId>
-    </dependency>
     <!-- Testing -->
     <dependency>
       <groupId>org.eclipse.sisu</groupId>
       <artifactId>org.eclipse.sisu.inject</artifactId>
+      <classifier>no_asm</classifier>
     </dependency>
     <dependency>
       <groupId>org.eclipse.sisu</groupId>
@@ -75,7 +78,7 @@
     <dependency>
       <groupId>com.google.inject</groupId>
       <artifactId>guice</artifactId>
-      <classifier>no_aop</classifier>
+      <classifier>classes</classifier>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -89,6 +92,11 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>org.xmlunit</groupId>
       <artifactId>xmlunit-core</artifactId>
       <scope>test</scope>
@@ -98,6 +106,11 @@
       <artifactId>xmlunit-matchers</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.xmlunit</groupId>
+      <artifactId>xmlunit-assertj</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <build>
@@ -106,6 +119,74 @@
         <groupId>org.eclipse.sisu</groupId>
         <artifactId>sisu-maven-plugin</artifactId>
       </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <oldVersion>
+            <dependency>
+              <groupId>${project.groupId}</groupId>
+              <artifactId>${project.artifactId}</artifactId>
+              <version>${maven.baseline}</version>
+            </dependency>
+          </oldVersion>
+          <parameter>
+            <excludes>
+              <exclude>org.apache.maven.model.building.DefaultModelBuilder#DefaultModelBuilder():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.building.DefaultModelProcessor#setModelLocator(org.apache.maven.model.locator.ModelLocator):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.building.DefaultModelProcessor#setModelReader(org.apache.maven.model.io.ModelReader):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.building.DefaultModelProcessor#DefaultModelProcessor():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#get(org.apache.maven.building.Source,java.lang.String):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#get(org.apache.maven.building.Source,org.apache.maven.model.building.ModelCacheTag):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#get(java.lang.String,java.lang.String,java.lang.String,org.apache.maven.model.building.ModelCacheTag):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#put(org.apache.maven.building.Source,java.lang.String,java.lang.Object):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#put(org.apache.maven.building.Source,org.apache.maven.model.building.ModelCacheTag,java.lang.Object):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#put(java.lang.String,java.lang.String,java.lang.String,org.apache.maven.model.building.ModelCacheTag,java.lang.Object):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#computeIfAbsent(java.lang.String,java.lang.String,java.lang.String,org.apache.maven.model.building.ModelCacheTag,java.util.function.Supplier):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.building.ModelCache#computeIfAbsent(org.apache.maven.building.Source,org.apache.maven.model.building.ModelCacheTag,java.util.function.Supplier):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.composition.DependencyManagementImporter#importManagement(org.apache.maven.model.Model,java.util.List,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.composition.DefaultDependencyManagementImporter#importManagement(org.apache.maven.model.Model,java.util.List,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.inheritance.DefaultInheritanceAssembler</exclude>
+              <exclude>org.apache.maven.model.inheritance.InheritanceAssembler#assembleModelInheritance(org.apache.maven.model.Model,org.apache.maven.model.Model,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.interpolation.AbstractStringBasedModelInterpolator</exclude>
+              <exclude>org.apache.maven.model.interpolation.StringSearchModelInterpolator</exclude>
+              <exclude>org.apache.maven.model.interpolation.StringVisitorModelInterpolator</exclude>
+              <exclude>org.apache.maven.model.io.DefaultModelReader#DefaultModelReader():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.locator.ModelLocator#locateExistingPom(java.io.File):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.management.DefaultDependencyManagementInjector$ManagementModelMerger</exclude>
+              <exclude>org.apache.maven.model.management.DefaultPluginManagementInjector$ManagementModelMerger</exclude>
+              <exclude>org.apache.maven.model.merge.MavenModelMerger</exclude>
+              <exclude>org.apache.maven.model.normalization.DefaultModelNormalizer$DuplicateMerger#mergePlugin(org.apache.maven.model.Plugin,org.apache.maven.model.Plugin):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.normalization.DefaultModelNormalizer$DuplicateMerger:METHOD_REMOVED_IN_SUPERCLASS</exclude>
+              <exclude>org.apache.maven.model.path.DefaultModelPathTranslator#setPathTranslator(org.apache.maven.model.path.PathTranslator):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.path.DefaultModelPathTranslator#DefaultModelPathTranslator():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.path.DefaultModelUrlNormalizer#setUrlNormalizer(org.apache.maven.model.path.UrlNormalizer):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.path.DefaultModelUrlNormalizer#DefaultModelUrlNormalizer():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.path.ProfileActivationFilePathInterpolator#setPathTranslator(org.apache.maven.model.path.PathTranslator):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.path.ProfileActivationFilePathInterpolator#ProfileActivationFilePathInterpolator():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.profile.activation.FileProfileActivator#setProfileActivationFilePathInterpolator(org.apache.maven.model.path.ProfileActivationFilePathInterpolator):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.profile.activation.FileProfileActivator#FileProfileActivator():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.profile.DefaultProfileInjector</exclude>
+              <exclude>org.apache.maven.model.profile.ProfileInjector#injectProfile(org.apache.maven.api.model.Model,org.apache.maven.api.model.Profile,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.profile.ProfileInjector#injectProfiles(org.apache.maven.api.model.Model,java.util.List,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.profile.ProfileSelector#getActiveProfilesV4(java.util.Collection,org.apache.maven.model.profile.ProfileActivationContext,org.apache.maven.model.building.ModelProblemCollector):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.resolution.InvalidRepositoryException#getRepository():METHOD_RETURN_TYPE_CHANGED</exclude>
+              <exclude>org.apache.maven.model.resolution.InvalidRepositoryException#InvalidRepositoryException(java.lang.String,org.apache.maven.model.Repository,java.lang.Throwable):CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.resolution.InvalidRepositoryException#InvalidRepositoryException(java.lang.String,org.apache.maven.model.Repository):CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.resolution.ModelResolver#addRepository(org.apache.maven.api.model.Repository):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.resolution.ModelResolver#addRepository(org.apache.maven.api.model.Repository,boolean):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.resolution.ModelResolver#resolveModel(org.apache.maven.api.model.Parent,java.util.concurrent.atomic.AtomicReference):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.resolution.ModelResolver#resolveModel(org.apache.maven.api.model.Dependency,java.util.concurrent.atomic.AtomicReference):METHOD_NEW_DEFAULT</exclude>
+              <exclude>org.apache.maven.model.superpom.DefaultSuperPomProvider#getSuperModel(java.lang.String):METHOD_RETURN_TYPE_CHANGED</exclude>
+              <exclude>org.apache.maven.model.superpom.DefaultSuperPomProvider#setModelProcessor(org.apache.maven.model.building.ModelProcessor):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.superpom.DefaultSuperPomProvider#DefaultSuperPomProvider():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.model.superpom.SuperPomProvider#getSuperModel(java.lang.String):METHOD_RETURN_TYPE_CHANGED</exclude>
+              <exclude>org.apache.maven.model.validation.DefaultModelValidator#validateDependencyVersion(org.apache.maven.model.building.ModelProblemCollector,org.apache.maven.model.Dependency,java.lang.String):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.validation.ModelValidator#validateFileModel(org.apache.maven.model.Model,org.apache.maven.model.building.ModelBuildingRequest,org.apache.maven.model.building.ModelProblemCollector):METHOD_NEW_DEFAULT</exclude>
+            </excludes>
+          </parameter>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
diff --git a/maven-model-builder/src/main/java/org/apache/maven/feature/Features.java b/maven-model-builder/src/main/java/org/apache/maven/feature/Features.java
deleted file mode 100644
index 47608a6..0000000
--- a/maven-model-builder/src/main/java/org/apache/maven/feature/Features.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package org.apache.maven.feature;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Properties;
-
-/**
- * Centralized class for feature information
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public final class Features
-{
-    private Features()
-    {
-    }
-
-    public static Feature buildConsumer( Properties userProperties )
-    {
-        return new Feature( userProperties, "maven.experimental.buildconsumer", "true" );
-    }
-
-    /**
-     * Represents some feature
-     *
-     * @author Robert Scholte
-     * @since 4.0.0
-     */
-    public static class Feature
-    {
-        private final boolean active;
-
-        private final String name;
-
-        Feature( Properties userProperties, String name, String defaultValue )
-        {
-            this.name = name;
-            this.active = "true".equals( userProperties.getProperty( name, defaultValue ) );
-        }
-
-        public boolean isActive()
-        {
-           return active;
-        }
-
-        public String propertyName()
-        {
-            return name;
-        }
-
-    }
-
-}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelBuildingListener.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelBuildingListener.java
index 5138776..c76bb89 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelBuildingListener.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelBuildingListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,20 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 /**
  * Provides a skeleton implementation for model building listeners. The methods of this class are empty.
  *
- * @author Benjamin Bentmann
  */
-public class AbstractModelBuildingListener
-    implements ModelBuildingListener
-{
+public class AbstractModelBuildingListener implements ModelBuildingListener {
 
     @Override
-    public void buildExtensionsAssembled( ModelBuildingEvent event )
-    {
+    public void buildExtensionsAssembled(ModelBuildingEvent event) {
         // default does nothing
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
deleted file mode 100644
index 3ea1dbf..0000000
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/AbstractModelSourceTransformer.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.apache.maven.model.building;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- * Offers a transformation implementation based on PipelineStreams.
- * Subclasses are responsible for providing the right SAXFilter.
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public abstract class AbstractModelSourceTransformer
-    implements ModelSourceTransformer
-{
-
-}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ArtifactModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ArtifactModelSource.java
index 06d4faf..0657564 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ArtifactModelSource.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ArtifactModelSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
 import java.util.Objects;
@@ -27,11 +26,9 @@
 /**
  * Represents a model pulled from a repository
  *
- * @author Robert Scholte
  * @since 4.0.0
  */
-public class ArtifactModelSource extends FileSource implements ModelSource
-{
+public class ArtifactModelSource extends FileSource implements ModelSource {
     private final String groupId;
 
     private final String artifactId;
@@ -40,56 +37,52 @@
 
     private final int hashCode;
 
-    public ArtifactModelSource( File file, String groupId, String artifactId, String version )
-    {
-        super( file );
+    public ArtifactModelSource(File file, String groupId, String artifactId, String version) {
+        super(file);
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.version = version;
-        this.hashCode = Objects.hash( groupId, artifactId, version );
+        this.hashCode = Objects.hash(groupId, artifactId, version);
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         return hashCode;
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
-        if ( obj == null )
-        {
+        if (obj == null) {
             return false;
         }
 
-        if ( !ArtifactModelSource.class.equals( obj.getClass() )  )
-        {
+        if (!ArtifactModelSource.class.equals(obj.getClass())) {
             return false;
         }
 
         ArtifactModelSource other = (ArtifactModelSource) obj;
-        return Objects.equals( artifactId, other.artifactId )
-            && Objects.equals( groupId, other.groupId )
-            && Objects.equals( version, other.version );
+        return Objects.equals(artifactId, other.artifactId)
+                && Objects.equals(groupId, other.groupId)
+                && Objects.equals(version, other.version);
+    }
+
+    @Override
+    public String toString() {
+        return groupId + ":" + artifactId + ":" + version;
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
index 9da284b..cc1b90c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/BuildModelSourceTransformer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,33 +16,175 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.IOException;
-import java.nio.file.Path;
+package org.apache.maven.model.building;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.maven.model.transform.BuildToRawPomXMLFilterFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.maven.model.Dependency;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.Parent;
 
 /**
  * ModelSourceTransformer for the build pom
  *
- * @author Robert Scholte
  * @since 4.0.0
  */
 @Named
 @Singleton
-class BuildModelSourceTransformer implements ModelSourceTransformer
-{
-    @Override
-    public XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
-            throws IOException, TransformerException
-    {
-        BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory =
-                new DefaultBuildPomXMLFilterFactory( context, false );
+class BuildModelSourceTransformer implements ModelSourceTransformer {
 
-        return buildPomXMLFilterFactory.get( parser, pomFile );
+    public static final String NAMESPACE_PREFIX = "http://maven.apache.org/POM/";
+
+    @Override
+    public void transform(Path pomFile, TransformerContext context, Model model) {
+        handleModelVersion(model);
+        handleParent(pomFile, context, model);
+        handleReactorDependencies(context, model);
+        handleCiFriendlyVersion(context, model);
+    }
+
+    //
+    // Infer modelVersion from namespace URI
+    //
+    void handleModelVersion(Model model) {
+        String namespace = model.getDelegate().getNamespaceUri();
+        if (model.getModelVersion() == null && namespace != null && namespace.startsWith(NAMESPACE_PREFIX)) {
+            model.setModelVersion(namespace.substring(NAMESPACE_PREFIX.length()));
+        }
+    }
+
+    //
+    // Infer parent information
+    //
+    void handleParent(Path pomFile, TransformerContext context, Model model) {
+        Parent parent = model.getParent();
+        if (parent != null) {
+            String version = parent.getVersion();
+            String path = Optional.ofNullable(parent.getRelativePath()).orElse("..");
+            if (version == null && !path.isEmpty()) {
+                Optional<RelativeProject> resolvedParent = resolveRelativePath(
+                        pomFile, context, Paths.get(path), parent.getGroupId(), parent.getArtifactId());
+                resolvedParent.ifPresent(relativeProject -> parent.setVersion(relativeProject.getVersion()));
+            }
+        }
+    }
+
+    //
+    // CI friendly versions
+    //
+    void handleCiFriendlyVersion(TransformerContext context, Model model) {
+        String version = model.getVersion();
+        String modVersion = replaceCiFriendlyVersion(context, version);
+        model.setVersion(modVersion);
+
+        Parent parent = model.getParent();
+        if (parent != null) {
+            version = parent.getVersion();
+            modVersion = replaceCiFriendlyVersion(context, version);
+            parent.setVersion(modVersion);
+        }
+    }
+
+    //
+    // Infer inner reactor dependencies version
+    //
+    void handleReactorDependencies(TransformerContext context, Model model) {
+        for (Dependency dep : model.getDependencies()) {
+            if (dep.getVersion() == null) {
+                Model depModel =
+                        context.getRawModel(model.getDelegate().getPomFile(), dep.getGroupId(), dep.getArtifactId());
+                if (depModel != null) {
+                    String v = depModel.getVersion();
+                    if (v == null && depModel.getParent() != null) {
+                        v = depModel.getParent().getVersion();
+                    }
+                    dep.setVersion(v);
+                }
+            }
+        }
+    }
+
+    protected String replaceCiFriendlyVersion(TransformerContext context, String version) {
+        if (version != null) {
+            for (String key : Arrays.asList("changelist", "revision", "sha1")) {
+                String val = context.getUserProperty(key);
+                if (val != null) {
+                    version = version.replace("${" + key + "}", val);
+                }
+            }
+        }
+        return version;
+    }
+
+    protected Optional<RelativeProject> resolveRelativePath(
+            Path pomFile, TransformerContext context, Path relativePath, String groupId, String artifactId) {
+        Path pomPath = pomFile.resolveSibling(relativePath).normalize();
+        if (Files.isDirectory(pomPath)) {
+            pomPath = context.locate(pomPath);
+        }
+
+        if (pomPath == null || !Files.isRegularFile(pomPath)) {
+            return Optional.empty();
+        }
+
+        Optional<RelativeProject> mappedProject = Optional.ofNullable(context.getRawModel(pomFile, pomPath.normalize()))
+                .map(BuildModelSourceTransformer::toRelativeProject);
+
+        if (mappedProject.isPresent()) {
+            RelativeProject project = mappedProject.get();
+
+            if (Objects.equals(groupId, project.getGroupId()) && Objects.equals(artifactId, project.getArtifactId())) {
+                return mappedProject;
+            }
+        }
+        return Optional.empty();
+    }
+
+    private static RelativeProject toRelativeProject(final org.apache.maven.model.Model m) {
+        String groupId = m.getGroupId();
+        if (groupId == null && m.getParent() != null) {
+            groupId = m.getParent().getGroupId();
+        }
+
+        String version = m.getVersion();
+        if (version == null && m.getParent() != null) {
+            version = m.getParent().getVersion();
+        }
+
+        return new RelativeProject(groupId, m.getArtifactId(), version);
+    }
+
+    static class RelativeProject {
+        private final String groupId;
+
+        private final String artifactId;
+
+        private final String version;
+
+        RelativeProject(String groupId, String artifactId, String version) {
+            this.groupId = groupId;
+            this.artifactId = artifactId;
+            this.version = version;
+        }
+
+        public String getGroupId() {
+            return groupId;
+        }
+
+        public String getArtifactId() {
+            return artifactId;
+        }
+
+        public String getVersion() {
+            return version;
+        }
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
deleted file mode 100644
index e415461..0000000
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultBuildPomXMLFilterFactory.java
+++ /dev/null
@@ -1,114 +0,0 @@
-package org.apache.maven.model.building;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import org.apache.maven.model.Model;
-import org.apache.maven.model.transform.BuildToRawPomXMLFilterFactory;
-import org.apache.maven.model.transform.RelativeProject;
-
-/**
- * A BuildPomXMLFilterFactory which is context aware
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class DefaultBuildPomXMLFilterFactory extends BuildToRawPomXMLFilterFactory
-{
-    private final TransformerContext context;
-
-    /**
-     *
-     * @param context a set of data to extract values from as required for the build pom
-     * @param consume {@code true} if this factory is being used for creating the consumer pom, otherwise {@code false}
-     */
-    public DefaultBuildPomXMLFilterFactory( TransformerContext context,
-                                            boolean consume )
-    {
-        super( consume );
-        this.context = context;
-    }
-
-    @Override
-    protected Function<Path, Optional<RelativeProject>> getRelativePathMapper()
-    {
-        return p -> Optional.ofNullable( context.getRawModel( p ) )
-                .map( DefaultBuildPomXMLFilterFactory::toRelativeProject );
-    }
-
-    @Override
-    protected BiFunction<String, String, String> getDependencyKeyToVersionMapper()
-    {
-        return ( g, a ) -> Optional.ofNullable( context.getRawModel( g, a ) )
-                            .map( DefaultBuildPomXMLFilterFactory::toVersion )
-                            .orElse( null );
-    }
-
-    @Override
-    protected Optional<String> getChangelist()
-    {
-        return Optional.ofNullable( context.getUserProperty( "changelist" ) );
-    }
-
-    @Override
-    protected Optional<String> getRevision()
-    {
-        return Optional.ofNullable( context.getUserProperty( "revision" ) );
-    }
-
-    @Override
-    protected Optional<String> getSha1()
-    {
-        return Optional.ofNullable( context.getUserProperty( "sha1" ) );
-    }
-
-    private static RelativeProject toRelativeProject( final Model m )
-    {
-        String groupId = m.getGroupId();
-        if ( groupId == null && m.getParent() != null )
-        {
-            groupId = m.getParent().getGroupId();
-        }
-
-        String version = m.getVersion();
-        if ( version == null && m.getParent() != null )
-        {
-            version = m.getParent().getVersion();
-        }
-
-        return new RelativeProject( groupId, m.getArtifactId(), version );
-    }
-
-    private static String toVersion( final Model m )
-    {
-        String version = m.getVersion();
-        if ( version == null && m.getParent() != null )
-        {
-            version = m.getParent().getVersion();
-        }
-
-        return version;
-    }
-}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
index de84b90..033ca11 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,60 +16,49 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static org.apache.maven.model.building.Result.error;
-import static org.apache.maven.model.building.Result.newResult;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Properties;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+package org.apache.maven.model.building;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.*;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ForkJoinTask;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.feature.Features;
+import org.apache.maven.api.model.Exclusion;
+import org.apache.maven.api.model.InputSource;
 import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
 import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
 import org.apache.maven.artifact.versioning.VersionRange;
 import org.apache.maven.building.Source;
-import org.apache.maven.feature.Features;
 import org.apache.maven.model.Activation;
-import org.apache.maven.model.ActivationFile;
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Dependency;
 import org.apache.maven.model.DependencyManagement;
 import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.InputSource;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Parent;
 import org.apache.maven.model.Plugin;
 import org.apache.maven.model.PluginManagement;
 import org.apache.maven.model.Profile;
-import org.apache.maven.model.Repository;
 import org.apache.maven.model.building.ModelProblem.Severity;
 import org.apache.maven.model.building.ModelProblem.Version;
 import org.apache.maven.model.composition.DependencyManagementImporter;
 import org.apache.maven.model.inheritance.InheritanceAssembler;
 import org.apache.maven.model.interpolation.ModelInterpolator;
+import org.apache.maven.model.interpolation.ModelVersionProcessor;
 import org.apache.maven.model.io.ModelParseException;
 import org.apache.maven.model.io.ModelReader;
 import org.apache.maven.model.management.DependencyManagementInjector;
 import org.apache.maven.model.management.PluginManagementInjector;
-import org.apache.maven.model.merge.ModelMerger;
 import org.apache.maven.model.normalization.ModelNormalizer;
 import org.apache.maven.model.path.ModelPathTranslator;
 import org.apache.maven.model.path.ModelUrlNormalizer;
@@ -89,21 +76,21 @@
 import org.apache.maven.model.resolution.UnresolvableModelException;
 import org.apache.maven.model.resolution.WorkspaceModelResolver;
 import org.apache.maven.model.superpom.SuperPomProvider;
+import org.apache.maven.model.validation.DefaultModelValidator;
 import org.apache.maven.model.validation.ModelValidator;
 import org.codehaus.plexus.interpolation.InterpolationException;
 import org.codehaus.plexus.interpolation.MapBasedValueSource;
 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
 import org.eclipse.sisu.Nullable;
 
+import static org.apache.maven.model.building.Result.error;
+import static org.apache.maven.model.building.Result.newResult;
+
 /**
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultModelBuilder
-    implements ModelBuilder
-{
-    private final ModelMerger modelMerger = new FileToRawModelMerger();
+public class DefaultModelBuilder implements ModelBuilder {
 
     private final ModelProcessor modelProcessor;
     private final ModelValidator modelValidator;
@@ -121,9 +108,11 @@
     private final LifecycleBindingsInjector lifecycleBindingsInjector;
     private final PluginConfigurationExpander pluginConfigurationExpander;
     private final ReportConfigurationExpander reportConfigurationExpander;
-    private final ReportingConverter reportingConverter;
     private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
+    private final ModelVersionProcessor versionProcessor;
+    private final ModelSourceTransformer transformer;
 
+    @SuppressWarnings("checkstyle:ParameterNumber")
     @Inject
     public DefaultModelBuilder(
             ModelProcessor modelProcessor,
@@ -142,9 +131,9 @@
             @Nullable LifecycleBindingsInjector lifecycleBindingsInjector,
             PluginConfigurationExpander pluginConfigurationExpander,
             ReportConfigurationExpander reportConfigurationExpander,
-            ReportingConverter reportingConverter,
-            ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator )
-    {
+            ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator,
+            ModelVersionProcessor versionProcessor,
+            ModelSourceTransformer transformer) {
         this.modelProcessor = modelProcessor;
         this.modelValidator = modelValidator;
         this.modelNormalizer = modelNormalizer;
@@ -161,64 +150,121 @@
         this.lifecycleBindingsInjector = lifecycleBindingsInjector;
         this.pluginConfigurationExpander = pluginConfigurationExpander;
         this.reportConfigurationExpander = reportConfigurationExpander;
-        this.reportingConverter = reportingConverter;
         this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
+        this.versionProcessor = versionProcessor;
+        this.transformer = transformer;
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setModelProcessor(ModelProcessor) 
+     * @see DefaultModelBuilderFactory#setModelProcessor(ModelProcessor)
      */
     @Deprecated
-    public DefaultModelBuilder setModelProcessor( ModelProcessor modelProcessor )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setModelProcessor(ModelProcessor modelProcessor) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setModelProcessor(ModelProcessor) 
+     * @see DefaultModelBuilderFactory#setModelProcessor(ModelProcessor)
      */
     @Deprecated
-    public DefaultModelBuilder setModelValidator( ModelValidator modelValidator )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setModelValidator(ModelValidator modelValidator) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setModelNormalizer(ModelNormalizer) 
+     * @see DefaultModelBuilderFactory#setModelNormalizer(ModelNormalizer)
      */
     @Deprecated
-    public DefaultModelBuilder setModelNormalizer( ModelNormalizer modelNormalizer )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setModelNormalizer(ModelNormalizer modelNormalizer) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setModelInterpolator(ModelInterpolator) 
+     * @see DefaultModelBuilderFactory#setModelInterpolator(ModelInterpolator)
      */
     @Deprecated
-    public DefaultModelBuilder setModelInterpolator( ModelInterpolator modelInterpolator )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setModelInterpolator(ModelInterpolator modelInterpolator) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
@@ -226,55 +272,111 @@
      * @see DefaultModelBuilderFactory#setModelPathTranslator(ModelPathTranslator)
      */
     @Deprecated
-    public DefaultModelBuilder setModelPathTranslator( ModelPathTranslator modelPathTranslator )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setModelPathTranslator(ModelPathTranslator modelPathTranslator) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setModelUrlNormalizer(ModelUrlNormalizer) 
+     * @see DefaultModelBuilderFactory#setModelUrlNormalizer(ModelUrlNormalizer)
      */
     @Deprecated
-    public DefaultModelBuilder setModelUrlNormalizer( ModelUrlNormalizer modelUrlNormalizer )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setModelUrlNormalizer(ModelUrlNormalizer modelUrlNormalizer) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setSuperPomProvider(SuperPomProvider) 
+     * @see DefaultModelBuilderFactory#setSuperPomProvider(SuperPomProvider)
      */
     @Deprecated
-    public DefaultModelBuilder setSuperPomProvider( SuperPomProvider superPomProvider )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setSuperPomProvider(SuperPomProvider superPomProvider) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setInheritanceAssembler(InheritanceAssembler) 
+     * @see DefaultModelBuilderFactory#setInheritanceAssembler(InheritanceAssembler)
      */
     @Deprecated
-    public DefaultModelBuilder setInheritanceAssembler( InheritanceAssembler inheritanceAssembler )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setInheritanceAssembler(InheritanceAssembler inheritanceAssembler) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
@@ -282,127 +384,225 @@
      * @see DefaultModelBuilderFactory#setProfileSelector(ProfileSelector)
      */
     @Deprecated
-    public DefaultModelBuilder setProfileSelector( ProfileSelector profileSelector )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setProfileSelector(ProfileSelector profileSelector) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setProfileInjector(ProfileInjector) 
+     * @see DefaultModelBuilderFactory#setProfileInjector(ProfileInjector)
      */
     @Deprecated
-    public DefaultModelBuilder setProfileInjector( ProfileInjector profileInjector )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setProfileInjector(ProfileInjector profileInjector) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setPluginManagementInjector(PluginManagementInjector) 
+     * @see DefaultModelBuilderFactory#setPluginManagementInjector(PluginManagementInjector)
      */
     @Deprecated
-    public DefaultModelBuilder setPluginManagementInjector( PluginManagementInjector pluginManagementInjector )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setPluginManagementInjector(PluginManagementInjector pluginManagementInjector) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setDependencyManagementInjector(DependencyManagementInjector)  
+     * @see DefaultModelBuilderFactory#setDependencyManagementInjector(DependencyManagementInjector)
      */
     @Deprecated
     public DefaultModelBuilder setDependencyManagementInjector(
-            DependencyManagementInjector dependencyManagementInjector )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+            DependencyManagementInjector dependencyManagementInjector) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setDependencyManagementImporter(DependencyManagementImporter) 
+     * @see DefaultModelBuilderFactory#setDependencyManagementImporter(DependencyManagementImporter)
      */
     @Deprecated
     public DefaultModelBuilder setDependencyManagementImporter(
-            DependencyManagementImporter dependencyManagementImporter )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+            DependencyManagementImporter dependencyManagementImporter) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setLifecycleBindingsInjector(LifecycleBindingsInjector) 
+     * @see DefaultModelBuilderFactory#setLifecycleBindingsInjector(LifecycleBindingsInjector)
      */
     @Deprecated
-    public DefaultModelBuilder setLifecycleBindingsInjector( LifecycleBindingsInjector lifecycleBindingsInjector )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setLifecycleBindingsInjector(LifecycleBindingsInjector lifecycleBindingsInjector) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setPluginConfigurationExpander(PluginConfigurationExpander) 
+     * @see DefaultModelBuilderFactory#setPluginConfigurationExpander(PluginConfigurationExpander)
      */
     @Deprecated
-    public DefaultModelBuilder setPluginConfigurationExpander( PluginConfigurationExpander pluginConfigurationExpander )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setPluginConfigurationExpander(PluginConfigurationExpander pluginConfigurationExpander) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
      * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setReportConfigurationExpander(ReportConfigurationExpander)  
+     * @see DefaultModelBuilderFactory#setReportConfigurationExpander(ReportConfigurationExpander)
      */
     @Deprecated
-    public DefaultModelBuilder setReportConfigurationExpander( ReportConfigurationExpander reportConfigurationExpander )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
-    }
-
-    /**
-     * @deprecated since Maven 4
-     * @see DefaultModelBuilderFactory#setReportingConverter(ReportingConverter) 
-     */
-    @Deprecated
-    public DefaultModelBuilder setReportingConverter( ReportingConverter reportingConverter )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+    public DefaultModelBuilder setReportConfigurationExpander(ReportConfigurationExpander reportConfigurationExpander) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
     }
 
     /**
@@ -411,661 +611,671 @@
      */
     @Deprecated
     public DefaultModelBuilder setProfileActivationFilePathInterpolator(
-            ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator )
-    {
-        return new DefaultModelBuilder( modelProcessor, modelValidator, modelNormalizer, modelInterpolator,
-                modelPathTranslator, modelUrlNormalizer, superPomProvider, inheritanceAssembler, profileSelector,
-                profileInjector, pluginManagementInjector, dependencyManagementInjector, dependencyManagementImporter,
-                lifecycleBindingsInjector, pluginConfigurationExpander, reportConfigurationExpander,
-                reportingConverter, profileActivationFilePathInterpolator );
+            ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator) {
+        return new DefaultModelBuilder(
+                modelProcessor,
+                modelValidator,
+                modelNormalizer,
+                modelInterpolator,
+                modelPathTranslator,
+                modelUrlNormalizer,
+                superPomProvider,
+                inheritanceAssembler,
+                profileSelector,
+                profileInjector,
+                pluginManagementInjector,
+                dependencyManagementInjector,
+                dependencyManagementImporter,
+                lifecycleBindingsInjector,
+                pluginConfigurationExpander,
+                reportConfigurationExpander,
+                profileActivationFilePathInterpolator,
+                versionProcessor,
+                transformer);
+    }
+
+    /**
+     * @deprecated since Maven 4
+     * @see DefaultModelBuilderFactory#setReportingConverter(ReportingConverter)
+     */
+    @Deprecated
+    public DefaultModelBuilder setReportingConverter(ReportingConverter reportingConverter) {
+        return this;
     }
 
     @Override
-    public DefaultTransformerContextBuilder newTransformerContextBuilder()
-    {
-        return new DefaultTransformerContextBuilder();
+    public DefaultTransformerContextBuilder newTransformerContextBuilder() {
+        return new DefaultTransformerContextBuilder(this);
     }
 
     @Override
-    public ModelBuildingResult build( ModelBuildingRequest request )
-        throws ModelBuildingException
-    {
-        return build( request, new LinkedHashSet<>() );
+    public ModelBuildingResult build(ModelBuildingRequest request) throws ModelBuildingException {
+        return build(request, new LinkedHashSet<>());
     }
 
-    protected ModelBuildingResult build( ModelBuildingRequest request, Collection<String> importIds )
-        throws ModelBuildingException
-    {
+    protected ModelBuildingResult build(ModelBuildingRequest request, Collection<String> importIds)
+            throws ModelBuildingException {
         // phase 1
         DefaultModelBuildingResult result = new DefaultModelBuildingResult();
 
-        DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result );
+        DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
 
         // read and validate raw model
-        Model fileModel = readFileModel( request, problems );
+        Model fileModel = readFileModel(request, problems);
 
-        request.setFileModel( fileModel );
-        result.setFileModel( fileModel );
+        request.setFileModel(fileModel);
+        result.setFileModel(fileModel.clone());
 
-        activateFileModel( request, result, problems );
+        activateFileModel(request, result, problems);
 
-        if ( !request.isTwoPhaseBuilding() )
-        {
-            return build( request, result, importIds );
-        }
-        else if ( hasModelErrors( problems ) )
-        {
+        if (!request.isTwoPhaseBuilding()) {
+            return build(request, result, importIds);
+        } else if (hasModelErrors(problems)) {
             throw problems.newModelBuildingException();
         }
 
         return result;
     }
 
-    private void activateFileModel( final ModelBuildingRequest request, final DefaultModelBuildingResult result,
-                          DefaultModelProblemCollector problems )
-        throws ModelBuildingException
-    {
+    private void activateFileModel(
+            final ModelBuildingRequest request,
+            final DefaultModelBuildingResult result,
+            DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
         Model inputModel = request.getFileModel();
-        problems.setRootModel( inputModel );
+        problems.setRootModel(inputModel);
 
         // profile activation
-        DefaultProfileActivationContext profileActivationContext = getProfileActivationContext( request );
+        DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request);
 
-        problems.setSource( "(external profiles)" );
-        List<Profile> activeExternalProfiles = profileSelector.getActiveProfiles( request.getProfiles(),
-                                                                                  profileActivationContext, problems );
+        problems.setSource("(external profiles)");
+        List<Profile> activeExternalProfiles =
+                profileSelector.getActiveProfiles(request.getProfiles(), profileActivationContext, problems);
 
-        result.setActiveExternalProfiles( activeExternalProfiles );
+        result.setActiveExternalProfiles(activeExternalProfiles);
 
-        if ( !activeExternalProfiles.isEmpty() )
-        {
+        if (!activeExternalProfiles.isEmpty()) {
             Properties profileProps = new Properties();
-            for ( Profile profile : activeExternalProfiles )
-            {
-                profileProps.putAll( profile.getProperties() );
+            for (Profile profile : activeExternalProfiles) {
+                profileProps.putAll(profile.getProperties());
             }
-            profileProps.putAll( profileActivationContext.getUserProperties() );
-            profileActivationContext.setUserProperties( profileProps );
+            profileProps.putAll(profileActivationContext.getUserProperties());
+            profileActivationContext.setUserProperties(profileProps);
         }
 
-        profileActivationContext.setProjectProperties( inputModel.getProperties() );
-        problems.setSource( inputModel );
-        List<Profile> activePomProfiles = profileSelector.getActiveProfiles( inputModel.getProfiles(),
-                                                                             profileActivationContext, problems );
+        profileActivationContext.setProjectProperties(inputModel.getDelegate().getProperties());
+        problems.setSource(inputModel);
+        List<Profile> activePomProfiles =
+                profileSelector.getActiveProfiles(inputModel.getProfiles(), profileActivationContext, problems);
 
         // model normalization
-        problems.setSource( inputModel );
-        modelNormalizer.mergeDuplicates( inputModel, request, problems );
+        problems.setSource(inputModel);
+        inputModel.update(modelNormalizer.mergeDuplicates(inputModel.getDelegate(), request, problems));
 
-        Map<String, Activation> interpolatedActivations = getProfileActivations( inputModel, false );
-        injectProfileActivations( inputModel, interpolatedActivations );
+        Map<String, Activation> interpolatedActivations = getProfileActivations(inputModel, false);
+        injectProfileActivations(inputModel, interpolatedActivations);
 
         // profile injection
-        for ( Profile activeProfile : activePomProfiles )
-        {
-            profileInjector.injectProfile( inputModel, activeProfile, request, problems );
+        for (Profile activeProfile : activePomProfiles) {
+            profileInjector.injectProfile(inputModel, activeProfile, request, problems);
         }
 
-        for ( Profile activeProfile : activeExternalProfiles )
-        {
-            profileInjector.injectProfile( inputModel, activeProfile, request, problems );
+        for (Profile activeProfile : activeExternalProfiles) {
+            profileInjector.injectProfile(inputModel, activeProfile, request, problems);
         }
     }
 
-    @SuppressWarnings( "checkstyle:methodlength" )
-    private Model readEffectiveModel( final ModelBuildingRequest request, final DefaultModelBuildingResult result,
-                          DefaultModelProblemCollector problems )
-        throws ModelBuildingException
-    {
-        Model inputModel =
-            readRawModel( request, problems );
+    @SuppressWarnings("checkstyle:methodlength")
+    private Model readEffectiveModel(
+            final ModelBuildingRequest request,
+            final DefaultModelBuildingResult result,
+            DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
+        Model inputModel = readRawModel(request, problems);
+        if (problems.hasFatalErrors()) {
+            throw problems.newModelBuildingException();
+        }
 
-        problems.setRootModel( inputModel );
+        problems.setRootModel(inputModel);
 
-        ModelData resultData = new ModelData( request.getModelSource(), inputModel );
-        ModelData superData = new ModelData( null, getSuperModel() );
+        ModelData resultData = new ModelData(request.getModelSource(), inputModel);
+        String superModelVersion = inputModel.getModelVersion() != null ? inputModel.getModelVersion() : "4.0.0";
+        if (!DefaultModelValidator.VALID_MODEL_VERSIONS.contains(superModelVersion)) {
+            // Maven 3.x is always using 4.0.0 version to load the supermodel, so
+            // do the same when loading a dependency.  The model validator will also
+            // check that field later.
+            superModelVersion = "4.0.0";
+        }
+        ModelData superData = new ModelData(null, getSuperModel(superModelVersion));
 
         // profile activation
-        DefaultProfileActivationContext profileActivationContext = getProfileActivationContext( request );
+        DefaultProfileActivationContext profileActivationContext = getProfileActivationContext(request);
 
         List<Profile> activeExternalProfiles = result.getActiveExternalProfiles();
 
-        if ( !activeExternalProfiles.isEmpty() )
-        {
+        if (!activeExternalProfiles.isEmpty()) {
             Properties profileProps = new Properties();
-            for ( Profile profile : activeExternalProfiles )
-            {
-                profileProps.putAll( profile.getProperties() );
+            for (Profile profile : activeExternalProfiles) {
+                profileProps.putAll(profile.getProperties());
             }
-            profileProps.putAll( profileActivationContext.getUserProperties() );
-            profileActivationContext.setUserProperties( profileProps );
+            profileProps.putAll(profileActivationContext.getUserProperties());
+            profileActivationContext.setUserProperties(profileProps);
         }
 
         Collection<String> parentIds = new LinkedHashSet<>();
 
         List<Model> lineage = new ArrayList<>();
 
-        for ( ModelData currentData = resultData; ; )
-        {
+        for (ModelData currentData = resultData; ; ) {
             String modelId = currentData.getId();
-            result.addModelId( modelId );
+            result.addModelId(modelId);
 
-            Model rawModel = currentData.getModel();
-            result.setRawModel( modelId, rawModel );
-
-            profileActivationContext.setProjectProperties( rawModel.getProperties() );
-            problems.setSource( rawModel );
-            List<Profile> activePomProfiles = profileSelector.getActiveProfiles( rawModel.getProfiles(),
-                                                                                 profileActivationContext, problems );
-            result.setActivePomProfiles( modelId, activePomProfiles );
-
-            Model tmpModel = rawModel.clone();
-
-            problems.setSource( tmpModel );
+            Model model = currentData.getModel();
+            result.setRawModel(modelId, model);
+            problems.setSource(model);
+            org.apache.maven.api.model.Model modelv4 = model.getDelegate();
 
             // model normalization
-            modelNormalizer.mergeDuplicates( tmpModel, request, problems );
+            modelv4 = modelNormalizer.mergeDuplicates(modelv4, request, problems);
 
-            profileActivationContext.setProjectProperties( tmpModel.getProperties() );
+            // profile activation
+            profileActivationContext.setProjectProperties(modelv4.getProperties());
 
-            Map<String, Activation> interpolatedActivations = getInterpolatedActivations( rawModel,
-                                                                                          profileActivationContext,
-                                                                                          problems );
-            injectProfileActivations( tmpModel, interpolatedActivations );
+            List<org.apache.maven.api.model.Profile> interpolatedProfiles =
+                    interpolateActivations(modelv4.getProfiles(), profileActivationContext, problems);
 
             // profile injection
-            for ( Profile activeProfile : result.getActivePomProfiles( modelId ) )
-            {
-                profileInjector.injectProfile( tmpModel, activeProfile, request, problems );
-            }
-
-            if ( currentData == resultData )
-            {
-                for ( Profile activeProfile : activeExternalProfiles )
-                {
-                    profileInjector.injectProfile( tmpModel, activeProfile, request, problems );
+            List<org.apache.maven.api.model.Profile> activePomProfiles =
+                    profileSelector.getActiveProfilesV4(interpolatedProfiles, profileActivationContext, problems);
+            result.setActivePomProfiles(
+                    modelId, activePomProfiles.stream().map(Profile::new).collect(Collectors.toList()));
+            modelv4 = profileInjector.injectProfiles(modelv4, activePomProfiles, request, problems);
+            if (currentData == resultData) {
+                for (Profile activeProfile : activeExternalProfiles) {
+                    modelv4 = profileInjector.injectProfile(modelv4, activeProfile.getDelegate(), request, problems);
                 }
-                result.setEffectiveModel( tmpModel );
             }
 
-            lineage.add( tmpModel );
+            lineage.add(new Model(modelv4));
 
-            if ( currentData == superData )
-            {
+            if (currentData == superData) {
                 break;
             }
 
-            configureResolver( request.getModelResolver(), tmpModel, problems );
+            // add repositories specified by the current model so that we can resolve the parent
+            configureResolver(request.getModelResolver(), modelv4, problems, false);
 
-            ModelData parentData =
-                readParent( currentData.getModel(), currentData.getSource(), request, result, problems );
+            // we pass a cloned model, so that resolving the parent version does not affect the returned model
+            ModelData parentData = readParent(new Model(modelv4), currentData.getSource(), request, problems);
 
-            if ( parentData == null )
-            {
+            if (parentData == null) {
                 currentData = superData;
-            }
-            else if ( !parentIds.add( parentData.getId() ) )
-            {
-                StringBuilder message = new StringBuilder( "The parents form a cycle: " );
-                for ( String parentId : parentIds )
-                {
-                    message.append( parentId ).append( " -> " );
+            } else if (!parentIds.add(parentData.getId())) {
+                StringBuilder message = new StringBuilder("The parents form a cycle: ");
+                for (String parentId : parentIds) {
+                    message.append(parentId).append(" -> ");
                 }
-                message.append( parentData.getId() );
+                message.append(parentData.getId());
 
-                problems.add( new ModelProblemCollectorRequest( ModelProblem.Severity.FATAL, ModelProblem.Version.BASE )
-                    .setMessage( message.toString() ) );
+                problems.add(new ModelProblemCollectorRequest(ModelProblem.Severity.FATAL, ModelProblem.Version.BASE)
+                        .setMessage(message.toString()));
 
                 throw problems.newModelBuildingException();
-            }
-            else
-            {
+            } else {
                 currentData = parentData;
             }
         }
 
-        problems.setSource( result.getRawModel() );
-        checkPluginVersions( lineage, request, problems );
+        Model tmpModel = lineage.get(0);
+
+        // inject interpolated activations
+        List<org.apache.maven.api.model.Profile> interpolated =
+                interpolateActivations(tmpModel.getDelegate().getProfiles(), profileActivationContext, problems);
+        if (interpolated != tmpModel.getDelegate().getProfiles()) {
+            tmpModel.update(tmpModel.getDelegate().withProfiles(interpolated));
+        }
+
+        // inject external profile into current model
+        tmpModel.update(profileInjector.injectProfiles(
+                tmpModel.getDelegate(),
+                activeExternalProfiles.stream().map(Profile::getDelegate).collect(Collectors.toList()),
+                request,
+                problems));
+
+        checkPluginVersions(lineage, request, problems);
 
         // inheritance assembly
-        assembleInheritance( lineage, request, problems );
-
-        Model resultModel = lineage.get( 0 );
+        Model resultModel = assembleInheritance(lineage, request, problems);
 
         // consider caching inherited model
 
-        problems.setSource( resultModel );
-        problems.setRootModel( resultModel );
+        problems.setSource(resultModel);
+        problems.setRootModel(resultModel);
 
         // model interpolation
-        resultModel = interpolateModel( resultModel, request, problems );
+        resultModel = interpolateModel(resultModel, request, problems);
 
         // url normalization
-        modelUrlNormalizer.normalize( resultModel, request );
+        modelUrlNormalizer.normalize(resultModel, request);
 
-        result.setEffectiveModel( resultModel );
+        result.setEffectiveModel(resultModel);
 
         // Now the fully interpolated model is available: reconfigure the resolver
-        configureResolver( request.getModelResolver(), resultModel, problems, true );
+        configureResolver(request.getModelResolver(), resultModel.getDelegate(), problems, true);
 
         return resultModel;
     }
 
-    private Map<String, Activation> getInterpolatedActivations( Model rawModel,
-                                                                DefaultProfileActivationContext context,
-                                                                DefaultModelProblemCollector problems )
-    {
-        Map<String, Activation> interpolatedActivations = getProfileActivations( rawModel, true );
-        for ( Activation activation : interpolatedActivations.values() )
-        {
-            if ( activation.getFile() != null )
-            {
-                replaceWithInterpolatedValue( activation.getFile(), context, problems );
+    private List<org.apache.maven.api.model.Profile> interpolateActivations(
+            List<org.apache.maven.api.model.Profile> profiles,
+            DefaultProfileActivationContext context,
+            DefaultModelProblemCollector problems) {
+        List<org.apache.maven.api.model.Profile> newProfiles = null;
+        for (int index = 0; index < profiles.size(); index++) {
+            org.apache.maven.api.model.Profile profile = profiles.get(index);
+            org.apache.maven.api.model.Activation activation = profile.getActivation();
+            if (activation != null) {
+                org.apache.maven.api.model.ActivationFile file = activation.getFile();
+                if (file != null) {
+                    String oldExists = file.getExists();
+                    if (isNotEmpty(oldExists)) {
+                        try {
+                            String newExists = interpolate(oldExists, context);
+                            if (!Objects.equals(oldExists, newExists)) {
+                                if (newProfiles == null) {
+                                    newProfiles = new ArrayList<>(profiles);
+                                }
+                                newProfiles.set(
+                                        index, profile.withActivation(activation.withFile(file.withExists(newExists))));
+                            }
+                        } catch (InterpolationException e) {
+                            addInterpolationProblem(problems, file, oldExists, e, "exists");
+                        }
+                    } else {
+                        String oldMissing = file.getMissing();
+                        if (isNotEmpty(oldMissing)) {
+                            try {
+                                String newMissing = interpolate(oldMissing, context);
+                                if (!Objects.equals(oldMissing, newMissing)) {
+                                    if (newProfiles == null) {
+                                        newProfiles = new ArrayList<>(profiles);
+                                    }
+                                    newProfiles.set(
+                                            index,
+                                            profile.withActivation(activation.withFile(file.withMissing(newMissing))));
+                                }
+                            } catch (InterpolationException e) {
+                                addInterpolationProblem(problems, file, oldMissing, e, "missing");
+                            }
+                        }
+                    }
+                }
             }
         }
-        return interpolatedActivations;
+        return newProfiles != null ? newProfiles : profiles;
     }
 
-    private void replaceWithInterpolatedValue( ActivationFile activationFile, ProfileActivationContext context,
-                                               DefaultModelProblemCollector problems  )
-    {
-        try
-        {
-            if ( isNotEmpty( activationFile.getExists() ) )
-            {
-                String path = activationFile.getExists();
-                String absolutePath = profileActivationFilePathInterpolator.interpolate( path, context );
-                activationFile.setExists( absolutePath );
-            }
-            else if ( isNotEmpty( activationFile.getMissing() ) )
-            {
-                String path = activationFile.getMissing();
-                String absolutePath = profileActivationFilePathInterpolator.interpolate( path, context );
-                activationFile.setMissing( absolutePath );
-            }
-        }
-        catch ( InterpolationException e )
-        {
-            String path = isNotEmpty(
-                    activationFile.getExists() ) ? activationFile.getExists() : activationFile.getMissing();
-
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage(
-                    "Failed to interpolate file location " + path + ": " + e.getMessage() ).setLocation(
-                    activationFile.getLocation( isNotEmpty( activationFile.getExists() ) ? "exists" : "missing"  ) )
-                    .setException( e ) );
-        }
+    private static void addInterpolationProblem(
+            DefaultModelProblemCollector problems,
+            org.apache.maven.api.model.ActivationFile file,
+            String path,
+            InterpolationException e,
+            String locationKey) {
+        problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                .setMessage("Failed to interpolate file location " + path + ": " + e.getMessage())
+                .setLocation(Optional.ofNullable(file.getLocation(locationKey))
+                        .map(InputLocation::new)
+                        .orElse(null))
+                .setException(e));
     }
 
-    private static boolean isNotEmpty( String string )
-    {
+    private String interpolate(String path, ProfileActivationContext context) throws InterpolationException {
+        return isNotEmpty(path) ? profileActivationFilePathInterpolator.interpolate(path, context) : path;
+    }
+
+    private static boolean isNotEmpty(String string) {
         return string != null && !string.isEmpty();
     }
 
     @Override
-    public ModelBuildingResult build( final ModelBuildingRequest request, final ModelBuildingResult result )
-        throws ModelBuildingException
-    {
-        return build( request, result, new LinkedHashSet<>() );
+    public ModelBuildingResult build(final ModelBuildingRequest request, final ModelBuildingResult result)
+            throws ModelBuildingException {
+        return build(request, result, new LinkedHashSet<>());
     }
 
-    private ModelBuildingResult build( final ModelBuildingRequest request, final ModelBuildingResult phaseOneResult,
-                                       Collection<String> imports )
-        throws ModelBuildingException
-    {
-        DefaultModelBuildingResult result = asDefaultModelBuildingResult( phaseOneResult );
+    public Model buildRawModel(final ModelBuildingRequest request) throws ModelBuildingException {
+        DefaultModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuildingResult());
+        Model model = readRawModel(request, problems);
+        if (hasModelErrors(problems)) {
+            throw problems.newModelBuildingException();
+        }
+        return model;
+    }
 
-        DefaultModelProblemCollector problems = new DefaultModelProblemCollector( result );
+    private ModelBuildingResult build(
+            final ModelBuildingRequest request, final ModelBuildingResult phaseOneResult, Collection<String> imports)
+            throws ModelBuildingException {
+        DefaultModelBuildingResult result = asDefaultModelBuildingResult(phaseOneResult);
+
+        DefaultModelProblemCollector problems = new DefaultModelProblemCollector(result);
 
         // phase 2
-        Model resultModel = readEffectiveModel( request, result, problems );
-        problems.setSource( resultModel );
-        problems.setRootModel( resultModel );
+        Model resultModel = readEffectiveModel(request, result, problems);
+        problems.setSource(resultModel);
+        problems.setRootModel(resultModel);
 
         // model path translation
-        modelPathTranslator.alignToBaseDirectory( resultModel, resultModel.getProjectDirectory(), request );
+        modelPathTranslator.alignToBaseDirectory(resultModel, resultModel.getProjectDirectory(), request);
 
         // plugin management injection
-        pluginManagementInjector.injectManagement( resultModel, request, problems );
+        pluginManagementInjector.injectManagement(resultModel, request, problems);
 
-        fireEvent( resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED );
+        fireEvent(resultModel, request, problems, ModelBuildingEventCatapult.BUILD_EXTENSIONS_ASSEMBLED);
 
-        if ( request.isProcessPlugins() )
-        {
-            if ( lifecycleBindingsInjector == null )
-            {
-                throw new IllegalStateException( "lifecycle bindings injector is missing" );
+        if (request.isProcessPlugins()) {
+            if (lifecycleBindingsInjector == null) {
+                throw new IllegalStateException("lifecycle bindings injector is missing");
             }
 
             // lifecycle bindings injection
-            lifecycleBindingsInjector.injectLifecycleBindings( resultModel, request, problems );
+            lifecycleBindingsInjector.injectLifecycleBindings(resultModel, request, problems);
         }
 
         // dependency management import
-        importDependencyManagement( resultModel, request, problems, imports );
+        importDependencyManagement(resultModel, request, problems, imports);
 
         // dependency management injection
-        dependencyManagementInjector.injectManagement( resultModel, request, problems );
+        dependencyManagementInjector.injectManagement(resultModel, request, problems);
 
-        modelNormalizer.injectDefaultValues( resultModel, request, problems );
+        resultModel.update(modelNormalizer.injectDefaultValues(resultModel.getDelegate(), request, problems));
 
-        if ( request.isProcessPlugins() )
-        {
+        if (request.isProcessPlugins()) {
             // reports configuration
-            reportConfigurationExpander.expandPluginConfiguration( resultModel, request, problems );
-
-            // reports conversion to decoupled site plugin
-            reportingConverter.convertReporting( resultModel, request, problems );
+            reportConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
 
             // plugins configuration
-            pluginConfigurationExpander.expandPluginConfiguration( resultModel, request, problems );
+            pluginConfigurationExpander.expandPluginConfiguration(resultModel, request, problems);
         }
 
         // effective model validation
-        modelValidator.validateEffectiveModel( resultModel, request, problems );
+        modelValidator.validateEffectiveModel(resultModel, request, problems);
 
-        if ( hasModelErrors( problems ) )
-        {
+        if (hasModelErrors(problems)) {
             throw problems.newModelBuildingException();
         }
 
         return result;
     }
 
-    private DefaultModelBuildingResult asDefaultModelBuildingResult( ModelBuildingResult phaseOneResult )
-    {
-        if ( phaseOneResult instanceof DefaultModelBuildingResult )
-        {
+    private DefaultModelBuildingResult asDefaultModelBuildingResult(ModelBuildingResult phaseOneResult) {
+        if (phaseOneResult instanceof DefaultModelBuildingResult) {
             return (DefaultModelBuildingResult) phaseOneResult;
-        }
-        else
-        {
-            return new DefaultModelBuildingResult( phaseOneResult );
+        } else {
+            return new DefaultModelBuildingResult(phaseOneResult);
         }
     }
 
     @Override
-    public Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean locationTracking )
-    {
-        final ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( validationLevel )
-            .setLocationTracking( locationTracking )
-            .setModelSource( new FileModelSource( pomFile ) );
-        final DefaultModelProblemCollector collector =
-            new DefaultModelProblemCollector( new DefaultModelBuildingResult() );
-        try
-        {
-            return newResult( readFileModel( request, collector ), collector.getProblems() );
-        }
-        catch ( ModelBuildingException e )
-        {
-            return error( collector.getProblems() );
+    public Result<? extends Model> buildRawModel(File pomFile, int validationLevel, boolean locationTracking) {
+        return buildRawModel(pomFile, validationLevel, locationTracking, null);
+    }
+
+    @Override
+    public Result<? extends Model> buildRawModel(
+            File pomFile, int validationLevel, boolean locationTracking, TransformerContext context) {
+        final ModelBuildingRequest request = new DefaultModelBuildingRequest()
+                .setValidationLevel(validationLevel)
+                .setLocationTracking(locationTracking)
+                .setModelSource(new FileModelSource(pomFile));
+        DefaultModelProblemCollector problems = new DefaultModelProblemCollector(new DefaultModelBuildingResult());
+        try {
+            Model model = readFileModel(request, problems);
+
+            try {
+                if (transformer != null && context != null) {
+                    transformer.transform(pomFile.toPath(), context, model);
+                }
+            } catch (TransformerException e) {
+                problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V40).setException(e));
+            }
+
+            return newResult(model, problems.getProblems());
+        } catch (ModelBuildingException e) {
+            return error(problems.getProblems());
         }
     }
 
-    private Model readFileModel( ModelBuildingRequest request,
-                                 DefaultModelProblemCollector problems )
-        throws ModelBuildingException
-    {
+    Model readFileModel(ModelBuildingRequest request, DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
         ModelSource modelSource = request.getModelSource();
-        Model model = fromCache( request.getModelCache(), modelSource, ModelCacheTag.FILE );
-        if ( model == null )
-        {
-            model = doReadFileModel( modelSource, request, problems );
+        org.apache.maven.api.model.Model model = cache(
+                request.getModelCache(),
+                modelSource,
+                ModelCacheTag.FILE,
+                () -> doReadFileModel(modelSource, request, problems));
 
-            intoCache( request.getModelCache(), modelSource, ModelCacheTag.FILE, model );
-        }
-
-        if ( modelSource instanceof FileModelSource )
-        {
-            if ( request.getTransformerContextBuilder() instanceof DefaultTransformerContextBuilder )
-            {
+        if (modelSource instanceof FileModelSource) {
+            if (request.getTransformerContextBuilder() instanceof DefaultTransformerContextBuilder) {
                 DefaultTransformerContextBuilder contextBuilder =
                         (DefaultTransformerContextBuilder) request.getTransformerContextBuilder();
-                contextBuilder.putSource( getGroupId( model ), model.getArtifactId(), modelSource );
+                contextBuilder.putSource(getGroupId(model), model.getArtifactId(), (FileModelSource) modelSource);
             }
         }
 
-        return model;
+        return new Model(model);
     }
 
-    @SuppressWarnings( "checkstyle:methodlength" )
-    private Model doReadFileModel( ModelSource modelSource, ModelBuildingRequest request,
-                                 DefaultModelProblemCollector problems )
-            throws ModelBuildingException
-    {
-        Model model;
-        problems.setSource( modelSource.getLocation() );
-        try
-        {
+    @SuppressWarnings("checkstyle:methodlength")
+    private org.apache.maven.api.model.Model doReadFileModel(
+            ModelSource modelSource, ModelBuildingRequest request, DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
+        org.apache.maven.api.model.Model model;
+        problems.setSource(modelSource.getLocation());
+        try {
             boolean strict = request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0;
 
-            Map<String, Object> options = new HashMap<>( 3 );
-            options.put( ModelProcessor.IS_STRICT, strict );
-            options.put( ModelProcessor.SOURCE, modelSource );
+            Map<String, Object> options = new HashMap<>(3);
+            options.put(ModelProcessor.IS_STRICT, strict);
+            options.put(ModelProcessor.SOURCE, modelSource);
+            options.put(ModelReader.ROOT_DIRECTORY, request.getRootDirectory());
 
             InputSource source;
-            if ( request.isLocationTracking() )
-            {
-                source = (InputSource) options.computeIfAbsent( ModelProcessor.INPUT_SOURCE, k -> new InputSource() );
-            }
-            else
-            {
+            if (request.isLocationTracking()) {
+                source = new InputSource(null, modelSource.getLocation());
+                options.put(ModelProcessor.INPUT_SOURCE, new org.apache.maven.model.InputSource(source));
+            } else {
                 source = null;
             }
 
-            try
-            {
-                model = modelProcessor.read( modelSource.getInputStream(), options );
-            }
-            catch ( ModelParseException e )
-            {
-                if ( !strict )
-                {
+            try {
+                model = modelProcessor
+                        .read(modelSource.getInputStream(), options)
+                        .getDelegate();
+            } catch (ModelParseException e) {
+                if (!strict) {
                     throw e;
                 }
 
-                options.put( ModelProcessor.IS_STRICT, Boolean.FALSE );
+                options.put(ModelProcessor.IS_STRICT, Boolean.FALSE);
 
-                try
-                {
-                    model = modelProcessor.read( modelSource.getInputStream(), options );
-                }
-                catch ( ModelParseException ne )
-                {
+                try {
+                    model = modelProcessor
+                            .read(modelSource.getInputStream(), options)
+                            .getDelegate();
+                } catch (ModelParseException ne) {
                     // still unreadable even in non-strict mode, rethrow original error
                     throw e;
                 }
 
-                Severity severity = ( modelSource instanceof FileModelSource ) ? Severity.ERROR : Severity.WARNING;
-                problems.add( new ModelProblemCollectorRequest( severity, Version.V20 )
-                    .setMessage( "Malformed POM " + modelSource.getLocation() + ": " + e.getMessage() )
-                    .setException( e ) );
+                Severity severity = (modelSource instanceof FileModelSource) ? Severity.ERROR : Severity.WARNING;
+                problems.add(new ModelProblemCollectorRequest(severity, Version.V20)
+                        .setMessage("Malformed POM " + modelSource.getLocation() + ": " + e.getMessage())
+                        .setException(e));
             }
 
-            if ( source != null )
-            {
-                source.setModelId( ModelProblemUtils.toId( model ) );
-                source.setLocation( modelSource.getLocation() );
-            }
-        }
-        catch ( ModelParseException e )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
-                .setMessage( "Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage() )
-                .setException( e ) );
-            throw problems.newModelBuildingException();
-        }
-        catch ( IOException e )
-        {
-            String msg = e.getMessage();
-            if ( msg == null || msg.length() <= 0 )
-            {
-                // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException
-                if ( e.getClass().getName().endsWith( "MalformedInputException" ) )
-                {
-                    msg = "Some input bytes do not match the file encoding.";
+            if (source != null) {
+                try {
+                    org.apache.maven.api.model.InputLocation loc = model.getLocation("");
+                    org.apache.maven.api.model.InputSource v4src = loc != null ? loc.getSource() : null;
+                    if (v4src != null) {
+                        Field field = InputSource.class.getDeclaredField("modelId");
+                        field.setAccessible(true);
+                        field.set(v4src, ModelProblemUtils.toId(model));
+                    }
+                } catch (Throwable t) {
+                    // TODO: use a lazy source ?
+                    throw new IllegalStateException("Unable to set modelId on InputSource", t);
                 }
-                else
-                {
+            }
+        } catch (ModelParseException e) {
+            problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
+                    .setMessage("Non-parseable POM " + modelSource.getLocation() + ": " + e.getMessage())
+                    .setException(e));
+            throw problems.newModelBuildingException();
+        } catch (IOException e) {
+            String msg = e.getMessage();
+            if (msg == null || msg.length() <= 0) {
+                // NOTE: There's java.nio.charset.MalformedInputException and sun.io.MalformedInputException
+                if (e.getClass().getName().endsWith("MalformedInputException")) {
+                    msg = "Some input bytes do not match the file encoding.";
+                } else {
                     msg = e.getClass().getSimpleName();
                 }
             }
-            problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
-                .setMessage( "Non-readable POM " + modelSource.getLocation() + ": " + msg ).setException( e ) );
+            problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
+                    .setMessage("Non-readable POM " + modelSource.getLocation() + ": " + msg)
+                    .setException(e));
             throw problems.newModelBuildingException();
         }
 
-        if ( modelSource instanceof FileModelSource )
-        {
-            model.setPomFile( ( (FileModelSource) modelSource ).getFile() );
+        if (modelSource instanceof FileModelSource) {
+            model = model.withPomFile(((FileModelSource) modelSource).getFile().toPath());
         }
-        problems.setSource( model );
 
-        modelValidator.validateFileModel( model, request, problems );
+        Model retModel = new Model(model);
 
-        if ( hasFatalErrors( problems ) )
-        {
+        problems.setSource(retModel);
+
+        modelValidator.validateFileModel(retModel, request, problems);
+
+        if (hasFatalErrors(problems)) {
             throw problems.newModelBuildingException();
         }
 
         return model;
     }
 
-    private Model readRawModel( ModelBuildingRequest request, DefaultModelProblemCollector problems )
-        throws ModelBuildingException
-    {
+    Model readRawModel(ModelBuildingRequest request, DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
         ModelSource modelSource = request.getModelSource();
 
-        ModelData cachedData = fromCache( request.getModelCache(), modelSource, ModelCacheTag.RAW );
-        if ( cachedData != null )
-        {
-            return cachedData.getModel();
-        }
+        ModelData modelData = cache(
+                request.getModelCache(),
+                modelSource,
+                ModelCacheTag.RAW,
+                () -> doReadRawModel(modelSource, request, problems));
 
+        return modelData.getModel();
+    }
+
+    private ModelData doReadRawModel(
+            ModelSource modelSource, ModelBuildingRequest request, DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
         Model rawModel;
-        if ( Features.buildConsumer( request.getUserProperties() ).isActive()
-            && modelSource instanceof FileModelSource )
-        {
-            rawModel = readFileModel( request, problems );
-            File pomFile = ( (FileModelSource) modelSource ).getFile();
+        if (Features.buildConsumer(request.getUserProperties()) && modelSource instanceof FileModelSource) {
+            rawModel = readFileModel(request, problems);
+            File pomFile = ((FileModelSource) modelSource).getFile();
 
-            TransformerContext context = null;
-            if ( request.getTransformerContextBuilder() != null )
-            {
-                context = request.getTransformerContextBuilder().initialize( request, problems );
+            try {
+                if (request.getTransformerContextBuilder() != null) {
+                    TransformerContext context =
+                            request.getTransformerContextBuilder().initialize(request, problems);
+                    transformer.transform(pomFile.toPath(), context, rawModel);
+                }
+            } catch (TransformerException e) {
+                problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V40).setException(e));
             }
-
-            try
-            {
-                // must implement TransformContext, but should use request to access system properties/modelcache
-                Model transformedFileModel = modelProcessor.read( pomFile,
-                   Collections.singletonMap( ModelReader.TRANSFORMER_CONTEXT, context ) );
-
-                // rawModel with locationTrackers, required for proper feedback during validations
-
-                // Apply enriched data
-                modelMerger.merge( rawModel, transformedFileModel, false, null );
-            }
-            catch ( IOException e )
-            {
-                problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V40 ).setException( e ) );
-            }
-        }
-        else if ( request.getFileModel() == null )
-        {
-            rawModel = readFileModel( request, problems );
-        }
-        else
-        {
+        } else if (request.getFileModel() == null) {
+            rawModel = readFileModel(request, problems);
+        } else {
             rawModel = request.getFileModel().clone();
         }
 
-        modelValidator.validateRawModel( rawModel, request, problems );
+        modelValidator.validateRawModel(rawModel, request, problems);
 
-        if ( hasFatalErrors( problems ) )
-        {
+        if (hasFatalErrors(problems)) {
             throw problems.newModelBuildingException();
         }
 
-        String groupId = getGroupId( rawModel );
+        String groupId = getGroupId(rawModel);
         String artifactId = rawModel.getArtifactId();
-        String version = getVersion( rawModel );
+        String version = getVersion(rawModel);
 
-        ModelData modelData = new ModelData( modelSource, rawModel, groupId, artifactId, version );
-        intoCache( request.getModelCache(), modelSource, ModelCacheTag.RAW, modelData );
-
-        return rawModel;
+        return new ModelData(modelSource, rawModel, groupId, artifactId, version);
     }
 
-    private String getGroupId( Model model )
-    {
+    String getGroupId(Model model) {
+        return getGroupId(model.getDelegate());
+    }
+
+    private String getGroupId(org.apache.maven.api.model.Model model) {
         String groupId = model.getGroupId();
-        if ( groupId == null && model.getParent() != null )
-        {
+        if (groupId == null && model.getParent() != null) {
             groupId = model.getParent().getGroupId();
         }
         return groupId;
     }
 
-    private String getVersion( Model model )
-    {
+    private String getVersion(Model model) {
         String version = model.getVersion();
-        if ( version == null && model.getParent() != null )
-        {
+        if (version == null && model.getParent() != null) {
             version = model.getParent().getVersion();
         }
         return version;
     }
 
-    private DefaultProfileActivationContext getProfileActivationContext( ModelBuildingRequest request )
-    {
+    private DefaultProfileActivationContext getProfileActivationContext(ModelBuildingRequest request) {
         DefaultProfileActivationContext context = new DefaultProfileActivationContext();
 
-        context.setActiveProfileIds( request.getActiveProfileIds() );
-        context.setInactiveProfileIds( request.getInactiveProfileIds() );
-        context.setSystemProperties( request.getSystemProperties() );
-        context.setUserProperties( request.getUserProperties() );
-        context.setProjectDirectory( ( request.getPomFile() != null ) ? request.getPomFile().getParentFile() : null );
+        context.setActiveProfileIds(request.getActiveProfileIds());
+        context.setInactiveProfileIds(request.getInactiveProfileIds());
+        context.setSystemProperties(request.getSystemProperties());
+        // enrich user properties with project packaging
+        Properties userProperties = request.getUserProperties();
+        if (!userProperties.containsKey(ProfileActivationContext.PROPERTY_NAME_PACKAGING)) {
+            userProperties.put(
+                    ProfileActivationContext.PROPERTY_NAME_PACKAGING,
+                    request.getFileModel().getPackaging());
+        }
+        context.setUserProperties(userProperties);
+        context.setProjectDirectory(
+                (request.getPomFile() != null) ? request.getPomFile().getParentFile() : null);
 
         return context;
     }
 
-    private void configureResolver( ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems )
-    {
-        configureResolver( modelResolver, model, problems, false );
-    }
-
-    private void configureResolver( ModelResolver modelResolver, Model model, DefaultModelProblemCollector problems,
-                                    boolean replaceRepositories )
-    {
-        if ( modelResolver == null )
-        {
-            return;
-        }
-
-        problems.setSource( model );
-
-        List<Repository> repositories = model.getRepositories();
-
-        for ( Repository repository : repositories )
-        {
-            try
-            {
-                modelResolver.addRepository( repository, replaceRepositories );
-            }
-            catch ( InvalidRepositoryException e )
-            {
-                problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "Invalid repository " + repository.getId() + ": " + e.getMessage() )
-                    .setLocation( repository.getLocation( "" ) ).setException( e ) );
+    private void configureResolver(
+            ModelResolver modelResolver,
+            org.apache.maven.api.model.Model model,
+            DefaultModelProblemCollector problems,
+            boolean replaceRepositories) {
+        if (modelResolver != null) {
+            for (org.apache.maven.api.model.Repository repository : model.getRepositories()) {
+                try {
+                    modelResolver.addRepository(repository, replaceRepositories);
+                } catch (InvalidRepositoryException e) {
+                    problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                            .setMessage("Invalid repository " + repository.getId() + ": " + e.getMessage())
+                            .setLocation(new InputLocation(repository.getLocation("")))
+                            .setException(e));
+                }
             }
         }
     }
 
-    private void checkPluginVersions( List<Model> lineage, ModelBuildingRequest request,
-                                      ModelProblemCollector problems )
-    {
-        if ( request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
-        {
+    private void checkPluginVersions(
+            List<Model> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
+        if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
             return;
         }
 
@@ -1073,205 +1283,172 @@
         Map<String, String> versions = new HashMap<>();
         Map<String, String> managedVersions = new HashMap<>();
 
-        for ( int i = lineage.size() - 1; i >= 0; i-- )
-        {
-            Model model = lineage.get( i );
+        for (int i = lineage.size() - 1; i >= 0; i--) {
+            Model model = lineage.get(i);
             Build build = model.getBuild();
-            if ( build != null )
-            {
-                for ( Plugin plugin : build.getPlugins() )
-                {
+            if (build != null) {
+                for (Plugin plugin : build.getPlugins()) {
                     String key = plugin.getKey();
-                    if ( versions.get( key ) == null )
-                    {
-                        versions.put( key, plugin.getVersion() );
-                        plugins.put( key, plugin );
+                    if (versions.get(key) == null) {
+                        versions.put(key, plugin.getVersion());
+                        plugins.put(key, plugin);
                     }
                 }
                 PluginManagement mgmt = build.getPluginManagement();
-                if ( mgmt != null )
-                {
-                    for ( Plugin plugin : mgmt.getPlugins() )
-                    {
+                if (mgmt != null) {
+                    for (Plugin plugin : mgmt.getPlugins()) {
                         String key = plugin.getKey();
-                        managedVersions.computeIfAbsent( key, k -> plugin.getVersion() );
+                        managedVersions.computeIfAbsent(key, k -> plugin.getVersion());
                     }
                 }
             }
         }
 
-        for ( String key : versions.keySet() )
-        {
-            if ( versions.get( key ) == null && managedVersions.get( key ) == null )
-            {
-                InputLocation location = plugins.get( key ).getLocation( "" );
-                problems
-                    .add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V20 )
-                        .setMessage( "'build.plugins.plugin.version' for " + key + " is missing." )
-                        .setLocation( location ) );
+        for (String key : versions.keySet()) {
+            if (versions.get(key) == null && managedVersions.get(key) == null) {
+                InputLocation location = plugins.get(key).getLocation("");
+                problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20)
+                        .setMessage("'build.plugins.plugin.version' for " + key + " is missing.")
+                        .setLocation(location));
             }
         }
     }
 
-    private void assembleInheritance( List<Model> lineage, ModelBuildingRequest request,
-                                      ModelProblemCollector problems )
-    {
-        for ( int i = lineage.size() - 2; i >= 0; i-- )
-        {
-            Model parent = lineage.get( i + 1 );
-            Model child = lineage.get( i );
-            inheritanceAssembler.assembleModelInheritance( child, parent, request, problems );
+    private Model assembleInheritance(
+            List<Model> lineage, ModelBuildingRequest request, ModelProblemCollector problems) {
+        org.apache.maven.api.model.Model parent =
+                lineage.get(lineage.size() - 1).getDelegate();
+        for (int i = lineage.size() - 2; i >= 0; i--) {
+            Model child = lineage.get(i);
+            parent = inheritanceAssembler.assembleModelInheritance(child.getDelegate(), parent, request, problems);
         }
+        return new Model(parent);
     }
 
-    private Map<String, Activation> getProfileActivations( Model model, boolean clone )
-    {
+    private Map<String, Activation> getProfileActivations(Model model, boolean clone) {
         Map<String, Activation> activations = new HashMap<>();
-        for ( Profile profile : model.getProfiles() )
-        {
+        for (Profile profile : model.getProfiles()) {
             Activation activation = profile.getActivation();
 
-            if ( activation == null )
-            {
+            if (activation == null) {
                 continue;
             }
 
-            if ( clone )
-            {
+            if (clone) {
                 activation = activation.clone();
             }
 
-            activations.put( profile.getId(), activation );
+            activations.put(profile.getId(), activation);
         }
 
         return activations;
     }
 
-    private void injectProfileActivations( Model model, Map<String, Activation> activations )
-    {
-        for ( Profile profile : model.getProfiles() )
-        {
+    private void injectProfileActivations(Model model, Map<String, Activation> activations) {
+        for (Profile profile : model.getProfiles()) {
             Activation activation = profile.getActivation();
 
-            if ( activation == null )
-            {
+            if (activation == null) {
                 continue;
             }
 
             // restore activation
-            profile.setActivation( activations.get( profile.getId() ) );
+            profile.setActivation(activations.get(profile.getId()));
         }
     }
 
-    private Model interpolateModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    private Model interpolateModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
         // save profile activations before interpolation, since they are evaluated with limited scope
-        Map<String, Activation> originalActivations = getProfileActivations( model, true );
+        Map<String, Activation> originalActivations = getProfileActivations(model, true);
 
-        Model interpolatedModel =
-            modelInterpolator.interpolateModel( model, model.getProjectDirectory(), request, problems );
-        if ( interpolatedModel.getParent() != null )
-        {
+        Model interpolatedModel = new Model(modelInterpolator.interpolateModel(
+                model.getDelegate(), model.getProjectDirectory(), request, problems));
+        if (interpolatedModel.getParent() != null) {
             StringSearchInterpolator ssi = new StringSearchInterpolator();
-            ssi.addValueSource( new MapBasedValueSource( request.getUserProperties() ) );
+            ssi.addValueSource(new MapBasedValueSource(request.getUserProperties()));
 
-            ssi.addValueSource( new MapBasedValueSource( model.getProperties() ) );
+            ssi.addValueSource(new MapBasedValueSource(model.getProperties()));
 
-            ssi.addValueSource( new MapBasedValueSource( request.getSystemProperties() ) );
+            ssi.addValueSource(new MapBasedValueSource(request.getSystemProperties()));
 
-            try
-            {
-                String interpolated = ssi.interpolate( interpolatedModel.getParent().getVersion() );
-                interpolatedModel.getParent().setVersion( interpolated );
+            try {
+                String interpolated =
+                        ssi.interpolate(interpolatedModel.getParent().getVersion());
+                interpolatedModel.getParent().setVersion(interpolated);
+            } catch (Exception e) {
+                ModelProblemCollectorRequest mpcr = new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                        .setMessage("Failed to interpolate field: "
+                                + interpolatedModel.getParent().getVersion()
+                                + " on class: ")
+                        .setException(e);
+                problems.add(mpcr);
             }
-            catch ( Exception e )
-            {
-                ModelProblemCollectorRequest mpcr =
-                    new ModelProblemCollectorRequest( Severity.ERROR,
-                                                      Version.BASE ).setMessage( "Failed to interpolate field: "
-                                                          + interpolatedModel.getParent().getVersion()
-                                                          + " on class: " ).setException( e );
-                problems.add( mpcr );
-            }
-
-
         }
-        interpolatedModel.setPomFile( model.getPomFile() );
+        interpolatedModel.setPomFile(model.getPomFile());
 
         // restore profiles with file activation to their value before full interpolation
-        injectProfileActivations( model, originalActivations );
+        injectProfileActivations(model, originalActivations);
 
         return interpolatedModel;
     }
 
-    private ModelData readParent( Model childModel, Source childSource, ModelBuildingRequest request,
-                                  ModelBuildingResult result, DefaultModelProblemCollector problems )
-        throws ModelBuildingException
-    {
+    private ModelData readParent(
+            Model childModel, Source childSource, ModelBuildingRequest request, DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
         ModelData parentData = null;
 
         Parent parent = childModel.getParent();
-        if ( parent != null )
-        {
-            parentData = readParentLocally( childModel, childSource, request, result, problems );
-            if ( parentData == null )
-            {
-                parentData = readParentExternally( childModel, request, result, problems );
+        if (parent != null) {
+            parentData = readParentLocally(childModel, childSource, request, problems);
+            if (parentData == null) {
+                parentData = readParentExternally(childModel, request, problems);
             }
 
             Model parentModel = parentData.getModel();
-            if ( !"pom".equals( parentModel.getPackaging() ) )
-            {
-                problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint( parentModel )
-                                     + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"" )
-                    .setLocation( parentModel.getLocation( "packaging" ) ) );
+            if (!"pom".equals(parentModel.getPackaging())) {
+                problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                        .setMessage("Invalid packaging for parent POM " + ModelProblemUtils.toSourceHint(parentModel)
+                                + ", must be \"pom\" but is \"" + parentModel.getPackaging() + "\"")
+                        .setLocation(parentModel.getLocation("packaging")));
             }
         }
 
         return parentData;
     }
 
-    private ModelData readParentLocally( Model childModel, Source childSource, ModelBuildingRequest request,
-                                         ModelBuildingResult result, DefaultModelProblemCollector problems )
-        throws ModelBuildingException
-    {
+    private ModelData readParentLocally(
+            Model childModel, Source childSource, ModelBuildingRequest request, DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
         final Parent parent = childModel.getParent();
-        final ModelSource candidateSource;
+        final ModelSource2 candidateSource;
         final Model candidateModel;
         final WorkspaceModelResolver resolver = request.getWorkspaceModelResolver();
-        if ( resolver == null )
-        {
-            candidateSource = getParentPomFile( childModel, childSource );
+        if (resolver == null) {
+            candidateSource = getParentPomFile(childModel, childSource);
 
-            if ( candidateSource == null )
-            {
+            if (candidateSource == null) {
                 return null;
             }
 
-            ModelBuildingRequest candidateBuildRequest = new DefaultModelBuildingRequest( request )
-                .setModelSource( candidateSource );
+            ModelBuildingRequest candidateBuildRequest =
+                    new DefaultModelBuildingRequest(request).setModelSource(candidateSource);
 
-            candidateModel = readRawModel( candidateBuildRequest, problems );
-        }
-        else
-        {
-            try
-            {
+            candidateModel = readRawModel(candidateBuildRequest, problems);
+        } else {
+            try {
                 candidateModel =
-                    resolver.resolveRawModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-            }
-            catch ( UnresolvableModelException e )
-            {
-                problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE ) //
-                    .setMessage( e.getMessage() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
+                        resolver.resolveRawModel(parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
+            } catch (UnresolvableModelException e) {
+                problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE) //
+                        .setMessage(e.getMessage())
+                        .setLocation(parent.getLocation(""))
+                        .setException(e));
                 throw problems.newModelBuildingException();
             }
-            if ( candidateModel == null )
-            {
+            if (candidateModel == null) {
                 return null;
             }
-            candidateSource = new FileModelSource( candidateModel.getPomFile() );
+            candidateSource = new FileModelSource(candidateModel.getPomFile());
         }
 
         //
@@ -1280,71 +1457,62 @@
         // before because with parents as ranges it will never work in this scenario.
         //
 
-        String groupId = getGroupId( candidateModel );
+        String groupId = getGroupId(candidateModel);
         String artifactId = candidateModel.getArtifactId();
 
-        if ( groupId == null || !groupId.equals( parent.getGroupId() ) || artifactId == null
-            || !artifactId.equals( parent.getArtifactId() ) )
-        {
-            StringBuilder buffer = new StringBuilder( 256 );
-            buffer.append( "'parent.relativePath'" );
-            if ( childModel != problems.getRootModel() )
-            {
-                buffer.append( " of POM " ).append( ModelProblemUtils.toSourceHint( childModel ) );
+        if (groupId == null
+                || !groupId.equals(parent.getGroupId())
+                || artifactId == null
+                || !artifactId.equals(parent.getArtifactId())) {
+            StringBuilder buffer = new StringBuilder(256);
+            buffer.append("'parent.relativePath'");
+            if (childModel != problems.getRootModel()) {
+                buffer.append(" of POM ").append(ModelProblemUtils.toSourceHint(childModel));
             }
-            buffer.append( " points at " ).append( groupId ).append( ':' ).append( artifactId );
-            buffer.append( " instead of " ).append( parent.getGroupId() ).append( ':' );
-            buffer.append( parent.getArtifactId() ).append( ", please verify your project structure" );
+            buffer.append(" points at ").append(groupId).append(':').append(artifactId);
+            buffer.append(" instead of ").append(parent.getGroupId()).append(':');
+            buffer.append(parent.getArtifactId()).append(", please verify your project structure");
 
-            problems.setSource( childModel );
-            problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE )
-                .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ) );
+            problems.setSource(childModel);
+            problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.BASE)
+                    .setMessage(buffer.toString())
+                    .setLocation(parent.getLocation("")));
             return null;
         }
 
-        String version = getVersion( candidateModel );
-        if ( version != null && parent.getVersion() != null && !version.equals( parent.getVersion() ) )
-        {
-            try
-            {
-                VersionRange parentRange = VersionRange.createFromVersionSpec( parent.getVersion() );
-                if ( !parentRange.hasRestrictions() )
-                {
+        String version = getVersion(candidateModel);
+        if (version != null && parent.getVersion() != null && !version.equals(parent.getVersion())) {
+            try {
+                VersionRange parentRange = VersionRange.createFromVersionSpec(parent.getVersion());
+                if (!parentRange.hasRestrictions()) {
                     // the parent version is not a range, we have version skew, drop back to resolution from repo
                     return null;
                 }
-                if ( !parentRange.containsVersion( new DefaultArtifactVersion( version ) ) )
-                {
+                if (!parentRange.containsVersion(new DefaultArtifactVersion(version))) {
                     // version skew drop back to resolution from the repository
                     return null;
                 }
 
                 // Validate versions aren't inherited when using parent ranges the same way as when read externally.
                 String rawChildModelVersion = childModel.getVersion();
-                
-                if ( rawChildModelVersion == null )
-                {
+
+                if (rawChildModelVersion == null) {
                     // Message below is checked for in the MNG-2199 core IT.
-                    problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
-                        .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
+                    problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
+                            .setMessage("Version must be a constant")
+                            .setLocation(childModel.getLocation("")));
 
-                }
-                else
-                {
-                    if ( rawChildVersionReferencesParent( rawChildModelVersion ) )
-                    {
+                } else {
+                    if (rawChildVersionReferencesParent(rawChildModelVersion)) {
                         // Message below is checked for in the MNG-2199 core IT.
-                        problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
-                            .setMessage( "Version must be a constant" )
-                            .setLocation( childModel.getLocation( "version" ) ) );
-
+                        problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
+                                .setMessage("Version must be a constant")
+                                .setLocation(childModel.getLocation("version")));
                     }
                 }
 
                 // MNG-2199: What else to check here ?
-            }
-            catch ( InvalidVersionSpecificationException e )
-            {
+            } catch (InvalidVersionSpecificationException e) {
                 // invalid version range, so drop back to resolution from the repository
                 return null;
             }
@@ -1359,39 +1527,38 @@
          * if ( version == null || !version.equals( parent.getVersion() ) ) { return null; }
          */
 
-        return new ModelData( candidateSource, candidateModel, groupId, artifactId, version );
+        return new ModelData(candidateSource, candidateModel, groupId, artifactId, version);
     }
 
-    private boolean rawChildVersionReferencesParent( String rawChildModelVersion )
-    {
-        return rawChildModelVersion.equals( "${pom.version}" )
-                || rawChildModelVersion.equals( "${project.version}" )
-                || rawChildModelVersion.equals( "${pom.parent.version}" )
-                || rawChildModelVersion.equals( "${project.parent.version}" );
+    private boolean rawChildVersionReferencesParent(String rawChildModelVersion) {
+        return rawChildModelVersion.equals("${pom.version}")
+                || rawChildModelVersion.equals("${project.version}")
+                || rawChildModelVersion.equals("${pom.parent.version}")
+                || rawChildModelVersion.equals("${project.parent.version}");
     }
 
-    private ModelSource getParentPomFile( Model childModel, Source source )
-    {
-        if ( !( source instanceof ModelSource2 ) )
-        {
+    private ModelSource2 getParentPomFile(Model childModel, Source source) {
+        if (!(source instanceof ModelSource2)) {
             return null;
         }
 
         String parentPath = childModel.getParent().getRelativePath();
 
-        if ( parentPath == null || parentPath.length() <= 0 )
-        {
+        if (parentPath == null || parentPath.length() <= 0) {
             return null;
         }
 
-        return ( (ModelSource2) source ).getRelatedSource( parentPath );
+        if (source instanceof ModelSource3) {
+            return ((ModelSource3) source).getRelatedSource(modelProcessor, parentPath);
+        } else {
+            return ((ModelSource2) source).getRelatedSource(parentPath);
+        }
     }
 
-    private ModelData readParentExternally( Model childModel, ModelBuildingRequest request,
-                                            ModelBuildingResult result, DefaultModelProblemCollector problems )
-        throws ModelBuildingException
-    {
-        problems.setSource( childModel );
+    private ModelData readParentExternally(
+            Model childModel, ModelBuildingRequest request, DefaultModelProblemCollector problems)
+            throws ModelBuildingException {
+        problems.setSource(childModel);
 
         Parent parent = childModel.getParent();
 
@@ -1400,502 +1567,371 @@
         String version = parent.getVersion();
 
         ModelResolver modelResolver = request.getModelResolver();
-        Objects.requireNonNull( modelResolver,
-                                String.format( "request.modelResolver cannot be null (parent POM %s and POM %s)",
-                                               ModelProblemUtils.toId( groupId, artifactId, version ),
-                                               ModelProblemUtils.toSourceHint( childModel ) ) );
+        Objects.requireNonNull(
+                modelResolver,
+                String.format(
+                        "request.modelResolver cannot be null (parent POM %s and POM %s)",
+                        ModelProblemUtils.toId(groupId, artifactId, version),
+                        ModelProblemUtils.toSourceHint(childModel)));
 
         ModelSource modelSource;
-        try
-        {
-            modelSource = modelResolver.resolveModel( parent );
-        }
-        catch ( UnresolvableModelException e )
-        {
+        try {
+            modelSource = modelResolver.resolveModel(parent);
+        } catch (UnresolvableModelException e) {
             // Message below is checked for in the MNG-2199 core IT.
-            StringBuilder buffer = new StringBuilder( 256 );
-            buffer.append( "Non-resolvable parent POM" );
-            if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
-            {
-                buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
+            StringBuilder buffer = new StringBuilder(256);
+            buffer.append("Non-resolvable parent POM");
+            if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
+                buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
             }
-            if ( childModel != problems.getRootModel() )
-            {
-                buffer.append( " for " ).append( ModelProblemUtils.toId( childModel ) );
+            if (childModel != problems.getRootModel()) {
+                buffer.append(" for ").append(ModelProblemUtils.toId(childModel));
             }
-            buffer.append( ": " ).append( e.getMessage() );
-            if ( childModel.getProjectDirectory() != null )
-            {
-                if ( parent.getRelativePath() == null || parent.getRelativePath().length() <= 0 )
-                {
-                    buffer.append( " and 'parent.relativePath' points at no local POM" );
-                }
-                else
-                {
-                    buffer.append( " and 'parent.relativePath' points at wrong local POM" );
+            buffer.append(": ").append(e.getMessage());
+            if (childModel.getProjectDirectory() != null) {
+                if (parent.getRelativePath() == null || parent.getRelativePath().length() <= 0) {
+                    buffer.append(" and 'parent.relativePath' points at no local POM");
+                } else {
+                    buffer.append(" and 'parent.relativePath' points at wrong local POM");
                 }
             }
 
-            problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
-                .setMessage( buffer.toString() ).setLocation( parent.getLocation( "" ) ).setException( e ) );
+            problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
+                    .setMessage(buffer.toString())
+                    .setLocation(parent.getLocation(""))
+                    .setException(e));
             throw problems.newModelBuildingException();
         }
 
-        int validationLevel = Math.min( request.getValidationLevel(), ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 );
-        ModelBuildingRequest lenientRequest = new DefaultModelBuildingRequest( request )
-                .setValidationLevel( validationLevel )
-                .setFileModel( null )
-                .setModelSource( modelSource );
+        int validationLevel = Math.min(request.getValidationLevel(), ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0);
+        ModelBuildingRequest lenientRequest = new DefaultModelBuildingRequest(request)
+                .setValidationLevel(validationLevel)
+                .setFileModel(null)
+                .setModelSource(modelSource);
 
-        Model parentModel = readRawModel( lenientRequest, problems );
+        Model parentModel = readRawModel(lenientRequest, problems);
 
-        if ( !parent.getVersion().equals( version ) )
-        {
+        if (!parent.getVersion().equals(version)) {
             String rawChildModelVersion = childModel.getVersion();
-            
-            if ( rawChildModelVersion == null )
-            {
+
+            if (rawChildModelVersion == null) {
                 // Message below is checked for in the MNG-2199 core IT.
-                problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
-                    .setMessage( "Version must be a constant" ).setLocation( childModel.getLocation( "" ) ) );
+                problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
+                        .setMessage("Version must be a constant")
+                        .setLocation(childModel.getLocation("")));
 
-            }
-            else
-            {
-                if ( rawChildVersionReferencesParent( rawChildModelVersion )  )
-                {
+            } else {
+                if (rawChildVersionReferencesParent(rawChildModelVersion)) {
                     // Message below is checked for in the MNG-2199 core IT.
-                    problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.V31 )
-                        .setMessage( "Version must be a constant" )
-                        .setLocation( childModel.getLocation( "version" ) ) );
-
+                    problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.V31)
+                            .setMessage("Version must be a constant")
+                            .setLocation(childModel.getLocation("version")));
                 }
             }
 
             // MNG-2199: What else to check here ?
         }
 
-        return new ModelData( modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(),
-                              parent.getVersion() );
+        return new ModelData(
+                modelSource, parentModel, parent.getGroupId(), parent.getArtifactId(), parent.getVersion());
     }
 
-    private Model getSuperModel()
-    {
-        return superPomProvider.getSuperModel( "4.0.0" ).clone();
+    private Model getSuperModel(String modelVersion) {
+        return superPomProvider.getSuperModel(modelVersion);
     }
 
-    private void importDependencyManagement( Model model, ModelBuildingRequest request,
-                                             DefaultModelProblemCollector problems, Collection<String> importIds )
-    {
+    private void importDependencyManagement(
+            Model model,
+            ModelBuildingRequest request,
+            DefaultModelProblemCollector problems,
+            Collection<String> importIds) {
         DependencyManagement depMgmt = model.getDependencyManagement();
 
-        if ( depMgmt == null )
-        {
+        if (depMgmt == null) {
             return;
         }
 
         String importing = model.getGroupId() + ':' + model.getArtifactId() + ':' + model.getVersion();
 
-        importIds.add( importing );
+        importIds.add(importing);
 
-        List<DependencyManagement> importMgmts = null;
+        List<org.apache.maven.api.model.DependencyManagement> importMgmts = null;
 
-        for ( Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); )
-        {
+        for (Iterator<Dependency> it = depMgmt.getDependencies().iterator(); it.hasNext(); ) {
             Dependency dependency = it.next();
 
-            if ( !"pom".equals( dependency.getType() ) || !"import".equals( dependency.getScope() ) )
-            {
+            if (!("pom".equals(dependency.getType()) && "import".equals(dependency.getScope()))
+                    || "bom".equals(dependency.getType())) {
                 continue;
             }
 
             it.remove();
 
-            DependencyManagement importMgmt = loadDependencyManagement( model, request, problems,
-                                                                        dependency, importIds );
+            DependencyManagement importMgmt = loadDependencyManagement(model, request, problems, dependency, importIds);
 
-            if ( importMgmt != null )
-            {
-                if ( importMgmts == null )
-                {
+            if (importMgmt != null) {
+                if (importMgmts == null) {
                     importMgmts = new ArrayList<>();
                 }
 
-                importMgmts.add( importMgmt );
+                importMgmts.add(importMgmt.getDelegate());
             }
         }
 
-        importIds.remove( importing );
+        importIds.remove(importing);
 
-        dependencyManagementImporter.importManagement( model, importMgmts, request, problems );
+        model.update(
+                dependencyManagementImporter.importManagement(model.getDelegate(), importMgmts, request, problems));
     }
 
-    private DependencyManagement loadDependencyManagement( Model model, ModelBuildingRequest request,
-                                                           DefaultModelProblemCollector problems,
-                                                           Dependency dependency,
-                                                           Collection<String> importIds )
-    {
+    private DependencyManagement loadDependencyManagement(
+            Model model,
+            ModelBuildingRequest request,
+            DefaultModelProblemCollector problems,
+            Dependency dependency,
+            Collection<String> importIds) {
         String groupId = dependency.getGroupId();
         String artifactId = dependency.getArtifactId();
         String version = dependency.getVersion();
 
-        if ( groupId == null || groupId.length() <= 0 )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "'dependencyManagement.dependencies.dependency.groupId' for "
-                                     + dependency.getManagementKey() + " is missing." )
-                    .setLocation( dependency.getLocation( "" ) ) );
+        if (groupId == null || groupId.length() <= 0) {
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                    .setMessage("'dependencyManagement.dependencies.dependency.groupId' for "
+                            + dependency.getManagementKey() + " is missing.")
+                    .setLocation(dependency.getLocation("")));
             return null;
         }
-        if ( artifactId == null || artifactId.length() <= 0 )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "'dependencyManagement.dependencies.dependency.artifactId' for "
-                                     + dependency.getManagementKey() + " is missing." )
-                    .setLocation( dependency.getLocation( "" ) ) );
+        if (artifactId == null || artifactId.length() <= 0) {
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                    .setMessage("'dependencyManagement.dependencies.dependency.artifactId' for "
+                            + dependency.getManagementKey() + " is missing.")
+                    .setLocation(dependency.getLocation("")));
             return null;
         }
-        if ( version == null || version.length() <= 0 )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "'dependencyManagement.dependencies.dependency.version' for "
-                                     + dependency.getManagementKey() + " is missing." )
-                    .setLocation( dependency.getLocation( "" ) ) );
+        if (version == null || version.length() <= 0) {
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                    .setMessage("'dependencyManagement.dependencies.dependency.version' for "
+                            + dependency.getManagementKey() + " is missing.")
+                    .setLocation(dependency.getLocation("")));
             return null;
         }
 
         String imported = groupId + ':' + artifactId + ':' + version;
 
-        if ( importIds.contains( imported ) )
-        {
+        if (importIds.contains(imported)) {
             StringBuilder message =
-                    new StringBuilder( "The dependencies of type=pom and with scope=import form a cycle: " );
-            for ( String modelId : importIds )
-            {
-                message.append( modelId ).append( " -> " );
+                    new StringBuilder("The dependencies of type=pom and with scope=import form a cycle: ");
+            for (String modelId : importIds) {
+                message.append(modelId).append(" -> ");
             }
-            message.append( imported );
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage(
-                    message.toString() ) );
+            message.append(imported);
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE).setMessage(message.toString()));
 
             return null;
         }
 
-        DependencyManagement importMgmt = fromCache( request.getModelCache(), groupId, artifactId, version,
-                                                    ModelCacheTag.IMPORT );
-        if ( importMgmt == null )
-        {
-            importMgmt = doLoadDependencyManagement( model, request, problems, dependency,
-                                                     groupId, artifactId, version, importIds );
-            if ( importMgmt != null )
-            {
-                intoCache( request.getModelCache(), groupId, artifactId, version, ModelCacheTag.IMPORT, importMgmt );
-            }
+        org.apache.maven.api.model.DependencyManagement importMgmt = cache(
+                request.getModelCache(),
+                groupId,
+                artifactId,
+                version,
+                ModelCacheTag.IMPORT,
+                () -> doLoadDependencyManagement(
+                        model, request, problems, dependency, groupId, artifactId, version, importIds));
+
+        // [MNG-5600] Dependency management import should support exclusions.
+        List<Exclusion> exclusions = dependency.getDelegate().getExclusions();
+        if (importMgmt != null && !exclusions.isEmpty()) {
+            // Dependency excluded from import.
+            List<org.apache.maven.api.model.Dependency> dependencies = importMgmt.getDependencies().stream()
+                    .filter(candidate -> exclusions.stream().noneMatch(exclusion -> match(exclusion, candidate)))
+                    .map(candidate -> candidate.withExclusions(exclusions))
+                    .collect(Collectors.toList());
+            importMgmt = importMgmt.withDependencies(dependencies);
         }
 
-        return importMgmt;
+        return importMgmt != null ? new DependencyManagement(importMgmt) : null;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private DependencyManagement doLoadDependencyManagement( Model model, ModelBuildingRequest request,
-                                                             DefaultModelProblemCollector problems,
-                                                             Dependency dependency,
-                                                             String groupId,
-                                                             String artifactId,
-                                                             String version,
-                                                             Collection<String> importIds )
-    {
+    private boolean match(Exclusion exclusion, org.apache.maven.api.model.Dependency candidate) {
+        return match(exclusion.getGroupId(), candidate.getGroupId())
+                && match(exclusion.getArtifactId(), candidate.getArtifactId());
+    }
+
+    private boolean match(String match, String text) {
+        return match.equals("*") || match.equals(text);
+    }
+
+    @SuppressWarnings("checkstyle:parameternumber")
+    private org.apache.maven.api.model.DependencyManagement doLoadDependencyManagement(
+            Model model,
+            ModelBuildingRequest request,
+            DefaultModelProblemCollector problems,
+            Dependency dependency,
+            String groupId,
+            String artifactId,
+            String version,
+            Collection<String> importIds) {
         DependencyManagement importMgmt;
         final WorkspaceModelResolver workspaceResolver = request.getWorkspaceModelResolver();
         final ModelResolver modelResolver = request.getModelResolver();
-        if ( workspaceResolver == null && modelResolver == null )
-        {
-            throw new NullPointerException( String.format(
-                "request.workspaceModelResolver and request.modelResolver cannot be null (parent POM %s and POM %s)",
-                ModelProblemUtils.toId( groupId, artifactId, version ),
-                ModelProblemUtils.toSourceHint( model ) ) );
+        if (workspaceResolver == null && modelResolver == null) {
+            throw new NullPointerException(String.format(
+                    "request.workspaceModelResolver and request.modelResolver cannot be null (parent POM %s and POM %s)",
+                    ModelProblemUtils.toId(groupId, artifactId, version), ModelProblemUtils.toSourceHint(model)));
         }
 
         Model importModel = null;
-        if ( workspaceResolver != null )
-        {
-            try
-            {
-                importModel = workspaceResolver.resolveEffectiveModel( groupId, artifactId, version );
-            }
-            catch ( UnresolvableModelException e )
-            {
-                problems.add( new ModelProblemCollectorRequest( Severity.FATAL, Version.BASE )
-                    .setMessage( e.getMessage() ).setException( e ) );
+        if (workspaceResolver != null) {
+            try {
+                importModel = workspaceResolver.resolveEffectiveModel(groupId, artifactId, version);
+            } catch (UnresolvableModelException e) {
+                problems.add(new ModelProblemCollectorRequest(Severity.FATAL, Version.BASE)
+                        .setMessage(e.getMessage())
+                        .setException(e));
                 return null;
             }
         }
 
         // no workspace resolver or workspace resolver returned null (i.e. model not in workspace)
-        if ( importModel == null )
-        {
+        if (importModel == null) {
             final ModelSource importSource;
-            try
-            {
-                importSource = modelResolver.resolveModel( dependency );
-            }
-            catch ( UnresolvableModelException e )
-            {
-                StringBuilder buffer = new StringBuilder( 256 );
-                buffer.append( "Non-resolvable import POM" );
-                if ( !containsCoordinates( e.getMessage(), groupId, artifactId, version ) )
-                {
-                    buffer.append( ' ' ).append( ModelProblemUtils.toId( groupId, artifactId, version ) );
+            try {
+                importSource = modelResolver.resolveModel(dependency);
+            } catch (UnresolvableModelException e) {
+                StringBuilder buffer = new StringBuilder(256);
+                buffer.append("Non-resolvable import POM");
+                if (!containsCoordinates(e.getMessage(), groupId, artifactId, version)) {
+                    buffer.append(' ').append(ModelProblemUtils.toId(groupId, artifactId, version));
                 }
-                buffer.append( ": " ).append( e.getMessage() );
+                buffer.append(": ").append(e.getMessage());
 
-                problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( buffer.toString() ).setLocation( dependency.getLocation( "" ) )
-                    .setException( e ) );
+                problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                        .setMessage(buffer.toString())
+                        .setLocation(dependency.getLocation(""))
+                        .setException(e));
                 return null;
             }
 
             final ModelBuildingResult importResult;
-            try
-            {
+            try {
                 ModelBuildingRequest importRequest = new DefaultModelBuildingRequest();
-                importRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
-                importRequest.setModelCache( request.getModelCache() );
-                importRequest.setSystemProperties( request.getSystemProperties() );
-                importRequest.setUserProperties( request.getUserProperties() );
-                importRequest.setLocationTracking( request.isLocationTracking() );
+                importRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+                importRequest.setModelCache(request.getModelCache());
+                importRequest.setSystemProperties(request.getSystemProperties());
+                importRequest.setUserProperties(request.getUserProperties());
+                importRequest.setLocationTracking(request.isLocationTracking());
 
-                importRequest.setModelSource( importSource );
-                importRequest.setModelResolver( modelResolver.newCopy() );
+                importRequest.setModelSource(importSource);
+                importRequest.setModelResolver(modelResolver.newCopy());
 
-                importResult = build( importRequest, importIds );
-            }
-            catch ( ModelBuildingException e )
-            {
-                problems.addAll( e.getProblems() );
+                importResult = build(importRequest, importIds);
+            } catch (ModelBuildingException e) {
+                problems.addAll(e.getProblems());
                 return null;
             }
 
-            problems.addAll( importResult.getProblems() );
+            problems.addAll(importResult.getProblems());
 
             importModel = importResult.getEffectiveModel();
         }
 
         importMgmt = importModel.getDependencyManagement();
 
-        if ( importMgmt == null )
-        {
+        if (importMgmt == null) {
             importMgmt = new DependencyManagement();
         }
-        return importMgmt;
+        return importMgmt.getDelegate();
     }
 
-    private <T> void intoCache( ModelCache modelCache, String groupId, String artifactId, String version,
-                               ModelCacheTag<T> tag, T data )
-    {
-        if ( modelCache != null )
-        {
-            modelCache.put( groupId, artifactId, version, tag, data );
-        }
+    private static <T> T cache(
+            ModelCache cache,
+            String groupId,
+            String artifactId,
+            String version,
+            ModelCacheTag<T> tag,
+            Callable<T> supplier) {
+        return doWithCache(cache, supplier, s -> cache.computeIfAbsent(groupId, artifactId, version, tag, s));
     }
 
-    private <T> void intoCache( ModelCache modelCache, Source source, ModelCacheTag<T> tag, T data )
-    {
-        if ( modelCache != null )
-        {
-            modelCache.put( source, tag, data );
-        }
+    private static <T> T cache(ModelCache cache, Source source, ModelCacheTag<T> tag, Callable<T> supplier) {
+        return doWithCache(cache, supplier, s -> cache.computeIfAbsent(source, tag, s));
     }
 
-    private static <T> T fromCache( ModelCache modelCache, String groupId, String artifactId, String version,
-                            ModelCacheTag<T> tag )
-    {
-        if ( modelCache != null )
-        {
-            return modelCache.get( groupId, artifactId, version, tag );
-        }
-        return null;
-    }
-
-    private static <T> T fromCache( ModelCache modelCache, Source source, ModelCacheTag<T> tag )
-    {
-        if ( modelCache != null )
-        {
-            return modelCache.get( source, tag );
-        }
-        return null;
-    }
-
-    private void fireEvent( Model model, ModelBuildingRequest request, ModelProblemCollector problems,
-                            ModelBuildingEventCatapult catapult )
-        throws ModelBuildingException
-    {
-        ModelBuildingListener listener = request.getModelBuildingListener();
-
-        if ( listener != null )
-        {
-            ModelBuildingEvent event = new DefaultModelBuildingEvent( model, request, problems );
-
-            catapult.fire( listener, event );
-        }
-    }
-
-    private boolean containsCoordinates( String message, String groupId, String artifactId, String version )
-    {
-        return message != null && ( groupId == null || message.contains( groupId ) )
-            && ( artifactId == null || message.contains( artifactId ) )
-            && ( version == null || message.contains( version ) );
-    }
-
-    protected boolean hasModelErrors( ModelProblemCollectorExt problems )
-    {
-        if ( problems instanceof DefaultModelProblemCollector )
-        {
-            return ( (DefaultModelProblemCollector) problems ).hasErrors();
-        }
-        else
-        {
-            // the default execution path only knows the DefaultModelProblemCollector,
-            // only reason it's not in signature is because it's package private
-            throw new IllegalStateException();
-        }
-    }
-
-    protected boolean hasFatalErrors( ModelProblemCollectorExt problems )
-    {
-        if ( problems instanceof DefaultModelProblemCollector )
-        {
-            return ( (DefaultModelProblemCollector) problems ).hasFatalErrors();
-        }
-        else
-        {
-            // the default execution path only knows the DefaultModelProblemCollector,
-            // only reason it's not in signature is because it's package private
-            throw new IllegalStateException();
-        }
-    }
-
-    /**
-     * Builds up the transformer context.
-     * After the buildplan is ready, the build()-method returns the immutable context useful during distribution.
-     * This is an inner class, as it must be able to call readRawModel()
-     *
-     * @author Robert Scholte
-     * @since 4.0.0
-     */
-    private class DefaultTransformerContextBuilder implements TransformerContextBuilder
-    {
-        private final DefaultTransformerContext context = new DefaultTransformerContext();
-
-        private final Map<DefaultTransformerContext.GAKey, Set<Source>> mappedSources
-                = new ConcurrentHashMap<>( 64 );
-
-        /**
-         * If an interface could be extracted, DefaultModelProblemCollector should be ModelProblemCollectorExt
-         *
-         * @param request
-         * @param collector
-         * @return
-         */
-        @Override
-        public TransformerContext initialize( ModelBuildingRequest request, ModelProblemCollector collector )
-        {
-            // We must assume the TransformerContext was created using this.newTransformerContextBuilder()
-            DefaultModelProblemCollector problems = (DefaultModelProblemCollector) collector;
-            return new TransformerContext()
-            {
-                @Override
-                public String getUserProperty( String key )
-                {
-                    return context.userProperties.computeIfAbsent( key,
-                                                           k -> request.getUserProperties().getProperty( key ) );
-                }
-
-                @Override
-                public Model getRawModel( String gId, String aId )
-                {
-                    return context.modelByGA.computeIfAbsent( new DefaultTransformerContext.GAKey( gId, aId ),
-                                                              k -> new DefaultTransformerContext.Holder() )
-                            .computeIfAbsent( () -> findRawModel( gId, aId ) );
-                }
-
-                @Override
-                public Model getRawModel( Path path )
-                {
-                    return context.modelByPath.computeIfAbsent( path,
-                                                                k -> new DefaultTransformerContext.Holder() )
-                            .computeIfAbsent( () -> findRawModel( path ) );
-                }
-
-                private Model findRawModel( String groupId, String artifactId )
-                {
-                    Source source = getSource( groupId, artifactId );
-                    if ( source != null )
-                    {
-                        try
-                        {
-                            ModelBuildingRequest gaBuildingRequest = new DefaultModelBuildingRequest( request )
-                                .setModelSource( (ModelSource) source );
-                            return readRawModel( gaBuildingRequest, problems );
+    private static <T> T doWithCache(
+            ModelCache cache, Callable<T> supplier, Function<Supplier<Supplier<T>>, T> asyncSupplierConsumer) {
+        if (cache != null) {
+            return asyncSupplierConsumer.apply(() -> {
+                ForkJoinTask<T> task = ForkJoinTask.adapt(supplier);
+                task.fork();
+                return () -> {
+                    task.quietlyJoin();
+                    if (task.isCompletedAbnormally()) {
+                        Throwable e = task.getException();
+                        while (e instanceof RuntimeException && e.getCause() != null) {
+                            e = e.getCause();
                         }
-                        catch ( ModelBuildingException e )
-                        {
-                            // gathered with problem collector
-                        }
+                        uncheckedThrow(e);
                     }
-                    return null;
-                }
-
-                private Model findRawModel( Path p )
-                {
-                    if ( !Files.isRegularFile( p ) )
-                    {
-                        throw new IllegalArgumentException( "Not a regular file: " + p );
-                    }
-
-                    DefaultModelBuildingRequest req = new DefaultModelBuildingRequest( request )
-                                    .setPomFile( p.toFile() )
-                                    .setModelSource( new FileModelSource( p.toFile() ) );
-
-                    try
-                    {
-                        return readRawModel( req, problems );
-                    }
-                    catch ( ModelBuildingException e )
-                    {
-                        // gathered with problem collector
-                    }
-                    return null;
-                }
-            };
-        }
-
-        @Override
-        public TransformerContext build()
-        {
-            return context;
-        }
-
-        public Source getSource( String groupId, String artifactId )
-        {
-            Set<Source> sources = mappedSources.get( new DefaultTransformerContext.GAKey( groupId, artifactId ) );
-            if ( sources == null )
-            {
+                    return task.getRawResult();
+                };
+            });
+        } else {
+            try {
+                return supplier.call();
+            } catch (Exception e) {
+                uncheckedThrow(e);
                 return null;
             }
-            return sources.stream().reduce( ( a, b ) ->
-            {
-                throw new IllegalStateException( String.format( "No unique Source for %s:%s: %s and %s",
-                                                                groupId, artifactId,
-                                                                a.getLocation(), b.getLocation() ) );
-            } ).orElse( null );
         }
+    }
 
-        public void putSource( String groupId, String artifactId, Source source )
-        {
-            mappedSources.computeIfAbsent( new DefaultTransformerContext.GAKey( groupId, artifactId ),
-                    k -> new HashSet<>() ).add( source );
+    static <T extends Throwable> void uncheckedThrow(Throwable t) throws T {
+        throw (T) t; // rely on vacuous cast
+    }
+
+    private void fireEvent(
+            Model model,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems,
+            ModelBuildingEventCatapult catapult) {
+        ModelBuildingListener listener = request.getModelBuildingListener();
+
+        if (listener != null) {
+            ModelBuildingEvent event = new DefaultModelBuildingEvent(model, request, problems);
+
+            catapult.fire(listener, event);
         }
+    }
 
+    private boolean containsCoordinates(String message, String groupId, String artifactId, String version) {
+        return message != null
+                && (groupId == null || message.contains(groupId))
+                && (artifactId == null || message.contains(artifactId))
+                && (version == null || message.contains(version));
+    }
+
+    protected boolean hasModelErrors(ModelProblemCollectorExt problems) {
+        if (problems instanceof DefaultModelProblemCollector) {
+            return ((DefaultModelProblemCollector) problems).hasErrors();
+        } else {
+            // the default execution path only knows the DefaultModelProblemCollector,
+            // only reason it's not in signature is because it's package private
+            throw new IllegalStateException();
+        }
+    }
+
+    protected boolean hasFatalErrors(ModelProblemCollectorExt problems) {
+        if (problems instanceof DefaultModelProblemCollector) {
+            return ((DefaultModelProblemCollector) problems).hasFatalErrors();
+        } else {
+            // the default execution path only knows the DefaultModelProblemCollector,
+            // only reason it's not in signature is because it's package private
+            throw new IllegalStateException();
+        }
+    }
+
+    ModelProcessor getModelProcessor() {
+        return modelProcessor;
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java
index 8c7b603..dc474ce 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuilderFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.Arrays;
 
+import org.apache.maven.api.spi.ModelParser;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.composition.DefaultDependencyManagementImporter;
 import org.apache.maven.model.composition.DependencyManagementImporter;
@@ -65,6 +65,8 @@
 import org.apache.maven.model.profile.activation.OperatingSystemProfileActivator;
 import org.apache.maven.model.profile.activation.ProfileActivator;
 import org.apache.maven.model.profile.activation.PropertyProfileActivator;
+import org.apache.maven.model.root.DefaultRootLocator;
+import org.apache.maven.model.root.RootLocator;
 import org.apache.maven.model.superpom.DefaultSuperPomProvider;
 import org.apache.maven.model.superpom.SuperPomProvider;
 import org.apache.maven.model.validation.DefaultModelValidator;
@@ -72,16 +74,13 @@
 
 /**
  * A factory to create model builder instances when no dependency injection is available. <em>Note:</em> This class is
- * only meant as a utility for developers that want to employ the model builder outside of the Maven build system, Maven
+ * only meant as a utility for developers that want to employ the model builder outside the Maven build system, Maven
  * plugins should always acquire model builder instances via dependency injection. Developers might want to subclass
  * this factory to provide custom implementations for some of the components used by the model builder, or use the
  * builder API to inject custom instances.
  *
- * @author Benjamin Bentmann
- * @author Guillaume Nodet
  */
-public class DefaultModelBuilderFactory
-{
+public class DefaultModelBuilderFactory {
 
     private ModelProcessor modelProcessor;
     private ModelValidator modelValidator;
@@ -99,251 +98,239 @@
     private LifecycleBindingsInjector lifecycleBindingsInjector;
     private PluginConfigurationExpander pluginConfigurationExpander;
     private ReportConfigurationExpander reportConfigurationExpander;
-    private ReportingConverter reportingConverter;
     private ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
+    private ModelVersionProcessor versionProcessor;
+    private ModelSourceTransformer transformer;
 
-    public DefaultModelBuilderFactory setModelProcessor( ModelProcessor modelProcessor )
-    {
+    private RootLocator rootLocator;
+
+    public DefaultModelBuilderFactory setModelProcessor(ModelProcessor modelProcessor) {
         this.modelProcessor = modelProcessor;
         return this;
     }
 
-    public DefaultModelBuilderFactory setModelValidator( ModelValidator modelValidator )
-    {
+    public DefaultModelBuilderFactory setModelValidator(ModelValidator modelValidator) {
         this.modelValidator = modelValidator;
         return this;
     }
 
-    public DefaultModelBuilderFactory setModelNormalizer( ModelNormalizer modelNormalizer )
-    {
+    public DefaultModelBuilderFactory setModelNormalizer(ModelNormalizer modelNormalizer) {
         this.modelNormalizer = modelNormalizer;
         return this;
     }
 
-    public DefaultModelBuilderFactory setModelInterpolator( ModelInterpolator modelInterpolator )
-    {
+    public DefaultModelBuilderFactory setModelInterpolator(ModelInterpolator modelInterpolator) {
         this.modelInterpolator = modelInterpolator;
         return this;
     }
 
-    public DefaultModelBuilderFactory setModelPathTranslator( ModelPathTranslator modelPathTranslator )
-    {
+    public DefaultModelBuilderFactory setModelPathTranslator(ModelPathTranslator modelPathTranslator) {
         this.modelPathTranslator = modelPathTranslator;
         return this;
     }
 
-    public DefaultModelBuilderFactory setModelUrlNormalizer( ModelUrlNormalizer modelUrlNormalizer )
-    {
+    public DefaultModelBuilderFactory setModelUrlNormalizer(ModelUrlNormalizer modelUrlNormalizer) {
         this.modelUrlNormalizer = modelUrlNormalizer;
         return this;
     }
 
-    public DefaultModelBuilderFactory setSuperPomProvider( SuperPomProvider superPomProvider )
-    {
+    public DefaultModelBuilderFactory setSuperPomProvider(SuperPomProvider superPomProvider) {
         this.superPomProvider = superPomProvider;
         return this;
     }
 
-    public DefaultModelBuilderFactory setInheritanceAssembler( InheritanceAssembler inheritanceAssembler )
-    {
+    public DefaultModelBuilderFactory setInheritanceAssembler(InheritanceAssembler inheritanceAssembler) {
         this.inheritanceAssembler = inheritanceAssembler;
         return this;
     }
 
-    public DefaultModelBuilderFactory setProfileSelector( ProfileSelector profileSelector )
-    {
+    public DefaultModelBuilderFactory setProfileSelector(ProfileSelector profileSelector) {
         this.profileSelector = profileSelector;
         return this;
     }
 
-    public DefaultModelBuilderFactory setProfileInjector( ProfileInjector profileInjector )
-    {
+    public DefaultModelBuilderFactory setProfileInjector(ProfileInjector profileInjector) {
         this.profileInjector = profileInjector;
         return this;
     }
 
-    public DefaultModelBuilderFactory setPluginManagementInjector( PluginManagementInjector pluginManagementInjector )
-    {
+    public DefaultModelBuilderFactory setPluginManagementInjector(PluginManagementInjector pluginManagementInjector) {
         this.pluginManagementInjector = pluginManagementInjector;
         return this;
     }
 
     public DefaultModelBuilderFactory setDependencyManagementInjector(
-            DependencyManagementInjector dependencyManagementInjector )
-    {
+            DependencyManagementInjector dependencyManagementInjector) {
         this.dependencyManagementInjector = dependencyManagementInjector;
         return this;
     }
 
     public DefaultModelBuilderFactory setDependencyManagementImporter(
-            DependencyManagementImporter dependencyManagementImporter )
-    {
+            DependencyManagementImporter dependencyManagementImporter) {
         this.dependencyManagementImporter = dependencyManagementImporter;
         return this;
     }
 
     public DefaultModelBuilderFactory setLifecycleBindingsInjector(
-            LifecycleBindingsInjector lifecycleBindingsInjector )
-    {
+            LifecycleBindingsInjector lifecycleBindingsInjector) {
         this.lifecycleBindingsInjector = lifecycleBindingsInjector;
         return this;
     }
 
     public DefaultModelBuilderFactory setPluginConfigurationExpander(
-            PluginConfigurationExpander pluginConfigurationExpander )
-    {
+            PluginConfigurationExpander pluginConfigurationExpander) {
         this.pluginConfigurationExpander = pluginConfigurationExpander;
         return this;
     }
 
     public DefaultModelBuilderFactory setReportConfigurationExpander(
-            ReportConfigurationExpander reportConfigurationExpander )
-    {
+            ReportConfigurationExpander reportConfigurationExpander) {
         this.reportConfigurationExpander = reportConfigurationExpander;
         return this;
     }
 
-    public DefaultModelBuilderFactory setReportingConverter( ReportingConverter reportingConverter )
-    {
-        this.reportingConverter = reportingConverter;
+    @Deprecated
+    public DefaultModelBuilderFactory setReportingConverter(ReportingConverter reportingConverter) {
         return this;
     }
 
     public DefaultModelBuilderFactory setProfileActivationFilePathInterpolator(
-            ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator )
-    {
+            ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator) {
         this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
         return this;
     }
 
-    protected ModelProcessor newModelProcessor()
-    {
-        return new DefaultModelProcessor( newModelLocator(), newModelReader() );
+    public DefaultModelBuilderFactory setVersionProcessor(ModelVersionProcessor versionProcessor) {
+        this.versionProcessor = versionProcessor;
+        return this;
     }
 
-    protected ModelLocator newModelLocator()
-    {
+    public DefaultModelBuilderFactory setRootLocator(RootLocator rootLocator) {
+        this.rootLocator = rootLocator;
+        return this;
+    }
+
+    public DefaultModelBuilderFactory setTransformer(ModelSourceTransformer transformer) {
+        this.transformer = transformer;
+        return this;
+    }
+
+    protected ModelProcessor newModelProcessor() {
+        return new DefaultModelProcessor(Arrays.asList(newModelParsers()), newModelLocator(), newModelReader());
+    }
+
+    protected ModelParser[] newModelParsers() {
+        return new ModelParser[0];
+    }
+
+    protected ModelLocator newModelLocator() {
         return new DefaultModelLocator();
     }
 
-    protected ModelReader newModelReader()
-    {
-        return new DefaultModelReader( newModelSourceTransformer() );
+    protected ModelReader newModelReader() {
+        return new DefaultModelReader(newModelSourceTransformer());
     }
 
-    protected ProfileSelector newProfileSelector()
-    {
-        return new DefaultProfileSelector( Arrays.asList( newProfileActivators() ) );
+    protected ProfileSelector newProfileSelector() {
+        return new DefaultProfileSelector(Arrays.asList(newProfileActivators()));
     }
 
-    protected ProfileActivator[] newProfileActivators()
-    {
-        return new ProfileActivator[] { new JdkVersionProfileActivator(), new OperatingSystemProfileActivator(),
-            new PropertyProfileActivator(), new FileProfileActivator( newProfileActivationFilePathInterpolator() ) };
+    protected ProfileActivator[] newProfileActivators() {
+        return new ProfileActivator[] {
+            new JdkVersionProfileActivator(),
+            new OperatingSystemProfileActivator(),
+            new PropertyProfileActivator(),
+            new FileProfileActivator(newProfileActivationFilePathInterpolator())
+        };
     }
 
-    protected ProfileActivationFilePathInterpolator newProfileActivationFilePathInterpolator()
-    {
-        return new ProfileActivationFilePathInterpolator( newPathTranslator() );
+    protected ProfileActivationFilePathInterpolator newProfileActivationFilePathInterpolator() {
+        return new ProfileActivationFilePathInterpolator(newPathTranslator(), newRootLocator());
     }
 
-    protected UrlNormalizer newUrlNormalizer()
-    {
+    protected UrlNormalizer newUrlNormalizer() {
         return new DefaultUrlNormalizer();
     }
 
-    protected PathTranslator newPathTranslator()
-    {
+    protected PathTranslator newPathTranslator() {
         return new DefaultPathTranslator();
     }
 
-    protected ModelInterpolator newModelInterpolator()
-    {
-        UrlNormalizer normalizer = newUrlNormalizer();
-        PathTranslator pathTranslator = newPathTranslator();
-        ModelVersionProcessor versionProcessor = newModelVersionPropertiesProcessor();
-        return new StringVisitorModelInterpolator( pathTranslator, normalizer, versionProcessor );
+    protected RootLocator newRootLocator() {
+        return new DefaultRootLocator();
     }
 
-    protected ModelVersionProcessor newModelVersionPropertiesProcessor()
-    {
+    protected ModelInterpolator newModelInterpolator() {
+        UrlNormalizer normalizer = newUrlNormalizer();
+        PathTranslator pathTranslator = newPathTranslator();
+        RootLocator rootLocator = newRootLocator();
+        return new StringVisitorModelInterpolator(pathTranslator, normalizer, rootLocator);
+    }
+
+    protected ModelVersionProcessor newModelVersionPropertiesProcessor() {
         return new DefaultModelVersionProcessor();
     }
 
-    protected ModelValidator newModelValidator()
-    {
+    protected ModelValidator newModelValidator() {
         ModelVersionProcessor processor = newModelVersionPropertiesProcessor();
-        return new DefaultModelValidator( processor );
+        return new DefaultModelValidator(processor);
     }
 
-    protected ModelNormalizer newModelNormalizer()
-    {
+    protected ModelNormalizer newModelNormalizer() {
         return new DefaultModelNormalizer();
     }
 
-    protected ModelPathTranslator newModelPathTranslator()
-    {
-        return new DefaultModelPathTranslator( newPathTranslator() );
+    protected ModelPathTranslator newModelPathTranslator() {
+        return new DefaultModelPathTranslator(newPathTranslator());
     }
 
-    protected ModelUrlNormalizer newModelUrlNormalizer()
-    {
-        return new DefaultModelUrlNormalizer( newUrlNormalizer() );
+    protected ModelUrlNormalizer newModelUrlNormalizer() {
+        return new DefaultModelUrlNormalizer(newUrlNormalizer());
     }
 
-    protected InheritanceAssembler newInheritanceAssembler()
-    {
+    protected InheritanceAssembler newInheritanceAssembler() {
         return new DefaultInheritanceAssembler();
     }
 
-    protected ProfileInjector newProfileInjector()
-    {
+    protected ProfileInjector newProfileInjector() {
         return new DefaultProfileInjector();
     }
 
-    protected SuperPomProvider newSuperPomProvider()
-    {
-        return new DefaultSuperPomProvider( newModelProcessor() );
+    protected SuperPomProvider newSuperPomProvider() {
+        return new DefaultSuperPomProvider(newModelProcessor());
     }
 
-    protected DependencyManagementImporter newDependencyManagementImporter()
-    {
+    protected DependencyManagementImporter newDependencyManagementImporter() {
         return new DefaultDependencyManagementImporter();
     }
 
-    protected DependencyManagementInjector newDependencyManagementInjector()
-    {
+    protected DependencyManagementInjector newDependencyManagementInjector() {
         return new DefaultDependencyManagementInjector();
     }
 
-    protected LifecycleBindingsInjector newLifecycleBindingsInjector()
-    {
+    protected LifecycleBindingsInjector newLifecycleBindingsInjector() {
         return new StubLifecycleBindingsInjector();
     }
 
-    protected PluginManagementInjector newPluginManagementInjector()
-    {
+    protected PluginManagementInjector newPluginManagementInjector() {
         return new DefaultPluginManagementInjector();
     }
 
-    protected PluginConfigurationExpander newPluginConfigurationExpander()
-    {
+    protected PluginConfigurationExpander newPluginConfigurationExpander() {
         return new DefaultPluginConfigurationExpander();
     }
 
-    protected ReportConfigurationExpander newReportConfigurationExpander()
-    {
+    protected ReportConfigurationExpander newReportConfigurationExpander() {
         return new DefaultReportConfigurationExpander();
     }
 
-    protected ReportingConverter newReportingConverter()
-    {
+    @Deprecated
+    protected ReportingConverter newReportingConverter() {
         return new DefaultReportingConverter();
     }
 
-    private ModelSourceTransformer newModelSourceTransformer()
-    {
-        return new DefaultModelSourceTransformer();
+    private ModelSourceTransformer newModelSourceTransformer() {
+        return new BuildModelSourceTransformer();
     }
 
     /**
@@ -351,8 +338,7 @@
      *
      * @return The new model builder instance, never {@code null}.
      */
-    public DefaultModelBuilder newInstance()
-    {
+    public DefaultModelBuilder newInstance() {
         return new DefaultModelBuilder(
                 modelProcessor != null ? modelProcessor : newModelProcessor(),
                 modelValidator != null ? modelValidator : newModelValidator(),
@@ -370,21 +356,17 @@
                 lifecycleBindingsInjector != null ? lifecycleBindingsInjector : newLifecycleBindingsInjector(),
                 pluginConfigurationExpander != null ? pluginConfigurationExpander : newPluginConfigurationExpander(),
                 reportConfigurationExpander != null ? reportConfigurationExpander : newReportConfigurationExpander(),
-                reportingConverter != null ? reportingConverter : newReportingConverter(),
                 profileActivationFilePathInterpolator != null
-                        ? profileActivationFilePathInterpolator : newProfileActivationFilePathInterpolator()
-        );
+                        ? profileActivationFilePathInterpolator
+                        : newProfileActivationFilePathInterpolator(),
+                versionProcessor != null ? versionProcessor : newModelVersionPropertiesProcessor(),
+                transformer != null ? transformer : newModelSourceTransformer());
     }
 
-    private static class StubLifecycleBindingsInjector
-        implements LifecycleBindingsInjector
-    {
+    private static class StubLifecycleBindingsInjector implements LifecycleBindingsInjector {
 
         @Override
-        public void injectLifecycleBindings( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-        {
-        }
-
+        public void injectLifecycleBindings(
+                Model model, ModelBuildingRequest request, ModelProblemCollector problems) {}
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingEvent.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingEvent.java
index 01d23ef..df4ad58 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingEvent.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingEvent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,47 +16,40 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import org.apache.maven.model.Model;
 
 /**
  * Holds data relevant for a model building event.
  *
- * @author Benjamin Bentmann
  */
-class DefaultModelBuildingEvent
-    implements ModelBuildingEvent
-{
+class DefaultModelBuildingEvent implements ModelBuildingEvent {
 
-    private final Model model;
+    private Model model;
 
     private final ModelBuildingRequest request;
 
     private final ModelProblemCollector problems;
 
-    DefaultModelBuildingEvent( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    DefaultModelBuildingEvent(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
         this.model = model;
         this.request = request;
         this.problems = problems;
     }
 
     @Override
-    public Model getModel()
-    {
+    public Model getModel() {
         return model;
     }
 
     @Override
-    public ModelBuildingRequest getRequest()
-    {
+    public ModelBuildingRequest getRequest() {
         return request;
     }
 
     @Override
-    public ModelProblemCollector getProblems()
-    {
+    public ModelProblemCollector getProblems() {
         return problems;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java
index e01b363..9348098 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -33,11 +33,8 @@
 /**
  * Collects settings that control building of effective models.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultModelBuildingRequest
-    implements ModelBuildingRequest
-{
+public class DefaultModelBuildingRequest implements ModelBuildingRequest {
     private Model fileModel;
 
     private File pomFile;
@@ -74,131 +71,117 @@
 
     private TransformerContextBuilder contextBuilder;
 
+    private Path rootDirectory;
+
     /**
      * Creates an empty request.
      */
-    public DefaultModelBuildingRequest()
-    {
-    }
+    public DefaultModelBuildingRequest() {}
 
     /**
      * Creates a shallow copy of the specified request.
      *
      * @param request The request to copy, must not be {@code null}.
      */
-    public DefaultModelBuildingRequest( ModelBuildingRequest request )
-    {
-        setPomFile( request.getPomFile() );
-        setModelSource( request.getModelSource() );
-        setValidationLevel( request.getValidationLevel() );
-        setProcessPlugins( request.isProcessPlugins() );
-        setTwoPhaseBuilding( request.isTwoPhaseBuilding() );
-        setProfiles( request.getProfiles() );
-        setActiveProfileIds( request.getActiveProfileIds() );
-        setInactiveProfileIds( request.getInactiveProfileIds() );
-        setSystemProperties( request.getSystemProperties() );
-        setUserProperties( request.getUserProperties() );
-        setBuildStartTime( request.getBuildStartTime() );
-        setModelResolver( request.getModelResolver() );
-        setModelBuildingListener( request.getModelBuildingListener() );
-        setModelCache( request.getModelCache() );
-        setWorkspaceModelResolver( request.getWorkspaceModelResolver() );
-        setTransformerContextBuilder( request.getTransformerContextBuilder() );
+    public DefaultModelBuildingRequest(ModelBuildingRequest request) {
+        setPomFile(request.getPomFile());
+        setModelSource(request.getModelSource());
+        setValidationLevel(request.getValidationLevel());
+        setProcessPlugins(request.isProcessPlugins());
+        setTwoPhaseBuilding(request.isTwoPhaseBuilding());
+        setLocationTracking(request.isLocationTracking());
+        setProfiles(request.getProfiles());
+        setActiveProfileIds(request.getActiveProfileIds());
+        setInactiveProfileIds(request.getInactiveProfileIds());
+        setSystemProperties(request.getSystemProperties());
+        setUserProperties(request.getUserProperties());
+        setBuildStartTime(request.getBuildStartTime());
+        setModelResolver(request.getModelResolver());
+        setModelBuildingListener(request.getModelBuildingListener());
+        setModelCache(request.getModelCache());
+        setWorkspaceModelResolver(request.getWorkspaceModelResolver());
+        setTransformerContextBuilder(request.getTransformerContextBuilder());
+        setRootDirectory(request.getRootDirectory());
     }
 
     @Override
-    public File getPomFile()
-    {
+    public File getPomFile() {
         return pomFile;
     }
 
     @Override
-    public DefaultModelBuildingRequest setPomFile( File pomFile )
-    {
-        this.pomFile = ( pomFile != null ) ? pomFile.getAbsoluteFile() : null;
+    public DefaultModelBuildingRequest setPomFile(File pomFile) {
+        this.pomFile = (pomFile != null) ? pomFile.getAbsoluteFile() : null;
 
         return this;
     }
 
     @Override
-    public synchronized ModelSource getModelSource()
-    {
-        if ( modelSource == null && pomFile != null )
-        {
-            modelSource = new FileModelSource( pomFile );
+    public synchronized ModelSource getModelSource() {
+        if (modelSource == null && pomFile != null) {
+            modelSource = new FileModelSource(pomFile);
         }
         return modelSource;
     }
 
     @Override
-    public DefaultModelBuildingRequest setModelSource( ModelSource modelSource )
-    {
+    public DefaultModelBuildingRequest setModelSource(ModelSource modelSource) {
         this.modelSource = modelSource;
 
         return this;
     }
 
     @Override
-    public int getValidationLevel()
-    {
+    public int getValidationLevel() {
         return validationLevel;
     }
 
     @Override
-    public DefaultModelBuildingRequest setValidationLevel( int validationLevel )
-    {
+    public DefaultModelBuildingRequest setValidationLevel(int validationLevel) {
         this.validationLevel = validationLevel;
 
         return this;
     }
 
     @Override
-    public boolean isProcessPlugins()
-    {
+    public boolean isProcessPlugins() {
         return processPlugins;
     }
 
     @Override
-    public DefaultModelBuildingRequest setProcessPlugins( boolean processPlugins )
-    {
+    public DefaultModelBuildingRequest setProcessPlugins(boolean processPlugins) {
         this.processPlugins = processPlugins;
 
         return this;
     }
 
     @Override
-    public boolean isTwoPhaseBuilding()
-    {
+    public boolean isTwoPhaseBuilding() {
         return twoPhaseBuilding;
     }
 
     @Override
-    public DefaultModelBuildingRequest setTwoPhaseBuilding( boolean twoPhaseBuilding )
-    {
+    public DefaultModelBuildingRequest setTwoPhaseBuilding(boolean twoPhaseBuilding) {
         this.twoPhaseBuilding = twoPhaseBuilding;
 
         return this;
     }
 
     @Override
-    public boolean isLocationTracking()
-    {
+    public boolean isLocationTracking() {
         return locationTracking;
     }
 
     @Override
-    public DefaultModelBuildingRequest setLocationTracking( boolean locationTracking )
-    {
+    public DefaultModelBuildingRequest setLocationTracking(boolean locationTracking) {
         this.locationTracking = locationTracking;
 
         return this;
     }
 
     @Override
-    public List<Profile> getProfiles()
-    {
-        if ( profiles == null )
-        {
+    public List<Profile> getProfiles() {
+        if (profiles == null) {
             profiles = new ArrayList<>();
         }
 
@@ -206,14 +189,10 @@
     }
 
     @Override
-    public DefaultModelBuildingRequest setProfiles( List<Profile> profiles )
-    {
-        if ( profiles != null )
-        {
-            this.profiles = new ArrayList<>( profiles );
-        }
-        else
-        {
+    public DefaultModelBuildingRequest setProfiles(List<Profile> profiles) {
+        if (profiles != null) {
+            this.profiles = new ArrayList<>(profiles);
+        } else {
             this.profiles = null;
         }
 
@@ -221,10 +200,8 @@
     }
 
     @Override
-    public List<String> getActiveProfileIds()
-    {
-        if ( activeProfileIds == null )
-        {
+    public List<String> getActiveProfileIds() {
+        if (activeProfileIds == null) {
             activeProfileIds = new ArrayList<>();
         }
 
@@ -232,14 +209,10 @@
     }
 
     @Override
-    public DefaultModelBuildingRequest setActiveProfileIds( List<String> activeProfileIds )
-    {
-        if ( activeProfileIds != null )
-        {
-            this.activeProfileIds = new ArrayList<>( activeProfileIds );
-        }
-        else
-        {
+    public DefaultModelBuildingRequest setActiveProfileIds(List<String> activeProfileIds) {
+        if (activeProfileIds != null) {
+            this.activeProfileIds = new ArrayList<>(activeProfileIds);
+        } else {
             this.activeProfileIds = null;
         }
 
@@ -247,10 +220,8 @@
     }
 
     @Override
-    public List<String> getInactiveProfileIds()
-    {
-        if ( inactiveProfileIds == null )
-        {
+    public List<String> getInactiveProfileIds() {
+        if (inactiveProfileIds == null) {
             inactiveProfileIds = new ArrayList<>();
         }
 
@@ -258,14 +229,10 @@
     }
 
     @Override
-    public DefaultModelBuildingRequest setInactiveProfileIds( List<String> inactiveProfileIds )
-    {
-        if ( inactiveProfileIds != null )
-        {
-            this.inactiveProfileIds = new ArrayList<>( inactiveProfileIds );
-        }
-        else
-        {
+    public DefaultModelBuildingRequest setInactiveProfileIds(List<String> inactiveProfileIds) {
+        if (inactiveProfileIds != null) {
+            this.inactiveProfileIds = new ArrayList<>(inactiveProfileIds);
+        } else {
             this.inactiveProfileIds = null;
         }
 
@@ -273,10 +240,8 @@
     }
 
     @Override
-    public Properties getSystemProperties()
-    {
-        if ( systemProperties == null )
-        {
+    public Properties getSystemProperties() {
+        if (systemProperties == null) {
             systemProperties = new Properties();
         }
 
@@ -284,18 +249,14 @@
     }
 
     @Override
-    public DefaultModelBuildingRequest setSystemProperties( Properties systemProperties )
-    {
-        if ( systemProperties != null )
-        {
+    public DefaultModelBuildingRequest setSystemProperties(Properties systemProperties) {
+        if (systemProperties != null) {
             this.systemProperties = new Properties();
-            synchronized ( systemProperties )
-            { // avoid concurrent modification if someone else sets/removes an unrelated system property
-                this.systemProperties.putAll( systemProperties );
+            synchronized (systemProperties) { // avoid concurrent modification if someone else sets/removes an unrelated
+                // system property
+                this.systemProperties.putAll(systemProperties);
             }
-        }
-        else
-        {
+        } else {
             this.systemProperties = null;
         }
 
@@ -303,10 +264,8 @@
     }
 
     @Override
-    public Properties getUserProperties()
-    {
-        if ( userProperties == null )
-        {
+    public Properties getUserProperties() {
+        if (userProperties == null) {
             userProperties = new Properties();
         }
 
@@ -314,15 +273,11 @@
     }
 
     @Override
-    public DefaultModelBuildingRequest setUserProperties( Properties userProperties )
-    {
-        if ( userProperties != null )
-        {
+    public DefaultModelBuildingRequest setUserProperties(Properties userProperties) {
+        if (userProperties != null) {
             this.userProperties = new Properties();
-            this.userProperties.putAll( userProperties );
-        }
-        else
-        {
+            this.userProperties.putAll(userProperties);
+        } else {
             this.userProperties = null;
         }
 
@@ -330,110 +285,104 @@
     }
 
     @Override
-    public Date getBuildStartTime()
-    {
+    public Date getBuildStartTime() {
         return buildStartTime;
     }
 
     @Override
-    public ModelBuildingRequest setBuildStartTime( Date buildStartTime )
-    {
+    public ModelBuildingRequest setBuildStartTime(Date buildStartTime) {
         this.buildStartTime = buildStartTime;
 
         return this;
     }
 
     @Override
-    public ModelResolver getModelResolver()
-    {
+    public ModelResolver getModelResolver() {
         return this.modelResolver;
     }
 
     @Override
-    public DefaultModelBuildingRequest setModelResolver( ModelResolver modelResolver )
-    {
+    public DefaultModelBuildingRequest setModelResolver(ModelResolver modelResolver) {
         this.modelResolver = modelResolver;
 
         return this;
     }
 
     @Override
-    public ModelBuildingListener getModelBuildingListener()
-    {
+    public ModelBuildingListener getModelBuildingListener() {
         return modelBuildingListener;
     }
 
     @Override
-    public ModelBuildingRequest setModelBuildingListener( ModelBuildingListener modelBuildingListener )
-    {
+    public ModelBuildingRequest setModelBuildingListener(ModelBuildingListener modelBuildingListener) {
         this.modelBuildingListener = modelBuildingListener;
 
         return this;
     }
 
     @Override
-    public ModelCache getModelCache()
-    {
+    public ModelCache getModelCache() {
         return this.modelCache;
     }
 
     @Override
-    public DefaultModelBuildingRequest setModelCache( ModelCache modelCache )
-    {
+    public DefaultModelBuildingRequest setModelCache(ModelCache modelCache) {
         this.modelCache = modelCache;
 
         return this;
     }
 
     @Override
-    public Model getFileModel()
-    {
+    public Model getFileModel() {
         return fileModel;
     }
 
     @Override
-    public ModelBuildingRequest setFileModel( Model fileModel )
-    {
+    public ModelBuildingRequest setFileModel(Model fileModel) {
         this.fileModel = fileModel;
         return this;
     }
 
     @Override
-    public Model getRawModel()
-    {
+    public Model getRawModel() {
         return null;
     }
 
     @Override
-    public ModelBuildingRequest setRawModel( Model rawModel )
-    {
+    public ModelBuildingRequest setRawModel(Model rawModel) {
         return this;
     }
 
     @Override
-    public WorkspaceModelResolver getWorkspaceModelResolver()
-    {
+    public WorkspaceModelResolver getWorkspaceModelResolver() {
         return workspaceResolver;
     }
 
     @Override
-    public ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver )
-    {
+    public ModelBuildingRequest setWorkspaceModelResolver(WorkspaceModelResolver workspaceResolver) {
         this.workspaceResolver = workspaceResolver;
         return this;
     }
 
     @Override
-    public TransformerContextBuilder getTransformerContextBuilder()
-    {
+    public TransformerContextBuilder getTransformerContextBuilder() {
         return contextBuilder;
     }
 
     @Override
-    public ModelBuildingRequest setTransformerContextBuilder( TransformerContextBuilder contextBuilder )
-    {
+    public ModelBuildingRequest setTransformerContextBuilder(TransformerContextBuilder contextBuilder) {
         this.contextBuilder = contextBuilder;
         return this;
     }
 
+    @Override
+    public Path getRootDirectory() {
+        return rootDirectory;
+    }
+
+    @Override
+    public ModelBuildingRequest setRootDirectory(Path rootDirectory) {
+        this.rootDirectory = rootDirectory;
+        return this;
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java
index b2fcfa0..cbf9649 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -31,11 +30,8 @@
 /**
  * Collects the output of the model builder.
  *
- * @author Benjamin Bentmann
  */
-class DefaultModelBuildingResult
-    implements ModelBuildingResult
-{
+class DefaultModelBuildingResult implements ModelBuildingResult {
     private Model fileModel;
 
     private Model effectiveModel;
@@ -50,8 +46,7 @@
 
     private List<ModelProblem> problems;
 
-    DefaultModelBuildingResult()
-    {
+    DefaultModelBuildingResult() {
         modelIds = new ArrayList<>();
         rawModels = new HashMap<>();
         activePomProfiles = new HashMap<>();
@@ -59,123 +54,102 @@
         problems = new ArrayList<>();
     }
 
-    DefaultModelBuildingResult( ModelBuildingResult result )
-    {
+    DefaultModelBuildingResult(ModelBuildingResult result) {
         this();
-        this.activeExternalProfiles.addAll( result.getActiveExternalProfiles() );
+        this.activeExternalProfiles.addAll(result.getActiveExternalProfiles());
         this.effectiveModel = result.getEffectiveModel();
         this.fileModel = result.getFileModel();
-        this.problems.addAll( result.getProblems() );
+        this.problems.addAll(result.getProblems());
 
-        for ( String modelId : result.getModelIds() )
-        {
-            this.modelIds.add( modelId );
-            this.rawModels.put( modelId, result.getRawModel( modelId ) );
-            this.activePomProfiles.put( modelId, result.getActivePomProfiles( modelId ) );
+        for (String modelId : result.getModelIds()) {
+            this.modelIds.add(modelId);
+            this.rawModels.put(modelId, result.getRawModel(modelId));
+            this.activePomProfiles.put(modelId, result.getActivePomProfiles(modelId));
         }
     }
 
     @Override
-    public Model getFileModel()
-    {
+    public Model getFileModel() {
         return fileModel;
     }
 
-    public DefaultModelBuildingResult setFileModel( Model fileModel )
-    {
+    public DefaultModelBuildingResult setFileModel(Model fileModel) {
         this.fileModel = fileModel;
 
         return this;
     }
 
     @Override
-    public Model getEffectiveModel()
-    {
+    public Model getEffectiveModel() {
         return effectiveModel;
     }
 
-    public DefaultModelBuildingResult setEffectiveModel( Model model )
-    {
+    public DefaultModelBuildingResult setEffectiveModel(Model model) {
         this.effectiveModel = model;
 
         return this;
     }
 
     @Override
-    public List<String> getModelIds()
-    {
+    public List<String> getModelIds() {
         return modelIds;
     }
 
-    public DefaultModelBuildingResult addModelId( String modelId )
-    {
+    public DefaultModelBuildingResult addModelId(String modelId) {
         // Intentionally notNull because Super POM may not contain a modelId
-        Objects.requireNonNull( modelId, "modelId cannot null" );
+        Objects.requireNonNull(modelId, "modelId cannot null");
 
-        modelIds.add( modelId );
+        modelIds.add(modelId);
 
         return this;
     }
 
     @Override
-    public Model getRawModel()
-    {
-        return rawModels.get( modelIds.get( 0 ) );
+    public Model getRawModel() {
+        return rawModels.get(modelIds.get(0));
     }
 
     @Override
-    public Model getRawModel( String modelId )
-    {
-        return rawModels.get( modelId );
+    public Model getRawModel(String modelId) {
+        return rawModels.get(modelId);
     }
 
-    public DefaultModelBuildingResult setRawModel( String modelId, Model rawModel )
-    {
+    public DefaultModelBuildingResult setRawModel(String modelId, Model rawModel) {
         // Intentionally notNull because Super POM may not contain a modelId
-        Objects.requireNonNull( modelId, "modelId cannot null" );
+        Objects.requireNonNull(modelId, "modelId cannot null");
 
-        rawModels.put( modelId, rawModel );
+        rawModels.put(modelId, rawModel);
 
         return this;
     }
 
     @Override
-    public List<Profile> getActivePomProfiles( String modelId )
-    {
-        return activePomProfiles.get( modelId );
+    public List<Profile> getActivePomProfiles(String modelId) {
+        return activePomProfiles.get(modelId);
     }
 
-    public DefaultModelBuildingResult setActivePomProfiles( String modelId, List<Profile> activeProfiles )
-    {
+    public DefaultModelBuildingResult setActivePomProfiles(String modelId, List<Profile> activeProfiles) {
         // Intentionally notNull because Super POM may not contain a modelId
-        Objects.requireNonNull( modelId, "modelId cannot null" );
+        Objects.requireNonNull(modelId, "modelId cannot null");
 
-        if ( activeProfiles != null )
-        {
-            this.activePomProfiles.put( modelId, new ArrayList<>( activeProfiles ) );
-        }
-        else
-        {
-            this.activePomProfiles.remove( modelId );
+        if (activeProfiles != null) {
+            this.activePomProfiles.put(modelId, new ArrayList<>(activeProfiles));
+        } else {
+            this.activePomProfiles.remove(modelId);
         }
 
         return this;
     }
 
     @Override
-    public List<Profile> getActiveExternalProfiles()
-    {
+    public List<Profile> getActiveExternalProfiles() {
         return activeExternalProfiles;
     }
 
-    public DefaultModelBuildingResult setActiveExternalProfiles( List<Profile> activeProfiles )
-    {
-        if ( activeProfiles != null )
-        {
-            this.activeExternalProfiles = new ArrayList<>( activeProfiles );
-        }
-        else
-        {
+    public DefaultModelBuildingResult setActiveExternalProfiles(List<Profile> activeProfiles) {
+        if (activeProfiles != null) {
+            this.activeExternalProfiles = new ArrayList<>(activeProfiles);
+        } else {
             this.activeExternalProfiles.clear();
         }
 
@@ -183,23 +157,17 @@
     }
 
     @Override
-    public List<ModelProblem> getProblems()
-    {
+    public List<ModelProblem> getProblems() {
         return problems;
     }
 
-    public DefaultModelBuildingResult setProblems( List<ModelProblem> problems )
-    {
-        if ( problems != null )
-        {
-            this.problems = new ArrayList<>( problems );
-        }
-        else
-        {
+    public DefaultModelBuildingResult setProblems(List<ModelProblem> problems) {
+        if (problems != null) {
+            this.problems = new ArrayList<>(problems);
+        } else {
             this.problems.clear();
         }
 
         return this;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblem.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblem.java
index 95c71c5..fd0914d 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblem.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import org.apache.maven.model.Model;
 
@@ -26,11 +25,8 @@
  * or a simple string message. In addition, a problem carries a hint about its source, e.g. the POM file that exhibits
  * the problem.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultModelProblem
-    implements ModelProblem
-{
+public class DefaultModelProblem implements ModelProblem {
 
     private final String source;
 
@@ -48,7 +44,6 @@
 
     private final Version version;
 
-
     /**
      * Creates a new problem with the specified message and exception.
      *
@@ -60,12 +55,24 @@
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      * @param exception The exception that caused this problem, may be {@code null}.
      */
-    //mkleint: does this need to be public?
-    public DefaultModelProblem( String message, Severity severity, Version version, Model source, int lineNumber,
-                                int columnNumber, Exception exception )
-    {
-        this( message, severity, version, ModelProblemUtils.toPath( source ), lineNumber, columnNumber,
-              ModelProblemUtils.toId( source ), exception );
+    // mkleint: does this need to be public?
+    public DefaultModelProblem(
+            String message,
+            Severity severity,
+            Version version,
+            Model source,
+            int lineNumber,
+            int columnNumber,
+            Exception exception) {
+        this(
+                message,
+                severity,
+                version,
+                ModelProblemUtils.toPath(source),
+                lineNumber,
+                columnNumber,
+                ModelProblemUtils.toId(source),
+                exception);
     }
 
     /**
@@ -81,66 +88,62 @@
      * @param modelId The identifier of the model that exhibits the problem, may be {@code null}.
      * @param exception The exception that caused this problem, may be {@code null}.
      */
-    //mkleint: does this need to be public?
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    public DefaultModelProblem( String message, Severity severity, Version version, String source, int lineNumber,
-                                int columnNumber, String modelId, Exception exception )
-    {
+    // mkleint: does this need to be public?
+    @SuppressWarnings("checkstyle:parameternumber")
+    public DefaultModelProblem(
+            String message,
+            Severity severity,
+            Version version,
+            String source,
+            int lineNumber,
+            int columnNumber,
+            String modelId,
+            Exception exception) {
         this.message = message;
-        this.severity = ( severity != null ) ? severity : Severity.ERROR;
-        this.source = ( source != null ) ? source : "";
+        this.severity = (severity != null) ? severity : Severity.ERROR;
+        this.source = (source != null) ? source : "";
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
-        this.modelId = ( modelId != null ) ? modelId : "";
+        this.modelId = (modelId != null) ? modelId : "";
         this.exception = exception;
         this.version = version;
     }
 
     @Override
-    public String getSource()
-    {
+    public String getSource() {
         return source;
     }
 
     @Override
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
 
     @Override
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
 
     @Override
-    public String getModelId()
-    {
+    public String getModelId() {
         return modelId;
     }
 
     @Override
-    public Exception getException()
-    {
+    public Exception getException() {
         return exception;
     }
 
     @Override
-    public String getMessage()
-    {
+    public String getMessage() {
         String msg;
 
-        if ( message != null && message.length() > 0 )
-        {
+        if (message != null && message.length() > 0) {
             msg = message;
-        }
-        else
-        {
+        } else {
             msg = exception.getMessage();
 
-            if ( msg == null )
-            {
+            if (msg == null) {
                 msg = "";
             }
         }
@@ -149,33 +152,27 @@
     }
 
     @Override
-    public Severity getSeverity()
-    {
+    public Severity getSeverity() {
         return severity;
     }
 
     @Override
-    public Version getVersion()
-    {
+    public Version getVersion() {
         return version;
     }
 
-
     @Override
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder( 128 );
+    public String toString() {
+        StringBuilder buffer = new StringBuilder(128);
 
-        buffer.append( '[' ).append( getSeverity() ).append( "] " );
-        buffer.append( getMessage() );
-        String location = ModelProblemUtils.formatLocation( this, null );
-        if ( !location.isEmpty() )
-        {
-            buffer.append( " @ " );
-            buffer.append( location );
+        buffer.append('[').append(getSeverity()).append("] ");
+        buffer.append(getMessage());
+        String location = ModelProblemUtils.formatLocation(this, null);
+        if (!location.isEmpty()) {
+            buffer.append(" @ ");
+            buffer.append(location);
         }
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblemCollector.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblemCollector.java
index c06869a..756719a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblemCollector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProblemCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.EnumSet;
 import java.util.List;
@@ -33,11 +32,8 @@
  * it delegates to other components that potentially encounter problems. Then, the problem reporter can focus on
  * providing a simple error message, leaving the donkey work of creating a nice model problem to this component.
  *
- * @author Benjamin Bentmann
  */
-class DefaultModelProblemCollector
-    implements ModelProblemCollectorExt
-{
+class DefaultModelProblemCollector implements ModelProblemCollectorExt {
 
     private final ModelBuildingResult result;
 
@@ -49,152 +45,133 @@
 
     private Model rootModel;
 
-    private Set<ModelProblem.Severity> severities = EnumSet.noneOf( ModelProblem.Severity.class );
+    private Set<ModelProblem.Severity> severities = EnumSet.noneOf(ModelProblem.Severity.class);
 
-    DefaultModelProblemCollector( ModelBuildingResult result )
-    {
+    DefaultModelProblemCollector(ModelBuildingResult result) {
         this.result = result;
         this.problems = result.getProblems();
 
-        for ( ModelProblem problem : this.problems )
-        {
-            severities.add( problem.getSeverity() );
+        for (ModelProblem problem : this.problems) {
+            severities.add(problem.getSeverity());
         }
     }
 
-    public boolean hasFatalErrors()
-    {
-        return severities.contains( ModelProblem.Severity.FATAL );
+    public boolean hasFatalErrors() {
+        return severities.contains(ModelProblem.Severity.FATAL);
     }
 
-    public boolean hasErrors()
-    {
-        return severities.contains( ModelProblem.Severity.ERROR ) || severities.contains( ModelProblem.Severity.FATAL );
+    public boolean hasErrors() {
+        return severities.contains(ModelProblem.Severity.ERROR) || severities.contains(ModelProblem.Severity.FATAL);
     }
 
     @Override
-    public List<ModelProblem> getProblems()
-    {
+    public List<ModelProblem> getProblems() {
         return problems;
     }
 
-    public void setSource( String source )
-    {
+    public void setSource(String source) {
         this.source = source;
         this.sourceModel = null;
     }
 
-    public void setSource( Model source )
-    {
+    public void setSource(Model source) {
         this.sourceModel = source;
         this.source = null;
 
-        if ( rootModel == null )
-        {
+        if (rootModel == null) {
             rootModel = source;
         }
     }
 
-    private String getSource()
-    {
-        if ( source == null && sourceModel != null )
-        {
-            source = ModelProblemUtils.toPath( sourceModel );
+    private String getSource() {
+        if (source == null && sourceModel != null) {
+            source = ModelProblemUtils.toPath(sourceModel);
         }
         return source;
     }
 
-    private String getModelId()
-    {
-        return ModelProblemUtils.toId( sourceModel );
+    private String getModelId() {
+        return ModelProblemUtils.toId(sourceModel);
     }
 
-    public void setRootModel( Model rootModel )
-    {
+    public void setRootModel(Model rootModel) {
         this.rootModel = rootModel;
     }
 
-    public Model getRootModel()
-    {
+    public Model getRootModel() {
         return rootModel;
     }
 
-    public String getRootModelId()
-    {
-        return ModelProblemUtils.toId( rootModel );
+    public String getRootModelId() {
+        return ModelProblemUtils.toId(rootModel);
     }
 
-    public void add( ModelProblem problem )
-    {
-        problems.add( problem );
+    public void add(ModelProblem problem) {
+        problems.add(problem);
 
-        severities.add( problem.getSeverity() );
+        severities.add(problem.getSeverity());
     }
 
-    public void addAll( List<ModelProblem> problems )
-    {
-        this.problems.addAll( problems );
+    public void addAll(List<ModelProblem> problems) {
+        this.problems.addAll(problems);
 
-        for ( ModelProblem problem : problems )
-        {
-            severities.add( problem.getSeverity() );
+        for (ModelProblem problem : problems) {
+            severities.add(problem.getSeverity());
         }
     }
 
     @Override
-    public void add( ModelProblemCollectorRequest req )
-    {
+    public void add(ModelProblemCollectorRequest req) {
         int line = -1;
         int column = -1;
         String source = null;
         String modelId = null;
 
-        if ( req.getLocation() != null )
-        {
+        if (req.getLocation() != null) {
             line = req.getLocation().getLineNumber();
             column = req.getLocation().getColumnNumber();
-            if ( req.getLocation().getSource() != null )
-            {
+            if (req.getLocation().getSource() != null) {
                 modelId = req.getLocation().getSource().getModelId();
                 source = req.getLocation().getSource().getLocation();
             }
         }
 
-        if ( modelId == null )
-        {
+        if (modelId == null) {
             modelId = getModelId();
             source = getSource();
         }
 
-        if ( line <= 0 && column <= 0 && req.getException() instanceof ModelParseException )
-        {
+        if (line <= 0 && column <= 0 && req.getException() instanceof ModelParseException) {
             ModelParseException e = (ModelParseException) req.getException();
             line = e.getLineNumber();
             column = e.getColumnNumber();
         }
 
-        ModelProblem problem =
-            new DefaultModelProblem( req.getMessage(), req.getSeverity(), req.getVersion(), source, line, column,
-                                     modelId, req.getException() );
+        ModelProblem problem = new DefaultModelProblem(
+                req.getMessage(),
+                req.getSeverity(),
+                req.getVersion(),
+                source,
+                line,
+                column,
+                modelId,
+                req.getException());
 
-        add( problem );
+        add(problem);
     }
 
-    public ModelBuildingException newModelBuildingException()
-    {
+    public ModelBuildingException newModelBuildingException() {
         ModelBuildingResult result = this.result;
-        if ( result.getModelIds().isEmpty() )
-        {
+        if (result.getModelIds().isEmpty()) {
             DefaultModelBuildingResult tmp = new DefaultModelBuildingResult();
-            tmp.setEffectiveModel( result.getEffectiveModel() );
-            tmp.setProblems( getProblems() );
-            tmp.setActiveExternalProfiles( result.getActiveExternalProfiles() );
+            tmp.setEffectiveModel(result.getEffectiveModel());
+            tmp.setProblems(getProblems());
+            tmp.setActiveExternalProfiles(result.getActiveExternalProfiles());
             String id = getRootModelId();
-            tmp.addModelId( id );
-            tmp.setRawModel( id, getRootModel() );
+            tmp.addModelId(id);
+            tmp.setRawModel(id, getRootModel());
             result = tmp;
         }
-        return new ModelBuildingException( result );
+        return new ModelBuildingException(result);
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java
index 168612d..b3c459c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.util.Map;
+package org.apache.maven.model.building;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.maven.model.Model;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.spi.ModelParser;
+import org.apache.maven.api.spi.ModelParserException;
+import org.apache.maven.building.Source;
+import org.apache.maven.model.io.ModelParseException;
 import org.apache.maven.model.io.ModelReader;
 import org.apache.maven.model.locator.ModelLocator;
 import org.eclipse.sisu.Typed;
@@ -59,48 +68,133 @@
  * of the same interface. Since we want to allow overriding this doesn't matter in this case.
  * (if it did we could add @Priority of 0 to match the priority given to default components.)
  */
-@Named( "core-default" )
+@Named("core-default")
 @Singleton
-@Typed( ModelProcessor.class )
-public class DefaultModelProcessor
-    implements ModelProcessor
-{
+@Typed(ModelProcessor.class)
+public class DefaultModelProcessor implements ModelProcessor {
 
-    private final ModelLocator locator;
-    private final ModelReader reader;
+    private final Collection<ModelParser> modelParsers;
+    private final ModelLocator modelLocator;
+    private final ModelReader modelReader;
 
     @Inject
-    public DefaultModelProcessor( ModelLocator locator, ModelReader reader )
-    {
-        this.locator = locator;
-        this.reader = reader;
+    public DefaultModelProcessor(
+            Collection<ModelParser> modelParsers, ModelLocator modelLocator, ModelReader modelReader) {
+        this.modelParsers = modelParsers;
+        this.modelLocator = modelLocator;
+        this.modelReader = modelReader;
     }
 
     @Override
-    public File locatePom( File projectDirectory )
-    {
-        return locator.locatePom( projectDirectory );
+    public File locatePom(File projectDirectory) {
+        return locatePom(projectDirectory.toPath()).toFile();
+    }
+
+    public Path locatePom(Path projectDirectory) {
+        // Note that the ModelProcessor#locatePom never returns null
+        // while the ModelParser#locatePom needs to return an existing path!
+        Path pom = modelParsers.stream()
+                .map(m -> m.locate(projectDirectory)
+                        .map(org.apache.maven.api.services.Source::getPath)
+                        .orElse(null))
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElseGet(
+                        () -> modelLocator.locatePom(projectDirectory.toFile()).toPath());
+        if (!pom.equals(projectDirectory) && !pom.getParent().equals(projectDirectory)) {
+            throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
+        }
+        return pom;
+    }
+
+    public File locateExistingPom(File projectDirectory) {
+        Path path = locateExistingPom(projectDirectory.toPath());
+        return path != null ? path.toFile() : null;
+    }
+
+    public Path locateExistingPom(Path projectDirectory) {
+        // Note that the ModelProcessor#locatePom never returns null
+        // while the ModelParser#locatePom needs to return an existing path!
+        Path pom = modelParsers.stream()
+                .map(m -> m.locate(projectDirectory).map(s -> s.getPath()).orElse(null))
+                .filter(Objects::nonNull)
+                .findFirst()
+                .orElseGet(() -> {
+                    File f = modelLocator.locateExistingPom(projectDirectory.toFile());
+                    return f != null ? f.toPath() : null;
+                });
+        if (pom != null && !pom.equals(projectDirectory) && !pom.getParent().equals(projectDirectory)) {
+            throw new IllegalArgumentException("The POM found does not belong to the given directory: " + pom);
+        }
+        return pom;
+    }
+
+    protected org.apache.maven.api.model.Model read(
+            Path pomFile, InputStream input, Reader reader, Map<String, ?> options) throws IOException {
+        Source source = (Source) options.get(ModelProcessor.SOURCE);
+        if (pomFile == null && source instanceof org.apache.maven.building.FileSource) {
+            pomFile = ((org.apache.maven.building.FileSource) source).getFile().toPath();
+        }
+        if (pomFile != null) {
+            Path projectDirectory = pomFile.getParent();
+            List<ModelParserException> exceptions = new ArrayList<>();
+            for (ModelParser parser : modelParsers) {
+                try {
+                    Optional<Model> model = parser.locateAndParse(projectDirectory, options);
+                    if (model.isPresent()) {
+                        return model.get().withPomFile(pomFile);
+                    }
+                } catch (ModelParserException e) {
+                    exceptions.add(e);
+                }
+            }
+            try {
+                return readXmlModel(pomFile, null, null, options);
+            } catch (IOException e) {
+                exceptions.forEach(e::addSuppressed);
+                throw e;
+            }
+        } else {
+            return readXmlModel(pomFile, input, reader, options);
+        }
+    }
+
+    private org.apache.maven.api.model.Model readXmlModel(
+            Path pomFile, InputStream input, Reader reader, Map<String, ?> options) throws IOException {
+        if (pomFile != null) {
+            return modelReader.read(pomFile.toFile(), options).getDelegate();
+        } else if (input != null) {
+            return modelReader.read(input, options).getDelegate();
+        } else {
+            return modelReader.read(reader, options).getDelegate();
+        }
     }
 
     @Override
-    public Model read( File input, Map<String, ?> options )
-        throws IOException
-    {
-        return reader.read( input, options );
+    public org.apache.maven.model.Model read(File file, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(file, "file cannot be null");
+        Path path = file.toPath();
+        org.apache.maven.api.model.Model model = read(path, null, null, options);
+        return new org.apache.maven.model.Model(model);
     }
 
     @Override
-    public Model read( Reader input, Map<String, ?> options )
-        throws IOException
-    {
-        return reader.read( input, options );
+    public org.apache.maven.model.Model read(InputStream input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
+        try (InputStream in = input) {
+            org.apache.maven.api.model.Model model = read(null, in, null, options);
+            return new org.apache.maven.model.Model(model);
+        } catch (ModelParserException e) {
+            throw new ModelParseException("Unable to read model: " + e, e.getLineNumber(), e.getColumnNumber(), e);
+        }
     }
 
     @Override
-    public Model read( InputStream input, Map<String, ?> options )
-        throws IOException
-    {
-        return reader.read( input, options );
+    public org.apache.maven.model.Model read(Reader reader, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(reader, "reader cannot be null");
+        try (Reader r = reader) {
+            org.apache.maven.api.model.Model model = read(null, null, r, options);
+            return new org.apache.maven.model.Model(model);
+        }
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelSourceTransformer.java
deleted file mode 100644
index e6e4073..0000000
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultModelSourceTransformer.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.apache.maven.model.building;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.nio.file.Path;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * Default ModelSourceTransformer, provides pomFile as inputStream and ignores the context
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class DefaultModelSourceTransformer implements ModelSourceTransformer
-{
-
-    @Override
-    public XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
-            throws IOException, TransformerException
-    {
-        return parser;
-    }
-
-}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java
index 3c70b3c..4622784 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContext.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,7 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
+import java.io.File;
 import java.nio.file.Path;
 import java.util.Map;
 import java.util.Objects;
@@ -26,48 +26,43 @@
 import java.util.function.Supplier;
 
 import org.apache.maven.model.Model;
+import org.apache.maven.model.locator.ModelLocator;
 
 /**
  *
- * @author Robert Scholte
  * @since 4.0.0
  */
-class DefaultTransformerContext implements TransformerContext
-{
+class DefaultTransformerContext implements TransformerContext {
+    final ModelLocator modelLocator;
+
     final Map<String, String> userProperties = new ConcurrentHashMap<>();
 
     final Map<Path, Holder> modelByPath = new ConcurrentHashMap<>();
 
     final Map<GAKey, Holder> modelByGA = new ConcurrentHashMap<>();
 
-    public static class Holder
-    {
+    public static class Holder {
         private volatile boolean set;
         private volatile Model model;
 
-        Holder()
-        {
+        Holder() {}
+
+        Holder(Model model) {
+            this.model = Objects.requireNonNull(model);
+            this.set = true;
         }
 
-        public static Model deref( Holder holder )
-        {
+        public static Model deref(Holder holder) {
             return holder != null ? holder.get() : null;
         }
 
-        public Model get()
-        {
-            if ( !set )
-            {
-                synchronized ( this )
-                {
-                    if ( !set )
-                    {
-                        try
-                        {
+        public Model get() {
+            if (!set) {
+                synchronized (this) {
+                    if (!set) {
+                        try {
                             this.wait();
-                        }
-                        catch ( InterruptedException e )
-                        {
+                        } catch (InterruptedException e) {
                             // Ignore
                         }
                     }
@@ -76,14 +71,10 @@
             return model;
         }
 
-        public Model computeIfAbsent( Supplier<Model> supplier )
-        {
-            if ( !set )
-            {
-                synchronized ( this )
-                {
-                    if ( !set )
-                    {
+        public Model computeIfAbsent(Supplier<Model> supplier) {
+            if (!set) {
+                synchronized (this) {
+                    if (!set) {
                         this.set = true;
                         this.model = supplier.get();
                         this.notifyAll();
@@ -92,60 +83,60 @@
             }
             return model;
         }
+    }
 
+    DefaultTransformerContext(ModelLocator modelLocator) {
+        this.modelLocator = modelLocator;
     }
 
     @Override
-    public String getUserProperty( String key )
-    {
-        return userProperties.get( key );
+    public String getUserProperty(String key) {
+        return userProperties.get(key);
     }
 
     @Override
-    public Model getRawModel( Path p )
-    {
-        return Holder.deref( modelByPath.get( p ) );
+    public Model getRawModel(Path from, Path p) {
+        return Holder.deref(modelByPath.get(p));
     }
 
     @Override
-    public Model getRawModel( String groupId, String artifactId )
-    {
-        return Holder.deref( modelByGA.get( new GAKey( groupId, artifactId ) ) );
+    public Model getRawModel(Path from, String groupId, String artifactId) {
+        return Holder.deref(modelByGA.get(new GAKey(groupId, artifactId)));
     }
 
-    static class GAKey
-    {
+    @Override
+    public Path locate(Path path) {
+        File file = modelLocator.locateExistingPom(path.toFile());
+        return file != null ? file.toPath() : null;
+    }
+
+    static class GAKey {
         private final String groupId;
         private final String artifactId;
         private final int hashCode;
 
-        GAKey( String groupId, String artifactId )
-        {
+        GAKey(String groupId, String artifactId) {
             this.groupId = groupId;
             this.artifactId = artifactId;
-            this.hashCode = Objects.hash( groupId, artifactId );
+            this.hashCode = Objects.hash(groupId, artifactId);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
 
         @Override
-        public boolean equals( Object obj )
-        {
-            if ( this == obj )
-            {
+        public boolean equals(Object obj) {
+            if (this == obj) {
                 return true;
             }
-            if ( !( obj instanceof GAKey ) )
-            {
+            if (!(obj instanceof GAKey)) {
                 return false;
             }
 
             GAKey other = (GAKey) obj;
-            return Objects.equals( artifactId, other.artifactId ) && Objects.equals( groupId, other.groupId );
+            return Objects.equals(artifactId, other.artifactId) && Objects.equals(groupId, other.groupId);
         }
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContextBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContextBuilder.java
new file mode 100644
index 0000000..f86f1aa
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/DefaultTransformerContextBuilder.java
@@ -0,0 +1,226 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.building;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.DefaultTransformerContext.GAKey;
+import org.apache.maven.model.building.DefaultTransformerContext.Holder;
+
+/**
+ * Builds up the transformer context.
+ * After the buildplan is ready, the build()-method returns the immutable context useful during distribution.
+ * This is an inner class, as it must be able to call readRawModel()
+ *
+ * @since 4.0.0
+ */
+class DefaultTransformerContextBuilder implements TransformerContextBuilder {
+    private final Graph dag = new Graph();
+    private final DefaultModelBuilder defaultModelBuilder;
+    private final DefaultTransformerContext context;
+
+    private final Map<String, Set<FileModelSource>> mappedSources = new ConcurrentHashMap<>(64);
+
+    DefaultTransformerContextBuilder(DefaultModelBuilder defaultModelBuilder) {
+        this.defaultModelBuilder = defaultModelBuilder;
+        this.context = new DefaultTransformerContext(defaultModelBuilder.getModelProcessor());
+    }
+
+    /**
+     * If an interface could be extracted, DefaultModelProblemCollector should be ModelProblemCollectorExt
+     */
+    @Override
+    public TransformerContext initialize(ModelBuildingRequest request, ModelProblemCollector collector) {
+        // We must assume the TransformerContext was created using this.newTransformerContextBuilder()
+        DefaultModelProblemCollector problems = (DefaultModelProblemCollector) collector;
+        return new TransformerContext() {
+
+            private volatile boolean fullReactorLoaded;
+
+            @Override
+            public Path locate(Path path) {
+                return context.locate(path);
+            }
+
+            @Override
+            public String getUserProperty(String key) {
+                return context.userProperties.computeIfAbsent(
+                        key, k -> request.getUserProperties().getProperty(key));
+            }
+
+            @Override
+            public Model getRawModel(Path from, String gId, String aId) {
+                Model model = findRawModel(from, gId, aId);
+                if (model != null) {
+                    context.modelByGA.put(new GAKey(gId, aId), new Holder(model));
+                    context.modelByPath.put(model.getPomFile().toPath(), new Holder(model));
+                }
+                return model;
+            }
+
+            @Override
+            public Model getRawModel(Path from, Path path) {
+                Model model = findRawModel(from, path);
+                if (model != null) {
+                    String groupId = defaultModelBuilder.getGroupId(model);
+                    context.modelByGA.put(
+                            new DefaultTransformerContext.GAKey(groupId, model.getArtifactId()), new Holder(model));
+                    context.modelByPath.put(path, new Holder(model));
+                }
+                return model;
+            }
+
+            private Model findRawModel(Path from, String groupId, String artifactId) {
+                FileModelSource source = getSource(groupId, artifactId);
+                if (source == null) {
+                    // we need to check the whole reactor in case it's a dependency
+                    loadFullReactor();
+                    source = getSource(groupId, artifactId);
+                }
+                if (source != null) {
+                    if (!addEdge(from, source.getFile().toPath(), problems)) {
+                        return null;
+                    }
+                    try {
+                        ModelBuildingRequest gaBuildingRequest =
+                                new DefaultModelBuildingRequest(request).setModelSource(source);
+                        return defaultModelBuilder.readRawModel(gaBuildingRequest, problems);
+                    } catch (ModelBuildingException e) {
+                        // gathered with problem collector
+                    }
+                }
+                return null;
+            }
+
+            private void loadFullReactor() {
+                if (!fullReactorLoaded) {
+                    synchronized (this) {
+                        if (!fullReactorLoaded) {
+                            doLoadFullReactor();
+                            fullReactorLoaded = true;
+                        }
+                    }
+                }
+            }
+
+            private void doLoadFullReactor() {
+                Path rootDirectory = request.getRootDirectory();
+                if (rootDirectory == null) {
+                    return;
+                }
+                List<File> toLoad = new ArrayList<>();
+                File root = defaultModelBuilder.getModelProcessor().locateExistingPom(rootDirectory.toFile());
+                toLoad.add(root);
+                while (!toLoad.isEmpty()) {
+                    File pom = toLoad.remove(0);
+                    try {
+                        ModelBuildingRequest gaBuildingRequest =
+                                new DefaultModelBuildingRequest(request).setModelSource(new FileModelSource(pom));
+                        Model rawModel = defaultModelBuilder.readFileModel(gaBuildingRequest, problems);
+                        for (String module : rawModel.getModules()) {
+                            File moduleFile = defaultModelBuilder
+                                    .getModelProcessor()
+                                    .locateExistingPom(new File(pom.getParent(), module));
+                            if (moduleFile != null) {
+                                toLoad.add(moduleFile);
+                            }
+                        }
+                    } catch (ModelBuildingException e) {
+                        // gathered with problem collector
+                    }
+                }
+            }
+
+            private Model findRawModel(Path from, Path p) {
+                if (!Files.isRegularFile(p)) {
+                    throw new IllegalArgumentException("Not a regular file: " + p);
+                }
+
+                if (!addEdge(from, p, problems)) {
+                    return null;
+                }
+
+                DefaultModelBuildingRequest req = new DefaultModelBuildingRequest(request)
+                        .setPomFile(p.toFile())
+                        .setModelSource(new FileModelSource(p.toFile()));
+
+                try {
+                    return defaultModelBuilder.readRawModel(req, problems);
+                } catch (ModelBuildingException e) {
+                    // gathered with problem collector
+                }
+                return null;
+            }
+        };
+    }
+
+    private boolean addEdge(Path from, Path p, DefaultModelProblemCollector problems) {
+        try {
+            synchronized (dag) {
+                dag.addEdge(dag.addVertex(from.toString()), dag.addVertex(p.toString()));
+            }
+            return true;
+        } catch (Graph.CycleDetectedException e) {
+            problems.add(new DefaultModelProblem(
+                    "Cycle detected between models at " + from + " and " + p,
+                    ModelProblem.Severity.FATAL,
+                    null,
+                    null,
+                    0,
+                    0,
+                    null,
+                    e));
+            return false;
+        }
+    }
+
+    @Override
+    public TransformerContext build() {
+        return context;
+    }
+
+    public FileModelSource getSource(String groupId, String artifactId) {
+        Set<FileModelSource> sources = mappedSources.get(groupId + ":" + artifactId);
+        if (sources == null) {
+            return null;
+        }
+        return sources.stream()
+                .reduce((a, b) -> {
+                    throw new IllegalStateException(String.format(
+                            "No unique Source for %s:%s: %s and %s",
+                            groupId, artifactId, a.getLocation(), b.getLocation()));
+                })
+                .orElse(null);
+    }
+
+    public void putSource(String groupId, String artifactId, FileModelSource source) {
+        mappedSources
+                .computeIfAbsent(groupId + ":" + artifactId, k -> new HashSet<>())
+                .add(source);
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java
index 215de36..5bbf0eb 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileModelSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,28 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
 import java.net.URI;
 
 import org.apache.maven.building.FileSource;
+import org.apache.maven.model.locator.ModelLocator;
 
 /**
  * Wraps an ordinary {@link File} as a model source.
  *
- * @author Benjamin Bentmann
  */
-public class FileModelSource extends FileSource implements ModelSource2
-{
+public class FileModelSource extends FileSource implements ModelSource3 {
 
     /**
      * Creates a new model source backed by the specified file.
      *
      * @param pomFile The POM file, must not be {@code null}.
      */
-    public FileModelSource( File pomFile )
-    {
-        super( pomFile );
+    public FileModelSource(File pomFile) {
+        super(pomFile);
     }
 
     /**
@@ -49,63 +46,49 @@
      * @deprecated instead use {@link #getFile()}
      */
     @Deprecated
-    public File getPomFile()
-    {
+    public File getPomFile() {
         return getFile();
     }
 
     @Override
-    public ModelSource2 getRelatedSource( String relPath )
-    {
-        relPath = relPath.replace( '\\', File.separatorChar ).replace( '/', File.separatorChar );
+    public ModelSource3 getRelatedSource(ModelLocator locator, String relPath) {
+        relPath = relPath.replace('\\', File.separatorChar).replace('/', File.separatorChar);
 
-        File relatedPom = new File( getFile().getParentFile(), relPath );
+        File path = new File(getFile().getParentFile(), relPath);
 
-        if ( relatedPom.isDirectory() )
-        {
-            // TODO figure out how to reuse ModelLocator.locatePom(File) here
-            relatedPom = new File( relatedPom, "pom.xml" );
-        }
+        File relatedPom = locator.locateExistingPom(path);
 
-        if ( relatedPom.isFile() && relatedPom.canRead() )
-        {
-            return new FileModelSource( new File( relatedPom.toURI().normalize() ) );
+        if (relatedPom != null) {
+            return new FileModelSource(relatedPom.toPath().normalize().toFile());
         }
 
         return null;
     }
 
     @Override
-    public URI getLocationURI()
-    {
+    public URI getLocationURI() {
         return getFile().toURI();
     }
 
     @Override
-    public boolean equals( Object obj )
-    {
-        if ( this == obj )
-        {
+    public boolean equals(Object obj) {
+        if (this == obj) {
             return true;
         }
 
-        if ( obj == null )
-        {
+        if (obj == null) {
             return false;
         }
 
-        if ( !FileModelSource.class.equals( obj.getClass() )  )
-        {
+        if (!FileModelSource.class.equals(obj.getClass())) {
             return false;
         }
-        FileModelSource other = ( FileModelSource ) obj;
-        return getFile().equals( other.getFile() );
+        FileModelSource other = (FileModelSource) obj;
+        return getFile().equals(other.getFile());
     }
 
     @Override
-    public int hashCode()
-    {
+    public int hashCode() {
         return getFile().hashCode();
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileToRawModelMerger.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileToRawModelMerger.java
index 47af900..e35e6b8 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/FileToRawModelMerger.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FileToRawModelMerger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,173 +16,201 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.Iterator;
 import java.util.Map;
+import java.util.stream.Collectors;
 
-import org.apache.maven.model.Build;
-import org.apache.maven.model.BuildBase;
-import org.apache.maven.model.CiManagement;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.ModelBase;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.Profile;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.Reporting;
-import org.apache.maven.model.merge.ModelMerger;
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.BuildBase;
+import org.apache.maven.api.model.CiManagement;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.ModelBase;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginContainer;
+import org.apache.maven.api.model.Profile;
+import org.apache.maven.api.model.ReportPlugin;
+import org.apache.maven.api.model.Reporting;
+import org.apache.maven.model.v4.MavenMerger;
 
 /**
  * As long as Maven controls the BuildPomXMLFilter, the entities that need merging are known.
  * All others can simply be copied from source to target to restore the locationTracker
  *
- * @author Robert Scholte
  * @since 4.0.0
  */
-class FileToRawModelMerger extends ModelMerger
-{
+class FileToRawModelMerger extends MavenMerger {
 
     @Override
-    protected void mergeBuild_Extensions( Build target, Build source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        // don't merge
-    }
-
-
-    @Override
-    protected void mergeBuildBase_Resources( BuildBase target, BuildBase source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
+    protected void mergeBuild_Extensions(
+            Build.Builder builder, Build target, Build source, boolean sourceDominant, Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeBuildBase_TestResources( BuildBase target, BuildBase source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
+    protected void mergeBuildBase_Resources(
+            BuildBase.Builder builder,
+            BuildBase target,
+            BuildBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeCiManagement_Notifiers( CiManagement target, CiManagement source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
+    protected void mergeBuildBase_TestResources(
+            BuildBase.Builder builder,
+            BuildBase target,
+            BuildBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeDependencyManagement_Dependencies( DependencyManagement target, DependencyManagement source,
-                                                           boolean sourceDominant, Map<Object, Object> context )
-    {
+    protected void mergeCiManagement_Notifiers(
+            CiManagement.Builder builder,
+            CiManagement target,
+            CiManagement source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
+        // don't merge
+    }
+
+    @Override
+    protected void mergeDependencyManagement_Dependencies(
+            DependencyManagement.Builder builder,
+            DependencyManagement target,
+            DependencyManagement source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
-        target.getDependencies().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
-                                                                         context ) );
+        builder.dependencies(target.getDependencies().stream()
+                .map(d -> mergeDependency(d, sourceIterator.next(), sourceDominant, context))
+                .collect(Collectors.toList()));
     }
 
     @Override
-    protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
+    protected void mergeDependency_Exclusions(
+            Dependency.Builder builder,
+            Dependency target,
+            Dependency source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeModel_Contributors( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
+    protected void mergeModel_Contributors(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeModel_Developers( Model target, Model source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
+    protected void mergeModel_Developers(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeModel_Licenses( Model target, Model source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
+    protected void mergeModel_Licenses(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeModel_MailingLists( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
+    protected void mergeModel_MailingLists(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeModel_Profiles( Model target, Model source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
+    protected void mergeModel_Profiles(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         Iterator<Profile> sourceIterator = source.getProfiles().iterator();
-        target.getProfiles().forEach( t -> mergeProfile( t, sourceIterator.next(), sourceDominant,
-                                                                  context ) );
+        builder.profiles(target.getProfiles().stream()
+                .map(d -> mergeProfile(d, sourceIterator.next(), sourceDominant, context))
+                .collect(Collectors.toList()));
     }
 
     @Override
-    protected void mergeModelBase_Dependencies( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
+    protected void mergeModelBase_Dependencies(
+            ModelBase.Builder builder,
+            ModelBase target,
+            ModelBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
-        target.getDependencies().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
-                                                                         context ) );
+        builder.dependencies(target.getDependencies().stream()
+                .map(d -> mergeDependency(d, sourceIterator.next(), sourceDominant, context))
+                .collect(Collectors.toList()));
     }
 
     @Override
-    protected void mergeModelBase_PluginRepositories( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                      Map<Object, Object> context )
-    {
-        target.setPluginRepositories( source.getPluginRepositories() );
+    protected void mergeModelBase_PluginRepositories(
+            ModelBase.Builder builder,
+            ModelBase target,
+            ModelBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
+        builder.pluginRepositories(source.getPluginRepositories());
     }
 
     @Override
-    protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
+    protected void mergeModelBase_Repositories(
+            ModelBase.Builder builder,
+            ModelBase target,
+            ModelBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergePlugin_Dependencies( Plugin target, Plugin source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
+    protected void mergePlugin_Dependencies(
+            Plugin.Builder builder, Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
         Iterator<Dependency> sourceIterator = source.getDependencies().iterator();
-        target.getDependencies().forEach( t -> mergeDependency( t, sourceIterator.next(), sourceDominant,
-                                                                         context ) );
+        builder.dependencies(target.getDependencies().stream()
+                .map(d -> mergeDependency(d, sourceIterator.next(), sourceDominant, context))
+                .collect(Collectors.toList()));
     }
 
     @Override
-    protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
+    protected void mergePlugin_Executions(
+            Plugin.Builder builder, Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
+    protected void mergeReporting_Plugins(
+            Reporting.Builder builder,
+            Reporting target,
+            Reporting source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
+    protected void mergeReportPlugin_ReportSets(
+            ReportPlugin.Builder builder,
+            ReportPlugin target,
+            ReportPlugin source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         // don't merge
     }
 
     @Override
-    protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
-                                                 boolean sourceDominant, Map<Object, Object> context )
-    {
+    protected void mergePluginContainer_Plugins(
+            PluginContainer.Builder builder,
+            PluginContainer target,
+            PluginContainer source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         // don't merge
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java
index d12a89a..2f6acac 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/FilterModelBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.Date;
 import java.util.List;
 import java.util.Properties;
@@ -33,278 +33,247 @@
  * A model building request that delegates all methods invocations to another request, meant for easy transformations by
  * subclassing.
  *
- * @author Benjamin Bentmann
  */
-class FilterModelBuildingRequest
-    implements ModelBuildingRequest
-{
+class FilterModelBuildingRequest implements ModelBuildingRequest {
 
     protected ModelBuildingRequest request;
 
-    FilterModelBuildingRequest( ModelBuildingRequest request )
-    {
+    FilterModelBuildingRequest(ModelBuildingRequest request) {
         this.request = request;
     }
 
     @Override
-    public File getPomFile()
-    {
+    public File getPomFile() {
         return request.getPomFile();
     }
 
     @Override
-    public FilterModelBuildingRequest setPomFile( File pomFile )
-    {
-        request.setPomFile( pomFile );
+    public FilterModelBuildingRequest setPomFile(File pomFile) {
+        request.setPomFile(pomFile);
 
         return this;
     }
 
     @Override
-    public ModelSource getModelSource()
-    {
+    public ModelSource getModelSource() {
         return request.getModelSource();
     }
 
     @Override
-    public FilterModelBuildingRequest setModelSource( ModelSource modelSource )
-    {
-        request.setModelSource( modelSource );
+    public FilterModelBuildingRequest setModelSource(ModelSource modelSource) {
+        request.setModelSource(modelSource);
 
         return this;
     }
 
     @Override
-    public int getValidationLevel()
-    {
+    public int getValidationLevel() {
         return request.getValidationLevel();
     }
 
     @Override
-    public FilterModelBuildingRequest setValidationLevel( int validationLevel )
-    {
-        request.setValidationLevel( validationLevel );
+    public FilterModelBuildingRequest setValidationLevel(int validationLevel) {
+        request.setValidationLevel(validationLevel);
 
         return this;
     }
 
     @Override
-    public boolean isProcessPlugins()
-    {
+    public boolean isProcessPlugins() {
         return request.isProcessPlugins();
     }
 
     @Override
-    public FilterModelBuildingRequest setProcessPlugins( boolean processPlugins )
-    {
-        request.setProcessPlugins( processPlugins );
+    public FilterModelBuildingRequest setProcessPlugins(boolean processPlugins) {
+        request.setProcessPlugins(processPlugins);
 
         return this;
     }
 
     @Override
-    public boolean isTwoPhaseBuilding()
-    {
+    public boolean isTwoPhaseBuilding() {
         return request.isTwoPhaseBuilding();
     }
 
     @Override
-    public FilterModelBuildingRequest setTwoPhaseBuilding( boolean twoPhaseBuilding )
-    {
-        request.setTwoPhaseBuilding( twoPhaseBuilding );
+    public FilterModelBuildingRequest setTwoPhaseBuilding(boolean twoPhaseBuilding) {
+        request.setTwoPhaseBuilding(twoPhaseBuilding);
 
         return this;
     }
 
     @Override
-    public boolean isLocationTracking()
-    {
+    public boolean isLocationTracking() {
         return request.isLocationTracking();
     }
 
     @Override
-    public FilterModelBuildingRequest setLocationTracking( boolean locationTracking )
-    {
-        request.setLocationTracking( locationTracking );
+    public FilterModelBuildingRequest setLocationTracking(boolean locationTracking) {
+        request.setLocationTracking(locationTracking);
 
         return this;
     }
 
     @Override
-    public List<Profile> getProfiles()
-    {
+    public List<Profile> getProfiles() {
         return request.getProfiles();
     }
 
     @Override
-    public FilterModelBuildingRequest setProfiles( List<Profile> profiles )
-    {
-        request.setProfiles( profiles );
+    public FilterModelBuildingRequest setProfiles(List<Profile> profiles) {
+        request.setProfiles(profiles);
 
         return this;
     }
 
     @Override
-    public List<String> getActiveProfileIds()
-    {
+    public List<String> getActiveProfileIds() {
         return request.getActiveProfileIds();
     }
 
     @Override
-    public FilterModelBuildingRequest setActiveProfileIds( List<String> activeProfileIds )
-    {
-        request.setActiveProfileIds( activeProfileIds );
+    public FilterModelBuildingRequest setActiveProfileIds(List<String> activeProfileIds) {
+        request.setActiveProfileIds(activeProfileIds);
 
         return this;
     }
 
     @Override
-    public List<String> getInactiveProfileIds()
-    {
+    public List<String> getInactiveProfileIds() {
         return request.getInactiveProfileIds();
     }
 
     @Override
-    public FilterModelBuildingRequest setInactiveProfileIds( List<String> inactiveProfileIds )
-    {
-        request.setInactiveProfileIds( inactiveProfileIds );
+    public FilterModelBuildingRequest setInactiveProfileIds(List<String> inactiveProfileIds) {
+        request.setInactiveProfileIds(inactiveProfileIds);
 
         return this;
     }
 
     @Override
-    public Properties getSystemProperties()
-    {
+    public Properties getSystemProperties() {
         return request.getSystemProperties();
     }
 
     @Override
-    public FilterModelBuildingRequest setSystemProperties( Properties systemProperties )
-    {
-        request.setSystemProperties( systemProperties );
+    public FilterModelBuildingRequest setSystemProperties(Properties systemProperties) {
+        request.setSystemProperties(systemProperties);
 
         return this;
     }
 
     @Override
-    public Properties getUserProperties()
-    {
+    public Properties getUserProperties() {
         return request.getUserProperties();
     }
 
     @Override
-    public FilterModelBuildingRequest setUserProperties( Properties userProperties )
-    {
-        request.setUserProperties( userProperties );
+    public FilterModelBuildingRequest setUserProperties(Properties userProperties) {
+        request.setUserProperties(userProperties);
 
         return this;
     }
 
     @Override
-    public Date getBuildStartTime()
-    {
+    public Date getBuildStartTime() {
         return request.getBuildStartTime();
     }
 
     @Override
-    public ModelBuildingRequest setBuildStartTime( Date buildStartTime )
-    {
-        request.setBuildStartTime( buildStartTime );
+    public ModelBuildingRequest setBuildStartTime(Date buildStartTime) {
+        request.setBuildStartTime(buildStartTime);
 
         return this;
     }
 
     @Override
-    public ModelResolver getModelResolver()
-    {
+    public ModelResolver getModelResolver() {
         return request.getModelResolver();
     }
 
     @Override
-    public FilterModelBuildingRequest setModelResolver( ModelResolver modelResolver )
-    {
-        request.setModelResolver( modelResolver );
+    public FilterModelBuildingRequest setModelResolver(ModelResolver modelResolver) {
+        request.setModelResolver(modelResolver);
 
         return this;
     }
 
     @Override
-    public ModelBuildingListener getModelBuildingListener()
-    {
+    public ModelBuildingListener getModelBuildingListener() {
         return request.getModelBuildingListener();
     }
 
     @Override
-    public ModelBuildingRequest setModelBuildingListener( ModelBuildingListener modelBuildingListener )
-    {
-        request.setModelBuildingListener( modelBuildingListener );
+    public ModelBuildingRequest setModelBuildingListener(ModelBuildingListener modelBuildingListener) {
+        request.setModelBuildingListener(modelBuildingListener);
 
         return this;
     }
 
     @Override
-    public ModelCache getModelCache()
-    {
+    public ModelCache getModelCache() {
         return request.getModelCache();
     }
 
     @Override
-    public FilterModelBuildingRequest setModelCache( ModelCache modelCache )
-    {
-        request.setModelCache( modelCache );
+    public FilterModelBuildingRequest setModelCache(ModelCache modelCache) {
+        request.setModelCache(modelCache);
 
         return this;
     }
 
     @Override
-    public Model getFileModel()
-    {
+    public Model getFileModel() {
         return request.getFileModel();
     }
 
     @Override
-    public ModelBuildingRequest setFileModel( Model fileModel )
-    {
-        request.setFileModel( fileModel );
+    public ModelBuildingRequest setFileModel(Model fileModel) {
+        request.setFileModel(fileModel);
         return this;
     }
 
     @Override
-    public Model getRawModel()
-    {
+    public Model getRawModel() {
         return request.getRawModel();
     }
 
     @Override
-    public ModelBuildingRequest setRawModel( Model rawModel )
-    {
-        request.setRawModel( rawModel );
+    public ModelBuildingRequest setRawModel(Model rawModel) {
+        request.setRawModel(rawModel);
         return this;
     }
 
     @Override
-    public WorkspaceModelResolver getWorkspaceModelResolver()
-    {
+    public WorkspaceModelResolver getWorkspaceModelResolver() {
         return request.getWorkspaceModelResolver();
     }
 
     @Override
-    public ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver )
-    {
-        request.setWorkspaceModelResolver( workspaceResolver );
+    public ModelBuildingRequest setWorkspaceModelResolver(WorkspaceModelResolver workspaceResolver) {
+        request.setWorkspaceModelResolver(workspaceResolver);
         return this;
     }
 
     @Override
-    public TransformerContextBuilder getTransformerContextBuilder()
-    {
+    public TransformerContextBuilder getTransformerContextBuilder() {
         return request.getTransformerContextBuilder();
     }
 
     @Override
-    public ModelBuildingRequest setTransformerContextBuilder( TransformerContextBuilder contextBuilder )
-    {
-        request.setTransformerContextBuilder( contextBuilder );
+    public ModelBuildingRequest setTransformerContextBuilder(TransformerContextBuilder contextBuilder) {
+        request.setTransformerContextBuilder(contextBuilder);
         return this;
     }
-}
\ No newline at end of file
+
+    @Override
+    public Path getRootDirectory() {
+        return request.getRootDirectory();
+    }
+
+    @Override
+    public ModelBuildingRequest setRootDirectory(Path rootDirectory) {
+        request.setRootDirectory(rootDirectory);
+        return this;
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/Graph.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/Graph.java
new file mode 100644
index 0000000..1f8abee
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/Graph.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.building;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+class Graph {
+    private enum DfsState {
+        VISITING,
+        VISITED
+    }
+
+    final Map<String, Vertex> vertices = new LinkedHashMap<>();
+
+    public Vertex getVertex(String id) {
+        return vertices.get(id);
+    }
+
+    public Collection<Vertex> getVertices() {
+        return vertices.values();
+    }
+
+    Vertex addVertex(String label) {
+        return vertices.computeIfAbsent(label, Vertex::new);
+    }
+
+    void addEdge(Vertex from, Vertex to) throws CycleDetectedException {
+        from.children.add(to);
+        to.parents.add(from);
+        List<String> cycle = findCycle(to);
+        if (cycle != null) {
+            // remove edge which introduced cycle
+            removeEdge(from, to);
+            throw new CycleDetectedException(
+                    "Edge between '" + from.label + "' and '" + to.label + "' introduces to cycle in the graph", cycle);
+        }
+    }
+
+    void removeEdge(Vertex from, Vertex to) {
+        from.children.remove(to);
+        to.parents.remove(from);
+    }
+
+    List<String> visitAll() {
+        return visitAll(vertices.values(), new HashMap<>(), new ArrayList<>());
+    }
+
+    List<String> findCycle(Vertex vertex) {
+        return visitCycle(Collections.singleton(vertex), new HashMap<>(), new LinkedList<>());
+    }
+
+    private static List<String> visitAll(
+            Collection<Vertex> children, Map<Vertex, DfsState> stateMap, List<String> list) {
+        for (Vertex v : children) {
+            DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
+            if (state == null) {
+                visitAll(v.children, stateMap, list);
+                stateMap.put(v, DfsState.VISITED);
+                list.add(v.label);
+            }
+        }
+        return list;
+    }
+
+    private static List<String> visitCycle(
+            Collection<Vertex> children, Map<Vertex, DfsState> stateMap, LinkedList<String> cycle) {
+        for (Vertex v : children) {
+            DfsState state = stateMap.putIfAbsent(v, DfsState.VISITING);
+            if (state == null) {
+                cycle.addLast(v.label);
+                List<String> ret = visitCycle(v.children, stateMap, cycle);
+                if (ret != null) {
+                    return ret;
+                }
+                cycle.removeLast();
+                stateMap.put(v, DfsState.VISITED);
+            } else if (state == DfsState.VISITING) {
+                // we are already visiting this vertex, this mean we have a cycle
+                int pos = cycle.lastIndexOf(v.label);
+                List<String> ret = cycle.subList(pos, cycle.size());
+                ret.add(v.label);
+                return ret;
+            }
+        }
+        return null;
+    }
+
+    static class Vertex {
+        final String label;
+        final List<Vertex> children = new ArrayList<>();
+        final List<Vertex> parents = new ArrayList<>();
+
+        Vertex(String label) {
+            this.label = label;
+        }
+
+        String getLabel() {
+            return label;
+        }
+
+        List<Vertex> getChildren() {
+            return children;
+        }
+
+        List<Vertex> getParents() {
+            return parents;
+        }
+    }
+
+    public static class CycleDetectedException extends Exception {
+        private final List<String> cycle;
+
+        CycleDetectedException(String message, List<String> cycle) {
+            super(message);
+            this.cycle = cycle;
+        }
+
+        public List<String> getCycle() {
+            return cycle;
+        }
+
+        @Override
+        public String getMessage() {
+            return super.getMessage() + " " + String.join(" --> ", cycle);
+        }
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java
index 74c1fa6..90e7020 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
 
@@ -26,10 +25,8 @@
 /**
  * Builds the effective model from a POM.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelBuilder
-{
+public interface ModelBuilder {
 
     /**
      * Builds the effective model of the specified POM.
@@ -38,8 +35,7 @@
      * @return The result of the model building, never {@code null}.
      * @throws ModelBuildingException If the effective model could not be built.
      */
-    ModelBuildingResult build( ModelBuildingRequest request )
-        throws ModelBuildingException;
+    ModelBuildingResult build(ModelBuildingRequest request) throws ModelBuildingException;
 
     /**
      * Builds the effective model by completing the specified interim result which was produced by a previous call to
@@ -52,14 +48,15 @@
      * @return The result of the model building, never {@code null}.
      * @throws ModelBuildingException If the effective model could not be built.
      */
-    ModelBuildingResult build( ModelBuildingRequest request, ModelBuildingResult result )
-        throws ModelBuildingException;
+    ModelBuildingResult build(ModelBuildingRequest request, ModelBuildingResult result) throws ModelBuildingException;
 
     /**
      * Performs only the part of {@link ModelBuilder#build(ModelBuildingRequest)} that loads the raw model
      */
-    Result<? extends Model> buildRawModel( File pomFile, int validationLevel, boolean locationTracking );
+    Result<? extends Model> buildRawModel(File pomFile, int validationLevel, boolean locationTracking);
+
+    Result<? extends Model> buildRawModel(
+            File pomFile, int validationLevel, boolean locationTracking, TransformerContext context);
 
     TransformerContextBuilder newTransformerContextBuilder();
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEvent.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEvent.java
index 2995b1b..c463308 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEvent.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEvent.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import org.apache.maven.model.Model;
 
 /**
  * Holds data relevant for a model building event.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelBuildingEvent
-{
+public interface ModelBuildingEvent {
 
     /**
      * Gets the model being built. The precise state of this model depends on the event being fired.
@@ -49,5 +46,4 @@
      * @return The container used to collect problems that were encountered, never {@code null}.
      */
     ModelProblemCollector getProblems();
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEventCatapult.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEventCatapult.java
index b6cfe1a..ce42b3d 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEventCatapult.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingEventCatapult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 /**
  * Assists in firing events from a generic method by abstracting from the actual callback method to be called on the
  * listener.
  *
- * @author Benjamin Bentmann
  */
-interface ModelBuildingEventCatapult
-{
+interface ModelBuildingEventCatapult {
 
     /**
      * Notifies the specified listener of the given event.
@@ -34,8 +31,7 @@
      * @param listener The listener to notify, must not be {@code null}.
      * @param event The event to fire, must not be {@code null}.
      */
-    void fire( ModelBuildingListener listener, ModelBuildingEvent event );
+    void fire(ModelBuildingListener listener, ModelBuildingEvent event);
 
     ModelBuildingEventCatapult BUILD_EXTENSIONS_ASSEMBLED = ModelBuildingListener::buildExtensionsAssembled;
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java
index 0485b84..ffb3e33 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -31,11 +30,8 @@
  * before eventually failing to provide callers with rich error information. Use {@link #getProblems()} to query the
  * details of the failure.
  *
- * @author Benjamin Bentmann
  */
-public class ModelBuildingException
-    extends Exception
-{
+public class ModelBuildingException extends Exception {
 
     private final ModelBuildingResult result;
 
@@ -48,24 +44,19 @@
      * @deprecated Use {@link #ModelBuildingException(ModelBuildingResult)} instead.
      */
     @Deprecated
-    public ModelBuildingException( Model model, String modelId, List<ModelProblem> problems )
-    {
-        super( toMessage( modelId, problems ) );
+    public ModelBuildingException(Model model, String modelId, List<ModelProblem> problems) {
+        super(toMessage(modelId, problems));
 
-        if ( model != null )
-        {
+        if (model != null) {
             DefaultModelBuildingResult tmp = new DefaultModelBuildingResult();
-            if ( modelId == null )
-            {
+            if (modelId == null) {
                 modelId = "";
             }
-            tmp.addModelId( modelId );
-            tmp.setRawModel( modelId, model );
-            tmp.setProblems( problems );
+            tmp.addModelId(modelId);
+            tmp.setRawModel(modelId, model);
+            tmp.setProblems(problems);
             result = tmp;
-        }
-        else
-        {
+        } else {
             result = null;
         }
     }
@@ -75,9 +66,8 @@
      *
      * @param result The interim result, may be {@code null}.
      */
-    public ModelBuildingException( ModelBuildingResult result )
-    {
-        super( toMessage( result ) );
+    public ModelBuildingException(ModelBuildingResult result) {
+        super(toMessage(result));
         this.result = result;
     }
 
@@ -86,8 +76,7 @@
      *
      * @return The interim model building result or {@code null} if not available.
      */
-    public ModelBuildingResult getResult()
-    {
+    public ModelBuildingResult getResult() {
         return result;
     }
 
@@ -96,14 +85,11 @@
      *
      * @return The erroneous model or {@code null} if not available.
      */
-    public Model getModel()
-    {
-        if ( result == null )
-        {
+    public Model getModel() {
+        if (result == null) {
             return null;
         }
-        if ( result.getEffectiveModel() != null )
-        {
+        if (result.getEffectiveModel() != null) {
             return result.getEffectiveModel();
         }
         return result.getRawModel();
@@ -116,13 +102,11 @@
      *
      * @return The identifier of the POM or an empty string if not known, never {@code null}.
      */
-    public String getModelId()
-    {
-        if ( result == null || result.getModelIds().isEmpty() )
-        {
+    public String getModelId() {
+        if (result == null || result.getModelIds().isEmpty()) {
             return "";
         }
-        return result.getModelIds().get( 0 );
+        return result.getModelIds().get(0);
     }
 
     /**
@@ -130,55 +114,47 @@
      *
      * @return The problems that caused this exception, never {@code null}.
      */
-    public List<ModelProblem> getProblems()
-    {
-        if ( result == null )
-        {
+    public List<ModelProblem> getProblems() {
+        if (result == null) {
             return Collections.emptyList();
         }
-        return Collections.unmodifiableList( result.getProblems() );
+        return Collections.unmodifiableList(result.getProblems());
     }
 
-    private static String toMessage( ModelBuildingResult result )
-    {
-        if ( result != null && !result.getModelIds().isEmpty() )
-        {
-            return toMessage( result.getModelIds().get( 0 ), result.getProblems() );
+    private static String toMessage(ModelBuildingResult result) {
+        if (result != null && !result.getModelIds().isEmpty()) {
+            return toMessage(result.getModelIds().get(0), result.getProblems());
         }
         return null;
     }
 
-    private static String toMessage( String modelId, List<ModelProblem> problems )
-    {
-        StringWriter buffer = new StringWriter( 1024 );
+    // Package protected for test
+    static String toMessage(String modelId, List<ModelProblem> problems) {
+        StringWriter buffer = new StringWriter(1024);
 
-        PrintWriter writer = new PrintWriter( buffer );
+        PrintWriter writer = new PrintWriter(buffer);
 
-        writer.print( problems.size() );
-        writer.print( ( problems.size() == 1 ) ? " problem was " : " problems were " );
-        writer.print( "encountered while building the effective model" );
-        if ( modelId != null && modelId.length() > 0 )
-        {
-            writer.print( " for " );
-            writer.print( modelId );
+        writer.print(problems.size());
+        writer.print((problems.size() == 1) ? " problem was " : " problems were ");
+        writer.print("encountered while building the effective model");
+        if (modelId != null && modelId.length() > 0) {
+            writer.print(" for ");
+            writer.print(modelId);
         }
-        writer.println();
 
-        for ( ModelProblem problem : problems )
-        {
-            writer.print( "[" );
-            writer.print( problem.getSeverity() );
-            writer.print( "] " );
-            writer.print( problem.getMessage() );
-            String location = ModelProblemUtils.formatLocation( problem, modelId );
-            if ( !location.isEmpty() )
-            {
-                writer.print( " @ " );
-                writer.println( location );
+        for (ModelProblem problem : problems) {
+            writer.println();
+            writer.print("    - [");
+            writer.print(problem.getSeverity());
+            writer.print("] ");
+            writer.print(problem.getMessage());
+            String location = ModelProblemUtils.formatLocation(problem, modelId);
+            if (!location.isEmpty()) {
+                writer.print(" @ ");
+                writer.print(location);
             }
         }
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingListener.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingListener.java
index 186507c..6cc22a6 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingListener.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 /**
  * Defines events that the model builder fires during construction of the effective model. When a listener encounters
@@ -25,16 +24,13 @@
  * <em>Note:</em> To cope with future extensions to this interface, it is strongly recommended to extend
  * {@link AbstractModelBuildingListener} rather than to directly implement this interface.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelBuildingListener
-{
+public interface ModelBuildingListener {
 
     /**
      * Notifies the listener that the model has been constructed to the extent where build extensions can be processed.
      *
      * @param event The details about the event.
      */
-    void buildExtensionsAssembled( ModelBuildingEvent event );
-
+    void buildExtensionsAssembled(ModelBuildingEvent event);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java
index 9cdb06c..fb08761 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
+import java.nio.file.Path;
 import java.util.Date;
 import java.util.List;
 import java.util.Properties;
@@ -32,10 +32,8 @@
 /**
  * Collects settings that control the building of effective models.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelBuildingRequest
-{
+public interface ModelBuildingRequest {
 
     /**
      * Denotes minimal validation of POMs. This validation level is meant for processing of POMs from repositories
@@ -55,14 +53,19 @@
     int VALIDATION_LEVEL_MAVEN_3_0 = 30;
 
     /**
-     * Denotes validation as performed by Maven 3.1. This validation level is meant for new projects.
+     * Denotes validation as performed by Maven 3.1. This validation level is meant for existing projects.
      */
     int VALIDATION_LEVEL_MAVEN_3_1 = 31;
 
     /**
+     * Denotes validation as performed by Maven 4.0. This validation level is meant for new projects.
+     */
+    int VALIDATION_LEVEL_MAVEN_4_0 = 40;
+
+    /**
      * Denotes strict validation as recommended by the current Maven version.
      */
-    int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_3_1;
+    int VALIDATION_LEVEL_STRICT = VALIDATION_LEVEL_MAVEN_4_0;
 
     /**
      * Gets the file model to build (with profile activation).
@@ -80,7 +83,7 @@
      * @return This request, never {@code null}.
      * @since 4.0.0
      */
-    ModelBuildingRequest setFileModel( Model fileModel );
+    ModelBuildingRequest setFileModel(Model fileModel);
 
     /**
      * @deprecated rawModel is never set, instead the fileModel is set
@@ -92,7 +95,7 @@
      * @deprecated setting the rawModel has no effect, instead the fileModel of phase one will be set
      */
     @Deprecated
-    ModelBuildingRequest setRawModel( Model rawModel );
+    ModelBuildingRequest setRawModel(Model rawModel);
 
     /**
      * Gets the source of the POM to process.
@@ -108,7 +111,7 @@
      * @param modelSource The source of the POM to process, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setModelSource( ModelSource modelSource );
+    ModelBuildingRequest setModelSource(ModelSource modelSource);
 
     /**
      * Gets the POM file of the project to build.
@@ -129,7 +132,7 @@
      *            model of some POM from the repository.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setPomFile( File pomFile );
+    ModelBuildingRequest setPomFile(File pomFile);
 
     /**
      * Gets the level of validation to perform on processed models.
@@ -147,7 +150,7 @@
      * @param validationLevel The level of validation to perform on processed models.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setValidationLevel( int validationLevel );
+    ModelBuildingRequest setValidationLevel(int validationLevel);
 
     /**
      * Indicates whether plugin executions and configurations should be processed. If enabled, lifecycle-induced plugin
@@ -164,7 +167,7 @@
      * @param processPlugins {@code true} to enable plugin processing, {@code false} otherwise.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setProcessPlugins( boolean processPlugins );
+    ModelBuildingRequest setProcessPlugins(boolean processPlugins);
 
     /**
      * Indicates whether the model building should happen in two phases. If enabled, the initial invocation of the model
@@ -185,7 +188,7 @@
      *            a single step.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setTwoPhaseBuilding( boolean twoPhaseBuilding );
+    ModelBuildingRequest setTwoPhaseBuilding(boolean twoPhaseBuilding);
 
     /**
      * Indicates whether the model should track the line/column number of the model source from which it was parsed.
@@ -201,7 +204,7 @@
      * @param locationTracking {@code true} to enable location tracking, {@code false} to disable it.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setLocationTracking( boolean locationTracking );
+    ModelBuildingRequest setLocationTracking(boolean locationTracking);
 
     /**
      * Gets the external profiles that should be considered for model building.
@@ -216,7 +219,7 @@
      * @param profiles The external profiles that should be considered for model building, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setProfiles( List<Profile> profiles );
+    ModelBuildingRequest setProfiles(List<Profile> profiles);
 
     /**
      * Gets the identifiers of those profiles that should be activated by explicit demand.
@@ -231,7 +234,7 @@
      * @param activeProfileIds The identifiers of those profiles to activate, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setActiveProfileIds( List<String> activeProfileIds );
+    ModelBuildingRequest setActiveProfileIds(List<String> activeProfileIds);
 
     /**
      * Gets the identifiers of those profiles that should be deactivated by explicit demand.
@@ -246,7 +249,7 @@
      * @param inactiveProfileIds The identifiers of those profiles to deactivate, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setInactiveProfileIds( List<String> inactiveProfileIds );
+    ModelBuildingRequest setInactiveProfileIds(List<String> inactiveProfileIds);
 
     /**
      * Gets the system properties to use for interpolation and profile activation. The system properties are collected
@@ -263,7 +266,7 @@
      * @param systemProperties The system properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setSystemProperties( Properties systemProperties );
+    ModelBuildingRequest setSystemProperties(Properties systemProperties);
 
     /**
      * Gets the user properties to use for interpolation and profile activation. The user properties have been
@@ -282,7 +285,7 @@
      * @param userProperties The user properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setUserProperties( Properties userProperties );
+    ModelBuildingRequest setUserProperties(Properties userProperties);
 
     /**
      * Gets the start time of the build.
@@ -297,7 +300,7 @@
      * @param buildStartTime The start time of the build, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setBuildStartTime( Date buildStartTime );
+    ModelBuildingRequest setBuildStartTime(Date buildStartTime);
 
     /**
      * Gets the model resolver to use for resolution of mixins or parents that are not locally reachable from the
@@ -314,7 +317,7 @@
      * @param modelResolver The model resolver to use, never {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setModelResolver( ModelResolver modelResolver );
+    ModelBuildingRequest setModelResolver(ModelResolver modelResolver);
 
     /**
      * Gets the model building listener to notify during the build process.
@@ -329,7 +332,7 @@
      * @param modelBuildingListener The model building listener to notify, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setModelBuildingListener( ModelBuildingListener modelBuildingListener );
+    ModelBuildingRequest setModelBuildingListener(ModelBuildingListener modelBuildingListener);
 
     /**
      * Gets the model cache to use for reuse of previously built models.
@@ -345,14 +348,17 @@
      * @param modelCache The model cache to use, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    ModelBuildingRequest setModelCache( ModelCache modelCache );
+    ModelBuildingRequest setModelCache(ModelCache modelCache);
 
     WorkspaceModelResolver getWorkspaceModelResolver();
 
-    ModelBuildingRequest setWorkspaceModelResolver( WorkspaceModelResolver workspaceResolver );
+    ModelBuildingRequest setWorkspaceModelResolver(WorkspaceModelResolver workspaceResolver);
 
     TransformerContextBuilder getTransformerContextBuilder();
 
-    ModelBuildingRequest setTransformerContextBuilder( TransformerContextBuilder contextBuilder );
+    ModelBuildingRequest setTransformerContextBuilder(TransformerContextBuilder contextBuilder);
 
+    Path getRootDirectory();
+
+    ModelBuildingRequest setRootDirectory(Path rootDirectory);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java
index 603d214..d4238e8 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.List;
 
@@ -27,10 +26,8 @@
 /**
  * Collects the output of the model builder.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelBuildingResult
-{
+public interface ModelBuildingResult {
 
     /**
      * Gets the sequence of model identifiers that denote the lineage of models from which the effective model was
@@ -73,7 +70,7 @@
      * @param modelId The identifier of the desired raw model, must not be {@code null}.
      * @return The raw model or {@code null} if the specified model id does not refer to a known model.
      */
-    Model getRawModel( String modelId );
+    Model getRawModel(String modelId);
 
     /**
      * Gets the profiles from the specified model that were active during model building. The model identifier should be
@@ -84,7 +81,7 @@
      * @return The active profiles of the model or an empty list if none or {@code null} if the specified model id does
      *         not refer to a known model.
      */
-    List<Profile> getActivePomProfiles( String modelId );
+    List<Profile> getActivePomProfiles(String modelId);
 
     /**
      * Gets the external profiles that were active during model building. External profiles are those that were
@@ -102,5 +99,4 @@
      * @return The problems that were encountered during the model building, can be empty but never {@code null}.
      */
     List<ModelProblem> getProblems();
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java
index 25fb268..6f9cba3 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
+
+import java.util.function.Supplier;
 
 import org.apache.maven.building.Source;
 
@@ -28,11 +29,8 @@
  * identify of a model. The tag allows for further classification of the associated data on the sole discretion of the
  * model builder.
  *
- * @author Benjamin Bentmann
- * @author Robert Scholte
  */
-public interface ModelCache
-{
+public interface ModelCache {
     /**
      * Puts the specified data into the cache.
      *
@@ -41,8 +39,7 @@
      * @param data The data to store in the cache, must not be {@code null}.
      * @since 4.0.0
      */
-    default void put( Source path, String tag, Object data )
-    {
+    default void put(Source path, String tag, Object data) {
         // only useful for ReactorModelCache
     }
 
@@ -54,8 +51,7 @@
      * @return The requested data or {@code null} if none was present in the cache.
      * @since 4.0.0
      */
-    default Object get( Source path, String tag )
-    {
+    default Object get(Source path, String tag) {
         // only useful for ReactorModelCache
         return null;
     }
@@ -69,7 +65,7 @@
      * @param tag The tag of the cache record, must not be {@code null}.
      * @param data The data to store in the cache, must not be {@code null}.
      */
-    void put( String groupId, String artifactId, String version, String tag, Object data );
+    void put(String groupId, String artifactId, String version, String tag, Object data);
 
     /**
      * Gets the specified data from the cache.
@@ -80,7 +76,7 @@
      * @param tag The tag of the cache record, must not be {@code null}.
      * @return The requested data or {@code null} if none was present in the cache.
      */
-    Object get( String groupId, String artifactId, String version, String tag );
+    Object get(String groupId, String artifactId, String version, String tag);
 
     /**
      * Puts the specified data into the cache.
@@ -90,9 +86,8 @@
      * @param data The data to store in the cache, must not be {@code null}.
      * @since 4.0.0
      */
-    default <T> void put( Source path, ModelCacheTag<T> tag, T data )
-    {
-        put( path, tag.getName(), tag.intoCache( data ) );
+    default <T> void put(Source path, ModelCacheTag<T> tag, T data) {
+        put(path, tag.getName(), tag.intoCache(data));
     }
 
     /**
@@ -103,10 +98,9 @@
      * @return The requested data or {@code null} if none was present in the cache.
      * @since 4.0.0
      */
-    default <T> T get( Source path, ModelCacheTag<T> tag )
-    {
-        Object obj = get( path, tag.getName() );
-        return ( obj != null ) ? tag.fromCache( tag.getType().cast( obj ) ) : null;
+    default <T> T get(Source path, ModelCacheTag<T> tag) {
+        Object obj = get(path, tag.getName());
+        return (obj != null) ? tag.fromCache(tag.getType().cast(obj)) : null;
     }
 
     /**
@@ -118,9 +112,8 @@
      * @param tag The tag of the cache record, must not be {@code null}.
      * @param data The data to store in the cache, must not be {@code null}.
      */
-    default <T> void put( String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data )
-    {
-        put( groupId, artifactId, version, tag.getName(), tag.intoCache( data ) );
+    default <T> void put(String groupId, String artifactId, String version, ModelCacheTag<T> tag, T data) {
+        put(groupId, artifactId, version, tag.getName(), tag.intoCache(data));
     }
 
     /**
@@ -132,10 +125,23 @@
      * @param tag The tag of the cache record, must not be {@code null}.
      * @return The requested data or {@code null} if none was present in the cache.
      */
-    default <T> T get( String groupId, String artifactId, String version, ModelCacheTag<T> tag )
-    {
-        Object obj = get( groupId, artifactId, version, tag.getName() );
-        return ( obj != null ) ? tag.fromCache( tag.getType().cast( obj ) ) : null;
+    default <T> T get(String groupId, String artifactId, String version, ModelCacheTag<T> tag) {
+        Object obj = get(groupId, artifactId, version, tag.getName());
+        return (obj != null) ? tag.fromCache(tag.getType().cast(obj)) : null;
     }
 
+    default <T> T computeIfAbsent(
+            String groupId, String artifactId, String version, ModelCacheTag<T> tag, Supplier<Supplier<T>> data) {
+        Object obj = computeIfAbsent(groupId, artifactId, version, tag.getName(), (Supplier) data);
+        return (obj != null) ? tag.fromCache(tag.getType().cast(obj)) : null;
+    }
+
+    default <T> T computeIfAbsent(Source path, ModelCacheTag<T> tag, Supplier<Supplier<T>> data) {
+        Object obj = computeIfAbsent(path, tag.getName(), (Supplier) data);
+        return (obj != null) ? tag.fromCache(tag.getType().cast(obj)) : null;
+    }
+
+    Object computeIfAbsent(String groupId, String artifactId, String version, String tag, Supplier<Supplier<?>> data);
+
+    Object computeIfAbsent(Source path, String tag, Supplier<Supplier<?>> data);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java
index 7e0cb0d..f3e4ded 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelCacheTag.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,19 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.Model;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.Model;
 
 /**
  * Describes a tag used by the model builder to access a {@link ModelCache}. This interface basically aggregates a name
  * and a class to provide some type safety when working with the otherwise untyped cache.
  *
- * @author Benjamin Bentmann
  * @param <T> The type of data associated with the tag.
  */
-interface ModelCacheTag<T>
-{
+interface ModelCacheTag<T> {
 
     /**
      * Gets the name of the tag.
@@ -53,7 +50,7 @@
      * @param data The data to store in the cache, must not be {@code null}.
      * @return The data being stored in the cache, never {@code null}.
      */
-    T intoCache( T data );
+    T intoCache(T data);
 
     /**
      * Creates a copy of the data suitable for retrieval from the cache. The retrieved data can be mutated after the
@@ -62,101 +59,83 @@
      * @param data The data to retrieve from the cache, must not be {@code null}.
      * @return The data being retrieved from the cache, never {@code null}.
      */
-    T fromCache( T data );
+    T fromCache(T data);
 
     /**
      * The tag used for the raw model without profile activation
      */
-    ModelCacheTag<ModelData> RAW = new ModelCacheTag<ModelData>()
-    {
+    ModelCacheTag<ModelData> RAW = new ModelCacheTag<ModelData>() {
 
         @Override
-        public String getName()
-        {
+        public String getName() {
             return "raw";
         }
 
         @Override
-        public Class<ModelData> getType()
-        {
+        public Class<ModelData> getType() {
             return ModelData.class;
         }
 
         @Override
-        public ModelData intoCache( ModelData data )
-        {
-            Model model = ( data.getModel() != null ) ? data.getModel().clone() : null;
-            return new ModelData( data.getSource(), model, data.getGroupId(), data.getArtifactId(), data.getVersion() );
+        public ModelData intoCache(ModelData data) {
+            return data;
         }
 
         @Override
-        public ModelData fromCache( ModelData data )
-        {
-            return intoCache( data );
+        public ModelData fromCache(ModelData data) {
+            return data;
         }
-
     };
 
     /**
      * The tag used to denote an effective dependency management section from an imported model.
      */
-    ModelCacheTag<DependencyManagement> IMPORT = new ModelCacheTag<DependencyManagement>()
-    {
+    ModelCacheTag<DependencyManagement> IMPORT = new ModelCacheTag<DependencyManagement>() {
 
         @Override
-        public String getName()
-        {
+        public String getName() {
             return "import";
         }
 
         @Override
-        public Class<DependencyManagement> getType()
-        {
+        public Class<DependencyManagement> getType() {
             return DependencyManagement.class;
         }
 
         @Override
-        public DependencyManagement intoCache( DependencyManagement data )
-        {
-            return ( data != null ) ? data.clone() : null;
+        public DependencyManagement intoCache(DependencyManagement data) {
+            return data;
         }
 
         @Override
-        public DependencyManagement fromCache( DependencyManagement data )
-        {
-            return intoCache( data );
+        public DependencyManagement fromCache(DependencyManagement data) {
+            return data;
         }
-
     };
 
     /**
      * The tag used for the file model without profile activation
      * @since 4.0.0
      */
-    ModelCacheTag<Model> FILE = new ModelCacheTag<Model>()
-    {
+    ModelCacheTag<Model> FILE = new ModelCacheTag<Model>() {
         @Override
-        public String getName()
-        {
+        public String getName() {
             return "file";
         }
 
         @Override
-        public Class<Model> getType()
-        {
+        public Class<Model> getType() {
             return Model.class;
         }
 
         @Override
-        public Model intoCache( Model data )
-        {
-            return ( data != null ) ? data.clone() : null;
+        public Model intoCache(Model data) {
+            return data;
         }
 
         @Override
-        public Model fromCache( Model data )
-        {
-            return intoCache( data );
+        public Model fromCache(Model data) {
+            return data;
         }
     };
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java
index 7a3e5e6..f89cacf 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelData.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.Objects;
 
@@ -28,10 +27,8 @@
  * Holds a model along with some auxiliary information. This internal utility class assists the model builder during POM
  * processing by providing a means to transport information that cannot be (easily) extracted from the model itself.
  *
- * @author Benjamin Bentmann
  */
-class ModelData
-{
+class ModelData {
     private final Source source;
 
     private final Model model;
@@ -47,8 +44,7 @@
      *
      * @param model The model to wrap, may be {@code null}.
      */
-    ModelData( Source source, Model model )
-    {
+    ModelData(Source source, Model model) {
         this.source = source;
         this.model = model;
     }
@@ -61,8 +57,7 @@
      * @param artifactId The effective artifact identifier of the model, may be {@code null}.
      * @param version The effective version of the model, may be {@code null}.
      */
-    ModelData( Source source, Model model, String groupId, String artifactId, String version )
-    {
+    ModelData(Source source, Model model, String groupId, String artifactId, String version) {
         this.source = source;
         this.model = model;
         this.groupId = groupId;
@@ -70,8 +65,7 @@
         this.version = version;
     }
 
-    public Source getSource()
-    {
+    public Source getSource() {
         return source;
     }
 
@@ -80,8 +74,7 @@
      *
      * @return The model or {@code null} if not set.
      */
-    public Model getModel()
-    {
+    public Model getModel() {
         return model;
     }
 
@@ -90,9 +83,8 @@
      *
      * @return The effective group identifier of the model or an empty string if unknown, never {@code null}.
      */
-    public String getGroupId()
-    {
-        return ( groupId != null ) ? groupId : "";
+    public String getGroupId() {
+        return (groupId != null) ? groupId : "";
     }
 
     /**
@@ -100,9 +92,8 @@
      *
      * @return The effective artifact identifier of the model or an empty string if unknown, never {@code null}.
      */
-    public String getArtifactId()
-    {
-        return ( artifactId != null ) ? artifactId : "";
+    public String getArtifactId() {
+        return (artifactId != null) ? artifactId : "";
     }
 
     /**
@@ -110,9 +101,8 @@
      *
      * @return The effective version of the model or an empty string if unknown, never {@code null}.
      */
-    public String getVersion()
-    {
-        return ( version != null ) ? version : "";
+    public String getVersion() {
+        return (version != null) ? version : "";
     }
 
     /**
@@ -120,16 +110,13 @@
      *
      * @return The effective identifier of the model, never {@code null}.
      */
-    public String getId()
-    {
+    public String getId() {
         // if source is null, it is the super model, which can be accessed via empty string
-        return Objects.toString( source, "" );
+        return Objects.toString(source, "");
     }
 
     @Override
-    public String toString()
-    {
-        return String.valueOf( model );
+    public String toString() {
+        return String.valueOf(model);
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java
index 581a41c..e25b67a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,35 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 /**
  * Describes a problem that was encountered during model building. A problem can either be an exception that was thrown
  * or a simple string message. In addition, a problem carries a hint about its source, e.g. the POM file that exhibits
  * the problem.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelProblem
-{
+public interface ModelProblem {
 
     /**
      * The different severity levels for a problem, in decreasing order.
      */
-    enum Severity
-    {
-
+    enum Severity {
         FATAL, //
         ERROR, //
         WARNING //
-
     }
 
     /**
      * Version
      */
-    enum Version
-    {
-        //based on ModeBuildingResult.validationLevel
+    enum Version {
+        // based on ModeBuildingResult.validationLevel
         BASE,
         V20,
         V30,
@@ -117,5 +110,4 @@
      * @return The version, never {@code null}.
      */
     Version getVersion();
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollector.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollector.java
index e9561e5..a8d64bf 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 /**
  * Collects problems that are encountered during model building. The primary purpose of this component is to account for
@@ -26,16 +25,13 @@
  * it delegates to other components that potentially encounter problems. Then, the problem reporter can focus on
  * providing a simple error message, leaving the donkey work of creating a nice model problem to this component.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelProblemCollector
-{
+public interface ModelProblemCollector {
 
     /**
      * Adds the specified problem.
      *
      * @param req must not be null
      */
-    void add( ModelProblemCollectorRequest req );
-
+    void add(ModelProblemCollectorRequest req);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorExt.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorExt.java
index 8bbaf80..e45308c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorExt.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorExt.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,20 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.List;
 
 /**
  * Extends the ModelProblemCollector by the capacity of returning the collected problems.
- * @author Milos Kleint
  */
-public interface ModelProblemCollectorExt extends ModelProblemCollector
-{
+public interface ModelProblemCollectorExt extends ModelProblemCollector {
 
     /**
      * The collected problems.
      * @return a list of model problems encountered, never {@code null}
      */
     List<ModelProblem> getProblems();
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorRequest.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorRequest.java
index 8edab3c..37c1783 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorRequest.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemCollectorRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.Objects;
 
@@ -28,10 +27,8 @@
 /**
  * Class to wrap request parameters to ModelProblemCollector.addProblem
  *
- * @author mkleint
  */
-public final class ModelProblemCollectorRequest
-{
+public final class ModelProblemCollectorRequest {
 
     private final ModelProblem.Severity severity;
     private final ModelProblem.Version version;
@@ -44,51 +41,42 @@
      * @param severity
      * @param version
      */
-    public ModelProblemCollectorRequest( Severity severity, Version version )
-    {
-        this.severity = Objects.requireNonNull( severity, "severity cannot be null" );
-        this.version = Objects.requireNonNull( version, "version cannot be null" );
+    public ModelProblemCollectorRequest(Severity severity, Version version) {
+        this.severity = Objects.requireNonNull(severity, "severity cannot be null");
+        this.version = Objects.requireNonNull(version, "version cannot be null");
     }
 
-    public Severity getSeverity()
-    {
+    public Severity getSeverity() {
         return severity;
     }
 
-    public Version getVersion()
-    {
+    public Version getVersion() {
         return version;
     }
 
-    public Exception getException()
-    {
+    public Exception getException() {
         return exception;
     }
 
-    public ModelProblemCollectorRequest setException( Exception exception )
-    {
+    public ModelProblemCollectorRequest setException(Exception exception) {
         this.exception = exception;
         return this;
     }
 
-    public String getMessage()
-    {
+    public String getMessage() {
         return message;
     }
 
-    public ModelProblemCollectorRequest setMessage( String message )
-    {
+    public ModelProblemCollectorRequest setMessage(String message) {
         this.message = message;
         return this;
     }
 
-    public InputLocation getLocation()
-    {
+    public InputLocation getLocation() {
         return location;
     }
 
-    public ModelProblemCollectorRequest setLocation( InputLocation location )
-    {
+    public ModelProblemCollectorRequest setLocation(InputLocation location) {
         this.location = location;
         return this;
     }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemUtils.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemUtils.java
index 150d60d..f11f285 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemUtils.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProblemUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
 
@@ -26,10 +25,8 @@
 /**
  * Assists in the handling of model problems.
  *
- * @author Benjamin Bentmann
  */
-public class ModelProblemUtils
-{
+public class ModelProblemUtils {
 
     /**
      * Creates a user-friendly source hint for the specified model.
@@ -37,36 +34,30 @@
      * @param model The model to create a source hint for, may be {@code null}.
      * @return The user-friendly source hint, never {@code null}.
      */
-    static String toSourceHint( Model model )
-    {
-        if ( model == null )
-        {
+    static String toSourceHint(Model model) {
+        if (model == null) {
             return "";
         }
 
-        StringBuilder buffer = new StringBuilder( 128 );
+        StringBuilder buffer = new StringBuilder(128);
 
-        buffer.append( toId( model ) );
+        buffer.append(toId(model));
 
         File pomFile = model.getPomFile();
-        if ( pomFile != null )
-        {
-            buffer.append( " (" ).append( pomFile ).append( ')' );
+        if (pomFile != null) {
+            buffer.append(" (").append(pomFile).append(')');
         }
 
         return buffer.toString();
     }
 
-    static String toPath( Model model )
-    {
+    static String toPath(Model model) {
         String path = "";
 
-        if ( model != null )
-        {
+        if (model != null) {
             File pomFile = model.getPomFile();
 
-            if ( pomFile != null )
-            {
+            if (pomFile != null) {
                 path = pomFile.getAbsolutePath();
             }
         }
@@ -74,32 +65,30 @@
         return path;
     }
 
-    static String toId( Model model )
-    {
-        if ( model == null )
-        {
+    static String toId(Model model) {
+        if (model == null) {
             return "";
         }
+        return toId(model.getDelegate());
+    }
 
+    static String toId(org.apache.maven.api.model.Model model) {
         String groupId = model.getGroupId();
-        if ( groupId == null && model.getParent() != null )
-        {
+        if (groupId == null && model.getParent() != null) {
             groupId = model.getParent().getGroupId();
         }
 
         String artifactId = model.getArtifactId();
 
         String version = model.getVersion();
-        if ( version == null && model.getParent() != null )
-        {
+        if (version == null && model.getParent() != null) {
             version = model.getParent().getVersion();
         }
-        if ( version == null )
-        {
+        if (version == null) {
             version = "[unknown-version]";
         }
 
-        return toId( groupId, artifactId, version );
+        return toId(groupId, artifactId, version);
     }
 
     /**
@@ -110,15 +99,14 @@
      * @param version The version, may be {@code null}.
      * @return The user-friendly artifact id, never {@code null}.
      */
-    static String toId( String groupId, String artifactId, String version )
-    {
-        StringBuilder buffer = new StringBuilder( 128 );
+    static String toId(String groupId, String artifactId, String version) {
+        StringBuilder buffer = new StringBuilder(128);
 
-        buffer.append( ( groupId != null && groupId.length() > 0 ) ? groupId : "[unknown-group-id]" );
-        buffer.append( ':' );
-        buffer.append( ( artifactId != null && artifactId.length() > 0 ) ? artifactId : "[unknown-artifact-id]" );
-        buffer.append( ':' );
-        buffer.append( ( version != null && version.length() > 0 ) ? version : "[unknown-version]" );
+        buffer.append((groupId != null && groupId.length() > 0) ? groupId : "[unknown-group-id]");
+        buffer.append(':');
+        buffer.append((artifactId != null && artifactId.length() > 0) ? artifactId : "[unknown-artifact-id]");
+        buffer.append(':');
+        buffer.append((version != null && version.length() > 0) ? version : "[unknown-version]");
 
         return buffer.toString();
     }
@@ -133,43 +121,34 @@
      *            to force output of model id and source.
      * @return The formatted problem location or an empty string if unknown, never {@code null}.
      */
-    public static String formatLocation( ModelProblem problem, String projectId )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
+    public static String formatLocation(ModelProblem problem, String projectId) {
+        StringBuilder buffer = new StringBuilder(256);
 
-        if ( !problem.getModelId().equals( projectId ) )
-        {
-            buffer.append( problem.getModelId() );
+        if (!problem.getModelId().equals(projectId)) {
+            buffer.append(problem.getModelId());
 
-            if ( problem.getSource().length() > 0 )
-            {
-                if ( buffer.length() > 0 )
-                {
-                    buffer.append( ", " );
+            if (problem.getSource().length() > 0) {
+                if (buffer.length() > 0) {
+                    buffer.append(", ");
                 }
-                buffer.append( problem.getSource() );
+                buffer.append(problem.getSource());
             }
         }
 
-        if ( problem.getLineNumber() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (problem.getLineNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( "line " ).append( problem.getLineNumber() );
+            buffer.append("line ").append(problem.getLineNumber());
         }
 
-        if ( problem.getColumnNumber() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (problem.getColumnNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( "column " ).append( problem.getColumnNumber() );
+            buffer.append("column ").append(problem.getColumnNumber());
         }
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProcessor.java
index c2c2ec0..6137c86 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProcessor.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import org.apache.maven.model.io.ModelReader;
 import org.apache.maven.model.locator.ModelLocator;
@@ -25,11 +24,8 @@
 /**
  * ModelProcessor
  */
-@SuppressWarnings( "checkstyle:interfaceistype" )
-public interface ModelProcessor
-    extends ModelLocator, ModelReader
-{
+@SuppressWarnings("checkstyle:interfaceistype")
+public interface ModelProcessor extends ModelLocator, ModelReader {
 
     String SOURCE = "org.apache.maven.model.building.source";
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java
index 5db8edb..b1b158e 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import org.apache.maven.building.Source;
 
@@ -27,12 +26,8 @@
  * This interface does not support loading of parent POM(s) from the same backing store, integrators are strongly
  * encouraged to implement {@link ModelSource2} instead of implementing this interface directly.
  *
- * @author Benjamin Bentmann
  * @see ModelSource2
  * @deprecated instead use {@link Source}
  */
 @Deprecated
-public interface ModelSource extends Source
-{
-
-}
+public interface ModelSource extends Source {}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java
index 3e123d0..39e2e65 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource2.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.net.URI;
 
@@ -31,9 +30,7 @@
  * ModelSource2 instances are cached in {@link ModelBuildingRequest#getModelCache()}. Implementations must guarantee
  * that the connection to the backing store remains active until request's {@link ModelCache} is discarded or flushed.
  */
-public interface ModelSource2
-    extends ModelSource
-{
+public interface ModelSource2 extends ModelSource {
     /**
      * Returns model source identified by a path relative to this model source POM. Implementation <strong>MUST</strong>
      * be able to accept <code>relPath</code> parameter values that
@@ -47,7 +44,7 @@
      * @param relPath is the path of the requested model source relative to this model source POM.
      * @return related model source or <code>null</code> if no such model source.
      */
-    ModelSource2 getRelatedSource( String relPath );
+    ModelSource2 getRelatedSource(String relPath);
 
     /**
      * Returns location of the POM, never <code>null</code>.
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource3.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource3.java
new file mode 100644
index 0000000..89fed34
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSource3.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.building;
+
+import org.apache.maven.model.locator.ModelLocator;
+
+/**
+ * Enhancement to the {@link ModelSource2} to support locating POM files using the {@link ModelLocator}
+ * when pointing to a directory.
+ */
+public interface ModelSource3 extends ModelSource2 {
+    /**
+     * Returns model source identified by a path relative to this model source POM. Implementation <strong>MUST</strong>
+     * accept <code>relPath</code> parameter values that
+     * <ul>
+     * <li>use either / or \ file path separator</li>
+     * <li>have .. parent directory references</li>
+     * <li>point either at file or directory</li>
+     * </ul>
+     * If the given path points at a directory, the provided {@code ModelLocator} will be used
+     * to find the POM file, else if no locator is provided, a file named 'pom.xml' needs to be
+     * used by the requested model source.
+     *
+     * @param locator locator used to locate the pom file
+     * @param relPath path of the requested model source relative to this model source POM
+     * @return related model source or <code>null</code> if no such model source
+     */
+    ModelSource3 getRelatedSource(ModelLocator locator, String relPath);
+
+    /**
+     * When using a ModelSource3, the method with a {@code ModelLocator} argument should
+     * be used instead.
+     *
+     * @deprecated use {@link #getRelatedSource(ModelLocator, String)} instead
+     */
+    @Deprecated
+    default ModelSource3 getRelatedSource(String relPath) {
+        return getRelatedSource(null, relPath);
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java
index 56c80ce..d279324 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/ModelSourceTransformer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,32 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
-import java.io.IOException;
 import java.nio.file.Path;
 
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.apache.maven.model.Model;
 
 /**
  * The ModelSourceTransformer is a way to transform the local pom while streaming the input.
  *
- * The {@link #transform(XmlPullParser, Path, TransformerContext)} method uses a Path on purpose, to ensure the
+ * The {@link #transform(Path, TransformerContext, Model)} method uses a Path on purpose, to ensure the
  * local pom is the original source.
  *
- * @author Robert Scholte
- * @author Guillaume Nodet
  * @since 4.0.0
  */
-public interface ModelSourceTransformer
-{
+public interface ModelSourceTransformer {
     /**
      *
      * @param pomFile the pom file, cannot be null
      * @param context the context, cannot be null
-     * @return the InputStream for the ModelReader
-     * @throws IOException if an I/O error occurs
+     * @param  model the model to transform
      * @throws TransformerException if the transformation fails
      */
-    XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
-        throws IOException, TransformerException;
+    void transform(Path pomFile, TransformerContext context, Model model) throws TransformerException;
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java
index 5dd4797..c66afb1 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/Result.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import static java.util.Collections.singleton;
-import static org.apache.maven.model.building.ModelProblem.Severity.ERROR;
-import static org.apache.maven.model.building.ModelProblem.Severity.FATAL;
+package org.apache.maven.model.building;
 
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
+import static java.util.Collections.singleton;
+import static org.apache.maven.model.building.ModelProblem.Severity.ERROR;
+import static org.apache.maven.model.building.ModelProblem.Severity.FATAL;
+
 /**
  * There are various forms of results that are represented by this class:
  * <ol>
@@ -38,20 +37,17 @@
  * </ol>
  * Could encode these variants as subclasses, but kept in one for now
  *
- * @author bbusjaeger
  * @param <T> the model type
  */
-public class Result<T>
-{
+public class Result<T> {
 
     /**
      * Success without warnings
      *
      * @param model
      */
-    public static <T> Result<T> success( T model )
-    {
-        return success( model, Collections.emptyList() );
+    public static <T> Result<T> success(T model) {
+        return success(model, Collections.emptyList());
     }
 
     /**
@@ -60,10 +56,9 @@
      * @param model
      * @param problems
      */
-    public static <T> Result<T> success( T model, Iterable<? extends ModelProblem> problems )
-    {
-        assert !hasErrors( problems );
-        return new Result<>( false, model, problems );
+    public static <T> Result<T> success(T model, Iterable<? extends ModelProblem> problems) {
+        assert !hasErrors(problems);
+        return new Result<>(false, model, problems);
     }
 
     /**
@@ -72,19 +67,16 @@
      * @param model
      * @param results
      */
-    public static <T> Result<T> success( T model, Result<?>... results )
-    {
+    public static <T> Result<T> success(T model, Result<?>... results) {
         final List<ModelProblem> problemsList = new ArrayList<>();
 
-        for ( Result<?> result1 : results )
-        {
-            for ( ModelProblem modelProblem : result1.getProblems() )
-            {
-                problemsList.add( modelProblem );
+        for (Result<?> result1 : results) {
+            for (ModelProblem modelProblem : result1.getProblems()) {
+                problemsList.add(modelProblem);
             }
         }
 
-        return success( model, problemsList );
+        return success(model, problemsList);
     }
 
     /**
@@ -92,34 +84,28 @@
      *
      * @param problems
      */
-    public static <T> Result<T> error( Iterable<? extends ModelProblem> problems )
-    {
-        return error( null, problems );
+    public static <T> Result<T> error(Iterable<? extends ModelProblem> problems) {
+        return error(null, problems);
     }
 
-    public static <T> Result<T> error( T model )
-    {
-        return error( model, Collections.emptyList() );
+    public static <T> Result<T> error(T model) {
+        return error(model, Collections.emptyList());
     }
 
-    public static <T> Result<T> error( Result<?> result )
-    {
-        return error( result.getProblems() );
+    public static <T> Result<T> error(Result<?> result) {
+        return error(result.getProblems());
     }
 
-    public static <T> Result<T> error( Result<?>... results )
-    {
-        final List<ModelProblem> problemsList = new ArrayList<>( );
+    public static <T> Result<T> error(Result<?>... results) {
+        final List<ModelProblem> problemsList = new ArrayList<>();
 
-        for ( Result<?> result1 : results )
-        {
-            for ( ModelProblem modelProblem : result1.getProblems( ) )
-            {
-                problemsList.add( modelProblem );
+        for (Result<?> result1 : results) {
+            for (ModelProblem modelProblem : result1.getProblems()) {
+                problemsList.add(modelProblem);
             }
         }
 
-        return error( problemsList );
+        return error(problemsList);
     }
 
     /**
@@ -128,9 +114,8 @@
      * @param model
      * @param problems
      */
-    public static <T> Result<T> error( T model, Iterable<? extends ModelProblem> problems )
-    {
-        return new Result<>( true, model, problems );
+    public static <T> Result<T> error(T model, Iterable<? extends ModelProblem> problems) {
+        return new Result<>(true, model, problems);
     }
 
     /**
@@ -139,9 +124,8 @@
      * @param model
      * @param problems
      */
-    public static <T> Result<T> newResult( T model, Iterable<? extends ModelProblem> problems )
-    {
-        return new Result<>( hasErrors( problems ), model, problems );
+    public static <T> Result<T> newResult(T model, Iterable<? extends ModelProblem> problems) {
+        return new Result<>(hasErrors(problems), model, problems);
     }
 
     /**
@@ -151,9 +135,8 @@
      * @param result
      * @param problem
      */
-    public static <T> Result<T> addProblem( Result<T> result, ModelProblem problem )
-    {
-        return addProblems( result, singleton( problem ) );
+    public static <T> Result<T> addProblem(Result<T> result, ModelProblem problem) {
+        return addProblems(result, singleton(problem));
     }
 
     /**
@@ -162,32 +145,26 @@
      * @param result
      * @param problems
      */
-    public static <T> Result<T> addProblems( Result<T> result, Iterable<? extends ModelProblem> problems )
-    {
+    public static <T> Result<T> addProblems(Result<T> result, Iterable<? extends ModelProblem> problems) {
         Collection<ModelProblem> list = new ArrayList<>();
-        for ( ModelProblem item : problems )
-        {
-            list.add( item );
+        for (ModelProblem item : problems) {
+            list.add(item);
         }
-        for ( ModelProblem item : result.getProblems() )
-        {
-            list.add( item );
+        for (ModelProblem item : result.getProblems()) {
+            list.add(item);
         }
-        return new Result<>( result.hasErrors() || hasErrors( problems ), result.get(), list );
+        return new Result<>(result.hasErrors() || hasErrors(problems), result.get(), list);
     }
 
-    public static <T> Result<T> addProblems( Result<T> result, Result<?>... results )
-    {
+    public static <T> Result<T> addProblems(Result<T> result, Result<?>... results) {
         final List<ModelProblem> problemsList = new ArrayList<>();
 
-        for ( Result<?> result1 : results )
-        {
-            for ( ModelProblem modelProblem : result1.getProblems( ) )
-            {
-                problemsList.add( modelProblem );
+        for (Result<?> result1 : results) {
+            for (ModelProblem modelProblem : result1.getProblems()) {
+                problemsList.add(modelProblem);
             }
         }
-        return addProblems( result, problemsList );
+        return addProblems(result, problemsList);
     }
 
     /**
@@ -195,36 +172,29 @@
      *
      * @param results
      */
-    public static <T> Result<Iterable<T>> newResultSet( Iterable<? extends Result<? extends T>> results )
-    {
+    public static <T> Result<Iterable<T>> newResultSet(Iterable<? extends Result<? extends T>> results) {
         boolean hasErrors = false;
         List<T> modelsList = new ArrayList<>();
         List<ModelProblem> problemsList = new ArrayList<>();
 
-        for ( Result<? extends T> result : results )
-        {
-            modelsList.add( result.get() );
+        for (Result<? extends T> result : results) {
+            modelsList.add(result.get());
 
-            for ( ModelProblem modelProblem : result.getProblems() )
-            {
-                problemsList.add( modelProblem );
+            for (ModelProblem modelProblem : result.getProblems()) {
+                problemsList.add(modelProblem);
             }
 
-            if ( result.hasErrors() )
-            {
+            if (result.hasErrors()) {
                 hasErrors = true;
             }
         }
-        return new Result<>( hasErrors, ( Iterable<T> ) modelsList, problemsList );
+        return new Result<>(hasErrors, (Iterable<T>) modelsList, problemsList);
     }
 
     // helper to determine if problems contain error
-    private static boolean hasErrors( Iterable<? extends ModelProblem> problems )
-    {
-        for ( ModelProblem input : problems )
-        {
-            if ( input.getSeverity().equals( ERROR ) || input.getSeverity().equals( FATAL ) )
-            {
+    private static boolean hasErrors(Iterable<? extends ModelProblem> problems) {
+        for (ModelProblem input : problems) {
+            if (input.getSeverity().equals(ERROR) || input.getSeverity().equals(FATAL)) {
                 return true;
             }
         }
@@ -234,32 +204,27 @@
     /**
      * Class definition
      */
-
     private final boolean errors;
 
     private final T value;
 
     private final Iterable<? extends ModelProblem> problems;
 
-    private Result( boolean errors, T model, Iterable<? extends ModelProblem> problems )
-    {
+    private Result(boolean errors, T model, Iterable<? extends ModelProblem> problems) {
         this.errors = errors;
         this.value = model;
         this.problems = problems;
     }
 
-    public Iterable<? extends ModelProblem> getProblems()
-    {
+    public Iterable<? extends ModelProblem> getProblems() {
         return problems;
     }
 
-    public T get()
-    {
+    public T get() {
         return value;
     }
 
-    public boolean hasErrors()
-    {
+    public boolean hasErrors() {
         return errors;
     }
-}
\ No newline at end of file
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/StringModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/StringModelSource.java
index 4097146..c3ac98a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/StringModelSource.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/StringModelSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,29 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import org.apache.maven.building.StringSource;
 
 /**
  * Wraps an ordinary {@link CharSequence} as a model source.
  *
- * @author Benjamin Bentmann
  *
  * @deprecated instead use {@link StringSource}
  */
 @Deprecated
-public class StringModelSource extends StringSource
-    implements ModelSource
-{
+public class StringModelSource extends StringSource implements ModelSource {
 
     /**
      * Creates a new model source backed by the specified string.
      *
      * @param pom The POM's string representation, may be empty or {@code null}.
      */
-    public StringModelSource( CharSequence pom )
-    {
-        this( pom, null );
+    public StringModelSource(CharSequence pom) {
+        this(pom, null);
     }
 
     /**
@@ -49,8 +44,7 @@
      * @param pom The POM's string representation, may be empty or {@code null}.
      * @param location The location to report for this use, may be {@code null}.
      */
-    public StringModelSource( CharSequence pom, String location )
-    {
-        super( pom, location );
+    public StringModelSource(CharSequence pom, String location) {
+        super(pom, location);
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContext.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContext.java
index e041af4..7eb4fea 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContext.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContext.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.nio.file.Path;
 
@@ -27,38 +26,41 @@
  * Context used to transform a pom file.
  *
  *
- * @author Robert Scholte
  * @since 4.0.0
  */
-public interface TransformerContext
-{
+public interface TransformerContext {
     /**
      * Key to get the TransformerContext from the SessionData
      */
     Object KEY = TransformerContext.class;
 
     /**
-     * Get the value of the commandline argument {@code -Dkey=value}
-     * @param key
-     * @return
+     * Get the value of the Maven user property.
      */
-    String getUserProperty( String key );
+    String getUserProperty(String key);
 
     /**
-     * Get the model based on the path, will be used to resolve the parent based on relativePath
+     * Get the model based on the path when resolving the parent based on relativePath.
      *
+     * @param from    the requiring model
      * @param pomFile the path to the pomFile
      * @return the model, otherwise {@code null}
      */
-    Model getRawModel( Path pomFile );
+    Model getRawModel(Path from, Path pomFile);
 
     /**
-     * Get the model from the reactor based on the groupId and artifactId, will be used for reactor dependencies
+     * Get the model from the reactor based on the groupId and artifactId when resolving reactor dependencies.
      *
-     * @param groupId the groupId
+     * @param from    the requiring model
+     * @param groupId    the groupId
      * @param artifactId the artifactId
      * @return the model, otherwise {@code null}
      * @throws IllegalStateException if multiple versions of the same GA are part of the reactor
      */
-    Model getRawModel( String groupId, String artifactId );
+    Model getRawModel(Path from, String groupId, String artifactId);
+
+    /**
+     * Locate the POM file inside the given directory.
+     */
+    Path locate(Path path);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContextBuilder.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContextBuilder.java
index 6117f2a..68045ad 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContextBuilder.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerContextBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 /**
  * The transformerContextBuilder is responsible for initializing the TransformerContext.
  * In case rawModels are missing, it could do new buildingRequests on the ModelBuilder.
  *
- * @author Robert Scholte
  * @since 4.0.0
  */
-public interface TransformerContextBuilder
-{
+public interface TransformerContextBuilder {
     /**
      * This method is used to initialize the TransformerContext
      *
@@ -35,7 +32,7 @@
      * @param problems the problemCollector
      * @return the mutable transformerContext
      */
-    TransformerContext initialize( ModelBuildingRequest request, ModelProblemCollector problems );
+    TransformerContext initialize(ModelBuildingRequest request, ModelProblemCollector problems);
 
     /**
      * The immutable transformerContext, can be used after the buildplan is finished.
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerException.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerException.java
index 0644afe..ac5d08c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerException.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/TransformerException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 /**
  *
- * @author Robert Scholte
  * @since 4.0.0
  */
-public class TransformerException extends Exception
-{
+public class TransformerException extends Exception {
 
-    public TransformerException( Exception e )
-    {
-        super ( e );
+    public TransformerException(Exception e) {
+        super(e);
     }
 
-    public TransformerException( String message, Throwable exception )
-    {
-        super( message, exception );
+    public TransformerException(String message, Throwable exception) {
+        super(message, exception);
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/building/UrlModelSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/building/UrlModelSource.java
index dcbbc52..7fbf83b 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/building/UrlModelSource.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/building/UrlModelSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.net.URL;
 
@@ -26,21 +25,17 @@
 /**
  * Wraps an ordinary {@link URL} as a model source.
  *
- * @author Benjamin Bentmann
  *
  * @deprecated instead use {@link UrlSource}
  */
 @Deprecated
-public class UrlModelSource extends UrlSource
-    implements ModelSource
-{
+public class UrlModelSource extends UrlSource implements ModelSource {
     /**
      * Creates a new model source backed by the specified URL.
      *
      * @param pomUrl The POM file, must not be {@code null}.
      */
-    public UrlModelSource( URL pomUrl )
-    {
-        super( pomUrl );
+    public UrlModelSource(URL pomUrl) {
+        super(pomUrl);
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java
index b277bf3..4456c54 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DefaultDependencyManagementImporter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.composition;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,69 +16,57 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+package org.apache.maven.model.composition;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.Model;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 
 /**
  * Handles the import of dependency management from other models into the target model.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultDependencyManagementImporter
-    implements DependencyManagementImporter
-{
+public class DefaultDependencyManagementImporter implements DependencyManagementImporter {
 
     @Override
-    public void importManagement( Model target, List<? extends DependencyManagement> sources,
-                                  ModelBuildingRequest request, ModelProblemCollector problems )
-    {
-        if ( sources != null && !sources.isEmpty() )
-        {
+    public Model importManagement(
+            Model target,
+            List<? extends DependencyManagement> sources,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems) {
+        if (sources != null && !sources.isEmpty()) {
             Map<String, Dependency> dependencies = new LinkedHashMap<>();
 
             DependencyManagement depMgmt = target.getDependencyManagement();
 
-            if ( depMgmt != null )
-            {
-                for ( Dependency dependency : depMgmt.getDependencies() )
-                {
-                    dependencies.put( dependency.getManagementKey(), dependency );
+            if (depMgmt != null) {
+                for (Dependency dependency : depMgmt.getDependencies()) {
+                    dependencies.put(dependency.getManagementKey(), dependency);
                 }
-            }
-            else
-            {
-                depMgmt = new DependencyManagement();
-                target.setDependencyManagement( depMgmt );
+            } else {
+                depMgmt = DependencyManagement.newInstance();
             }
 
-            for ( DependencyManagement source : sources )
-            {
-                for ( Dependency dependency : source.getDependencies() )
-                {
+            for (DependencyManagement source : sources) {
+                for (Dependency dependency : source.getDependencies()) {
                     String key = dependency.getManagementKey();
-                    if ( !dependencies.containsKey( key ) )
-                    {
-                        dependencies.put( key, dependency );
-                    }
+                    dependencies.putIfAbsent(key, dependency);
                 }
             }
 
-            depMgmt.setDependencies( new ArrayList<>( dependencies.values() ) );
+            return target.withDependencyManagement(depMgmt.withDependencies(dependencies.values()));
         }
+        return target;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependencyManagementImporter.java b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependencyManagementImporter.java
index 0649642..911d1f4 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependencyManagementImporter.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/composition/DependencyManagementImporter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.composition;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,21 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.composition;
 
 import java.util.List;
 
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.Model;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 
 /**
  * Handles the import of dependency management from other models into the target model.
  *
- * @author Benjamin Bentmann
  */
-public interface DependencyManagementImporter
-{
+public interface DependencyManagementImporter {
 
     /**
      * Imports the specified dependency management sections into the given target model.
@@ -42,7 +39,9 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void importManagement( Model target, List<? extends DependencyManagement> sources, ModelBuildingRequest request,
-                           ModelProblemCollector problems );
-
+    Model importManagement(
+            Model target,
+            List<? extends DependencyManagement> sources,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/DefaultInheritanceAssembler.java b/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/DefaultInheritanceAssembler.java
index ae5ac0b..0a3e36f 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/DefaultInheritanceAssembler.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/DefaultInheritanceAssembler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.inheritance;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,56 +16,51 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.inheritance;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.ModelBase;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.Reporting;
+import org.apache.maven.api.model.InputLocation;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.ModelBase;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginContainer;
+import org.apache.maven.api.model.ReportPlugin;
+import org.apache.maven.api.model.Reporting;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.merge.MavenModelMerger;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Handles inheritance of model values.
  *
- * @author Benjamin Bentmann
  */
-@SuppressWarnings( { "checkstyle:methodname" } )
+@SuppressWarnings({"checkstyle:methodname"})
 @Named
 @Singleton
-public class DefaultInheritanceAssembler
-    implements InheritanceAssembler
-{
-
-    private InheritanceModelMerger merger = new InheritanceModelMerger();
+public class DefaultInheritanceAssembler implements InheritanceAssembler {
 
     private static final String CHILD_DIRECTORY = "child-directory";
 
     private static final String CHILD_DIRECTORY_PROPERTY = "project.directory";
 
+    private final InheritanceModelMerger merger = new InheritanceModelMerger();
+
     @Override
-    public void assembleModelInheritance( Model child, Model parent, ModelBuildingRequest request,
-                                          ModelProblemCollector problems )
-    {
+    public Model assembleModelInheritance(
+            Model child, Model parent, ModelBuildingRequest request, ModelProblemCollector problems) {
         Map<Object, Object> hints = new HashMap<>();
-        String childPath = child.getProperties().getProperty( CHILD_DIRECTORY_PROPERTY, child.getArtifactId() );
-        hints.put( CHILD_DIRECTORY, childPath );
-        hints.put( MavenModelMerger.CHILD_PATH_ADJUSTMENT, getChildPathAdjustment( child, parent, childPath ) );
-        merger.merge( child, parent, false, hints );
+        String childPath = child.getProperties().getOrDefault(CHILD_DIRECTORY_PROPERTY, child.getArtifactId());
+        hints.put(CHILD_DIRECTORY, childPath);
+        hints.put(MavenModelMerger.CHILD_PATH_ADJUSTMENT, getChildPathAdjustment(child, parent, childPath));
+        return merger.merge(child, parent, false, hints);
     }
 
     /**
@@ -89,12 +82,10 @@
      * @param childDirectory The directory defined in child model, may be <code>null</code>.
      * @return The path adjustment, can be empty but never <code>null</code>.
      */
-    private String getChildPathAdjustment( Model child, Model parent, String childDirectory )
-    {
+    private String getChildPathAdjustment(Model child, Model parent, String childDirectory) {
         String adjustment = "";
 
-        if ( parent != null )
-        {
+        if (parent != null) {
             String childName = child.getArtifactId();
 
             /*
@@ -104,33 +95,28 @@
              * repository. In other words, modules where artifactId != moduleDirName will see different effective URLs
              * depending on how the model was constructed (from filesystem or from repository).
              */
-            if ( child.getProjectDirectory() != null )
-            {
-                childName = child.getProjectDirectory().getName();
+            if (child.getProjectDirectory() != null) {
+                childName = child.getProjectDirectory().getFileName().toString();
             }
 
-            for ( String module : parent.getModules() )
-            {
-                module = module.replace( '\\', '/' );
+            for (String module : parent.getModules()) {
+                module = module.replace('\\', '/');
 
-                if ( module.regionMatches( true, module.length() - 4, ".xml", 0, 4 ) )
-                {
-                    module = module.substring( 0, module.lastIndexOf( '/' ) + 1 );
+                if (module.regionMatches(true, module.length() - 4, ".xml", 0, 4)) {
+                    module = module.substring(0, module.lastIndexOf('/') + 1);
                 }
 
                 String moduleName = module;
-                if ( moduleName.endsWith( "/" ) )
-                {
-                    moduleName = moduleName.substring( 0, moduleName.length() - 1 );
+                if (moduleName.endsWith("/")) {
+                    moduleName = moduleName.substring(0, moduleName.length() - 1);
                 }
 
-                int lastSlash = moduleName.lastIndexOf( '/' );
+                int lastSlash = moduleName.lastIndexOf('/');
 
-                moduleName = moduleName.substring( lastSlash + 1 );
+                moduleName = moduleName.substring(lastSlash + 1);
 
-                if ( ( moduleName.equals( childName ) || ( moduleName.equals( childDirectory ) ) ) && lastSlash >= 0 )
-                {
-                    adjustment = module.substring( 0, lastSlash );
+                if ((moduleName.equals(childName) || (moduleName.equals(childDirectory))) && lastSlash >= 0) {
+                    adjustment = module.substring(0, lastSlash);
                     break;
                 }
             }
@@ -142,222 +128,204 @@
     /**
      * InheritanceModelMerger
      */
-    protected static class InheritanceModelMerger
-        extends MavenModelMerger
-    {
+    protected static class InheritanceModelMerger extends MavenModelMerger {
 
         @Override
-        protected String extrapolateChildUrl( String parentUrl, boolean appendPath, Map<Object, Object> context )
-        {
-            Object childDirectory = context.get( CHILD_DIRECTORY );
-            Object childPathAdjustment = context.get( CHILD_PATH_ADJUSTMENT );
+        protected String extrapolateChildUrl(String parentUrl, boolean appendPath, Map<Object, Object> context) {
+            Object childDirectory = context.get(CHILD_DIRECTORY);
+            Object childPathAdjustment = context.get(CHILD_PATH_ADJUSTMENT);
 
-            if ( StringUtils.isBlank( parentUrl ) || childDirectory == null || childPathAdjustment == null
-                || !appendPath )
-            {
+            boolean isBlankParentUrl = true;
+
+            if (parentUrl != null) {
+                for (int i = 0; i < parentUrl.length(); i++) {
+                    if (!Character.isWhitespace(parentUrl.charAt(i))) {
+                        isBlankParentUrl = false;
+                    }
+                }
+            }
+
+            if (isBlankParentUrl || childDirectory == null || childPathAdjustment == null || !appendPath) {
                 return parentUrl;
             }
 
             // append childPathAdjustment and childDirectory to parent url
-            return appendPath( parentUrl, childDirectory.toString(), childPathAdjustment.toString() );
+            return appendPath(parentUrl, childDirectory.toString(), childPathAdjustment.toString());
         }
 
-        private String appendPath( String parentUrl, String childPath, String pathAdjustment )
-        {
-            StringBuilder url = new StringBuilder( parentUrl.length() + pathAdjustment.length() + childPath.length()
-                + ( ( pathAdjustment.length() == 0 ) ? 1 : 2 ) );
+        private String appendPath(String parentUrl, String childPath, String pathAdjustment) {
+            StringBuilder url = new StringBuilder(parentUrl.length()
+                    + pathAdjustment.length()
+                    + childPath.length()
+                    + ((pathAdjustment.length() == 0) ? 1 : 2));
 
-            url.append( parentUrl );
-            concatPath( url, pathAdjustment );
-            concatPath( url, childPath );
+            url.append(parentUrl);
+            concatPath(url, pathAdjustment);
+            concatPath(url, childPath);
 
             return url.toString();
         }
 
-        private void concatPath( StringBuilder url, String path )
-        {
-            if ( path.length() > 0 )
-            {
-                boolean initialUrlEndsWithSlash = url.charAt( url.length() - 1 ) == '/';
-                boolean pathStartsWithSlash = path.charAt( 0 ) ==  '/';
+        private void concatPath(StringBuilder url, String path) {
+            if (path.length() > 0) {
+                boolean initialUrlEndsWithSlash = url.charAt(url.length() - 1) == '/';
+                boolean pathStartsWithSlash = path.charAt(0) == '/';
 
-                if ( pathStartsWithSlash )
-                {
-                    if ( initialUrlEndsWithSlash )
-                    {
+                if (pathStartsWithSlash) {
+                    if (initialUrlEndsWithSlash) {
                         // 1 extra '/' to remove
-                        url.setLength( url.length() - 1 );
+                        url.setLength(url.length() - 1);
                     }
-                }
-                else if ( !initialUrlEndsWithSlash )
-                {
+                } else if (!initialUrlEndsWithSlash) {
                     // add missing '/' between url and path
-                    url.append( '/' );
+                    url.append('/');
                 }
 
-                url.append( path );
+                url.append(path);
 
                 // ensure resulting url ends with slash if initial url was
-                if ( initialUrlEndsWithSlash && !path.endsWith( "/" ) )
-                {
-                    url.append( '/' );
+                if (initialUrlEndsWithSlash && !path.endsWith("/")) {
+                    url.append('/');
                 }
             }
         }
 
         @Override
-        protected void mergeModelBase_Properties( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                  Map<Object, Object> context )
-        {
-            Properties merged = new Properties();
-            if ( sourceDominant )
-            {
-                merged.putAll( target.getProperties() );
-                putAll( merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY );
+        protected void mergeModelBase_Properties(
+                ModelBase.Builder builder,
+                ModelBase target,
+                ModelBase source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
+            Map<String, String> merged = new HashMap<>();
+            if (sourceDominant) {
+                merged.putAll(target.getProperties());
+                putAll(merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY);
+            } else {
+                putAll(merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY);
+                merged.putAll(target.getProperties());
             }
-            else
-            {
-                putAll( merged, source.getProperties(), CHILD_DIRECTORY_PROPERTY );
-                merged.putAll( target.getProperties() );
-            }
-            target.setProperties( merged );
-            target.setLocation( "properties",
-                                InputLocation.merge( target.getLocation( "properties" ),
-                                                     source.getLocation( "properties" ), sourceDominant ) );
+            builder.properties(merged);
+            builder.location(
+                    "properties",
+                    InputLocation.merge(
+                            target.getLocation("properties"), source.getLocation("properties"), sourceDominant));
         }
 
-        private void putAll( Map<Object, Object> s, Map<Object, Object> t, Object excludeKey )
-        {
-            for ( Map.Entry<Object, Object> e : t.entrySet() )
-            {
-                if ( !e.getKey().equals( excludeKey ) )
-                {
-                    s.put( e.getKey(), e.getValue() );
+        private void putAll(Map<String, String> s, Map<String, String> t, Object excludeKey) {
+            for (Map.Entry<String, String> e : t.entrySet()) {
+                if (!e.getKey().equals(excludeKey)) {
+                    s.put(e.getKey(), e.getValue());
                 }
             }
         }
 
         @Override
-        protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
-                                                     boolean sourceDominant, Map<Object, Object> context )
-        {
+        protected void mergePluginContainer_Plugins(
+                PluginContainer.Builder builder,
+                PluginContainer target,
+                PluginContainer source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<Plugin> src = source.getPlugins();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<Plugin> tgt = target.getPlugins();
-                Map<Object, Plugin> master = new LinkedHashMap<>( src.size() * 2 );
+                Map<Object, Plugin> master = new LinkedHashMap<>(src.size() * 2);
 
-                for ( Plugin element : src )
-                {
-                    if ( element.isInherited() || !element.getExecutions().isEmpty() )
-                    {
+                for (Plugin element : src) {
+                    if (element.isInherited() || !element.getExecutions().isEmpty()) {
                         // NOTE: Enforce recursive merge to trigger merging/inheritance logic for executions
-                        Plugin plugin = new Plugin();
-                        plugin.setLocation( "", element.getLocation( "" ) );
-                        plugin.setGroupId( null );
-                        mergePlugin( plugin, element, sourceDominant, context );
+                        Plugin plugin = Plugin.newInstance(false);
+                        plugin = mergePlugin(plugin, element, sourceDominant, context);
 
-                        Object key = getPluginKey().apply( element );
+                        Object key = getPluginKey().apply(plugin);
 
-                        master.put( key, plugin );
+                        master.put(key, plugin);
                     }
                 }
 
                 Map<Object, List<Plugin>> predecessors = new LinkedHashMap<>();
                 List<Plugin> pending = new ArrayList<>();
-                for ( Plugin element : tgt )
-                {
-                    Object key = getPluginKey().apply( element );
-                    Plugin existing = master.get( key );
-                    if ( existing != null )
-                    {
-                        mergePlugin( element, existing, sourceDominant, context );
+                for (Plugin element : tgt) {
+                    Object key = getPluginKey().apply(element);
+                    Plugin existing = master.get(key);
+                    if (existing != null) {
+                        element = mergePlugin(element, existing, sourceDominant, context);
 
-                        master.put( key, element );
+                        master.put(key, element);
 
-                        if ( !pending.isEmpty() )
-                        {
-                            predecessors.put( key, pending );
+                        if (!pending.isEmpty()) {
+                            predecessors.put(key, pending);
                             pending = new ArrayList<>();
                         }
-                    }
-                    else
-                    {
-                        pending.add( element );
+                    } else {
+                        pending.add(element);
                     }
                 }
 
-                List<Plugin> result = new ArrayList<>( src.size() + tgt.size() );
-                for ( Map.Entry<Object, Plugin> entry : master.entrySet() )
-                {
-                    List<Plugin> pre = predecessors.get( entry.getKey() );
-                    if ( pre != null )
-                    {
-                        result.addAll( pre );
+                List<Plugin> result = new ArrayList<>(src.size() + tgt.size());
+                for (Map.Entry<Object, Plugin> entry : master.entrySet()) {
+                    List<Plugin> pre = predecessors.get(entry.getKey());
+                    if (pre != null) {
+                        result.addAll(pre);
                     }
-                    result.add( entry.getValue() );
+                    result.add(entry.getValue());
                 }
-                result.addAll( pending );
+                result.addAll(pending);
 
-                target.setPlugins( result );
+                builder.plugins(result);
             }
         }
 
         @Override
-        protected void mergePlugin( Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context )
-        {
-            if ( source.isInherited() )
-            {
-                mergeConfigurationContainer( target, source, sourceDominant, context );
+        protected Plugin mergePlugin(
+                Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
+            Plugin.Builder builder = Plugin.newBuilder(target);
+            if (source.isInherited()) {
+                mergeConfigurationContainer(builder, target, source, sourceDominant, context);
             }
-            mergePlugin_GroupId( target, source, sourceDominant, context );
-            mergePlugin_ArtifactId( target, source, sourceDominant, context );
-            mergePlugin_Version( target, source, sourceDominant, context );
-            mergePlugin_Extensions( target, source, sourceDominant, context );
-            mergePlugin_Dependencies( target, source, sourceDominant, context );
-            mergePlugin_Executions( target, source, sourceDominant, context );
+            mergePlugin_GroupId(builder, target, source, sourceDominant, context);
+            mergePlugin_ArtifactId(builder, target, source, sourceDominant, context);
+            mergePlugin_Version(builder, target, source, sourceDominant, context);
+            mergePlugin_Extensions(builder, target, source, sourceDominant, context);
+            mergePlugin_Executions(builder, target, source, sourceDominant, context);
+            mergePlugin_Dependencies(builder, target, source, sourceDominant, context);
+            return builder.build();
         }
 
         @Override
-        protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-        {
+        protected void mergeReporting_Plugins(
+                Reporting.Builder builder,
+                Reporting target,
+                Reporting source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<ReportPlugin> src = source.getPlugins();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<ReportPlugin> tgt = target.getPlugins();
-                Map<Object, ReportPlugin> merged =
-                    new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+                Map<Object, ReportPlugin> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-                for ( ReportPlugin element :  src )
-                {
-                    Object key = getReportPluginKey().apply( element );
-                    if ( element.isInherited() )
-                    {
+                for (ReportPlugin element : src) {
+                    if (element.isInherited()) {
                         // NOTE: Enforce recursive merge to trigger merging/inheritance logic for executions as well
-                        ReportPlugin plugin = new ReportPlugin();
-                        plugin.setLocation( "", element.getLocation( "" ) );
-                        plugin.setGroupId( null );
-                        mergeReportPlugin( plugin, element, sourceDominant, context );
+                        ReportPlugin plugin = ReportPlugin.newInstance(false);
+                        plugin = mergeReportPlugin(plugin, element, sourceDominant, context);
 
-                        merged.put( key, plugin );
+                        merged.put(getReportPluginKey().apply(element), plugin);
                     }
                 }
 
-                for ( ReportPlugin element : tgt )
-                {
-                    Object key = getReportPluginKey().apply( element );
-                    ReportPlugin existing = merged.get( key );
-                    if ( existing != null )
-                    {
-                        mergeReportPlugin( element, existing, sourceDominant, context );
+                for (ReportPlugin element : tgt) {
+                    Object key = getReportPluginKey().apply(element);
+                    ReportPlugin existing = merged.get(key);
+                    if (existing != null) {
+                        element = mergeReportPlugin(element, existing, sourceDominant, context);
                     }
-                    merged.put( key, element );
+                    merged.put(key, element);
                 }
 
-                target.setPlugins( new ArrayList<>( merged.values() ) );
+                builder.plugins(merged.values());
             }
         }
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/InheritanceAssembler.java b/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/InheritanceAssembler.java
index a191e52..0e303eb 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/InheritanceAssembler.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/inheritance/InheritanceAssembler.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.inheritance;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.inheritance;
 
-import org.apache.maven.model.Model;
+import org.apache.maven.api.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 
 /**
  * Handles inheritance of model values.
  *
- * @author Benjamin Bentmann
  */
-public interface InheritanceAssembler
-{
+public interface InheritanceAssembler {
 
     /**
      * Merges values from the specified parent model into the given child model. Implementations are expected to keep
@@ -42,7 +39,6 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void assembleModelInheritance( Model child, Model parent, ModelBuildingRequest request,
-                                   ModelProblemCollector problems );
-
+    Model assembleModelInheritance(
+            Model child, Model parent, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java
index e42e6e3..97c8984 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/AbstractStringBasedModelInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,26 +16,31 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
+
+import javax.inject.Inject;
 
 import java.io.File;
+import java.net.URI;
+import java.nio.file.Path;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Properties;
+import java.util.Map;
 
-import javax.inject.Inject;
-
-import org.apache.maven.model.Model;
+import org.apache.maven.api.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.path.PathTranslator;
 import org.apache.maven.model.path.UrlNormalizer;
+import org.apache.maven.model.root.RootLocator;
 import org.codehaus.plexus.interpolation.AbstractValueSource;
 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
 import org.codehaus.plexus.interpolation.MapBasedValueSource;
 import org.codehaus.plexus.interpolation.PrefixAwareRecursionInterceptor;
-import org.codehaus.plexus.interpolation.PrefixedObjectValueSource;
 import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
 import org.codehaus.plexus.interpolation.RecursionInterceptor;
 import org.codehaus.plexus.interpolation.ValueSource;
@@ -45,17 +48,16 @@
 /**
  * Use a regular expression search to find and resolve expressions within the POM.
  *
- * @author jdcasey Created on Feb 3, 2005
  */
-public abstract class AbstractStringBasedModelInterpolator
-    implements ModelInterpolator
-{
-    private static final List<String> PROJECT_PREFIXES = Collections.singletonList( "project." );
+public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator {
+    private static final String PREFIX_PROJECT = "project.";
+    private static final String PREFIX_POM = "pom.";
+    private static final List<String> PROJECT_PREFIXES_3_1 = Arrays.asList(PREFIX_POM, PREFIX_PROJECT);
+    private static final List<String> PROJECT_PREFIXES_4_0 = Collections.singletonList(PREFIX_PROJECT);
 
     private static final Collection<String> TRANSLATED_PATH_EXPRESSIONS;
 
-    static
-    {
+    static {
         Collection<String> translatedPrefixes = new HashSet<>();
 
         // MNG-1927, MNG-2124, MNG-3355:
@@ -63,113 +65,169 @@
         // sure interpolation of the directories below uses translated paths.
         // Afterward, we'll double back and translate any paths that weren't covered during interpolation via the
         // code below...
-        translatedPrefixes.add( "build.directory" );
-        translatedPrefixes.add( "build.outputDirectory" );
-        translatedPrefixes.add( "build.testOutputDirectory" );
-        translatedPrefixes.add( "build.sourceDirectory" );
-        translatedPrefixes.add( "build.testSourceDirectory" );
-        translatedPrefixes.add( "build.scriptSourceDirectory" );
-        translatedPrefixes.add( "reporting.outputDirectory" );
+        translatedPrefixes.add("build.directory");
+        translatedPrefixes.add("build.outputDirectory");
+        translatedPrefixes.add("build.testOutputDirectory");
+        translatedPrefixes.add("build.sourceDirectory");
+        translatedPrefixes.add("build.testSourceDirectory");
+        translatedPrefixes.add("build.scriptSourceDirectory");
+        translatedPrefixes.add("reporting.outputDirectory");
 
         TRANSLATED_PATH_EXPRESSIONS = translatedPrefixes;
     }
 
     private final PathTranslator pathTranslator;
     private final UrlNormalizer urlNormalizer;
-    private final ModelVersionProcessor versionProcessor;
+
+    private final RootLocator rootLocator;
 
     @Inject
-    public AbstractStringBasedModelInterpolator( PathTranslator pathTranslator, UrlNormalizer urlNormalizer,
-                                                 ModelVersionProcessor processor )
-    {
+    public AbstractStringBasedModelInterpolator(
+            PathTranslator pathTranslator, UrlNormalizer urlNormalizer, RootLocator rootLocator) {
         this.pathTranslator = pathTranslator;
         this.urlNormalizer = urlNormalizer;
-        this.versionProcessor = processor;
+        this.rootLocator = rootLocator;
     }
 
-    protected List<ValueSource> createValueSources( final Model model, final File projectDir,
-                                                    final ModelBuildingRequest config )
-    {
-        Properties modelProperties = model.getProperties();
+    @Override
+    public org.apache.maven.model.Model interpolateModel(
+            org.apache.maven.model.Model model,
+            File projectDir,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems) {
+        return new org.apache.maven.model.Model(interpolateModel(model.getDelegate(), projectDir, request, problems));
+    }
 
-        ValueSource projectPrefixValueSource = new PrefixedObjectValueSource( PROJECT_PREFIXES, model, false );
+    protected List<String> getProjectPrefixes(ModelBuildingRequest config) {
+        return config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0
+                ? PROJECT_PREFIXES_4_0
+                : PROJECT_PREFIXES_3_1;
+    }
 
-        // NOTE: Order counts here!
-        List<ValueSource> valueSources = new ArrayList<>( 8 );
+    protected List<ValueSource> createValueSources(
+            final Model model,
+            final File projectDir,
+            final ModelBuildingRequest config,
+            ModelProblemCollector problems) {
+        Map<String, String> modelProperties = model.getProperties();
 
-        if ( projectDir != null )
-        {
-            ValueSource basedirValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
-            {
-                @Override
-                public Object getValue( String expression )
-                {
-                    if ( "basedir".equals( expression ) )
-                    {
-                        return projectDir.getAbsolutePath();
-                    }
-                    return null;
-                }
-            }, PROJECT_PREFIXES, true );
-            valueSources.add( basedirValueSource );
+        ValueSource projectPrefixValueSource;
+        ValueSource prefixlessObjectBasedValueSource;
+        if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0) {
+            projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_4_0, model, false);
+            prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model);
+        } else {
+            projectPrefixValueSource = new PrefixedObjectValueSource(PROJECT_PREFIXES_3_1, model, false);
+            if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
+                projectPrefixValueSource =
+                        new ProblemDetectingValueSource(projectPrefixValueSource, PREFIX_POM, PREFIX_PROJECT, problems);
+            }
 
-            ValueSource baseUriValueSource = new PrefixedValueSourceWrapper( new AbstractValueSource( false )
-            {
-                @Override
-                public Object getValue( String expression )
-                {
-                    if ( "baseUri".equals( expression ) )
-                    {
-                        return projectDir.getAbsoluteFile().toPath().toUri().toASCIIString();
-                    }
-                    return null;
-                }
-            }, PROJECT_PREFIXES, false );
-            valueSources.add( baseUriValueSource );
-            valueSources.add( new BuildTimestampValueSource( config.getBuildStartTime(), modelProperties ) );
+            prefixlessObjectBasedValueSource = new ObjectBasedValueSource(model);
+            if (config.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
+                prefixlessObjectBasedValueSource =
+                        new ProblemDetectingValueSource(prefixlessObjectBasedValueSource, "", PREFIX_PROJECT, problems);
+            }
         }
 
-        valueSources.add( projectPrefixValueSource );
+        // NOTE: Order counts here!
+        List<ValueSource> valueSources = new ArrayList<>(9);
 
-        valueSources.add( new MapBasedValueSource( config.getUserProperties() ) );
+        if (projectDir != null) {
+            ValueSource basedirValueSource = new PrefixedValueSourceWrapper(
+                    new AbstractValueSource(false) {
+                        @Override
+                        public Object getValue(String expression) {
+                            if ("basedir".equals(expression)) {
+                                return projectDir.getAbsoluteFile().toPath().toString();
+                            } else if (expression.startsWith("basedir.")) {
+                                Path basedir = projectDir.getAbsoluteFile().toPath();
+                                return new ObjectBasedValueSource(basedir)
+                                        .getValue(expression.substring("basedir.".length()));
+                            }
+                            return null;
+                        }
+                    },
+                    getProjectPrefixes(config),
+                    true);
+            valueSources.add(basedirValueSource);
 
-        // Overwrite existing values in model properties. Otherwise it's not possible
-        // to define the version via command line: mvn -Drevision=6.5.7 ...
-        versionProcessor.overwriteModelProperties( modelProperties, config );
+            ValueSource baseUriValueSource = new PrefixedValueSourceWrapper(
+                    new AbstractValueSource(false) {
+                        @Override
+                        public Object getValue(String expression) {
+                            if ("baseUri".equals(expression)) {
+                                return projectDir
+                                        .getAbsoluteFile()
+                                        .toPath()
+                                        .toUri()
+                                        .toASCIIString();
+                            } else if (expression.startsWith("baseUri.")) {
+                                URI baseUri =
+                                        projectDir.getAbsoluteFile().toPath().toUri();
+                                return new ObjectBasedValueSource(baseUri)
+                                        .getValue(expression.substring("baseUri.".length()));
+                            }
+                            return null;
+                        }
+                    },
+                    getProjectPrefixes(config),
+                    false);
+            valueSources.add(baseUriValueSource);
+            valueSources.add(new BuildTimestampValueSource(config.getBuildStartTime(), modelProperties));
+        }
 
-        valueSources.add( new MapBasedValueSource( modelProperties ) );
+        valueSources.add(new PrefixedValueSourceWrapper(
+                new AbstractValueSource(false) {
+                    @Override
+                    public Object getValue(String expression) {
+                        if ("rootDirectory".equals(expression)) {
+                            Path base = projectDir != null ? projectDir.toPath() : null;
+                            Path root = rootLocator.findMandatoryRoot(base);
+                            return root.toFile().getPath();
+                        } else if (expression.startsWith("rootDirectory.")) {
+                            Path base = projectDir != null ? projectDir.toPath() : null;
+                            Path root = rootLocator.findMandatoryRoot(base);
+                            return new ObjectBasedValueSource(root)
+                                    .getValue(expression.substring("rootDirectory.".length()));
+                        }
+                        return null;
+                    }
+                },
+                getProjectPrefixes(config)));
 
-        valueSources.add( new MapBasedValueSource( config.getSystemProperties() ) );
+        valueSources.add(projectPrefixValueSource);
 
-        valueSources.add( new AbstractValueSource( false )
-        {
+        valueSources.add(new MapBasedValueSource(config.getUserProperties()));
+
+        valueSources.add(new MapBasedValueSource(modelProperties));
+
+        valueSources.add(new MapBasedValueSource(config.getSystemProperties()));
+
+        valueSources.add(new AbstractValueSource(false) {
             @Override
-            public Object getValue( String expression )
-            {
-                return config.getSystemProperties().getProperty( "env." + expression );
+            public Object getValue(String expression) {
+                return config.getSystemProperties().getProperty("env." + expression);
             }
-        } );
+        });
+
+        valueSources.add(prefixlessObjectBasedValueSource);
 
         return valueSources;
     }
 
-    protected List<? extends InterpolationPostProcessor> createPostProcessors( final Model model,
-                                                                               final File projectDir,
-                                                                               final ModelBuildingRequest config )
-    {
-        List<InterpolationPostProcessor> processors = new ArrayList<>( 2 );
-        if ( projectDir != null )
-        {
-            processors.add( new PathTranslatingPostProcessor( PROJECT_PREFIXES, TRANSLATED_PATH_EXPRESSIONS,
-                                                              projectDir, pathTranslator ) );
+    protected List<? extends InterpolationPostProcessor> createPostProcessors(
+            final Model model, final File projectDir, final ModelBuildingRequest config) {
+        List<InterpolationPostProcessor> processors = new ArrayList<>(2);
+        if (projectDir != null) {
+            processors.add(new PathTranslatingPostProcessor(
+                    getProjectPrefixes(config), TRANSLATED_PATH_EXPRESSIONS, projectDir, pathTranslator));
         }
-        processors.add( new UrlNormalizingPostProcessor( urlNormalizer ) );
+        processors.add(new UrlNormalizingPostProcessor(urlNormalizer));
         return processors;
     }
 
-    protected RecursionInterceptor createRecursionInterceptor()
-    {
-        return new PrefixAwareRecursionInterceptor( PROJECT_PREFIXES );
+    protected RecursionInterceptor createRecursionInterceptor(ModelBuildingRequest config) {
+        return new PrefixAwareRecursionInterceptor(getProjectPrefixes(config));
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/BuildTimestampValueSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/BuildTimestampValueSource.java
index c7ca305..e6f737d 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/BuildTimestampValueSource.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/BuildTimestampValueSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,29 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
 
 import java.util.Date;
-import java.util.Properties;
+import java.util.Map;
 
 import org.codehaus.plexus.interpolation.AbstractValueSource;
 
-class BuildTimestampValueSource
-    extends AbstractValueSource
-{
-    private final MavenBuildTimestamp mavenBuildTimestamp;
+class BuildTimestampValueSource extends AbstractValueSource {
+    private final Date startTime;
+    private final Map<String, String> properties;
 
-    BuildTimestampValueSource( Date startTime, Properties properties )
-    {
-        super( false );
-        this.mavenBuildTimestamp = new MavenBuildTimestamp( startTime, properties );
+    BuildTimestampValueSource(Date startTime, Map<String, String> properties) {
+        super(false);
+        this.startTime = startTime;
+        this.properties = properties;
     }
 
     @Override
-    public Object getValue( String expression )
-    {
-        if ( "build.timestamp".equals( expression ) || "maven.build.timestamp".equals( expression ) )
-        {
-            return mavenBuildTimestamp.formattedTimestamp();
+    public Object getValue(String expression) {
+        if ("build.timestamp".equals(expression) || "maven.build.timestamp".equals(expression)) {
+            return new MavenBuildTimestamp(startTime, properties).formattedTimestamp();
         }
         return null;
     }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java
index 27e3469..a01c4e6 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/DefaultModelVersionProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,12 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.Properties;
+package org.apache.maven.model.interpolation;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.Properties;
+
 import org.apache.maven.model.building.ModelBuildingRequest;
 
 /**
@@ -32,9 +31,7 @@
  */
 @Named
 @Singleton
-public class DefaultModelVersionProcessor
-    implements ModelVersionProcessor
-{
+public class DefaultModelVersionProcessor implements ModelVersionProcessor {
 
     private static final String SHA1_PROPERTY = "sha1";
 
@@ -43,27 +40,22 @@
     private static final String REVISION_PROPERTY = "revision";
 
     @Override
-    public boolean isValidProperty( String property )
-    {
-        return REVISION_PROPERTY.equals( property ) || CHANGELIST_PROPERTY.equals( property )
-            || SHA1_PROPERTY.equals( property );
+    public boolean isValidProperty(String property) {
+        return REVISION_PROPERTY.equals(property)
+                || CHANGELIST_PROPERTY.equals(property)
+                || SHA1_PROPERTY.equals(property);
     }
 
     @Override
-    public void overwriteModelProperties( Properties modelProperties, ModelBuildingRequest request )
-    {
-        if ( request.getSystemProperties().containsKey( REVISION_PROPERTY ) )
-        {
-            modelProperties.put( REVISION_PROPERTY, request.getSystemProperties().get( REVISION_PROPERTY ) );
+    public void overwriteModelProperties(Properties modelProperties, ModelBuildingRequest request) {
+        if (request.getUserProperties().containsKey(REVISION_PROPERTY)) {
+            modelProperties.put(REVISION_PROPERTY, request.getUserProperties().get(REVISION_PROPERTY));
         }
-        if ( request.getSystemProperties().containsKey( CHANGELIST_PROPERTY ) )
-        {
-            modelProperties.put( CHANGELIST_PROPERTY, request.getSystemProperties().get( CHANGELIST_PROPERTY ) );
+        if (request.getUserProperties().containsKey(CHANGELIST_PROPERTY)) {
+            modelProperties.put(CHANGELIST_PROPERTY, request.getUserProperties().get(CHANGELIST_PROPERTY));
         }
-        if ( request.getSystemProperties().containsKey( SHA1_PROPERTY ) )
-        {
-            modelProperties.put( SHA1_PROPERTY, request.getSystemProperties().get( SHA1_PROPERTY ) );
+        if (request.getUserProperties().containsKey(SHA1_PROPERTY)) {
+            modelProperties.put(SHA1_PROPERTY, request.getUserProperties().get(SHA1_PROPERTY));
         }
-
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/MavenBuildTimestamp.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/MavenBuildTimestamp.java
index fcec526..35f025a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/MavenBuildTimestamp.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/MavenBuildTimestamp.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,60 +16,64 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
 
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.GregorianCalendar;
+import java.util.Map;
 import java.util.Properties;
 import java.util.TimeZone;
 
 /**
  * MavenBuildTimestamp
  */
-public class MavenBuildTimestamp
-{
+public class MavenBuildTimestamp {
     // ISO 8601-compliant timestamp for machine readability
     public static final String DEFAULT_BUILD_TIMESTAMP_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
 
     public static final String BUILD_TIMESTAMP_FORMAT_PROPERTY = "maven.build.timestamp.format";
 
-    public static final TimeZone DEFAULT_BUILD_TIME_ZONE = TimeZone.getTimeZone( "Etc/UTC" );
+    public static final TimeZone DEFAULT_BUILD_TIME_ZONE = TimeZone.getTimeZone("Etc/UTC");
 
     private String formattedTimestamp;
 
-    public MavenBuildTimestamp()
-    {
-        this( new Date() );
+    public MavenBuildTimestamp() {
+        this(new Date());
     }
 
-    public MavenBuildTimestamp( Date time )
-    {
-        this( time, DEFAULT_BUILD_TIMESTAMP_FORMAT );
+    public MavenBuildTimestamp(Date time) {
+        this(time, DEFAULT_BUILD_TIMESTAMP_FORMAT);
     }
 
-    public MavenBuildTimestamp( Date time, Properties properties )
-    {
-        this( time, properties != null ? properties.getProperty( BUILD_TIMESTAMP_FORMAT_PROPERTY ) : null );
+    public MavenBuildTimestamp(Date time, Map<String, String> properties) {
+        this(time, properties != null ? properties.get(BUILD_TIMESTAMP_FORMAT_PROPERTY) : null);
     }
 
-    public MavenBuildTimestamp( Date time, String timestampFormat )
-    {
-        if ( timestampFormat == null )
-        {
+    /**
+     *
+     * @deprecated Use {@link #MavenBuildTimestamp(Date, Map)} or extract the format and pass it
+     *             to {@link #MavenBuildTimestamp(Date, String)} instead.
+     */
+    @Deprecated
+    public MavenBuildTimestamp(Date time, Properties properties) {
+        this(time, properties != null ? properties.getProperty(BUILD_TIMESTAMP_FORMAT_PROPERTY) : null);
+    }
+
+    public MavenBuildTimestamp(Date time, String timestampFormat) {
+        if (timestampFormat == null) {
             timestampFormat = DEFAULT_BUILD_TIMESTAMP_FORMAT;
         }
-        if ( time == null )
-        {
+        if (time == null) {
             time = new Date();
         }
-        SimpleDateFormat dateFormat = new SimpleDateFormat( timestampFormat );
-        dateFormat.setCalendar( new GregorianCalendar() );
-        dateFormat.setTimeZone( DEFAULT_BUILD_TIME_ZONE );
-        formattedTimestamp = dateFormat.format( time );
+        SimpleDateFormat dateFormat = new SimpleDateFormat(timestampFormat);
+        dateFormat.setCalendar(new GregorianCalendar());
+        dateFormat.setTimeZone(DEFAULT_BUILD_TIME_ZONE);
+        formattedTimestamp = dateFormat.format(time);
     }
 
-    public String formattedTimestamp()
-    {
+    public String formattedTimestamp() {
         return formattedTimestamp;
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelInterpolator.java
index 5fc4c9c..e150fdf 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelInterpolator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,21 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
+
+import java.io.File;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 
-import java.io.File;
-
 /**
  * Replaces expressions of the form <code>${token}</code> with their effective values. Effective values are basically
  * calculated from the elements of the model itself and the execution properties from the building request.
  *
- * @author jdcasey
  */
-public interface ModelInterpolator
-{
+public interface ModelInterpolator {
 
     /**
      * Interpolates expressions in the specified model. Note that implementations are free to either interpolate the
@@ -46,7 +43,11 @@
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      * @return The interpolated model, never {@code null}.
      */
-    Model interpolateModel( Model model, File projectDir, ModelBuildingRequest request,
-                            ModelProblemCollector problems );
+    Model interpolateModel(Model model, File projectDir, ModelBuildingRequest request, ModelProblemCollector problems);
 
+    org.apache.maven.api.model.Model interpolateModel(
+            org.apache.maven.api.model.Model model,
+            File projectDir,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java
index 06b17f3..20d43bd 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ModelVersionProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
 
 import java.util.Properties;
 
@@ -27,14 +26,13 @@
  * Allows a fixed set of properties that are valid inside a version and that could be overwritten for example on the
  * commandline
  */
-public interface ModelVersionProcessor
-{
+public interface ModelVersionProcessor {
 
     /**
      * @param property the property to check
      * @return <code>true</code> if this is a valid property for this processor
      */
-    boolean isValidProperty( String property );
+    boolean isValidProperty(String property);
 
     /**
      * This method is responsible for examining the request and possibly overwrite of the valid properties in the model
@@ -42,6 +40,5 @@
      * @param modelProperties
      * @param request
      */
-    void overwriteModelProperties( Properties modelProperties, ModelBuildingRequest request );
-
+    void overwriteModelProperties(Properties modelProperties, ModelBuildingRequest request);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ObjectBasedValueSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ObjectBasedValueSource.java
new file mode 100644
index 0000000..5a104b0
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ObjectBasedValueSource.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation;
+
+/*
+ * Copyright 2007 The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import org.apache.maven.model.interpolation.reflection.ReflectionValueExtractor;
+import org.codehaus.plexus.interpolation.AbstractValueSource;
+
+/**
+ * Wraps an object, providing reflective access to the object graph of which the
+ * supplied object is the root. Expressions like 'child.name' will translate into
+ * 'rootObject.getChild().getName()' for non-boolean properties, and
+ * 'rootObject.getChild().isName()' for boolean properties.
+ */
+public class ObjectBasedValueSource extends AbstractValueSource {
+
+    private final Object root;
+
+    /**
+     * Construct a new value source, using the supplied object as the root from
+     * which to start, and using expressions split at the dot ('.') to navigate
+     * the object graph beneath this root.
+     * @param root the root of the graph.
+     */
+    public ObjectBasedValueSource(Object root) {
+        super(true);
+        this.root = root;
+    }
+
+    /**
+     * <p>Split the expression into parts, tokenized on the dot ('.') character. Then,
+     * starting at the root object contained in this value source, apply each part
+     * to the object graph below this root, using either 'getXXX()' or 'isXXX()'
+     * accessor types to resolve the value for each successive expression part.
+     * Finally, return the result of the last expression part's resolution.</p>
+     *
+     * <p><b>NOTE:</b> The object-graph nagivation actually takes place via the
+     * {@link ReflectionValueExtractor} class.</p>
+     */
+    public Object getValue(String expression) {
+        if (expression == null || expression.trim().isEmpty()) {
+            return null;
+        }
+
+        try {
+            return ReflectionValueExtractor.evaluate(expression, root, false);
+        } catch (Exception e) {
+            addFeedback("Failed to extract \'" + expression + "\' from: " + root, e);
+        }
+
+        return null;
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java
index c05b86a..674cdc6 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PathTranslatingPostProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,30 +16,31 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.model.path.PathTranslator;
-import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
-import org.codehaus.plexus.interpolation.util.ValueSourceUtils;
+package org.apache.maven.model.interpolation;
 
 import java.io.File;
 import java.util.Collection;
 import java.util.List;
 
+import org.apache.maven.model.path.PathTranslator;
+import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
+import org.codehaus.plexus.interpolation.util.ValueSourceUtils;
+
 /**
  *
  */
-class PathTranslatingPostProcessor
-    implements InterpolationPostProcessor
-{
+class PathTranslatingPostProcessor implements InterpolationPostProcessor {
 
     private final Collection<String> unprefixedPathKeys;
     private final File projectDir;
     private final PathTranslator pathTranslator;
     private final List<String> expressionPrefixes;
 
-    PathTranslatingPostProcessor( List<String> expressionPrefixes, Collection<String> unprefixedPathKeys,
-                                         File projectDir, PathTranslator pathTranslator )
-    {
+    PathTranslatingPostProcessor(
+            List<String> expressionPrefixes,
+            Collection<String> unprefixedPathKeys,
+            File projectDir,
+            PathTranslator pathTranslator) {
         this.expressionPrefixes = expressionPrefixes;
         this.unprefixedPathKeys = unprefixedPathKeys;
         this.projectDir = projectDir;
@@ -49,19 +48,15 @@
     }
 
     @Override
-    public Object execute( String expression, Object value )
-    {
-        if ( value != null )
-        {
-            expression = ValueSourceUtils.trimPrefix( expression, expressionPrefixes, true );
+    public Object execute(String expression, Object value) {
+        if (value != null) {
+            expression = ValueSourceUtils.trimPrefix(expression, expressionPrefixes, true);
 
-            if ( unprefixedPathKeys.contains( expression ) )
-            {
-                return pathTranslator.alignToBaseDirectory( String.valueOf( value ), projectDir );
+            if (unprefixedPathKeys.contains(expression)) {
+                return pathTranslator.alignToBaseDirectory(String.valueOf(value), projectDir);
             }
         }
 
         return null;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PrefixedObjectValueSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PrefixedObjectValueSource.java
new file mode 100644
index 0000000..4a70115
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/PrefixedObjectValueSource.java
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation;
+
+import java.util.List;
+
+import org.codehaus.plexus.interpolation.AbstractDelegatingValueSource;
+import org.codehaus.plexus.interpolation.PrefixedValueSourceWrapper;
+import org.codehaus.plexus.interpolation.QueryEnabledValueSource;
+
+/**
+ * Wraps an arbitrary object with an {@link ObjectBasedValueSource} instance, then
+ * wraps that source with a {@link PrefixedValueSourceWrapper} instance, to which
+ * this class delegates all of its calls.
+ */
+public class PrefixedObjectValueSource extends AbstractDelegatingValueSource implements QueryEnabledValueSource {
+
+    /**
+     * Wrap the specified root object, allowing the specified expression prefix.
+     * @param prefix the prefix.
+     * @param root the root of the graph.
+     */
+    public PrefixedObjectValueSource(String prefix, Object root) {
+        super(new PrefixedValueSourceWrapper(new ObjectBasedValueSource(root), prefix));
+    }
+
+    /**
+     * Wrap the specified root object, allowing the specified list of expression
+     * prefixes and setting whether the {@link PrefixedValueSourceWrapper} allows
+     * unprefixed expressions.
+     * @param possiblePrefixes The possible prefixes.
+     * @param root The root of the graph.
+     * @param allowUnprefixedExpressions if we allow undefined expressions or not.
+     */
+    public PrefixedObjectValueSource(List<String> possiblePrefixes, Object root, boolean allowUnprefixedExpressions) {
+        super(new PrefixedValueSourceWrapper(
+                new ObjectBasedValueSource(root), possiblePrefixes, allowUnprefixedExpressions));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String getLastExpression() {
+        return ((QueryEnabledValueSource) getDelegate()).getLastExpression();
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java
new file mode 100644
index 0000000..d90eb2a
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/ProblemDetectingValueSource.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation;
+
+import java.util.List;
+
+import org.apache.maven.model.building.ModelProblem.Severity;
+import org.apache.maven.model.building.ModelProblem.Version;
+import org.apache.maven.model.building.ModelProblemCollector;
+import org.apache.maven.model.building.ModelProblemCollectorRequest;
+import org.codehaus.plexus.interpolation.ValueSource;
+
+/**
+ * Wraps another value source and intercepts interpolated expressions, checking for problems.
+ *
+ */
+class ProblemDetectingValueSource implements ValueSource {
+
+    private final ValueSource valueSource;
+
+    private final String bannedPrefix;
+
+    private final String newPrefix;
+
+    private final ModelProblemCollector problems;
+
+    ProblemDetectingValueSource(
+            ValueSource valueSource, String bannedPrefix, String newPrefix, ModelProblemCollector problems) {
+        this.valueSource = valueSource;
+        this.bannedPrefix = bannedPrefix;
+        this.newPrefix = newPrefix;
+        this.problems = problems;
+    }
+
+    @Override
+    public Object getValue(String expression) {
+        Object value = valueSource.getValue(expression);
+
+        if (value != null && expression.startsWith(bannedPrefix)) {
+            String msg = "The expression ${" + expression + "} is deprecated.";
+            if (newPrefix != null && newPrefix.length() > 0) {
+                msg += " Please use ${" + newPrefix + expression.substring(bannedPrefix.length()) + "} instead.";
+            }
+            problems.add(new ModelProblemCollectorRequest(Severity.WARNING, Version.V20).setMessage(msg));
+        }
+
+        return value;
+    }
+
+    @Override
+    public List getFeedback() {
+        return valueSource.getFeedback();
+    }
+
+    @Override
+    public void clearFeedback() {
+        valueSource.clearFeedback();
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
deleted file mode 100644
index d996097..0000000
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringSearchModelInterpolator.java
+++ /dev/null
@@ -1,527 +0,0 @@
-package org.apache.maven.model.interpolation;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.building.ModelBuildingRequest;
-import org.apache.maven.model.building.ModelProblem.Severity;
-import org.apache.maven.model.building.ModelProblem.Version;
-import org.apache.maven.model.building.ModelProblemCollector;
-import org.apache.maven.model.building.ModelProblemCollectorRequest;
-import org.apache.maven.model.path.PathTranslator;
-import org.apache.maven.model.path.UrlNormalizer;
-import org.codehaus.plexus.interpolation.InterpolationException;
-import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
-import org.codehaus.plexus.interpolation.RecursionInterceptor;
-import org.codehaus.plexus.interpolation.StringSearchInterpolator;
-import org.codehaus.plexus.interpolation.ValueSource;
-
-import java.io.File;
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import javax.inject.Inject;
-
-/**
- * StringSearchModelInterpolator
- * @deprecated replaced by StringVisitorModelInterpolator (MNG-6697)
- */
-@Deprecated
-public class StringSearchModelInterpolator
-    extends AbstractStringBasedModelInterpolator
-{
-    private static final Map<Class<?>, InterpolateObjectAction.CacheItem> CACHED_ENTRIES =
-        new ConcurrentHashMap<>( 80, 0.75f, 2 );
-    // Empirical data from 3.x, actual =40
-
-    private interface InnerInterpolator
-    {
-        String interpolate( String value );
-    }
-
-    @Inject
-    public StringSearchModelInterpolator( PathTranslator pathTranslator, UrlNormalizer urlNormalizer,
-                                          ModelVersionProcessor processor )
-    {
-        super( pathTranslator, urlNormalizer, processor );
-    }
-
-    @Override
-    public Model interpolateModel( Model model, File projectDir, ModelBuildingRequest config,
-                                   ModelProblemCollector problems )
-    {
-        interpolateObject( model, model, projectDir, config, problems );
-        return model;
-    }
-
-    void interpolateObject( Object obj, Model model, File projectDir, ModelBuildingRequest config,
-                            ModelProblemCollector problems )
-    {
-        List<? extends ValueSource> valueSources = createValueSources( model, projectDir, config );
-        List<? extends InterpolationPostProcessor> postProcessors = createPostProcessors( model, projectDir, config );
-
-        InnerInterpolator innerInterpolator = createInterpolator( valueSources, postProcessors, problems );
-
-        PrivilegedAction<Object> action = new InterpolateObjectAction( obj, innerInterpolator, problems );
-        AccessController.doPrivileged( action );
-    }
-
-    private InnerInterpolator createInterpolator( List<? extends ValueSource> valueSources,
-                                                  List<? extends InterpolationPostProcessor> postProcessors,
-                                                  final ModelProblemCollector problems )
-    {
-        final Map<String, String> cache = new HashMap<>();
-        final StringSearchInterpolator interpolator = new StringSearchInterpolator();
-        interpolator.setCacheAnswers( true );
-        for ( ValueSource vs : valueSources )
-        {
-            interpolator.addValueSource( vs );
-        }
-        for ( InterpolationPostProcessor postProcessor : postProcessors )
-        {
-            interpolator.addPostProcessor( postProcessor );
-        }
-        final RecursionInterceptor recursionInterceptor = createRecursionInterceptor();
-        return value ->
-        {
-            if ( value != null && value.contains( "${" ) )
-            {
-                String c = cache.get( value );
-                if ( c == null )
-                {
-                    try
-                    {
-                        c = interpolator.interpolate( value, recursionInterceptor );
-                    }
-                    catch ( InterpolationException e )
-                    {
-                        problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                                .setMessage( e.getMessage() ).setException( e ) );
-                    }
-                    cache.put( value, c );
-                }
-                return c;
-            }
-            return value;
-        };
-    }
-
-    private static final class InterpolateObjectAction
-        implements PrivilegedAction<Object>
-    {
-        private final LinkedList<Object> interpolationTargets;
-
-        private final InnerInterpolator interpolator;
-
-        private final ModelProblemCollector problems;
-
-        InterpolateObjectAction( Object target, InnerInterpolator interpolator, ModelProblemCollector problems )
-        {
-            this.interpolationTargets = new LinkedList<>();
-            interpolationTargets.add( target );
-            this.interpolator = interpolator;
-            this.problems = problems;
-        }
-
-        @Override
-        public Object run()
-        {
-            while ( !interpolationTargets.isEmpty() )
-            {
-                Object obj = interpolationTargets.removeFirst();
-
-                traverseObjectWithParents( obj.getClass(), obj );
-            }
-            return null;
-        }
-
-        private String interpolate( String value )
-        {
-            return interpolator.interpolate( value );
-        }
-
-        private void traverseObjectWithParents( Class<?> cls, Object target )
-        {
-            if ( cls == null )
-            {
-                return;
-            }
-
-            CacheItem cacheEntry = getCacheEntry( cls );
-            if ( cacheEntry.isArray() )
-            {
-                evaluateArray( target, this );
-            }
-            else if ( cacheEntry.isQualifiedForInterpolation )
-            {
-                cacheEntry.interpolate( target, this );
-
-                traverseObjectWithParents( cls.getSuperclass(), target );
-            }
-        }
-
-        private CacheItem getCacheEntry( Class<?> cls )
-        {
-            CacheItem cacheItem = CACHED_ENTRIES.get( cls );
-            if ( cacheItem == null )
-            {
-                cacheItem = new CacheItem( cls );
-                CACHED_ENTRIES.put( cls, cacheItem );
-            }
-            return cacheItem;
-        }
-
-        private static void evaluateArray( Object target, InterpolateObjectAction ctx )
-        {
-            int len = Array.getLength( target );
-            for ( int i = 0; i < len; i++ )
-            {
-                Object value = Array.get( target, i );
-                if ( value != null )
-                {
-                    if ( String.class == value.getClass() )
-                    {
-                        String interpolated = ctx.interpolate( (String) value );
-
-                        if ( !interpolated.equals( value ) )
-                        {
-                            Array.set( target, i, interpolated );
-                        }
-                    }
-                    else
-                    {
-                        ctx.interpolationTargets.add( value );
-                    }
-                }
-            }
-        }
-
-        private static class CacheItem
-        {
-            private final boolean isArray;
-
-            private final boolean isQualifiedForInterpolation;
-
-            private final CacheField[] fields;
-
-            private boolean isQualifiedForInterpolation( Class<?> cls )
-            {
-                Package pkg = cls.getPackage();
-                if ( pkg == null )
-                {
-                    return true;
-                }
-                String pkgName = pkg.getName();
-                return !pkgName.startsWith( "java." ) && !pkgName.startsWith( "javax." );
-            }
-
-            private boolean isQualifiedForInterpolation( Field field, Class<?> fieldType )
-            {
-                if ( Map.class.equals( fieldType ) && "locations".equals( field.getName() ) )
-                {
-                    return false;
-                }
-                if ( InputLocation.class.equals( fieldType ) )
-                {
-                    return false;
-                }
-
-                //noinspection SimplifiableIfStatement
-                if ( fieldType.isPrimitive() )
-                {
-                    return false;
-                }
-
-                return !"parent".equals( field.getName() );
-            }
-
-            CacheItem( Class clazz )
-            {
-                this.isQualifiedForInterpolation = isQualifiedForInterpolation( clazz );
-                this.isArray = clazz.isArray();
-                List<CacheField> fields = new ArrayList<>();
-                if ( isQualifiedForInterpolation )
-                {
-                    for ( Field currentField : clazz.getDeclaredFields() )
-                    {
-                        Class<?> type = currentField.getType();
-                        if ( isQualifiedForInterpolation( currentField, type ) )
-                        {
-                            if ( String.class == type )
-                            {
-                                if ( !Modifier.isFinal( currentField.getModifiers() ) )
-                                {
-                                    fields.add( new StringField( currentField ) );
-                                }
-                            }
-                            else if ( List.class.isAssignableFrom( type ) )
-                            {
-                                fields.add( new ListField( currentField ) );
-                            }
-                            else if ( Collection.class.isAssignableFrom( type ) )
-                            {
-                                throw new RuntimeException(
-                                        "We dont interpolate into collections, use a list instead" );
-                            }
-                            else if ( Map.class.isAssignableFrom( type ) )
-                            {
-                                fields.add( new MapField( currentField ) );
-                            }
-                            else
-                            {
-                                fields.add( new ObjectField( currentField ) );
-                            }
-                        }
-                    }
-                }
-                this.fields = fields.toArray( new CacheField[0] );
-            }
-
-            void interpolate( Object target, InterpolateObjectAction interpolateObjectAction )
-            {
-                for ( CacheField field : fields )
-                {
-                    field.interpolate( target, interpolateObjectAction );
-                }
-            }
-
-            boolean isArray()
-            {
-                return isArray;
-            }
-        }
-
-        abstract static class CacheField
-        {
-            final Field field;
-
-            CacheField( Field field )
-            {
-                this.field = field;
-                field.setAccessible( true );
-            }
-
-            void interpolate( Object target, InterpolateObjectAction interpolateObjectAction )
-            {
-                try
-                {
-                    doInterpolate( target, interpolateObjectAction );
-                }
-                catch ( IllegalArgumentException e )
-                {
-                    interpolateObjectAction.problems.add(
-                        new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage(
-                            "Failed to interpolate field3: " + field + " on class: "
-                                + field.getType().getName() ).setException(
-                            e ) ); // TODO Not entirely the same message
-                }
-                catch ( IllegalAccessException e )
-                {
-                    interpolateObjectAction.problems.add(
-                        new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE ).setMessage(
-                            "Failed to interpolate field4: " + field + " on class: "
-                                + field.getType().getName() ).setException( e ) );
-                }
-            }
-
-            abstract void doInterpolate( Object target, InterpolateObjectAction ctx )
-                throws IllegalAccessException;
-        }
-
-        static final class StringField
-            extends CacheField
-        {
-            StringField( Field field )
-            {
-                super( field );
-            }
-
-            @Override
-            void doInterpolate( Object target, InterpolateObjectAction ctx )
-                throws IllegalAccessException
-            {
-                String value = (String) field.get( target );
-                if ( value == null )
-                {
-                    return;
-                }
-
-                String interpolated = ctx.interpolate( value );
-
-                if ( interpolated != null && !interpolated.equals( value ) )
-                {
-                    field.set( target, interpolated );
-                }
-            }
-        }
-
-        static final class ListField
-            extends CacheField
-        {
-            ListField( Field field )
-            {
-                super( field );
-            }
-
-            @Override
-            void doInterpolate( Object target, InterpolateObjectAction ctx )
-                throws IllegalAccessException
-            {
-                @SuppressWarnings( "unchecked" ) List<Object> c = (List<Object>) field.get( target );
-                if ( c == null )
-                {
-                    return;
-                }
-
-                for ( int i = 0, size = c.size(); i < size; i++ )
-                {
-                    Object value = c.get( i );
-
-                    if ( value != null )
-                    {
-                        if ( String.class == value.getClass() )
-                        {
-                            String interpolated = ctx.interpolate( (String) value );
-
-                            if ( !interpolated.equals( value ) )
-                            {
-                                try
-                                {
-                                    c.set( i, interpolated );
-                                }
-                                catch ( UnsupportedOperationException e )
-                                {
-                                    return;
-                                }
-                            }
-                        }
-                        else
-                        {
-                            if ( value.getClass().isArray() )
-                            {
-                                evaluateArray( value, ctx );
-                            }
-                            else
-                            {
-                                ctx.interpolationTargets.add( value );
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        static final class MapField
-            extends CacheField
-        {
-            MapField( Field field )
-            {
-                super( field );
-            }
-
-            @Override
-            void doInterpolate( Object target, InterpolateObjectAction ctx )
-                throws IllegalAccessException
-            {
-                @SuppressWarnings( "unchecked" ) Map<Object, Object> m = (Map<Object, Object>) field.get( target );
-                if ( m == null || m.isEmpty() )
-                {
-                    return;
-                }
-
-                for ( Map.Entry<Object, Object> entry : m.entrySet() )
-                {
-                    Object value = entry.getValue();
-
-                    if ( value == null )
-                    {
-                        continue;
-                    }
-
-                    if ( String.class == value.getClass() )
-                    {
-                        String interpolated = ctx.interpolate( (String) value );
-
-                        if ( interpolated != null && !interpolated.equals( value ) )
-                        {
-                            try
-                            {
-                                entry.setValue( interpolated );
-                            }
-                            catch ( UnsupportedOperationException ignore )
-                            {
-                                // nop
-                            }
-                        }
-                    }
-                    else if ( value.getClass().isArray() )
-                    {
-                        evaluateArray( value, ctx );
-                    }
-                    else
-                    {
-                        ctx.interpolationTargets.add( value );
-                    }
-                }
-            }
-        }
-
-        static final class ObjectField
-            extends CacheField
-        {
-            private final boolean isArray;
-
-            ObjectField( Field field )
-            {
-                super( field );
-                this.isArray = field.getType().isArray();
-            }
-
-            @Override
-            void doInterpolate( Object target, InterpolateObjectAction ctx )
-                throws IllegalAccessException
-            {
-                Object value = field.get( target );
-                if ( value != null )
-                {
-                    if ( isArray )
-                    {
-                        evaluateArray( value, ctx );
-                    }
-                    else
-                    {
-                        ctx.interpolationTargets.add( value );
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java
index 3ba48ec..ae1d617 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,55 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-import java.util.Properties;
+package org.apache.maven.model.interpolation;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.maven.model.Activation;
-import org.apache.maven.model.ActivationFile;
-import org.apache.maven.model.ActivationOS;
-import org.apache.maven.model.ActivationProperty;
-import org.apache.maven.model.Build;
-import org.apache.maven.model.BuildBase;
-import org.apache.maven.model.CiManagement;
-import org.apache.maven.model.Contributor;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.Developer;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Exclusion;
-import org.apache.maven.model.Extension;
-import org.apache.maven.model.IssueManagement;
-import org.apache.maven.model.License;
-import org.apache.maven.model.MailingList;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.ModelBase;
-import org.apache.maven.model.Notifier;
-import org.apache.maven.model.Organization;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.PluginManagement;
-import org.apache.maven.model.Prerequisites;
-import org.apache.maven.model.Profile;
-import org.apache.maven.model.Relocation;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Reporting;
-import org.apache.maven.model.Repository;
-import org.apache.maven.model.RepositoryBase;
-import org.apache.maven.model.RepositoryPolicy;
-import org.apache.maven.model.Resource;
-import org.apache.maven.model.Scm;
-import org.apache.maven.model.Site;
+import java.io.File;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblem.Severity;
 import org.apache.maven.model.building.ModelProblem.Version;
@@ -74,12 +35,13 @@
 import org.apache.maven.model.building.ModelProblemCollectorRequest;
 import org.apache.maven.model.path.PathTranslator;
 import org.apache.maven.model.path.UrlNormalizer;
+import org.apache.maven.model.root.RootLocator;
+import org.apache.maven.model.v4.MavenTransformer;
 import org.codehaus.plexus.interpolation.InterpolationException;
 import org.codehaus.plexus.interpolation.InterpolationPostProcessor;
 import org.codehaus.plexus.interpolation.RecursionInterceptor;
 import org.codehaus.plexus.interpolation.StringSearchInterpolator;
 import org.codehaus.plexus.interpolation.ValueSource;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * StringVisitorModelInterpolator
@@ -88,1377 +50,59 @@
  */
 @Named
 @Singleton
-public class StringVisitorModelInterpolator
-    extends AbstractStringBasedModelInterpolator
-{
+public class StringVisitorModelInterpolator extends AbstractStringBasedModelInterpolator {
     @Inject
-    public StringVisitorModelInterpolator( PathTranslator pathTranslator, UrlNormalizer urlNormalizer,
-                                           ModelVersionProcessor processor )
-    {
-        super( pathTranslator, urlNormalizer, processor );
+    public StringVisitorModelInterpolator(
+            PathTranslator pathTranslator, UrlNormalizer urlNormalizer, RootLocator rootLocator) {
+        super(pathTranslator, urlNormalizer, rootLocator);
     }
 
-    interface InnerInterpolator
-    {
-        String interpolate( String value );
+    interface InnerInterpolator {
+        String interpolate(String value);
     }
 
     @Override
-    public Model interpolateModel( Model model, File projectDir, ModelBuildingRequest config,
-                                   ModelProblemCollector problems )
-    {
-        List<? extends ValueSource> valueSources = createValueSources( model, projectDir, config );
-        List<? extends InterpolationPostProcessor> postProcessors =
-            createPostProcessors( model, projectDir, config );
+    public Model interpolateModel(
+            Model model, File projectDir, ModelBuildingRequest config, ModelProblemCollector problems) {
+        List<? extends ValueSource> valueSources = createValueSources(model, projectDir, config, problems);
+        List<? extends InterpolationPostProcessor> postProcessors = createPostProcessors(model, projectDir, config);
 
-        InnerInterpolator innerInterpolator = createInterpolator( valueSources, postProcessors, problems );
+        InnerInterpolator innerInterpolator = createInterpolator(valueSources, postProcessors, problems, config);
 
-        new ModelVisitor( innerInterpolator ).visit( model );
-
-        return model;
+        return new MavenTransformer(innerInterpolator::interpolate).visit(model);
     }
 
-    private InnerInterpolator createInterpolator( List<? extends ValueSource> valueSources,
-                                                  List<? extends InterpolationPostProcessor> postProcessors,
-                                                  final ModelProblemCollector problems )
-    {
+    private InnerInterpolator createInterpolator(
+            List<? extends ValueSource> valueSources,
+            List<? extends InterpolationPostProcessor> postProcessors,
+            final ModelProblemCollector problems,
+            ModelBuildingRequest config) {
         final Map<String, String> cache = new HashMap<>();
         final StringSearchInterpolator interpolator = new StringSearchInterpolator();
-        interpolator.setCacheAnswers( true );
-        for ( ValueSource vs : valueSources )
-        {
-            interpolator.addValueSource( vs );
+        interpolator.setCacheAnswers(true);
+        for (ValueSource vs : valueSources) {
+            interpolator.addValueSource(vs);
         }
-        for ( InterpolationPostProcessor postProcessor : postProcessors )
-        {
-            interpolator.addPostProcessor( postProcessor );
+        for (InterpolationPostProcessor postProcessor : postProcessors) {
+            interpolator.addPostProcessor(postProcessor);
         }
-        final RecursionInterceptor recursionInterceptor = createRecursionInterceptor();
-        return value ->
-        {
-            if ( value != null && value.contains( "${" ) )
-            {
-                String c = cache.get( value );
-                if ( c == null )
-                {
-                    try
-                    {
-                        c = interpolator.interpolate( value, recursionInterceptor );
+        final RecursionInterceptor recursionInterceptor = createRecursionInterceptor(config);
+        return value -> {
+            if (value != null && value.contains("${")) {
+                String c = cache.get(value);
+                if (c == null) {
+                    try {
+                        c = interpolator.interpolate(value, recursionInterceptor);
+                    } catch (InterpolationException e) {
+                        problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                                .setMessage(e.getMessage())
+                                .setException(e));
                     }
-                    catch ( InterpolationException e )
-                    {
-                        problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                                .setMessage( e.getMessage() ).setException( e ) );
-                    }
-                    cache.put( value, c );
+                    cache.put(value, c);
                 }
                 return c;
             }
             return value;
         };
     }
-
-    @SuppressWarnings( "StringEquality" )
-    private static final class ModelVisitor
-    {
-        private final InnerInterpolator interpolator;
-
-        ModelVisitor( InnerInterpolator interpolator )
-        {
-            this.interpolator = interpolator;
-        }
-
-        void visit( Model model )
-        {
-            if ( model != null )
-            {
-                visit( (ModelBase) model );
-                // ModelVersion
-                String orgModelVersion = model.getModelVersion();
-                String intModelVersion = interpolate( orgModelVersion );
-                if ( orgModelVersion != intModelVersion )
-                {
-                    model.setModelVersion( intModelVersion );
-                }
-                visit( model.getParent() );
-                // GroupId
-                String orgGroupId = model.getGroupId();
-                String intGroupId = interpolate( orgGroupId );
-                if ( orgGroupId != intGroupId )
-                {
-                    model.setGroupId( intGroupId );
-                }
-                // ArtifactId
-                String orgArtifactId = model.getArtifactId();
-                String intArtifactId = interpolate( orgArtifactId );
-                if ( orgArtifactId != intArtifactId )
-                {
-                    model.setArtifactId( intArtifactId );
-                }
-                // Version
-                String orgVersion = model.getVersion();
-                String intVersion = interpolate( orgVersion );
-                if ( orgVersion != intVersion )
-                {
-                    model.setVersion( intVersion );
-                }
-
-                // Packaging
-                String orgPackaging = model.getPackaging();
-                String intPackaging = interpolate( orgPackaging );
-                if ( orgPackaging != intPackaging )
-                {
-                    model.setPackaging( intPackaging );
-                }
-                // Name
-                String orgName = model.getName();
-                String intName = interpolate( orgName );
-                if ( orgName != intName )
-                {
-                    model.setName( intName );
-                }
-                // Description
-                String orgDescription = model.getDescription();
-                String intDescription = interpolate( orgDescription );
-                if ( orgDescription != intDescription )
-                {
-                    model.setDescription( intDescription );
-                }
-                // Url
-                String orgUrl = model.getUrl();
-                String intUrl = interpolate( orgUrl );
-                if ( orgUrl != intUrl )
-                {
-                    model.setUrl( intUrl );
-                }
-                // ChildProjectUrlInheritAppendPath
-                String orgChildProjectUrlInheritAppendPath = model.getChildProjectUrlInheritAppendPath();
-                String intChildProjectUrlInheritAppendPath = interpolate( orgChildProjectUrlInheritAppendPath );
-                if ( orgChildProjectUrlInheritAppendPath != intChildProjectUrlInheritAppendPath )
-                {
-                    model.setChildProjectUrlInheritAppendPath( intChildProjectUrlInheritAppendPath );
-                }
-                // InceptionYear
-                String orgInceptionYear = model.getInceptionYear();
-                String intInceptionYear = interpolate( orgInceptionYear );
-                if ( orgInceptionYear != intInceptionYear )
-                {
-                    model.setInceptionYear( intInceptionYear );
-                }
-                visit( model.getOrganization() );
-                for ( License license : model.getLicenses() )
-                {
-                    visit( license );
-                }
-                for ( Developer developer : model.getDevelopers() )
-                {
-                    visit( developer );
-                }
-                for ( Contributor contributor : model.getContributors() )
-                {
-                    visit( contributor );
-                }
-                for ( MailingList mailingList : model.getMailingLists() )
-                {
-                    visit( mailingList );
-                }
-                visit( model.getPrerequisites() );
-                visit( model.getScm() );
-                visit( model.getIssueManagement() );
-                visit( model.getCiManagement() );
-                visit( model.getBuild() );
-                for ( Profile profile : model.getProfiles() )
-                {
-                    visit( profile );
-                }
-
-            }
-        }
-
-        private void visit( Parent parent )
-        {
-            if ( parent != null )
-            {
-                String org, val;
-                // GroupId
-                org = parent.getGroupId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    parent.setGroupId( val );
-                }
-                // ArtifactId
-                org = parent.getArtifactId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    parent.setArtifactId( val );
-                }
-                // Version
-                org = parent.getVersion();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    parent.setVersion( val );
-                }
-                // RelativePath
-                org = parent.getRelativePath();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    parent.setRelativePath( val );
-                }
-            }
-        }
-
-        private void visit( Organization organization )
-        {
-            if ( organization != null )
-            {
-                String org, val;
-                // Name
-                org = organization.getName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    organization.setName( val );
-                }
-                // Url
-                org = organization.getUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    organization.setUrl( val );
-                }
-            }
-        }
-
-        private void visit( License license )
-        {
-            if ( license != null )
-            {
-                String org, val;
-                // Name
-                org = license.getName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    license.setName( val );
-                }
-                // Url
-                org = license.getUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    license.setUrl( val );
-                }
-                // Distribution
-                org = license.getDistribution();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    license.setDistribution( val );
-                }
-                // Comments
-                org = license.getComments();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    license.setComments( val );
-                }
-            }
-        }
-
-        private void visit( Developer developer )
-        {
-            if ( developer != null )
-            {
-                String org, val;
-                // Contributor
-                visit( (Contributor) developer );
-                // Distribution
-                org = developer.getId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    developer.setId( val );
-                }
-            }
-        }
-
-        private void visit( Contributor contributor )
-        {
-            if ( contributor != null )
-            {
-                String org, val;
-                // Name
-                org = contributor.getName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    contributor.setName( val );
-                }
-                // Email
-                org = contributor.getEmail();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    contributor.setEmail( val );
-                }
-                // Url
-                org = contributor.getUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    contributor.setUrl( val );
-                }
-                // Organization
-                org = contributor.getOrganization();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    contributor.setOrganization( val );
-                }
-                // OrganizationUrl
-                org = contributor.getOrganizationUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    contributor.setOrganizationUrl( val );
-                }
-                // Roles
-                visit( contributor.getRoles() );
-            }
-        }
-
-        private void visit( MailingList mailingList )
-        {
-            if ( mailingList != null )
-            {
-                String org, val;
-                // Name
-                org = mailingList.getName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    mailingList.setName( val );
-                }
-                // Subscribe
-                org = mailingList.getSubscribe();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    mailingList.setSubscribe( val );
-                }
-                // Unsubscribe
-                org = mailingList.getUnsubscribe();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    mailingList.setUnsubscribe( val );
-                }
-                // Post
-                org = mailingList.getPost();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    mailingList.setPost( val );
-                }
-                // Archive
-                org = mailingList.getArchive();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    mailingList.setArchive( val );
-                }
-            }
-        }
-
-        private void visit( Prerequisites prerequisites )
-        {
-            if ( prerequisites != null )
-            {
-                String org, val;
-                // Maven
-                org = prerequisites.getMaven();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    prerequisites.setMaven( val );
-                }
-            }
-        }
-
-        private void visit( Scm scm )
-        {
-            if ( scm != null )
-            {
-                String org, val;
-                // Connection
-                org = scm.getConnection();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    scm.setConnection( val );
-                }
-                // DeveloperConnection
-                org = scm.getDeveloperConnection();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    scm.setDeveloperConnection( val );
-                }
-                // Tag
-                org = scm.getTag();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    scm.setTag( val );
-                }
-                // Url
-                org = scm.getUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    scm.setUrl( val );
-                }
-                // ChildScmConnectionInheritAppendPath
-                org = scm.getChildScmConnectionInheritAppendPath();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    scm.setChildScmConnectionInheritAppendPath( val );
-                }
-                // ChildScmDeveloperConnectionInheritAppendPath
-                org = scm.getChildScmDeveloperConnectionInheritAppendPath();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    scm.setChildScmDeveloperConnectionInheritAppendPath( val );
-                }
-                // ChildScmUrlInheritAppendPath
-                org = scm.getChildScmUrlInheritAppendPath();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    scm.setChildScmUrlInheritAppendPath( val );
-                }
-            }
-        }
-
-        private void visit( IssueManagement issueManagement )
-        {
-            if ( issueManagement != null )
-            {
-                String org, val;
-                // System
-                org = issueManagement.getSystem();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    issueManagement.setSystem( val );
-                }
-                // Url
-                org = issueManagement.getUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    issueManagement.setUrl( val );
-                }
-            }
-        }
-
-        private void visit( CiManagement ciManagement )
-        {
-            if ( ciManagement != null )
-            {
-                String org, val;
-                // System
-                org = ciManagement.getSystem();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    ciManagement.setSystem( val );
-                }
-                // Url
-                org = ciManagement.getUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    ciManagement.setUrl( val );
-                }
-                // Notifiers
-                for ( Notifier notifier : ciManagement.getNotifiers() )
-                {
-                    visit( notifier );
-                }
-            }
-        }
-
-        private void visit( Notifier notifier )
-        {
-            if ( notifier != null )
-            {
-                String org, val;
-                // Type
-                org = notifier.getType();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    notifier.setType( val );
-                }
-                // Configuration
-                visit( notifier.getConfiguration() );
-            }
-        }
-
-        private void visit( BuildBase build )
-        {
-            if ( build != null )
-            {
-                String org, val;
-                // Plugins
-                for ( Plugin plugin : build.getPlugins() )
-                {
-                    visit( plugin );
-                }
-                // PluginManagement
-                visit( build.getPluginManagement() );
-                // DefaultGoal
-                org = build.getDefaultGoal();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setDefaultGoal( val );
-                }
-                // Resources
-                for ( Resource resource : build.getResources() )
-                {
-                    visit( resource );
-                }
-                // TestResources
-                for ( Resource resource : build.getTestResources() )
-                {
-                    visit( resource );
-                }
-                // Directory
-                org = build.getDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setDirectory( val );
-                }
-                // FinalName
-                org = build.getFinalName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setFinalName( val );
-                }
-                // Filters
-                visit( build.getFilters() );
-            }
-        }
-
-        private void visit( PluginManagement pluginManagement )
-        {
-            if ( pluginManagement != null )
-            {
-                for ( Plugin plugin : pluginManagement.getPlugins() )
-                {
-                    visit( plugin );
-                }
-            }
-        }
-
-        private void visit( Build build )
-        {
-            if ( build != null )
-            {
-                String org, val;
-                // BuildBase
-                visit( (BuildBase) build );
-                // SourceDirectory
-                org = build.getSourceDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setSourceDirectory( val );
-                }
-                // ScriptSourceDirectory
-                org = build.getScriptSourceDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setScriptSourceDirectory( val );
-                }
-                // TestSourceDirectory
-                org = build.getTestSourceDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setTestSourceDirectory( val );
-                }
-                // OutputDirectory
-                org = build.getOutputDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setOutputDirectory( val );
-                }
-                // TestOutputDirectory
-                org = build.getTestOutputDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    build.setTestOutputDirectory( val );
-                }
-                // Extensions
-                for ( Extension extension : build.getExtensions() )
-                {
-                    visit( extension );
-                }
-            }
-        }
-
-        private void visit( Resource resource )
-        {
-            if ( resource != null )
-            {
-                String org, val;
-                // Includes
-                visit( resource.getIncludes() );
-                // Excludes
-                visit( resource.getExcludes() );
-                // Directory
-                org = resource.getDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    resource.setDirectory( val );
-                }
-                // TargetPath
-                org = resource.getTargetPath();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    resource.setTargetPath( val );
-                }
-                // Filtering
-                org = resource.getFiltering();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    resource.setFiltering( val );
-                }
-            }
-        }
-
-        private void visit( Plugin plugin )
-        {
-            if ( plugin != null )
-            {
-                String org, val;
-                // Inherited
-                org = plugin.getInherited();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setInherited( val );
-                }
-                // Configuration
-                visit( (Xpp3Dom) plugin.getConfiguration() );
-                // GroupId
-                org = plugin.getGroupId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setGroupId( val );
-                }
-                // ArtifactId
-                org = plugin.getArtifactId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setArtifactId( val );
-                }
-                // Version
-                org = plugin.getVersion();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setVersion( val );
-                }
-                // Extensions
-                org = plugin.getExtensions();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setExtensions( val );
-                }
-                // Executions
-                for ( PluginExecution execution : plugin.getExecutions() )
-                {
-                    visit( execution );
-                }
-                // Dependencies
-                for ( Dependency dependency : plugin.getDependencies() )
-                {
-                    visit( dependency );
-                }
-            }
-        }
-
-        private void visit( PluginExecution execution )
-        {
-            if ( execution != null )
-            {
-                String org, val;
-                // Inherited
-                org = execution.getInherited();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    execution.setInherited( val );
-                }
-                // Configuration
-                visit( (Xpp3Dom) execution.getConfiguration() );
-                // Id
-                org = execution.getId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    execution.setId( val );
-                }
-                // Phase
-                org = execution.getPhase();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    execution.setPhase( val );
-                }
-                // Goals
-                visit( execution.getGoals() );
-            }
-        }
-
-        private void visit( Xpp3Dom dom )
-        {
-            if ( dom != null )
-            {
-                String org, val;
-                // Content
-                org = dom.getValue();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dom.setValue( val );
-                }
-                // Attributes
-                for ( String attr : dom.getAttributeNames() )
-                {
-                    org = dom.getAttribute( attr );
-                    val = interpolate( org );
-                    if ( org != val )
-                    {
-                        dom.setAttribute( attr, val );
-                    }
-                }
-                // Children
-                for ( int i = 0, l = dom.getChildCount(); i < l; i++ )
-                {
-                    visit( dom.getChild( i ) );
-                }
-            }
-        }
-
-        private void visit( Extension extension )
-        {
-            if ( extension != null )
-            {
-                String org, val;
-                // GroupId
-                org = extension.getGroupId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    extension.setGroupId( val );
-                }
-                // ArtifactId
-                org = extension.getArtifactId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    extension.setArtifactId( val );
-                }
-                // Version
-                org = extension.getVersion();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    extension.setVersion( val );
-                }
-            }
-        }
-
-        private void visit( Profile profile )
-        {
-            if ( profile != null )
-            {
-                String org, val;
-                // ModelBase
-                visit( (ModelBase) profile );
-                // Id
-                org = profile.getId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    profile.setId( val );
-                }
-                // Activation
-                visit( profile.getActivation() );
-                // Build
-                visit( profile.getBuild() );
-            }
-        }
-
-        private void visit( Activation activation )
-        {
-            if ( activation != null )
-            {
-                String org, val;
-                // Jdk
-                org = activation.getJdk();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activation.setJdk( val );
-                }
-                // OS
-                visit( activation.getOs() );
-                // Property
-                visit( activation.getProperty() );
-                // File
-                visit( activation.getFile() );
-            }
-        }
-
-        private void visit( ActivationOS activationOS )
-        {
-            if ( activationOS != null )
-            {
-                String org, val;
-                // Name
-                org = activationOS.getName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationOS.setName( val );
-                }
-                // Family
-                org = activationOS.getFamily();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationOS.setFamily( val );
-                }
-                // Arch
-                org = activationOS.getArch();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationOS.setArch( val );
-                }
-                // Version
-                org = activationOS.getVersion();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationOS.setVersion( val );
-                }
-            }
-        }
-
-        private void visit( ActivationProperty activationProperty )
-        {
-            if ( activationProperty != null )
-            {
-                String org, val;
-                // Name
-                org = activationProperty.getName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationProperty.setName( val );
-                }
-                // Value
-                org = activationProperty.getValue();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationProperty.setValue( val );
-                }
-            }
-        }
-
-        private void visit( ActivationFile activationFile )
-        {
-            if ( activationFile != null )
-            {
-                String org, val;
-                // Missing
-                org = activationFile.getMissing();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationFile.setMissing( val );
-                }
-                // Exists
-                org = activationFile.getExists();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    activationFile.setExists( val );
-                }
-            }
-        }
-
-        private void visit( ModelBase modelBase )
-        {
-            if ( modelBase != null )
-            {
-                visit( modelBase.getModules() );
-                visit( modelBase.getDistributionManagement() );
-                visit( modelBase.getProperties() );
-                visit( modelBase.getDependencyManagement() );
-                for ( Dependency dependency : modelBase.getDependencies() )
-                {
-                    visit( dependency );
-                }
-                for ( Repository repository : modelBase.getRepositories() )
-                {
-                    visit( repository );
-                }
-                for ( Repository repository : modelBase.getPluginRepositories() )
-                {
-                    visit( repository );
-                }
-                visit( modelBase.getReporting() );
-            }
-        }
-
-        private void visit( DistributionManagement distributionManagement )
-        {
-            if ( distributionManagement != null )
-            {
-                String org, val;
-                // Repository
-                visit( distributionManagement.getRepository() );
-                // SnapshotRepository
-                visit( distributionManagement.getSnapshotRepository() );
-                // Site
-                visit( distributionManagement.getSite() );
-                // DownloadUrl
-                org = distributionManagement.getDownloadUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    distributionManagement.setDownloadUrl( val );
-                }
-                // Relocation
-                visit( distributionManagement.getRelocation() );
-            }
-        }
-
-        private void visit( Site site )
-        {
-            if ( site != null )
-            {
-                String org, val;
-                // Id
-                org = site.getId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    site.setId( val );
-                }
-                // Name
-                org = site.getName();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    site.setName( val );
-                }
-                // Url
-                org = site.getUrl();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    site.setUrl( val );
-                }
-                // ChildSiteUrlInheritAppendPath
-                org = site.getChildSiteUrlInheritAppendPath();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    site.setChildSiteUrlInheritAppendPath( val );
-                }
-            }
-        }
-
-        private void visit( Relocation relocation )
-        {
-            if ( relocation != null )
-            {
-                String org, val;
-                // GroupId
-                org = relocation.getGroupId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    relocation.setGroupId( val );
-                }
-                // ArtifactId
-                org = relocation.getArtifactId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    relocation.setArtifactId( val );
-                }
-                // Version
-                org = relocation.getVersion();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    relocation.setVersion( val );
-                }
-                // Message
-                org = relocation.getMessage();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    relocation.setMessage( val );
-                }
-            }
-        }
-
-        private void visit( DependencyManagement dependencyManagement )
-        {
-            if ( dependencyManagement != null )
-            {
-                // Dependencies
-                for ( Dependency dependency : dependencyManagement.getDependencies() )
-                {
-                    visit( dependency );
-                }
-            }
-        }
-
-        private void visit( Repository repository )
-        {
-            if ( repository != null )
-            {
-                visit( (RepositoryBase) repository );
-                visit( repository.getReleases() );
-                visit( repository.getSnapshots() );
-            }
-        }
-
-        private void visit( RepositoryBase repositoryBase )
-        {
-            if ( repositoryBase != null )
-            {
-                // Id
-                String orgId = repositoryBase.getId();
-                String intId = interpolate( orgId );
-                if ( orgId != intId )
-                {
-                    repositoryBase.setId( intId );
-                }
-                // Name
-                String orgName = repositoryBase.getName();
-                String intName = interpolate( orgName );
-                if ( orgName != intName )
-                {
-                    repositoryBase.setName( intName );
-                }
-                // Url
-                String orgUrl = repositoryBase.getUrl();
-                String intUrl = interpolate( orgUrl );
-                if ( orgUrl != intUrl )
-                {
-                    repositoryBase.setUrl( intUrl );
-                }
-                // Layout
-                String orgLayout = repositoryBase.getLayout();
-                String intLayout = interpolate( orgLayout );
-                if ( orgLayout != intLayout )
-                {
-                    repositoryBase.setLayout( intLayout );
-                }
-            }
-        }
-
-        private void visit( RepositoryPolicy repositoryPolicy )
-        {
-            if ( repositoryPolicy != null )
-            {
-                // Enabled
-                String orgEnabled = repositoryPolicy.getEnabled();
-                String intEnabled = interpolate( orgEnabled );
-                if ( orgEnabled != intEnabled )
-                {
-                    repositoryPolicy.setEnabled( intEnabled );
-                }
-                // UpdatePolicy
-                String orgUpdatePolicy = repositoryPolicy.getUpdatePolicy();
-                String intUpdatePolicy = interpolate( orgUpdatePolicy );
-                if ( orgUpdatePolicy != intUpdatePolicy )
-                {
-                    repositoryPolicy.setUpdatePolicy( intUpdatePolicy );
-                }
-                // ChecksumPolicy
-                String orgChecksumPolicy = repositoryPolicy.getChecksumPolicy();
-                String intChecksumPolicy = interpolate( orgChecksumPolicy );
-                if ( orgChecksumPolicy != intChecksumPolicy )
-                {
-                    repositoryPolicy.setChecksumPolicy( intChecksumPolicy );
-                }
-            }
-        }
-
-        private void visit( Dependency dependency )
-        {
-            if ( dependency != null )
-            {
-                String org, val;
-                // GroupId
-                org = dependency.getGroupId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setGroupId( val );
-                    dependency.clearManagementKey();
-                }
-                // ArtifactId
-                org = dependency.getArtifactId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setArtifactId( val );
-                    dependency.clearManagementKey();
-                }
-                // Version
-                org = dependency.getVersion();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setVersion( val );
-                }
-                // Type
-                org = dependency.getType();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setType( val );
-                    dependency.clearManagementKey();
-                }
-                // Classifier
-                org = dependency.getClassifier();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setClassifier( val );
-                    dependency.clearManagementKey();
-                }
-                // Scope
-                org = dependency.getScope();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setScope( val );
-                }
-                // SystemPath
-                org = dependency.getSystemPath();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setSystemPath( val );
-                }
-                // Exclusions
-                for ( Exclusion exclusion : dependency.getExclusions() )
-                {
-                    visit( exclusion );
-                }
-                // Optional
-                org = dependency.getOptional();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    dependency.setOptional( val );
-                }
-            }
-        }
-
-        private void visit( Exclusion exclusion )
-        {
-            if ( exclusion != null )
-            {
-                String org, val;
-                // GroupId
-                org = exclusion.getGroupId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    exclusion.setGroupId( val );
-                }
-                // ArtifactId
-                org = exclusion.getArtifactId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    exclusion.setArtifactId( val );
-                }
-            }
-        }
-
-        private void visit( Reporting reporting )
-        {
-            if ( reporting != null )
-            {
-                String org, val;
-                // ExcludeDefaults
-                org = reporting.getExcludeDefaults();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    reporting.setExcludeDefaults( val );
-                }
-                // OutputDirectory
-                org = reporting.getOutputDirectory();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    reporting.setOutputDirectory( val );
-                }
-                // Plugins
-                for ( ReportPlugin plugin : reporting.getPlugins() )
-                {
-                    visit( plugin );
-                }
-            }
-        }
-
-        private void visit( ReportPlugin plugin )
-        {
-            if ( plugin != null )
-            {
-                String org, val;
-                // Inherited
-                org = plugin.getInherited();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setInherited( val );
-                }
-                // Configuration
-                visit( (Xpp3Dom) plugin.getConfiguration() );
-                // GroupId
-                org = plugin.getGroupId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setGroupId( val );
-                }
-                // ArtifactId
-                org = plugin.getArtifactId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setArtifactId( val );
-                }
-                // Version
-                org = plugin.getVersion();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    plugin.setVersion( val );
-                }
-                // ReportSets
-                for ( ReportSet reportSet : plugin.getReportSets() )
-                {
-                    visit( reportSet );
-                }
-            }
-        }
-
-        private void visit( ReportSet reportSet )
-        {
-            if ( reportSet != null )
-            {
-                String org, val;
-                // Inherited
-                org = reportSet.getInherited();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    reportSet.setInherited( val );
-                }
-                // Configuration
-                visit( (Xpp3Dom) reportSet.getConfiguration() );
-                // Id
-                org = reportSet.getId();
-                val = interpolate( org );
-                if ( org != val )
-                {
-                    reportSet.setId( val );
-                }
-                // Reports
-                visit( reportSet.getReports() );
-            }
-        }
-
-        private void visit( Properties properties )
-        {
-            if ( properties != null )
-            {
-                for ( Map.Entry<Object, Object> entry : properties.entrySet() )
-                {
-                    Object v = entry.getValue();
-                    if ( v instanceof String )
-                    {
-                        String value = (String) v;
-                        String inter = interpolate( value );
-                        if ( value != inter && inter != null )
-                        {
-                            entry.setValue( inter );
-                        }
-                    }
-                }
-            }
-        }
-
-        private void visit( List<String> list )
-        {
-            if ( list != null )
-            {
-                ListIterator<String> it = list.listIterator();
-                while ( it.hasNext() )
-                {
-                    String value = it.next();
-                    String inter = interpolate( value );
-                    if ( value != inter )
-                    {
-                        it.set( inter );
-                    }
-                }
-            }
-        }
-
-        private String interpolate( String value )
-        {
-            return interpolator.interpolate( value );
-        }
-
-    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/UrlNormalizingPostProcessor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/UrlNormalizingPostProcessor.java
index 14beeac..2c47ab5 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/UrlNormalizingPostProcessor.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/UrlNormalizingPostProcessor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
 
 import java.util.HashSet;
 import java.util.Set;
@@ -28,42 +27,34 @@
 /**
  * Ensures that expressions referring to URLs evaluate to normalized URLs.
  *
- * @author Benjamin Bentmann
  */
-class UrlNormalizingPostProcessor
-    implements InterpolationPostProcessor
-{
+class UrlNormalizingPostProcessor implements InterpolationPostProcessor {
 
     private static final Set<String> URL_EXPRESSIONS;
 
-    static
-    {
+    static {
         Set<String> expressions = new HashSet<>();
-        expressions.add( "project.url" );
-        expressions.add( "project.scm.url" );
-        expressions.add( "project.scm.connection" );
-        expressions.add( "project.scm.developerConnection" );
-        expressions.add( "project.distributionManagement.site.url" );
+        expressions.add("project.url");
+        expressions.add("project.scm.url");
+        expressions.add("project.scm.connection");
+        expressions.add("project.scm.developerConnection");
+        expressions.add("project.distributionManagement.site.url");
 
         URL_EXPRESSIONS = expressions;
     }
 
     private UrlNormalizer normalizer;
 
-    UrlNormalizingPostProcessor( UrlNormalizer normalizer )
-    {
+    UrlNormalizingPostProcessor(UrlNormalizer normalizer) {
         this.normalizer = normalizer;
     }
 
     @Override
-    public Object execute( String expression, Object value )
-    {
-        if ( value != null && URL_EXPRESSIONS.contains( expression ) )
-        {
-            return normalizer.normalize( value.toString() );
+    public Object execute(String expression, Object value) {
+        if (value != null && URL_EXPRESSIONS.contains(expression)) {
+            return normalizer.normalize(value.toString());
         }
 
         return null;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/ClassMap.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/ClassMap.java
new file mode 100644
index 0000000..743875e
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/ClassMap.java
@@ -0,0 +1,388 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation.reflection;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * A cache of introspection information for a specific class instance.
+ * Keys {@link Method} objects by a concatenation of the
+ * method name and the names of classes that make up the parameters.
+ */
+class ClassMap {
+    private static final class CacheMiss {}
+
+    private static final CacheMiss CACHE_MISS = new CacheMiss();
+
+    private static final Object OBJECT = new Object();
+
+    /**
+     * Class passed into the constructor used to as
+     * the basis for the Method map.
+     */
+    private final Class<?> clazz;
+
+    /**
+     * Cache of Methods, or CACHE_MISS, keyed by method
+     * name and actual arguments used to find it.
+     */
+    private final Map<String, Object> methodCache = new Hashtable<>();
+
+    private MethodMap methodMap = new MethodMap();
+
+    /**
+     * Standard constructor
+     * @param clazz The class.
+     */
+    ClassMap(Class<?> clazz) {
+        this.clazz = clazz;
+        populateMethodCache();
+    }
+
+    /**
+     * @return the class object whose methods are cached by this map.
+     */
+    Class<?> getCachedClass() {
+        return clazz;
+    }
+
+    /**
+     * <p>Find a Method using the methodKey provided.</p>
+     * <p>Look in the methodMap for an entry. If found,
+     * it'll either be a CACHE_MISS, in which case we
+     * simply give up, or it'll be a Method, in which
+     * case, we return it.</p>
+     * <p>If nothing is found, then we must actually go
+     * and introspect the method from the MethodMap.</p>
+     * @param name Method name.
+     * @param params Method parameters.
+     * @return The found method.
+     * @throws MethodMap.AmbiguousException in case of duplicate methods.
+     */
+    public Method findMethod(String name, Object... params) throws MethodMap.AmbiguousException {
+        String methodKey = makeMethodKey(name, params);
+        Object cacheEntry = methodCache.get(methodKey);
+
+        if (cacheEntry == CACHE_MISS) {
+            return null;
+        }
+
+        if (cacheEntry == null) {
+            try {
+                cacheEntry = methodMap.find(name, params);
+            } catch (MethodMap.AmbiguousException ae) {
+                // that's a miss :)
+                methodCache.put(methodKey, CACHE_MISS);
+                throw ae;
+            }
+
+            if (cacheEntry == null) {
+                methodCache.put(methodKey, CACHE_MISS);
+            } else {
+                methodCache.put(methodKey, cacheEntry);
+            }
+        }
+
+        // Yes, this might just be null.
+        return (Method) cacheEntry;
+    }
+
+    /**
+     * Populate the Map of direct hits. These
+     * are taken from all the public methods
+     * that our class provides.
+     */
+    private void populateMethodCache() {
+        // get all publicly accessible methods
+        Method[] methods = getAccessibleMethods(clazz);
+
+        // map and cache them
+        for (Method method : methods) {
+            // now get the 'public method', the method declared by a
+            // public interface or class (because the actual implementing
+            // class may be a facade...)
+
+            Method publicMethod = getPublicMethod(method);
+
+            // it is entirely possible that there is no public method for
+            // the methods of this class (i.e. in the facade, a method
+            // that isn't on any of the interfaces or superclass
+            // in which case, ignore it.  Otherwise, map and cache
+            if (publicMethod != null) {
+                methodMap.add(publicMethod);
+                methodCache.put(makeMethodKey(publicMethod), publicMethod);
+            }
+        }
+    }
+
+    /**
+     * Make a methodKey for the given method using
+     * the concatenation of the name and the
+     * types of the method parameters.
+     */
+    private String makeMethodKey(Method method) {
+        Class<?>[] parameterTypes = method.getParameterTypes();
+
+        StringBuilder methodKey = new StringBuilder(method.getName());
+
+        for (Class<?> parameterType : parameterTypes) {
+            // If the argument type is primitive then we want
+            // to convert our primitive type signature to the
+            // corresponding Object type so introspection for
+            // methods with primitive types will work correctly.
+            if (parameterType.isPrimitive()) {
+                if (parameterType.equals(Boolean.TYPE)) {
+                    methodKey.append("java.lang.Boolean");
+                } else if (parameterType.equals(Byte.TYPE)) {
+                    methodKey.append("java.lang.Byte");
+                } else if (parameterType.equals(Character.TYPE)) {
+                    methodKey.append("java.lang.Character");
+                } else if (parameterType.equals(Double.TYPE)) {
+                    methodKey.append("java.lang.Double");
+                } else if (parameterType.equals(Float.TYPE)) {
+                    methodKey.append("java.lang.Float");
+                } else if (parameterType.equals(Integer.TYPE)) {
+                    methodKey.append("java.lang.Integer");
+                } else if (parameterType.equals(Long.TYPE)) {
+                    methodKey.append("java.lang.Long");
+                } else if (parameterType.equals(Short.TYPE)) {
+                    methodKey.append("java.lang.Short");
+                }
+            } else {
+                methodKey.append(parameterType.getName());
+            }
+        }
+
+        return methodKey.toString();
+    }
+
+    private static String makeMethodKey(String method, Object... params) {
+        StringBuilder methodKey = new StringBuilder().append(method);
+
+        for (Object param : params) {
+            Object arg = param;
+
+            if (arg == null) {
+                arg = OBJECT;
+            }
+
+            methodKey.append(arg.getClass().getName());
+        }
+
+        return methodKey.toString();
+    }
+
+    /**
+     * Retrieves public methods for a class. In case the class is not
+     * public, retrieves methods with same signature as its public methods
+     * from public superclasses and interfaces (if they exist). Basically
+     * upcasts every method to the nearest acccessible method.
+     */
+    private static Method[] getAccessibleMethods(Class<?> clazz) {
+        Method[] methods = clazz.getMethods();
+
+        // Short circuit for the (hopefully) majority of cases where the
+        // clazz is public
+        if (Modifier.isPublic(clazz.getModifiers())) {
+            return methods;
+        }
+
+        // No luck - the class is not public, so we're going the longer way.
+        MethodInfo[] methodInfos = new MethodInfo[methods.length];
+        for (int i = methods.length; i-- > 0; ) {
+            methodInfos[i] = new MethodInfo(methods[i]);
+        }
+
+        int upcastCount = getAccessibleMethods(clazz, methodInfos, 0);
+
+        // Reallocate array in case some method had no accessible counterpart.
+        if (upcastCount < methods.length) {
+            methods = new Method[upcastCount];
+        }
+
+        int j = 0;
+        for (MethodInfo methodInfo : methodInfos) {
+            if (methodInfo.upcast) {
+                methods[j++] = methodInfo.method;
+            }
+        }
+        return methods;
+    }
+
+    /**
+     * Recursively finds a match for each method, starting with the class, and then
+     * searching the superclass and interfaces.
+     *
+     * @param clazz       Class to check
+     * @param methodInfos array of methods we are searching to match
+     * @param upcastCount current number of methods we have matched
+     * @return count of matched methods
+     */
+    private static int getAccessibleMethods(Class<?> clazz, MethodInfo[] methodInfos, int upcastCount) {
+        int l = methodInfos.length;
+
+        // if this class is public, then check each of the currently
+        // 'non-upcasted' methods to see if we have a match
+        if (Modifier.isPublic(clazz.getModifiers())) {
+            for (int i = 0; i < l && upcastCount < l; ++i) {
+                try {
+                    MethodInfo methodInfo = methodInfos[i];
+                    if (!methodInfo.upcast) {
+                        methodInfo.tryUpcasting(clazz);
+                        upcastCount++;
+                    }
+                } catch (NoSuchMethodException e) {
+                    // Intentionally ignored - it means it wasn't found in the current class
+                }
+            }
+
+            /*
+             *  Short circuit if all methods were upcast
+             */
+
+            if (upcastCount == l) {
+                return upcastCount;
+            }
+        }
+
+        // Examine superclass
+        Class<?> superclazz = clazz.getSuperclass();
+        if (superclazz != null) {
+            upcastCount = getAccessibleMethods(superclazz, methodInfos, upcastCount);
+
+            // Short circuit if all methods were upcast
+            if (upcastCount == l) {
+                return upcastCount;
+            }
+        }
+
+        // Examine interfaces. Note we do it even if superclazz == null.
+        // This is redundant as currently java.lang.Object does not implement
+        // any interfaces, however nothing guarantees it will not in the future.
+        Class<?>[] interfaces = clazz.getInterfaces();
+        for (int i = interfaces.length; i-- > 0; ) {
+            upcastCount = getAccessibleMethods(interfaces[i], methodInfos, upcastCount);
+
+            // Short circuit if all methods were upcast
+            if (upcastCount == l) {
+                return upcastCount;
+            }
+        }
+
+        return upcastCount;
+    }
+
+    /**
+     * For a given method, retrieves its publicly accessible counterpart.
+     * This method will look for a method with same name
+     * and signature declared in a public superclass or implemented interface of this
+     * method's declaring class. This counterpart method is publicly callable.
+     *
+     * @param method a method whose publicly callable counterpart is requested.
+     * @return the publicly callable counterpart method. Note that if the parameter
+     *         method is itself declared by a public class, this method is an identity
+     *         function.
+     */
+    private static Method getPublicMethod(Method method) {
+        Class<?> clazz = method.getDeclaringClass();
+
+        // Short circuit for (hopefully the majority of) cases where the declaring
+        // class is public.
+        if ((clazz.getModifiers() & Modifier.PUBLIC) != 0) {
+            return method;
+        }
+
+        return getPublicMethod(clazz, method.getName(), method.getParameterTypes());
+    }
+
+    /**
+     * Looks up the method with specified name and signature in the first public
+     * superclass or implemented interface of the class.
+     *
+     * @param clazz      the class whose method is sought
+     * @param name       the name of the method
+     * @param paramTypes the classes of method parameters
+     */
+    private static Method getPublicMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
+        // if this class is public, then try to get it
+        if ((clazz.getModifiers() & Modifier.PUBLIC) != 0) {
+            try {
+                return clazz.getMethod(name, paramTypes);
+            } catch (NoSuchMethodException e) {
+                // If the class does not have the method, then neither its superclass
+                // nor any of its interfaces has it so quickly return null.
+                return null;
+            }
+        }
+
+        //  try the superclass
+        Class<?> superclazz = clazz.getSuperclass();
+
+        if (superclazz != null) {
+            Method superclazzMethod = getPublicMethod(superclazz, name, paramTypes);
+
+            if (superclazzMethod != null) {
+                return superclazzMethod;
+            }
+        }
+
+        // and interfaces
+        Class<?>[] interfaces = clazz.getInterfaces();
+
+        for (Class<?> anInterface : interfaces) {
+            Method interfaceMethod = getPublicMethod(anInterface, name, paramTypes);
+
+            if (interfaceMethod != null) {
+                return interfaceMethod;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Used for the iterative discovery process for public methods.
+     */
+    private static final class MethodInfo {
+        Method method;
+
+        String name;
+
+        Class<?>[] parameterTypes;
+
+        boolean upcast;
+
+        MethodInfo(Method method) {
+            this.method = null;
+            name = method.getName();
+            parameterTypes = method.getParameterTypes();
+            upcast = false;
+        }
+
+        void tryUpcasting(Class<?> clazz) throws NoSuchMethodException {
+            method = clazz.getMethod(name, parameterTypes);
+            name = null;
+            parameterTypes = null;
+            upcast = true;
+        }
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/IntrospectionException.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/IntrospectionException.java
new file mode 100644
index 0000000..65e75fb
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/IntrospectionException.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation.reflection;
+
+public class IntrospectionException extends Exception {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = -6090771282553728784L;
+
+    IntrospectionException(String message) {
+        super(message);
+    }
+
+    IntrospectionException(Throwable cause) {
+        super(cause);
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/MethodMap.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/MethodMap.java
new file mode 100644
index 0000000..1e7bc0e
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/MethodMap.java
@@ -0,0 +1,389 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation.reflection;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+class MethodMap {
+    private static final int MORE_SPECIFIC = 0;
+
+    private static final int LESS_SPECIFIC = 1;
+
+    private static final int INCOMPARABLE = 2;
+
+    /**
+     * Keep track of all methods with the same name.
+     */
+    private final Map<String, List<Method>> methodByNameMap = new Hashtable<>();
+
+    /**
+     * Add a method to a list of methods by name.
+     * For a particular class we are keeping track
+     * of all the methods with the same name.
+     *
+     * @param method The method
+     */
+    void add(Method method) {
+        String methodName = method.getName();
+
+        List<Method> l = get(methodName);
+
+        if (l == null) {
+            l = new ArrayList<>();
+            methodByNameMap.put(methodName, l);
+        }
+
+        l.add(method);
+    }
+
+    /**
+     * Return a list of methods with the same name.
+     *
+     * @param key The name of the method.
+     * @return List list of methods
+     */
+    List<Method> get(String key) {
+        return methodByNameMap.get(key);
+    }
+
+    /**
+     * Find a method.  Attempts to find the
+     * most specific applicable method using the
+     * algorithm described in the JLS section
+     * 15.12.2 (with the exception that it can't
+     * distinguish a primitive type argument from
+     * an object type argument, since in reflection
+     * primitive type arguments are represented by
+     * their object counterparts, so for an argument of
+     * type (say) java.lang.Integer, it will not be able
+     * to decide between a method that takes int and a
+     * method that takes java.lang.Integer as a parameter.
+     * <p>
+     * This turns out to be a relatively rare case
+     * where this is needed - however, functionality
+     * like this is needed.
+     *
+     * @param methodName name of method
+     * @param args       the actual arguments with which the method is called
+     * @return the most specific applicable method, or null if no
+     *         method is applicable.
+     * @throws AmbiguousException if there is more than one maximally
+     *                            specific applicable method
+     */
+    Method find(String methodName, Object... args) throws AmbiguousException {
+        List<Method> methodList = get(methodName);
+
+        if (methodList == null) {
+            return null;
+        }
+
+        int l = args.length;
+        Class<?>[] classes = new Class[l];
+
+        for (int i = 0; i < l; ++i) {
+            Object arg = args[i];
+            // if we are careful down below, a null argument goes in there
+            // so we can know that the null was passed to the method
+            classes[i] = arg == null ? null : arg.getClass();
+        }
+
+        return getMostSpecific(methodList, classes);
+    }
+
+    /**
+     * simple distinguishable exception, used when
+     * we run across ambiguous overloading
+     */
+    static class AmbiguousException extends Exception {
+
+        private static final long serialVersionUID = 751688436639650618L;
+    }
+
+    private static Method getMostSpecific(List<Method> methods, Class<?>... classes) throws AmbiguousException {
+        LinkedList<Method> applicables = getApplicables(methods, classes);
+
+        if (applicables.isEmpty()) {
+            return null;
+        }
+
+        if (applicables.size() == 1) {
+            return applicables.getFirst();
+        }
+
+        // This list will contain the maximally specific methods. Hopefully at
+        // the end of the below loop, the list will contain exactly one method,
+        // (the most specific method) otherwise we have ambiguity.
+        LinkedList<Method> maximals = new LinkedList<>();
+
+        for (Method app : applicables) {
+            Class<?>[] appArgs = app.getParameterTypes();
+            boolean lessSpecific = false;
+
+            for (Iterator<Method> maximal = maximals.iterator(); !lessSpecific && maximal.hasNext(); ) {
+                Method max = maximal.next();
+
+                switch (moreSpecific(appArgs, max.getParameterTypes())) {
+                    case MORE_SPECIFIC:
+                        // This method is more specific than the previously
+                        // known maximally specific, so remove the old maximum.
+                        maximal.remove();
+                        break;
+
+                    case LESS_SPECIFIC:
+                        // This method is less specific than some of the
+                        // currently known maximally specific methods, so we
+                        // won't add it into the set of maximally specific
+                        // methods
+                        lessSpecific = true;
+                        break;
+
+                    default:
+                }
+            }
+
+            if (!lessSpecific) {
+                maximals.addLast(app);
+            }
+        }
+
+        if (maximals.size() > 1) {
+            // We have more than one maximally specific method
+            throw new AmbiguousException();
+        }
+
+        return maximals.getFirst();
+    }
+
+    /**
+     * Determines which method signature (represented by a class array) is more
+     * specific. This defines a partial ordering on the method signatures.
+     *
+     * @param c1 first signature to compare
+     * @param c2 second signature to compare
+     * @return MORE_SPECIFIC if c1 is more specific than c2, LESS_SPECIFIC if
+     *         c1 is less specific than c2, INCOMPARABLE if they are incomparable.
+     */
+    private static int moreSpecific(Class<?>[] c1, Class<?>[] c2) {
+        boolean c1MoreSpecific = false;
+        boolean c2MoreSpecific = false;
+
+        for (int i = 0; i < c1.length; ++i) {
+            if (c1[i] != c2[i]) {
+                c1MoreSpecific = c1MoreSpecific || isStrictMethodInvocationConvertible(c2[i], c1[i]);
+                c2MoreSpecific = c2MoreSpecific || isStrictMethodInvocationConvertible(c1[i], c2[i]);
+            }
+        }
+
+        if (c1MoreSpecific) {
+            if (c2MoreSpecific) {
+                // Incomparable due to cross-assignable arguments (i.e.
+                // foo(String, Object) vs. foo(Object, String))
+                return INCOMPARABLE;
+            }
+
+            return MORE_SPECIFIC;
+        }
+
+        if (c2MoreSpecific) {
+            return LESS_SPECIFIC;
+        }
+
+        // Incomparable due to non-related arguments (i.e.
+        // foo(Runnable) vs. foo(Serializable))
+        return INCOMPARABLE;
+    }
+
+    /**
+     * Returns all methods that are applicable to actual argument types.
+     *
+     * @param methods list of all candidate methods
+     * @param classes the actual types of the arguments
+     * @return a list that contains only applicable methods (number of
+     *         formal and actual arguments matches, and argument types are assignable
+     *         to formal types through a method invocation conversion).
+     */
+    private static LinkedList<Method> getApplicables(List<Method> methods, Class<?>... classes) {
+        LinkedList<Method> list = new LinkedList<>();
+
+        for (Method method : methods) {
+            if (isApplicable(method, classes)) {
+                list.add(method);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Returns true if the supplied method is applicable to actual
+     * argument types.
+     *
+     * @param method  The method to check for applicability
+     * @param classes The arguments
+     * @return true if the method applies to the parameter types
+     */
+    private static boolean isApplicable(Method method, Class<?>... classes) {
+        Class<?>[] methodArgs = method.getParameterTypes();
+
+        if (methodArgs.length != classes.length) {
+            return false;
+        }
+
+        for (int i = 0; i < classes.length; ++i) {
+            if (!isMethodInvocationConvertible(methodArgs[i], classes[i])) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Determines whether a type represented by a class object is
+     * convertible to another type represented by a class object using a
+     * method invocation conversion, treating object types of primitive
+     * types as if they were primitive types (that is, a Boolean actual
+     * parameter type matches boolean primitive formal type). This behavior
+     * is because this method is used to determine applicable methods for
+     * an actual parameter list, and primitive types are represented by
+     * their object duals in reflective method calls.
+     *
+     * @param formal the formal parameter type to which the actual
+     *               parameter type should be convertible
+     * @param actual the actual parameter type.
+     * @return true if either formal type is assignable from actual type,
+     *         or formal is a primitive type and actual is its corresponding object
+     *         type or an object type of a primitive type that can be converted to
+     *         the formal type.
+     */
+    private static boolean isMethodInvocationConvertible(Class<?> formal, Class<?> actual) {
+        // if it's a null, it means the arg was null
+        if (actual == null && !formal.isPrimitive()) {
+            return true;
+        }
+
+        // Check for identity or widening reference conversion
+        if (actual != null && formal.isAssignableFrom(actual)) {
+            return true;
+        }
+
+        // Check for boxing with widening primitive conversion. Note that
+        // actual parameters are never primitives.
+        if (formal.isPrimitive()) {
+            if (formal == Boolean.TYPE && actual == Boolean.class) {
+                return true;
+            }
+            if (formal == Character.TYPE && actual == Character.class) {
+                return true;
+            }
+            if (formal == Byte.TYPE && actual == Byte.class) {
+                return true;
+            }
+            if (formal == Short.TYPE && (actual == Short.class || actual == Byte.class)) {
+                return true;
+            }
+            if (formal == Integer.TYPE && (actual == Integer.class || actual == Short.class || actual == Byte.class)) {
+                return true;
+            }
+            if (formal == Long.TYPE
+                    && (actual == Long.class
+                            || actual == Integer.class
+                            || actual == Short.class
+                            || actual == Byte.class)) {
+                return true;
+            }
+            if (formal == Float.TYPE
+                    && (actual == Float.class
+                            || actual == Long.class
+                            || actual == Integer.class
+                            || actual == Short.class
+                            || actual == Byte.class)) {
+                return true;
+            }
+            if (formal == Double.TYPE
+                    && (actual == Double.class
+                            || actual == Float.class
+                            || actual == Long.class
+                            || actual == Integer.class
+                            || actual == Short.class
+                            || actual == Byte.class)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Determines whether a type represented by a class object is
+     * convertible to another type represented by a class object using a
+     * method invocation conversion, without matching object and primitive
+     * types. This method is used to determine the more specific type when
+     * comparing signatures of methods.
+     *
+     * @param formal the formal parameter type to which the actual
+     *               parameter type should be convertible
+     * @param actual the actual parameter type.
+     * @return true if either formal type is assignable from actual type,
+     *         or formal and actual are both primitive types and actual can be
+     *         subject to widening conversion to formal.
+     */
+    private static boolean isStrictMethodInvocationConvertible(Class<?> formal, Class<?> actual) {
+        // we shouldn't get a null into, but if so
+        if (actual == null && !formal.isPrimitive()) {
+            return true;
+        }
+
+        // Check for identity or widening reference conversion
+        if (formal.isAssignableFrom(actual)) {
+            return true;
+        }
+
+        // Check for widening primitive conversion.
+        if (formal.isPrimitive()) {
+            if (formal == Short.TYPE && (actual == Byte.TYPE)) {
+                return true;
+            }
+            if (formal == Integer.TYPE && (actual == Short.TYPE || actual == Byte.TYPE)) {
+                return true;
+            }
+            if (formal == Long.TYPE && (actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) {
+                return true;
+            }
+            if (formal == Float.TYPE
+                    && (actual == Long.TYPE || actual == Integer.TYPE || actual == Short.TYPE || actual == Byte.TYPE)) {
+                return true;
+            }
+            if (formal == Double.TYPE
+                    && (actual == Float.TYPE
+                            || actual == Long.TYPE
+                            || actual == Integer.TYPE
+                            || actual == Short.TYPE
+                            || actual == Byte.TYPE)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/ReflectionValueExtractor.java b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/ReflectionValueExtractor.java
new file mode 100644
index 0000000..2054056
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/interpolation/reflection/ReflectionValueExtractor.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation.reflection;
+
+import java.lang.ref.Reference;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.WeakHashMap;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+import org.apache.maven.model.interpolation.reflection.MethodMap.AmbiguousException;
+
+/**
+ * Using simple dotted expressions to extract the values from an Object instance using JSP-like expressions
+ * such as {@code project.build.sourceDirectory}.
+ * <p>
+ * In addition to usual getters using {@code getXxx} or {@code isXxx} suffixes, accessors
+ * using {@code asXxx} or {@code toXxx} prefixes are also supported.
+ */
+public class ReflectionValueExtractor {
+    private static final Object[] OBJECT_ARGS = new Object[0];
+
+    /**
+     * Use a WeakHashMap here, so the keys (Class objects) can be garbage collected.
+     * This approach prevents permgen space overflows due to retention of discarded
+     * classloaders.
+     */
+    private static final Map<Class<?>, WeakReference<ClassMap>> CLASS_MAPS = new WeakHashMap<>();
+
+    static final int EOF = -1;
+
+    static final char PROPERTY_START = '.';
+
+    static final char INDEXED_START = '[';
+
+    static final char INDEXED_END = ']';
+
+    static final char MAPPED_START = '(';
+
+    static final char MAPPED_END = ')';
+
+    static class Tokenizer {
+        final String expression;
+
+        int idx;
+
+        Tokenizer(String expression) {
+            this.expression = expression;
+        }
+
+        public int peekChar() {
+            return idx < expression.length() ? expression.charAt(idx) : EOF;
+        }
+
+        public int skipChar() {
+            return idx < expression.length() ? expression.charAt(idx++) : EOF;
+        }
+
+        public String nextToken(char delimiter) {
+            int start = idx;
+
+            while (idx < expression.length() && delimiter != expression.charAt(idx)) {
+                idx++;
+            }
+
+            // delimiter MUST be present
+            if (idx <= start || idx >= expression.length()) {
+                return null;
+            }
+
+            return expression.substring(start, idx++);
+        }
+
+        public String nextPropertyName() {
+            final int start = idx;
+
+            while (idx < expression.length() && Character.isJavaIdentifierPart(expression.charAt(idx))) {
+                idx++;
+            }
+
+            // property name does not require delimiter
+            if (idx <= start || idx > expression.length()) {
+                return null;
+            }
+
+            return expression.substring(start, idx);
+        }
+
+        public int getPosition() {
+            return idx < expression.length() ? idx : EOF;
+        }
+
+        // to make tokenizer look pretty in debugger
+        @Override
+        public String toString() {
+            return idx < expression.length() ? expression.substring(idx) : "<EOF>";
+        }
+    }
+
+    private ReflectionValueExtractor() {}
+
+    /**
+     * <p>The implementation supports indexed, nested and mapped properties.</p>
+     * <ul>
+     * <li>nested properties should be defined by a dot, i.e. "user.address.street"</li>
+     * <li>indexed properties (java.util.List or array instance) should be contains <code>(\\w+)\\[(\\d+)\\]</code>
+     * pattern, i.e. "user.addresses[1].street"</li>
+     * <li>mapped properties should be contains <code>(\\w+)\\((.+)\\)</code> pattern,
+     *  i.e. "user.addresses(myAddress).street"</li>
+     * </ul>
+     *
+     * @param expression not null expression
+     * @param root       not null object
+     * @return the object defined by the expression
+     * @throws IntrospectionException if any
+     */
+    public static Object evaluate(@Nonnull String expression, @Nullable Object root) throws IntrospectionException {
+        return evaluate(expression, root, true);
+    }
+
+    /**
+     * <p>
+     * The implementation supports indexed, nested and mapped properties.
+     * </p>
+     * <ul>
+     * <li>nested properties should be defined by a dot, i.e. "user.address.street"</li>
+     * <li>indexed properties (java.util.List or array instance) should be contains <code>(\\w+)\\[(\\d+)\\]</code>
+     * pattern, i.e. "user.addresses[1].street"</li>
+     * <li>mapped properties should be contains <code>(\\w+)\\((.+)\\)</code> pattern, i.e.
+     * "user.addresses(myAddress).street"</li>
+     * </ul>
+     *
+     * @param expression not null expression
+     * @param root not null object
+     * @param trimRootToken trim root token yes/no.
+     * @return the object defined by the expression
+     * @throws IntrospectionException if any
+     */
+    public static Object evaluate(@Nonnull String expression, @Nullable Object root, boolean trimRootToken)
+            throws IntrospectionException {
+        Object value = root;
+
+        // ----------------------------------------------------------------------
+        // Walk the dots and retrieve the ultimate value desired from the
+        // MavenProject instance.
+        // ----------------------------------------------------------------------
+
+        if (expression == null || expression.isEmpty() || !Character.isJavaIdentifierStart(expression.charAt(0))) {
+            return null;
+        }
+
+        boolean hasDots = expression.indexOf(PROPERTY_START) >= 0;
+
+        final Tokenizer tokenizer;
+        if (trimRootToken && hasDots) {
+            tokenizer = new Tokenizer(expression);
+            tokenizer.nextPropertyName();
+            if (tokenizer.getPosition() == EOF) {
+                return null;
+            }
+        } else {
+            tokenizer = new Tokenizer("." + expression);
+        }
+
+        int propertyPosition = tokenizer.getPosition();
+        while (value != null && tokenizer.peekChar() != EOF) {
+            switch (tokenizer.skipChar()) {
+                case INDEXED_START:
+                    value = getIndexedValue(
+                            expression,
+                            propertyPosition,
+                            tokenizer.getPosition(),
+                            value,
+                            tokenizer.nextToken(INDEXED_END));
+                    break;
+                case MAPPED_START:
+                    value = getMappedValue(
+                            expression,
+                            propertyPosition,
+                            tokenizer.getPosition(),
+                            value,
+                            tokenizer.nextToken(MAPPED_END));
+                    break;
+                case PROPERTY_START:
+                    propertyPosition = tokenizer.getPosition();
+                    value = getPropertyValue(value, tokenizer.nextPropertyName());
+                    break;
+                default:
+                    // could not parse expression
+                    return null;
+            }
+        }
+
+        if (value instanceof Optional) {
+            value = ((Optional<?>) value).orElse(null);
+        }
+        return value;
+    }
+
+    private static Object getMappedValue(
+            final String expression, final int from, final int to, final Object value, final String key)
+            throws IntrospectionException {
+        if (value == null || key == null) {
+            return null;
+        }
+
+        if (value instanceof Map) {
+            return ((Map) value).get(key);
+        }
+
+        final String message = String.format(
+                "The token '%s' at position '%d' refers to a java.util.Map, but the value "
+                        + "seems is an instance of '%s'",
+                expression.subSequence(from, to), from, value.getClass());
+
+        throw new IntrospectionException(message);
+    }
+
+    private static Object getIndexedValue(
+            final String expression, final int from, final int to, final Object value, final String indexStr)
+            throws IntrospectionException {
+        try {
+            int index = Integer.parseInt(indexStr);
+
+            if (value.getClass().isArray()) {
+                return Array.get(value, index);
+            }
+
+            if (value instanceof List) {
+                return ((List) value).get(index);
+            }
+        } catch (NumberFormatException | IndexOutOfBoundsException e) {
+            return null;
+        }
+
+        final String message = String.format(
+                "The token '%s' at position '%d' refers to a java.util.List or an array, but the value "
+                        + "seems is an instance of '%s'",
+                expression.subSequence(from, to), from, value.getClass());
+
+        throw new IntrospectionException(message);
+    }
+
+    private static Object getPropertyValue(Object value, String property) throws IntrospectionException {
+        if (value == null || property == null || property.isEmpty()) {
+            return null;
+        }
+
+        ClassMap classMap = getClassMap(value.getClass());
+        String methodBase = Character.toTitleCase(property.charAt(0)) + property.substring(1);
+        try {
+            for (String prefix : Arrays.asList("get", "is", "to", "as")) {
+                Method method = classMap.findMethod(prefix + methodBase);
+                if (method != null) {
+                    return method.invoke(value, OBJECT_ARGS);
+                }
+            }
+            return null;
+        } catch (InvocationTargetException e) {
+            throw new IntrospectionException(e.getTargetException());
+        } catch (AmbiguousException | IllegalAccessException e) {
+            throw new IntrospectionException(e);
+        }
+    }
+
+    private static ClassMap getClassMap(Class<?> clazz) {
+        Reference<ClassMap> ref = CLASS_MAPS.get(clazz);
+        ClassMap classMap = ref != null ? ref.get() : null;
+
+        if (classMap == null) {
+            classMap = new ClassMap(clazz);
+
+            CLASS_MAPS.put(clazz, new WeakReference<>(classMap));
+        }
+
+        return classMap;
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
index 3501df9..07d2cab 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,188 +16,135 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.io;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.model.InputSource;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelSourceTransformer;
-import org.apache.maven.model.building.TransformerContext;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.apache.maven.model.io.xpp3.MavenXpp3ReaderEx;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.XmlStreamReader;
-import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
-import org.codehaus.plexus.util.xml.pull.MXParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.apache.maven.model.v4.MavenStaxReader;
 
 /**
  * Handles deserialization of a model from some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultModelReader
-    implements ModelReader
-{
+public class DefaultModelReader implements ModelReader {
     private final ModelSourceTransformer transformer;
 
-    private Method readMethod;
-
-    private Method readMethodEx;
-
     @Inject
-    public DefaultModelReader( ModelSourceTransformer transformer )
-    {
+    public DefaultModelReader(ModelSourceTransformer transformer) {
         this.transformer = transformer;
     }
 
     @Override
-    public Model read( File input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Model read(File input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        try ( XmlStreamReader in = ReaderFactory.newXmlReader( input ) )
-        {
-            Model model = read( in, input.toPath(), options );
+        try (InputStream in = Files.newInputStream(input.toPath())) {
+            Model model = read(in, input.toPath(), options);
 
-            model.setPomFile( input );
+            model.setPomFile(input);
 
             return model;
         }
     }
 
     @Override
-    public Model read( Reader input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Model read(Reader input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        try ( Reader in = input )
-        {
-            return read( in, null, options );
+        try (Reader in = input) {
+            return read(in, null, options);
         }
     }
 
     @Override
-    public Model read( InputStream input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Model read(InputStream input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        try ( XmlStreamReader in = ReaderFactory.newXmlReader( input ) )
-        {
-            return read( in, null, options );
+        try (InputStream in = input) {
+            return read(input, null, options);
         }
     }
 
-    private boolean isStrict( Map<String, ?> options )
-    {
-        Object value = ( options != null ) ? options.get( IS_STRICT ) : null;
-        return value == null || Boolean.parseBoolean( value.toString() );
+    private boolean isStrict(Map<String, ?> options) {
+        Object value = (options != null) ? options.get(IS_STRICT) : null;
+        return value == null || Boolean.parseBoolean(value.toString());
     }
 
-    private InputSource getSource( Map<String, ?> options )
-    {
-        Object value = ( options != null ) ? options.get( INPUT_SOURCE ) : null;
+    private InputSource getSource(Map<String, ?> options) {
+        Object value = (options != null) ? options.get(INPUT_SOURCE) : null;
         return (InputSource) value;
     }
 
-    private TransformerContext getTransformerContext( Map<String, ?> options )
-    {
-        Object value = ( options != null ) ? options.get( TRANSFORMER_CONTEXT ) : null;
-        return (TransformerContext) value;
+    private Path getRootDirectory(Map<String, ?> options) {
+        Object value = (options != null) ? options.get(ROOT_DIRECTORY) : null;
+        return (Path) value;
     }
 
-    private Model read( Reader reader, Path pomFile, Map<String, ?> options )
-        throws IOException
-    {
-        try
-        {
-            XmlPullParser parser = new MXParser( EntityReplacementMap.defaultEntityReplacementMap );
-            parser.setInput( reader );
+    private Model read(InputStream input, Path pomFile, Map<String, ?> options) throws IOException {
+        try {
+            XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
+            factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+            XMLStreamReader parser = factory.createXMLStreamReader(input);
 
-            TransformerContext context = getTransformerContext( options );
-            XmlPullParser transformingParser = context != null
-                    ? transformer.transform( parser, pomFile, context ) : parser;
-
-            InputSource source = getSource( options );
-            boolean strict = isStrict( options );
-            try
-            {
-                if ( source != null )
-                {
-                    return readModelEx( transformingParser, source, strict );
-                }
-                else
-                {
-                    return readModel( transformingParser, strict );
-                }
-            }
-            catch ( InvocationTargetException e )
-            {
-                Throwable cause = e.getCause();
-                if ( cause instanceof Exception )
-                {
-                    throw ( Exception ) cause;
-                }
-                throw e;
-            }
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new ModelParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
-        }
-        catch ( IOException e )
-        {
-            throw e;
-        }
-        catch ( Exception e )
-        {
-            throw new IOException( "Unable to transform pom", e );
+            InputSource source = getSource(options);
+            boolean strict = isStrict(options);
+            MavenStaxReader mr = new MavenStaxReader();
+            mr.setAddLocationInformation(source != null);
+            Model model = new Model(mr.read(parser, strict, source != null ? source.toApiSource() : null));
+            return model;
+        } catch (XMLStreamException e) {
+            Location location = e.getLocation();
+            throw new ModelParseException(
+                    e.getMessage(),
+                    location != null ? location.getLineNumber() : -1,
+                    location != null ? location.getColumnNumber() : -1,
+                    e);
+        } catch (Exception e) {
+            throw new IOException("Unable to transform pom", e);
         }
     }
 
-    private Model readModel( XmlPullParser parser, boolean strict )
-            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
-    {
-        if ( readMethod == null )
-        {
-            readMethod = MavenXpp3Reader.class.getDeclaredMethod( "read", XmlPullParser.class, boolean.class );
-            readMethod.setAccessible( true );
-        }
-        MavenXpp3Reader mr = new MavenXpp3Reader();
-        Object model = readMethod.invoke( mr, parser, strict );
-        return ( Model ) model;
-    }
+    private Model read(Reader reader, Path pomFile, Map<String, ?> options) throws IOException {
+        try {
+            XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
+            factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+            XMLStreamReader parser = factory.createXMLStreamReader(reader);
 
-    private Model readModelEx( XmlPullParser parser, InputSource source, boolean strict )
-            throws NoSuchMethodException, IllegalAccessException, InvocationTargetException
-    {
-        if ( readMethodEx == null )
-        {
-            readMethodEx = MavenXpp3ReaderEx.class.getDeclaredMethod( "read",
-                    XmlPullParser.class, boolean.class, InputSource.class );
-            readMethodEx.setAccessible( true );
+            InputSource source = getSource(options);
+            boolean strict = isStrict(options);
+            MavenStaxReader mr = new MavenStaxReader();
+            mr.setAddLocationInformation(source != null);
+            Model model = new Model(mr.read(parser, strict, source != null ? source.toApiSource() : null));
+            return model;
+        } catch (XMLStreamException e) {
+            Location location = e.getLocation();
+            throw new ModelParseException(
+                    e.getMessage(),
+                    location != null ? location.getLineNumber() : -1,
+                    location != null ? location.getColumnNumber() : -1,
+                    e);
+        } catch (Exception e) {
+            throw new IOException("Unable to transform pom", e);
         }
-        MavenXpp3ReaderEx mr = new MavenXpp3ReaderEx();
-        Object model = readMethodEx.invoke( mr, parser, strict, source );
-        return ( Model ) model;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelWriter.java b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelWriter.java
index a6d4d98..fc7493f 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelWriter.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/io/DefaultModelWriter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,76 +16,84 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.io;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.nio.file.Files;
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
-import org.codehaus.plexus.util.WriterFactory;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.model.v4.MavenStaxWriter;
+import org.codehaus.plexus.util.xml.XmlStreamWriter;
 
 /**
  * Handles serialization of a model into some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultModelWriter
-    implements ModelWriter
-{
+public class DefaultModelWriter implements ModelWriter {
 
     @Override
-    public void write( File output, Map<String, Object> options, Model model )
-        throws IOException
-    {
-        Objects.requireNonNull( output, "output cannot be null" );
-        Objects.requireNonNull( model, "model cannot be null" );
+    public void write(File output, Map<String, Object> options, Model model) throws IOException {
+        Objects.requireNonNull(output, "output cannot be null");
+        Objects.requireNonNull(model, "model cannot be null");
 
         output.getParentFile().mkdirs();
 
-        write( WriterFactory.newXmlWriter( output ), options, model );
+        write(new XmlStreamWriter(Files.newOutputStream(output.toPath())), options, model);
     }
 
     @Override
-    public void write( Writer output, Map<String, Object> options, Model model )
-        throws IOException
-    {
-        Objects.requireNonNull( output, "output cannot be null" );
-        Objects.requireNonNull( model, "model cannot be null" );
+    public void write(Writer output, Map<String, Object> options, Model model) throws IOException {
+        Objects.requireNonNull(output, "output cannot be null");
+        Objects.requireNonNull(model, "model cannot be null");
 
-        try ( Writer out = output )
-        {
-            new MavenXpp3Writer().write( out, model );
+        try (Writer out = output) {
+            new MavenStaxWriter().write(out, model);
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
         }
     }
 
     @Override
-    public void write( OutputStream output, Map<String, Object> options, Model model )
-        throws IOException
-    {
-        Objects.requireNonNull( output, "output cannot be null" );
-        Objects.requireNonNull( model, "model cannot be null" );
+    public void write(OutputStream output, Map<String, Object> options, Model model) throws IOException {
+        Objects.requireNonNull(output, "output cannot be null");
+        Objects.requireNonNull(model, "model cannot be null");
 
         String encoding = model.getModelEncoding();
-        // TODO Use StringUtils here
-        if ( encoding == null || encoding.length() <= 0 )
-        {
+        if (encoding == null || encoding.length() <= 0) {
             encoding = "UTF-8";
         }
 
-        try ( Writer out = new OutputStreamWriter( output, encoding ) )
-        {
-            write( out, options, model );
+        try (Writer out = new OutputStreamWriter(output, encoding)) {
+            write(out, options, model);
         }
     }
 
+    @Override
+    public void write(File output, Map<String, Object> options, org.apache.maven.model.Model model) throws IOException {
+        write(output, options, model.getDelegate());
+    }
+
+    @Override
+    public void write(Writer output, Map<String, Object> options, org.apache.maven.model.Model model)
+            throws IOException {
+        write(output, options, model.getDelegate());
+    }
+
+    @Override
+    public void write(OutputStream output, Map<String, Object> options, org.apache.maven.model.Model model)
+            throws IOException {
+        write(output, options, model.getDelegate());
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelParseException.java b/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelParseException.java
index cd3f14d..64e0003 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelParseException.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelParseException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.io;
 
 import java.io.IOException;
 
 /**
  * Signals a failure to parse the POM due to invalid syntax (e.g. non well formed XML or unknown elements).
  *
- * @author Benjamin Bentmann
  */
-public class ModelParseException
-    extends IOException
-{
+public class ModelParseException extends IOException {
 
     /**
      * The one-based index of the line containing the error.
@@ -47,9 +43,8 @@
      * @param lineNumber The one-based index of the line containing the error or {@code -1} if unknown.
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      */
-    public ModelParseException( String message, int lineNumber, int columnNumber )
-    {
-        super( message );
+    public ModelParseException(String message, int lineNumber, int columnNumber) {
+        super(message);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -62,10 +57,9 @@
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      * @param cause The nested cause of this error, may be {@code null}.
      */
-    public ModelParseException( String message, int lineNumber, int columnNumber, Throwable cause )
-    {
-        super( message );
-        initCause( cause );
+    public ModelParseException(String message, int lineNumber, int columnNumber, Throwable cause) {
+        super(message);
+        initCause(cause);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -75,8 +69,7 @@
      *
      * @return The one-based index of the line containing the error or a non-positive value if unknown.
      */
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
 
@@ -85,9 +78,7 @@
      *
      * @return The one-based index of the column containing the error or non-positive value if unknown.
      */
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelReader.java b/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelReader.java
index 04b1a30..601160d 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelReader.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.io;
 
 import java.io.File;
 import java.io.IOException;
@@ -30,10 +29,8 @@
 /**
  * Handles deserialization of a model from some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelReader
-{
+public interface ModelReader {
 
     /**
      * The key for the option to enable strict parsing. This option is of type {@link Boolean} and defaults to {@code
@@ -49,10 +46,10 @@
     String INPUT_SOURCE = "org.apache.maven.model.io.inputSource";
 
     /**
-     * The key for the option to provide a transformer context, which can be used to transform the input while reading
-     * to get an advanced version of the model.
+     * Name of the property used to store the project's root directory to use with
+     * XInclude support.
      */
-    String TRANSFORMER_CONTEXT = "transformerContext";
+    String ROOT_DIRECTORY = "rootDirectory";
 
     /**
      * Reads the model from the specified file.
@@ -63,8 +60,7 @@
      * @throws IOException If the model could not be deserialized.
      * @throws ModelParseException If the input format could not be parsed.
      */
-    Model read( File input, Map<String, ?> options )
-        throws IOException, ModelParseException;
+    Model read(File input, Map<String, ?> options) throws IOException, ModelParseException;
 
     /**
      * Reads the model from the specified character reader. The reader will be automatically closed before the method
@@ -76,8 +72,7 @@
      * @throws IOException If the model could not be deserialized.
      * @throws ModelParseException If the input format could not be parsed.
      */
-    Model read( Reader input, Map<String, ?> options )
-        throws IOException, ModelParseException;
+    Model read(Reader input, Map<String, ?> options) throws IOException, ModelParseException;
 
     /**
      * Reads the model from the specified byte stream. The stream will be automatically closed before the method
@@ -89,7 +84,5 @@
      * @throws IOException If the model could not be deserialized.
      * @throws ModelParseException If the input format could not be parsed.
      */
-    Model read( InputStream input, Map<String, ?> options )
-        throws IOException, ModelParseException;
-
+    Model read(InputStream input, Map<String, ?> options) throws IOException, ModelParseException;
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelWriter.java b/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelWriter.java
index af7e0ca..b2890c6 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelWriter.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/io/ModelWriter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.io;
 
 import java.io.File;
 import java.io.IOException;
@@ -25,15 +24,13 @@
 import java.io.Writer;
 import java.util.Map;
 
-import org.apache.maven.model.Model;
+import org.apache.maven.api.model.Model;
 
 /**
  * Handles serialization of a model into some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelWriter
-{
+public interface ModelWriter {
 
     /**
      * Writes the supplied model to the specified file. Any non-existing parent directories of the output file will be
@@ -44,8 +41,7 @@
      * @param model The model to serialize, must not be {@code null}.
      * @throws IOException If the model could not be serialized.
      */
-    void write( File output, Map<String, Object> options, Model model )
-        throws IOException;
+    void write(File output, Map<String, Object> options, Model model) throws IOException;
 
     /**
      * Writes the supplied model to the specified character writer. The writer will be automatically closed before the
@@ -56,8 +52,7 @@
      * @param model The model to serialize, must not be {@code null}.
      * @throws IOException If the model could not be serialized.
      */
-    void write( Writer output, Map<String, Object> options, Model model )
-        throws IOException;
+    void write(Writer output, Map<String, Object> options, Model model) throws IOException;
 
     /**
      * Writes the supplied model to the specified byte stream. The stream will be automatically closed before the method
@@ -68,7 +63,38 @@
      * @param model The model to serialize, must not be {@code null}.
      * @throws IOException If the model could not be serialized.
      */
-    void write( OutputStream output, Map<String, Object> options, Model model )
-        throws IOException;
+    void write(OutputStream output, Map<String, Object> options, Model model) throws IOException;
 
+    /**
+     * Writes the supplied model to the specified file. Any non-existing parent directories of the output file will be
+     * created automatically.
+     *
+     * @param output The file to serialize the model to, must not be {@code null}.
+     * @param options The options to use for serialization, may be {@code null} to use the default values.
+     * @param model The model to serialize, must not be {@code null}.
+     * @throws IOException If the model could not be serialized.
+     */
+    void write(File output, Map<String, Object> options, org.apache.maven.model.Model model) throws IOException;
+
+    /**
+     * Writes the supplied model to the specified character writer. The writer will be automatically closed before the
+     * method returns.
+     *
+     * @param output The writer to serialize the model to, must not be {@code null}.
+     * @param options The options to use for serialization, may be {@code null} to use the default values.
+     * @param model The model to serialize, must not be {@code null}.
+     * @throws IOException If the model could not be serialized.
+     */
+    void write(Writer output, Map<String, Object> options, org.apache.maven.model.Model model) throws IOException;
+
+    /**
+     * Writes the supplied model to the specified byte stream. The stream will be automatically closed before the method
+     * returns.
+     *
+     * @param output The stream to serialize the model to, must not be {@code null}.
+     * @param options The options to use for serialization, may be {@code null} to use the default values.
+     * @param model The model to serialize, must not be {@code null}.
+     * @throws IOException If the model could not be serialized.
+     */
+    void write(OutputStream output, Map<String, Object> options, org.apache.maven.model.Model model) throws IOException;
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java b/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
index fd29dc6..eb51e75 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/locator/DefaultModelLocator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.locator;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,27 +16,38 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
+package org.apache.maven.model.locator;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+
 /**
  * Locates a POM file within a project base directory.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultModelLocator
-    implements ModelLocator
-{
+public class DefaultModelLocator implements ModelLocator {
 
     @Override
-    public File locatePom( File projectDirectory )
-    {
-        return new File( projectDirectory, "pom.xml" );
+    public File locatePom(File projectDirectory) {
+        return projectDirectory != null ? projectDirectory : new File(".");
     }
 
+    @Override
+    public File locateExistingPom(File project) {
+        if (project == null || project.isDirectory()) {
+            project = locatePom(project);
+        }
+        if (project.isDirectory()) {
+            File pom = new File(project, "pom.xml");
+            return pom.isFile() ? pom : null;
+        } else if (project.isFile()) {
+            return project;
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java b/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java
index 831fed6..27b073c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/locator/ModelLocator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.locator;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.locator;
 
 import java.io.File;
 
 /**
  * Locates a POM file within a project base directory.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelLocator
-{
+public interface ModelLocator {
 
     /**
      * Locates the POM file within the specified project directory. In case the given project directory does not exist
@@ -39,6 +36,15 @@
      *            null}.
      * @return The path to the (possibly non-existent) POM file, never {@code null}.
      */
-    File locatePom( File projectDirectory );
+    File locatePom(File projectDirectory);
 
+    /**
+     * Returns the file containing the pom or null if a pom can not be found at the given file or in the given directory.
+     */
+    default File locateExistingPom(File project) {
+        if (project == null || project.isDirectory()) {
+            project = locatePom(project);
+        }
+        return project.isFile() ? project : null;
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java
index 499f355..1ea350d 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultDependencyManagementInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.management;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,19 +16,21 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.management;
 
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.Exclusion;
-import org.apache.maven.model.Model;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.Exclusion;
+import org.apache.maven.api.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.merge.MavenModelMerger;
@@ -38,80 +38,84 @@
 /**
  * Handles injection of dependency management into the model.
  *
- * @author Benjamin Bentmann
  */
-@SuppressWarnings( { "checkstyle:methodname" } )
+@SuppressWarnings({"checkstyle:methodname"})
 @Named
 @Singleton
-public class DefaultDependencyManagementInjector
-    implements DependencyManagementInjector
-{
+public class DefaultDependencyManagementInjector implements DependencyManagementInjector {
 
     private ManagementModelMerger merger = new ManagementModelMerger();
 
     @Override
-    public void injectManagement( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
-        merger.mergeManagedDependencies( model );
+    public void injectManagement(
+            org.apache.maven.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
+        model.update(merger.mergeManagedDependencies(model.getDelegate()));
     }
 
     /**
      * ManagementModelMerger
      */
-    protected static class ManagementModelMerger
-        extends MavenModelMerger
-    {
+    protected static class ManagementModelMerger extends MavenModelMerger {
 
-        public void mergeManagedDependencies( Model model )
-        {
+        public Model mergeManagedDependencies(Model model) {
             DependencyManagement dependencyManagement = model.getDependencyManagement();
-            if ( dependencyManagement != null )
-            {
+            if (dependencyManagement != null) {
                 Map<Object, Dependency> dependencies = new HashMap<>();
                 Map<Object, Object> context = Collections.emptyMap();
 
-                for ( Dependency dependency : model.getDependencies() )
-                {
-                    Object key = getDependencyKey().apply( dependency );
-                    dependencies.put( key, dependency );
+                for (Dependency dependency : model.getDependencies()) {
+                    Object key = getDependencyKey().apply(dependency);
+                    dependencies.put(key, dependency);
                 }
 
-                for ( Dependency managedDependency : dependencyManagement.getDependencies() )
-                {
-                    Object key = getDependencyKey().apply( managedDependency );
-                    Dependency dependency = dependencies.get( key );
-                    if ( dependency != null )
-                    {
-                        mergeDependency( dependency, managedDependency, false, context );
+                boolean modified = false;
+                for (Dependency managedDependency : dependencyManagement.getDependencies()) {
+                    Object key = getDependencyKey().apply(managedDependency);
+                    Dependency dependency = dependencies.get(key);
+                    if (dependency != null) {
+                        Dependency merged = mergeDependency(dependency, managedDependency, false, context);
+                        if (merged != dependency) {
+                            dependencies.put(key, merged);
+                            modified = true;
+                        }
                     }
                 }
+
+                if (modified) {
+                    List<Dependency> newDeps = new ArrayList<>(dependencies.size());
+                    for (Dependency dep : model.getDependencies()) {
+                        Object key = getDependencyKey().apply(dep);
+                        Dependency dependency = dependencies.get(key);
+                        newDeps.add(dependency);
+                    }
+                    return Model.newBuilder(model).dependencies(newDeps).build();
+                }
             }
+            return model;
         }
 
         @Override
-        protected void mergeDependency_Optional( Dependency target, Dependency source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-        {
+        protected void mergeDependency_Optional(
+                Dependency.Builder builder,
+                Dependency target,
+                Dependency source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             // optional flag is not managed
         }
 
         @Override
-        protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant,
-                                                   Map<Object, Object> context )
-        {
+        protected void mergeDependency_Exclusions(
+                Dependency.Builder builder,
+                Dependency target,
+                Dependency source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<Exclusion> tgt = target.getExclusions();
-            if ( tgt.isEmpty() )
-            {
+            if (tgt.isEmpty()) {
                 List<Exclusion> src = source.getExclusions();
-
-                for ( Exclusion element : src )
-                {
-                    Exclusion clone = element.clone();
-                    target.addExclusion( clone );
-                }
+                builder.exclusions(src);
             }
         }
-
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultPluginManagementInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultPluginManagementInjector.java
index 752b976..daad927 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultPluginManagementInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/management/DefaultPluginManagementInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.management;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.management;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -25,15 +27,12 @@
 import java.util.List;
 import java.util.Map;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.model.Build;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.PluginManagement;
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginContainer;
+import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.model.PluginManagement;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.merge.MavenModelMerger;
@@ -41,104 +40,91 @@
 /**
  * Handles injection of plugin management into the model.
  *
- * @author Benjamin Bentmann
  */
-@SuppressWarnings( { "checkstyle:methodname" } )
+@SuppressWarnings({"checkstyle:methodname"})
 @Named
 @Singleton
-public class DefaultPluginManagementInjector
-    implements PluginManagementInjector
-{
+public class DefaultPluginManagementInjector implements PluginManagementInjector {
 
     private ManagementModelMerger merger = new ManagementModelMerger();
 
     @Override
-    public void injectManagement( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
-        merger.mergeManagedBuildPlugins( model );
+    public void injectManagement(
+            org.apache.maven.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
+        model.update(merger.mergeManagedBuildPlugins(model.getDelegate()));
     }
 
     /**
      * ManagementModelMerger
      */
-    protected static class ManagementModelMerger
-        extends MavenModelMerger
-    {
+    protected static class ManagementModelMerger extends MavenModelMerger {
 
-        public void mergeManagedBuildPlugins( Model model )
-        {
+        public Model mergeManagedBuildPlugins(Model model) {
             Build build = model.getBuild();
-            if ( build != null )
-            {
+            if (build != null) {
                 PluginManagement pluginManagement = build.getPluginManagement();
-                if ( pluginManagement != null )
-                {
-                    mergePluginContainerPlugins( build, pluginManagement );
+                if (pluginManagement != null) {
+                    return model.withBuild(mergePluginContainerPlugins(build, pluginManagement));
                 }
             }
+            return model;
         }
 
-        private void mergePluginContainerPlugins( PluginContainer target, PluginContainer source )
-        {
+        private Build mergePluginContainerPlugins(Build target, PluginContainer source) {
             List<Plugin> src = source.getPlugins();
-            if ( !src.isEmpty() )
-            {
-                List<Plugin> tgt = target.getPlugins();
-
-                Map<Object, Plugin> managedPlugins = new LinkedHashMap<>( src.size() * 2 );
+            if (!src.isEmpty()) {
+                Map<Object, Plugin> managedPlugins = new LinkedHashMap<>(src.size() * 2);
 
                 Map<Object, Object> context = Collections.emptyMap();
 
-                for ( Plugin element : src )
-                {
-                    Object key = getPluginKey().apply( element );
-                    managedPlugins.put( key, element );
+                for (Plugin element : src) {
+                    Object key = getPluginKey().apply(element);
+                    managedPlugins.put(key, element);
                 }
 
-                for ( Plugin element : tgt )
-                {
-                    Object key = getPluginKey().apply( element );
-                    Plugin managedPlugin = managedPlugins.get( key );
-                    if ( managedPlugin != null )
-                    {
-                        mergePlugin( element, managedPlugin, false, context );
+                List<Plugin> newPlugins = new ArrayList<>();
+                for (Plugin element : target.getPlugins()) {
+                    Object key = getPluginKey().apply(element);
+                    Plugin managedPlugin = managedPlugins.get(key);
+                    if (managedPlugin != null) {
+                        element = mergePlugin(element, managedPlugin, false, context);
                     }
+                    newPlugins.add(element);
                 }
+                return target.withPlugins(newPlugins);
             }
+            return target;
         }
 
         @Override
-        protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-        {
+        protected void mergePlugin_Executions(
+                Plugin.Builder builder,
+                Plugin target,
+                Plugin source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<PluginExecution> src = source.getExecutions();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<PluginExecution> tgt = target.getExecutions();
 
-                Map<Object, PluginExecution> merged =
-                    new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+                Map<Object, PluginExecution> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-                for ( PluginExecution element : src )
-                {
-                    Object key = getPluginExecutionKey().apply( element );
-                    merged.put( key, element.clone() );
+                for (PluginExecution element : src) {
+                    Object key = getPluginExecutionKey().apply(element);
+                    merged.put(key, element);
                 }
 
-                for ( PluginExecution element : tgt )
-                {
-                    Object key = getPluginExecutionKey().apply( element );
-                    PluginExecution existing = merged.get( key );
-                    if ( existing != null )
-                    {
-                        mergePluginExecution( element, existing, sourceDominant, context );
+                for (PluginExecution element : tgt) {
+                    Object key = getPluginExecutionKey().apply(element);
+                    PluginExecution existing = merged.get(key);
+                    if (existing != null) {
+                        element = mergePluginExecution(element, existing, sourceDominant, context);
                     }
-                    merged.put( key, element );
+                    merged.put(key, element);
                 }
 
-                target.setExecutions( new ArrayList<>( merged.values() ) );
+                builder.executions(merged.values());
             }
         }
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/management/DependencyManagementInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/management/DependencyManagementInjector.java
index 3b70a09..3e9963b 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/management/DependencyManagementInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/management/DependencyManagementInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.management;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.management;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -26,10 +25,8 @@
 /**
  * Handles injection of dependency management into the model.
  *
- * @author Benjamin Bentmann
  */
-public interface DependencyManagementInjector
-{
+public interface DependencyManagementInjector {
 
     /**
      * Merges default values from the dependency management section of the given model into itself.
@@ -39,6 +36,5 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void injectManagement( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
-
+    void injectManagement(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/management/PluginManagementInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/management/PluginManagementInjector.java
index 7384fdf..7bca965 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/management/PluginManagementInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/management/PluginManagementInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.management;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.management;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -26,10 +25,8 @@
 /**
  * Handles injection of plugin management into the model.
  *
- * @author Benjamin Bentmann
  */
-public interface PluginManagementInjector
-{
+public interface PluginManagementInjector {
 
     /**
      * Merges default values from the plugin management section of the given model into itself.
@@ -39,6 +36,5 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void injectManagement( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
-
+    void injectManagement(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java b/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java
index 049ce1f..9d22606 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/merge/MavenModelMerger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.merge;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,45 +16,44 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.merge;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
-import org.apache.maven.model.BuildBase;
-import org.apache.maven.model.CiManagement;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DeploymentRepository;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Exclusion;
-import org.apache.maven.model.Extension;
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.IssueManagement;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.ModelBase;
-import org.apache.maven.model.Organization;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Repository;
-import org.apache.maven.model.RepositoryBase;
-import org.apache.maven.model.Scm;
-import org.apache.maven.model.Site;
-import org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.api.model.BuildBase;
+import org.apache.maven.api.model.CiManagement;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.DeploymentRepository;
+import org.apache.maven.api.model.DistributionManagement;
+import org.apache.maven.api.model.Exclusion;
+import org.apache.maven.api.model.Extension;
+import org.apache.maven.api.model.InputLocation;
+import org.apache.maven.api.model.IssueManagement;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.ModelBase;
+import org.apache.maven.api.model.Organization;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.model.ReportPlugin;
+import org.apache.maven.api.model.ReportSet;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.api.model.RepositoryBase;
+import org.apache.maven.api.model.Scm;
+import org.apache.maven.api.model.Site;
+import org.apache.maven.model.v4.MavenMerger;
 
 /**
  * The domain-specific model merger for the Maven POM, overriding generic code from parent class when necessary with
  * more adapted algorithms.
  *
- * @author Benjamin Bentmann
  */
-public class MavenModelMerger
-    extends ModelMerger
-{
+public class MavenModelMerger extends MavenMerger {
 
     /**
      * The hint key for the child path adjustment used during inheritance for URL calculations.
@@ -68,43 +65,69 @@
      */
     public static final String ARTIFACT_ID = "artifact-id";
 
-    @Override
-    protected void mergeModel( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        context.put( ARTIFACT_ID, target.getArtifactId() );
+    public MavenModelMerger() {
+        super(false);
+    }
 
-        super.mergeModel( target, source, sourceDominant, context );
+    /**
+     * Merges the specified source object into the given target object.
+     *
+     * @param target The target object whose existing contents should be merged with the source, must not be
+     *            <code>null</code>.
+     * @param source The (read-only) source object that should be merged into the target object, may be
+     *            <code>null</code>.
+     * @param sourceDominant A flag indicating whether either the target object or the source object provides the
+     *            dominant data.
+     * @param hints A set of key-value pairs that customized merger implementations can use to carry domain-specific
+     *            information along, may be <code>null</code>.
+     */
+    public void merge(
+            org.apache.maven.model.Model target,
+            org.apache.maven.model.Model source,
+            boolean sourceDominant,
+            Map<?, ?> hints) {
+        Objects.requireNonNull(target, "target cannot be null");
+        if (source == null) {
+            return;
+        }
+        target.update(merge(target.getDelegate(), source.getDelegate(), sourceDominant, hints));
     }
 
     @Override
-    protected void mergeModel_Name( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
+    public Model merge(Model target, Model source, boolean sourceDominant, Map<?, ?> hints) {
+        return super.merge(target, source, sourceDominant, hints);
+    }
+
+    @Override
+    protected Model mergeModel(Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
+        context.put(ARTIFACT_ID, target.getArtifactId());
+
+        return super.mergeModel(target, source, sourceDominant, context);
+    }
+
+    @Override
+    protected void mergeModel_Name(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
+        if (src != null) {
+            if (sourceDominant) {
+                builder.name(src);
+                builder.location("name", source.getLocation("name"));
             }
         }
     }
 
     @Override
-    protected void mergeModel_Url( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
+    protected void mergeModel_Url(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-            else if ( target.getUrl() == null )
-            {
-                target.setUrl( extrapolateChildUrl( src, source.isChildProjectUrlInheritAppendPath(), context ) );
-                target.setLocation( "url", source.getLocation( "url" ) );
+        if (src != null) {
+            if (sourceDominant) {
+                builder.url(src);
+                builder.location("url", source.getLocation("url"));
+            } else if (target.getUrl() == null) {
+                builder.url(extrapolateChildUrl(src, source.isChildProjectUrlInheritAppendPath(), context));
+                builder.location("url", source.getLocation("url"));
             }
         }
     }
@@ -114,155 +137,122 @@
      * merger
      */
     @Override
-    protected void mergeModel_Organization( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
+    protected void mergeModel_Organization(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         Organization src = source.getOrganization();
-        if ( src != null )
-        {
+        if (src != null) {
             Organization tgt = target.getOrganization();
-            if ( tgt == null )
-            {
-                tgt = new Organization();
-                tgt.setLocation( "", src.getLocation( "" ) );
-                target.setOrganization( tgt );
-                mergeOrganization( tgt, src, sourceDominant, context );
+            if (tgt == null) {
+                builder.organization(src);
+                builder.location("organisation", source.getLocation("organisation"));
             }
         }
     }
 
     @Override
-    protected void mergeModel_IssueManagement( Model target, Model source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
+    protected void mergeModel_IssueManagement(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         IssueManagement src = source.getIssueManagement();
-        if ( src != null )
-        {
+        if (src != null) {
             IssueManagement tgt = target.getIssueManagement();
-            if ( tgt == null )
-            {
-                tgt = new IssueManagement();
-                tgt.setLocation( "", src.getLocation( "" ) );
-                target.setIssueManagement( tgt );
-                mergeIssueManagement( tgt, src, sourceDominant, context );
+            if (tgt == null) {
+                builder.issueManagement(src);
+                builder.location("issueManagement", source.getLocation("issueManagement"));
             }
         }
     }
 
     @Override
-    protected void mergeModel_CiManagement( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
+    protected void mergeModel_CiManagement(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         CiManagement src = source.getCiManagement();
-        if ( src != null )
-        {
+        if (src != null) {
             CiManagement tgt = target.getCiManagement();
-            if ( tgt == null )
-            {
-                tgt = new CiManagement();
-                tgt.setLocation( "", src.getLocation( "" ) );
-                target.setCiManagement( tgt );
-                mergeCiManagement( tgt, src, sourceDominant, context );
+            if (tgt == null) {
+                builder.ciManagement(src);
+                builder.location("ciManagement", source.getLocation("ciManagement"));
             }
         }
     }
 
     @Override
-    protected void mergeModel_ModelVersion( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
+    protected void mergeModel_ModelVersion(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // neither inherited nor injected
     }
 
     @Override
-    protected void mergeModel_ArtifactId( Model target, Model source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
+    protected void mergeModel_ArtifactId(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // neither inherited nor injected
     }
 
     @Override
-    protected void mergeModel_Profiles( Model target, Model source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
+    protected void mergeModel_Profiles(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // neither inherited nor injected
     }
 
     @Override
-    protected void mergeModel_Prerequisites( Model target, Model source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
+    protected void mergeModel_Prerequisites(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
         // neither inherited nor injected
     }
 
     @Override
-    protected void mergeModel_Licenses( Model target, Model source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        if ( target.getLicenses().isEmpty() )
-        {
-            target.setLicenses( new ArrayList<>( source.getLicenses() ) );
+    protected void mergeModel_Licenses(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
+        builder.licenses(target.getLicenses().isEmpty() ? source.getLicenses() : target.getLicenses());
+    }
+
+    @Override
+    protected void mergeModel_Developers(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
+        builder.developers(target.getDevelopers().isEmpty() ? source.getDevelopers() : target.getDevelopers());
+    }
+
+    @Override
+    protected void mergeModel_Contributors(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
+        builder.contributors(target.getContributors().isEmpty() ? source.getContributors() : target.getContributors());
+    }
+
+    @Override
+    protected void mergeModel_MailingLists(
+            Model.Builder builder, Model target, Model source, boolean sourceDominant, Map<Object, Object> context) {
+        if (target.getMailingLists().isEmpty()) {
+            builder.mailingLists(source.getMailingLists());
         }
     }
 
     @Override
-    protected void mergeModel_Developers( Model target, Model source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        if ( target.getDevelopers().isEmpty() )
-        {
-            target.setDevelopers( new ArrayList<>( source.getDevelopers() ) );
-        }
-    }
-
-    @Override
-    protected void mergeModel_Contributors( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        if ( target.getContributors().isEmpty() )
-        {
-            target.setContributors( new ArrayList<>( source.getContributors() ) );
-        }
-    }
-
-    @Override
-    protected void mergeModel_MailingLists( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        if ( target.getMailingLists().isEmpty() )
-        {
-            target.setMailingLists( new ArrayList<>( source.getMailingLists() ) );
-        }
-    }
-
-    @Override
-    protected void mergeModelBase_Modules( ModelBase target, ModelBase source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
+    protected void mergeModelBase_Modules(
+            ModelBase.Builder builder,
+            ModelBase target,
+            ModelBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         List<String> src = source.getModules();
-        if ( !src.isEmpty() && sourceDominant )
-        {
+        if (!src.isEmpty() && sourceDominant) {
             List<Integer> indices = new ArrayList<>();
             List<String> tgt = target.getModules();
-            Set<String> excludes = new LinkedHashSet<>( tgt );
-            List<String> merged = new ArrayList<>( tgt.size() + src.size() );
-            merged.addAll( tgt );
-            for ( int i = 0, n = tgt.size(); i < n; i++ )
-            {
-                indices.add( i );
+            Set<String> excludes = new LinkedHashSet<>(tgt);
+            List<String> merged = new ArrayList<>(tgt.size() + src.size());
+            merged.addAll(tgt);
+            for (int i = 0, n = tgt.size(); i < n; i++) {
+                indices.add(i);
             }
-            for ( int i = 0, n = src.size(); i < n; i++ )
-            {
-                String s = src.get( i );
-                if ( !excludes.contains( s ) )
-                {
-                    merged.add( s );
-                    indices.add( ~i );
+            for (int i = 0, n = src.size(); i < n; i++) {
+                String s = src.get(i);
+                if (!excludes.contains(s)) {
+                    merged.add(s);
+                    indices.add(~i);
                 }
             }
-            target.setModules( merged );
-            target.setLocation( "modules", InputLocation.merge( target.getLocation( "modules" ),
-                                                                source.getLocation( "modules" ), indices ) );
+            builder.modules(merged);
+            builder.location(
+                    "modules",
+                    InputLocation.merge(target.getLocation("modules"), source.getLocation("modules"), indices));
         }
     }
 
@@ -271,84 +261,76 @@
      * source-first, dominant-first, recessive-first
      */
     @Override
-    protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
+    protected void mergeModelBase_Repositories(
+            ModelBase.Builder builder,
+            ModelBase target,
+            ModelBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         List<Repository> src = source.getRepositories();
-        if ( !src.isEmpty() )
-        {
+        if (!src.isEmpty()) {
             List<Repository> tgt = target.getRepositories();
-            Map<Object, Repository> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+            Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
             List<Repository> dominant, recessive;
-            if ( sourceDominant )
-            {
+            if (sourceDominant) {
                 dominant = src;
                 recessive = tgt;
-            }
-            else
-            {
+            } else {
                 dominant = tgt;
                 recessive = src;
             }
 
-            for ( Repository element : dominant )
-            {
-                Object key = getRepositoryKey().apply( element );
-                merged.put( key, element );
+            for (Repository element : dominant) {
+                Object key = getRepositoryKey().apply(element);
+                merged.put(key, element);
             }
 
-            for ( Repository element : recessive )
-            {
-                Object key = getRepositoryKey().apply( element );
-                if ( !merged.containsKey( key ) )
-                {
-                    merged.put( key, element );
+            for (Repository element : recessive) {
+                Object key = getRepositoryKey().apply(element);
+                if (!merged.containsKey(key)) {
+                    merged.put(key, element);
                 }
             }
 
-            target.setRepositories( new ArrayList<>( merged.values() ) );
+            builder.repositories(merged.values());
         }
     }
 
     @Override
-    protected void mergeModelBase_PluginRepositories( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                      Map<Object, Object> context )
-    {
+    protected void mergeModelBase_PluginRepositories(
+            ModelBase.Builder builder,
+            ModelBase target,
+            ModelBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         List<Repository> src = source.getPluginRepositories();
-        if ( !src.isEmpty() )
-        {
+        if (!src.isEmpty()) {
             List<Repository> tgt = target.getPluginRepositories();
-            Map<Object, Repository> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+            Map<Object, Repository> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
             List<Repository> dominant, recessive;
-            if ( sourceDominant )
-            {
+            if (sourceDominant) {
                 dominant = src;
                 recessive = tgt;
-            }
-            else
-            {
+            } else {
                 dominant = tgt;
                 recessive = src;
             }
 
-            for ( Repository element : dominant )
-            {
-                Object key = getRepositoryKey().apply( element );
-                merged.put( key, element );
+            for (Repository element : dominant) {
+                Object key = getRepositoryKey().apply(element);
+                merged.put(key, element);
             }
 
-            for ( Repository element : recessive )
-            {
-                Object key = getRepositoryKey().apply( element );
-                if ( !merged.containsKey( key ) )
-                {
-                    merged.put( key, element );
+            for (Repository element : recessive) {
+                Object key = getRepositoryKey().apply(element);
+                if (!merged.containsKey(key)) {
+                    merged.put(key, element);
                 }
             }
 
-            target.setPluginRepositories( new ArrayList<>( merged.values() ) );
+            builder.pluginRepositories(merged.values());
         }
     }
 
@@ -356,344 +338,309 @@
      * TODO: Whether duplicates should be removed looks like an option for the generated merger.
      */
     @Override
-    protected void mergeBuildBase_Filters( BuildBase target, BuildBase source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
+    protected void mergeBuildBase_Filters(
+            BuildBase.Builder builder,
+            BuildBase target,
+            BuildBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         List<String> src = source.getFilters();
-        if ( !src.isEmpty() )
-        {
+        if (!src.isEmpty()) {
             List<String> tgt = target.getFilters();
-            Set<String> excludes = new LinkedHashSet<>( tgt );
-            List<String> merged = new ArrayList<>( tgt.size() + src.size() );
-            merged.addAll( tgt );
-            for ( String s : src )
-            {
-                if ( !excludes.contains( s ) )
-                {
-                    merged.add( s );
+            Set<String> excludes = new LinkedHashSet<>(tgt);
+            List<String> merged = new ArrayList<>(tgt.size() + src.size());
+            merged.addAll(tgt);
+            for (String s : src) {
+                if (!excludes.contains(s)) {
+                    merged.add(s);
                 }
             }
-            target.setFilters( merged );
+            builder.filters(merged);
         }
     }
 
     @Override
-    protected void mergeBuildBase_Resources( BuildBase target, BuildBase source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        if ( sourceDominant || target.getResources().isEmpty() )
-        {
-            super.mergeBuildBase_Resources( target, source, sourceDominant, context );
+    protected void mergeBuildBase_Resources(
+            BuildBase.Builder builder,
+            BuildBase target,
+            BuildBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
+        if (sourceDominant || target.getResources().isEmpty()) {
+            super.mergeBuildBase_Resources(builder, target, source, sourceDominant, context);
         }
     }
 
     @Override
-    protected void mergeBuildBase_TestResources( BuildBase target, BuildBase source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
-        if ( sourceDominant || target.getTestResources().isEmpty() )
-        {
-            super.mergeBuildBase_TestResources( target, source, sourceDominant, context );
+    protected void mergeBuildBase_TestResources(
+            BuildBase.Builder builder,
+            BuildBase target,
+            BuildBase source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
+        if (sourceDominant || target.getTestResources().isEmpty()) {
+            super.mergeBuildBase_TestResources(builder, target, source, sourceDominant, context);
         }
     }
 
     @Override
-    protected void mergeDistributionManagement_Repository( DistributionManagement target,
-                                                           DistributionManagement source, boolean sourceDominant,
-                                                           Map<Object, Object> context )
-    {
+    protected void mergeDistributionManagement_Relocation(
+            DistributionManagement.Builder builder,
+            DistributionManagement target,
+            DistributionManagement source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {}
+
+    @Override
+    protected void mergeDistributionManagement_Repository(
+            DistributionManagement.Builder builder,
+            DistributionManagement target,
+            DistributionManagement source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         DeploymentRepository src = source.getRepository();
-        if ( src != null )
-        {
+        if (src != null) {
             DeploymentRepository tgt = target.getRepository();
-            if ( sourceDominant || tgt == null )
-            {
-                tgt = new DeploymentRepository();
-                tgt.setLocation( "", src.getLocation( "" ) );
-                target.setRepository( tgt );
-                mergeDeploymentRepository( tgt, src, sourceDominant, context );
+            if (sourceDominant || tgt == null) {
+                tgt = DeploymentRepository.newInstance(false);
+                builder.repository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
             }
         }
     }
 
     @Override
-    protected void mergeDistributionManagement_SnapshotRepository( DistributionManagement target,
-                                                                   DistributionManagement source,
-                                                                   boolean sourceDominant,
-                                                                   Map<Object, Object> context )
-    {
+    protected void mergeDistributionManagement_SnapshotRepository(
+            DistributionManagement.Builder builder,
+            DistributionManagement target,
+            DistributionManagement source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         DeploymentRepository src = source.getSnapshotRepository();
-        if ( src != null )
-        {
+        if (src != null) {
             DeploymentRepository tgt = target.getSnapshotRepository();
-            if ( sourceDominant || tgt == null )
-            {
-                tgt = new DeploymentRepository();
-                tgt.setLocation( "", src.getLocation( "" ) );
-                target.setSnapshotRepository( tgt );
-                mergeDeploymentRepository( tgt, src, sourceDominant, context );
+            if (sourceDominant || tgt == null) {
+                tgt = DeploymentRepository.newInstance(false);
+                builder.snapshotRepository(mergeDeploymentRepository(tgt, src, sourceDominant, context));
             }
         }
     }
 
     @Override
-    protected void mergeDistributionManagement_Site( DistributionManagement target, DistributionManagement source,
-                                                     boolean sourceDominant, Map<Object, Object> context )
-    {
+    protected void mergeDistributionManagement_Site(
+            DistributionManagement.Builder builder,
+            DistributionManagement target,
+            DistributionManagement source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         Site src = source.getSite();
-        if ( src != null )
-        {
+        if (src != null) {
             Site tgt = target.getSite();
-            if ( sourceDominant || tgt == null || isSiteEmpty( tgt ) )
-            {
-                if ( tgt == null )
-                {
-                    tgt = new Site();
-                }
-                tgt.setLocation( "", src.getLocation( "" ) );
-                target.setSite( tgt );
-                mergeSite( tgt, src, sourceDominant, context );
+            if (tgt == null) {
+                tgt = Site.newBuilder(false).build();
             }
-            mergeSite_ChildSiteUrlInheritAppendPath( tgt, src, sourceDominant, context );
+            Site.Builder sbuilder = Site.newBuilder(tgt);
+            if (sourceDominant || tgt == null || isSiteEmpty(tgt)) {
+                mergeSite(sbuilder, tgt, src, sourceDominant, context);
+            }
+            super.mergeSite_ChildSiteUrlInheritAppendPath(sbuilder, tgt, src, sourceDominant, context);
+            builder.site(sbuilder.build());
         }
     }
 
     @Override
-    protected void mergeSite( Site target, Site source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeSite_Id( target, source, sourceDominant, context );
-        mergeSite_Name( target, source, sourceDominant, context );
-        mergeSite_Url( target, source, sourceDominant, context );
-    }
+    protected void mergeSite_ChildSiteUrlInheritAppendPath(
+            Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {}
 
-    protected boolean isSiteEmpty( Site site )
-    {
-        return StringUtils.isEmpty( site.getId() ) && StringUtils.isEmpty( site.getName() )
-            && StringUtils.isEmpty( site.getUrl() );
+    protected boolean isSiteEmpty(Site site) {
+        return (site.getId() == null || site.getId().isEmpty())
+                && (site.getName() == null || site.getName().isEmpty())
+                && (site.getUrl() == null || site.getUrl().isEmpty());
     }
 
     @Override
-    protected void mergeSite_Url( Site target, Site source, boolean sourceDominant, Map<Object, Object> context )
-    {
+    protected void mergeSite_Url(
+            Site.Builder builder, Site target, Site source, boolean sourceDominant, Map<Object, Object> context) {
         String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-            else if ( target.getUrl() == null )
-            {
-                target.setUrl( extrapolateChildUrl( src, source.isChildSiteUrlInheritAppendPath(), context ) );
-                target.setLocation( "url", source.getLocation( "url" ) );
+        if (src != null) {
+            if (sourceDominant) {
+                builder.url(src);
+                builder.location("url", source.getLocation("url"));
+            } else if (target.getUrl() == null) {
+                builder.url(extrapolateChildUrl(src, source.isChildSiteUrlInheritAppendPath(), context));
+                builder.location("url", source.getLocation("url"));
             }
         }
     }
 
     @Override
-    protected void mergeScm_Url( Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context )
-    {
+    protected void mergeScm_Url(
+            Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
         String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-            else if ( target.getUrl() == null )
-            {
-                target.setUrl( extrapolateChildUrl( src, source.isChildScmUrlInheritAppendPath(), context ) );
-                target.setLocation( "url", source.getLocation( "url" ) );
+        if (src != null) {
+            if (sourceDominant) {
+                builder.url(src);
+                builder.location("url", source.getLocation("url"));
+            } else if (target.getUrl() == null) {
+                builder.url(extrapolateChildUrl(src, source.isChildScmUrlInheritAppendPath(), context));
+                builder.location("url", source.getLocation("url"));
             }
         }
     }
 
     @Override
-    protected void mergeScm_Connection( Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context )
-    {
+    protected void mergeScm_Connection(
+            Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
         String src = source.getConnection();
-        if ( src != null )
-        {
-            if ( sourceDominant )
-            {
-                target.setConnection( src );
-                target.setLocation( "connection", source.getLocation( "connection" ) );
-            }
-            else if ( target.getConnection() == null )
-            {
-                target.setConnection( extrapolateChildUrl( src, source.isChildScmConnectionInheritAppendPath(),
-                                                           context ) );
-                target.setLocation( "connection", source.getLocation( "connection" ) );
+        if (src != null) {
+            if (sourceDominant) {
+                builder.connection(src);
+                builder.location("connection", source.getLocation("connection"));
+            } else if (target.getConnection() == null) {
+                builder.connection(extrapolateChildUrl(src, source.isChildScmConnectionInheritAppendPath(), context));
+                builder.location("connection", source.getLocation("connection"));
             }
         }
     }
 
     @Override
-    protected void mergeScm_DeveloperConnection( Scm target, Scm source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
+    protected void mergeScm_DeveloperConnection(
+            Scm.Builder builder, Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context) {
         String src = source.getDeveloperConnection();
-        if ( src != null )
-        {
-            if ( sourceDominant )
-            {
-                target.setDeveloperConnection( src );
-                target.setLocation( "developerConnection", source.getLocation( "developerConnection" ) );
-            }
-            else if ( target.getDeveloperConnection() == null )
-            {
-                String e = extrapolateChildUrl( src, source.isChildScmDeveloperConnectionInheritAppendPath(), context );
-                target.setDeveloperConnection( e );
-                target.setLocation( "developerConnection", source.getLocation( "developerConnection" ) );
+        if (src != null) {
+            if (sourceDominant) {
+                builder.developerConnection(src);
+                builder.location("developerConnection", source.getLocation("developerConnection"));
+            } else if (target.getDeveloperConnection() == null) {
+                String e = extrapolateChildUrl(src, source.isChildScmDeveloperConnectionInheritAppendPath(), context);
+                builder.developerConnection(e);
+                builder.location("developerConnection", source.getLocation("developerConnection"));
             }
         }
     }
 
     @Override
-    protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
+    protected void mergePlugin_Executions(
+            Plugin.Builder builder, Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context) {
         List<PluginExecution> src = source.getExecutions();
-        if ( !src.isEmpty() )
-        {
+        if (!src.isEmpty()) {
             List<PluginExecution> tgt = target.getExecutions();
-            Map<Object, PluginExecution> merged =
-                new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+            Map<Object, PluginExecution> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-            for ( PluginExecution element : src )
-            {
-                if ( sourceDominant
-                                || ( element.getInherited() != null ? element.isInherited() : source.isInherited() ) )
-                {
-                    Object key = getPluginExecutionKey().apply( element );
-                    merged.put( key, element );
+            for (PluginExecution element : src) {
+                if (sourceDominant || (element.getInherited() != null ? element.isInherited() : source.isInherited())) {
+                    Object key = getPluginExecutionKey().apply(element);
+                    merged.put(key, element);
                 }
             }
 
-            for ( PluginExecution element : tgt )
-            {
-                Object key = getPluginExecutionKey().apply( element );
-                PluginExecution existing = merged.get( key );
-                if ( existing != null )
-                {
-                    mergePluginExecution( element, existing, sourceDominant, context );
+            for (PluginExecution element : tgt) {
+                Object key = getPluginExecutionKey().apply(element);
+                PluginExecution existing = merged.get(key);
+                if (existing != null) {
+                    element = mergePluginExecution(element, existing, sourceDominant, context);
                 }
-                merged.put( key, element );
+                merged.put(key, element);
             }
 
-            target.setExecutions( new ArrayList<>( merged.values() ) );
+            builder.executions(merged.values());
         }
     }
 
     @Override
-    protected void mergePluginExecution_Goals( PluginExecution target, PluginExecution source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
+    protected void mergePluginExecution_Goals(
+            PluginExecution.Builder builder,
+            PluginExecution target,
+            PluginExecution source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         List<String> src = source.getGoals();
-        if ( !src.isEmpty() )
-        {
+        if (!src.isEmpty()) {
             List<String> tgt = target.getGoals();
-            Set<String> excludes = new LinkedHashSet<>( tgt );
-            List<String> merged = new ArrayList<>( tgt.size() + src.size() );
-            merged.addAll( tgt );
-            for ( String s : src )
-            {
-                if ( !excludes.contains( s ) )
-                {
-                    merged.add( s );
+            Set<String> excludes = new LinkedHashSet<>(tgt);
+            List<String> merged = new ArrayList<>(tgt.size() + src.size());
+            merged.addAll(tgt);
+            for (String s : src) {
+                if (!excludes.contains(s)) {
+                    merged.add(s);
                 }
             }
-            target.setGoals( merged );
+            builder.goals(merged);
         }
     }
 
     @Override
-    protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
+    protected void mergeReportPlugin_ReportSets(
+            ReportPlugin.Builder builder,
+            ReportPlugin target,
+            ReportPlugin source,
+            boolean sourceDominant,
+            Map<Object, Object> context) {
         List<ReportSet> src = source.getReportSets();
-        if ( !src.isEmpty() )
-        {
+        if (!src.isEmpty()) {
             List<ReportSet> tgt = target.getReportSets();
-            Map<Object, ReportSet> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+            Map<Object, ReportSet> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-            for ( ReportSet rset : src )
-            {
-                if ( sourceDominant || ( rset.getInherited() != null ? rset.isInherited() : source.isInherited() ) )
-                {
-                    Object key = getReportSetKey().apply( rset );
-                    merged.put( key, rset );
+            for (ReportSet rset : src) {
+                if (sourceDominant || (rset.getInherited() != null ? rset.isInherited() : source.isInherited())) {
+                    Object key = getReportSetKey().apply(rset);
+                    merged.put(key, rset);
                 }
             }
 
-            for ( ReportSet element : tgt )
-            {
-                Object key = getReportSetKey().apply( element );
-                ReportSet existing = merged.get( key );
-                if ( existing != null )
-                {
-                    mergeReportSet( element, existing, sourceDominant, context );
+            for (ReportSet element : tgt) {
+                Object key = getReportSetKey().apply(element);
+                ReportSet existing = merged.get(key);
+                if (existing != null) {
+                    mergeReportSet(element, existing, sourceDominant, context);
                 }
-                merged.put( key, element );
+                merged.put(key, element);
             }
 
-            target.setReportSets( new ArrayList<>( merged.values() ) );
+            builder.reportSets(merged.values());
         }
     }
 
     @Override
-    protected KeyComputer<Dependency> getDependencyKey()
-    {
+    protected KeyComputer<Dependency> getDependencyKey() {
         return Dependency::getManagementKey;
     }
 
     @Override
-    protected KeyComputer<Plugin> getPluginKey()
-    {
+    protected KeyComputer<Plugin> getPluginKey() {
         return Plugin::getKey;
     }
 
     @Override
-    protected KeyComputer<PluginExecution> getPluginExecutionKey()
-    {
+    protected KeyComputer<PluginExecution> getPluginExecutionKey() {
         return PluginExecution::getId;
     }
 
     @Override
-    protected KeyComputer<ReportPlugin> getReportPluginKey()
-    {
+    protected KeyComputer<ReportPlugin> getReportPluginKey() {
         return ReportPlugin::getKey;
     }
 
     @Override
-    protected KeyComputer<ReportSet> getReportSetKey()
-    {
+    protected KeyComputer<ReportSet> getReportSetKey() {
         return ReportSet::getId;
     }
 
     @Override
-    protected KeyComputer<RepositoryBase> getRepositoryBaseKey()
-    {
+    protected KeyComputer<RepositoryBase> getRepositoryBaseKey() {
         return RepositoryBase::getId;
     }
 
     @Override
-    protected KeyComputer<Extension> getExtensionKey()
-    {
+    protected KeyComputer<Extension> getExtensionKey() {
         return e -> e.getGroupId() + ':' + e.getArtifactId();
     }
 
     @Override
-    protected KeyComputer<Exclusion> getExclusionKey()
-    {
+    protected KeyComputer<Exclusion> getExclusionKey() {
         return e -> e.getGroupId() + ':' + e.getArtifactId();
     }
 
-    protected String extrapolateChildUrl( String parentUrl, boolean appendPath, Map<Object, Object> context )
-    {
+    protected String extrapolateChildUrl(String parentUrl, boolean appendPath, Map<Object, Object> context) {
         return parentUrl;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/normalization/DefaultModelNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/normalization/DefaultModelNormalizer.java
index 9f86c09..3f79a79 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/normalization/DefaultModelNormalizer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/normalization/DefaultModelNormalizer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.normalization;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,61 +16,69 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.normalization;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Function;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.model.Build;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Plugin;
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Plugin;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.merge.MavenModelMerger;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Handles normalization of a model.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultModelNormalizer
-    implements ModelNormalizer
-{
+public class DefaultModelNormalizer implements ModelNormalizer {
 
     private DuplicateMerger merger = new DuplicateMerger();
 
     @Override
-    public void mergeDuplicates( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
-        Build build = model.getBuild();
-        if ( build != null )
-        {
-            List<Plugin> plugins = build.getPlugins();
-            Map<Object, Plugin> normalized = new LinkedHashMap<>( plugins.size() * 2 );
+    public void mergeDuplicates(
+            org.apache.maven.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
+        model.update(mergeDuplicates(model.getDelegate(), request, problems));
+    }
 
-            for ( Plugin plugin : plugins )
-            {
+    @Override
+    public void injectDefaultValues(
+            org.apache.maven.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
+        model.update(injectDefaultValues(model.getDelegate(), request, problems));
+    }
+
+    @Override
+    public Model mergeDuplicates(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
+        Model.Builder builder = Model.newBuilder(model);
+
+        Build build = model.getBuild();
+        if (build != null) {
+            List<Plugin> plugins = build.getPlugins();
+            Map<Object, Plugin> normalized = new LinkedHashMap<>(plugins.size() * 2);
+
+            for (Plugin plugin : plugins) {
                 Object key = plugin.getKey();
-                Plugin first = normalized.get( key );
-                if ( first != null )
-                {
-                    merger.mergePlugin( plugin, first );
+                Plugin first = normalized.get(key);
+                if (first != null) {
+                    plugin = merger.mergePlugin(plugin, first);
                 }
-                normalized.put( key, plugin );
+                normalized.put(key, plugin);
             }
 
-            if ( plugins.size() != normalized.size() )
-            {
-                build.setPlugins( new ArrayList<>( normalized.values() ) );
+            if (plugins.size() != normalized.size()) {
+                builder.build(
+                        Build.newBuilder(build).plugins(normalized.values()).build());
             }
         }
 
@@ -84,58 +90,71 @@
          * aftereffects and bogus error messages.
          */
         List<Dependency> dependencies = model.getDependencies();
-        Map<String, Dependency> normalized = new LinkedHashMap<>( dependencies.size() * 2 );
+        Map<String, Dependency> normalized = new LinkedHashMap<>(dependencies.size() * 2);
 
-        for ( Dependency dependency : dependencies )
-        {
-            normalized.put( dependency.getManagementKey(), dependency );
+        for (Dependency dependency : dependencies) {
+            normalized.put(dependency.getManagementKey(), dependency);
         }
 
-        if ( dependencies.size() != normalized.size() )
-        {
-            model.setDependencies( new ArrayList<>( normalized.values() ) );
+        if (dependencies.size() != normalized.size()) {
+            builder.dependencies(normalized.values());
         }
+
+        return builder.build();
     }
 
     /**
      * DuplicateMerger
      */
-    protected static class DuplicateMerger
-        extends MavenModelMerger
-    {
+    protected static class DuplicateMerger extends MavenModelMerger {
 
-        public void mergePlugin( Plugin target, Plugin source )
-        {
-            super.mergePlugin( target, source, false, Collections.emptyMap() );
+        public Plugin mergePlugin(Plugin target, Plugin source) {
+            return super.mergePlugin(target, source, false, Collections.emptyMap());
         }
-
     }
 
     @Override
-    public void injectDefaultValues( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
-        injectDependencyDefaults( model.getDependencies() );
+    public Model injectDefaultValues(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
+        Model.Builder builder = Model.newBuilder(model);
 
+        builder.dependencies(injectList(model.getDependencies(), this::injectDependency));
         Build build = model.getBuild();
-        if ( build != null )
-        {
-            for ( Plugin plugin : build.getPlugins() )
-            {
-                injectDependencyDefaults( plugin.getDependencies() );
-            }
+        if (build != null) {
+            Build newBuild = Build.newBuilder(build)
+                    .plugins(injectList(build.getPlugins(), this::injectPlugin))
+                    .build();
+            builder.build(newBuild != build ? newBuild : null);
         }
+
+        return builder.build();
     }
 
-    private void injectDependencyDefaults( List<Dependency> dependencies )
-    {
-        for ( Dependency dependency : dependencies )
-        {
-            if ( StringUtils.isEmpty( dependency.getScope() ) )
-            {
-                // we cannot set this directly in the MDO due to the interactions with dependency management
-                dependency.setScope( "compile" );
-            }
-        }
+    private Plugin injectPlugin(Plugin p) {
+        return Plugin.newBuilder(p)
+                .dependencies(injectList(p.getDependencies(), this::injectDependency))
+                .build();
     }
 
+    private Dependency injectDependency(Dependency d) {
+        // we cannot set this directly in the MDO due to the interactions with dependency management
+        return (d.getScope() == null || d.getScope().isEmpty()) ? d.withScope("compile") : d;
+    }
+
+    /**
+     * Returns a list suited for the builders, i.e. null if not modified
+     */
+    private <T> List<T> injectList(List<T> list, Function<T, T> modifer) {
+        List<T> newList = null;
+        for (int i = 0; i < list.size(); i++) {
+            T oldT = list.get(i);
+            T newT = modifer.apply(oldT);
+            if (newT != oldT) {
+                if (newList == null) {
+                    newList = new ArrayList<>(list);
+                }
+                newList.set(i, newT);
+            }
+        }
+        return newList;
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/normalization/ModelNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/normalization/ModelNormalizer.java
index 7cab86b..aedc334 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/normalization/ModelNormalizer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/normalization/ModelNormalizer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.normalization;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.normalization;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -27,10 +26,8 @@
  * Handles normalization of a model. In this context, normalization is the process of producing a canonical
  * representation for models that physically look different but are semantically equivalent.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelNormalizer
-{
+public interface ModelNormalizer {
 
     /**
      * Merges duplicate elements like multiple declarations of the same build plugin in the specified model.
@@ -39,7 +36,7 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void mergeDuplicates( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
+    void mergeDuplicates(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 
     /**
      * Sets default values in the specified model that for technical reasons cannot be set directly in the Modello
@@ -49,6 +46,11 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void injectDefaultValues( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
+    void injectDefaultValues(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 
+    org.apache.maven.api.model.Model mergeDuplicates(
+            org.apache.maven.api.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems);
+
+    org.apache.maven.api.model.Model injectDefaultValues(
+            org.apache.maven.api.model.Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelPathTranslator.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelPathTranslator.java
index 801499f..1ec7468 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelPathTranslator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelPathTranslator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,96 +16,106 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
+package org.apache.maven.model.path;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.maven.model.Build;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Reporting;
-import org.apache.maven.model.Resource;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Reporting;
+import org.apache.maven.api.model.Resource;
 import org.apache.maven.model.building.ModelBuildingRequest;
 
 /**
  * Resolves relative paths within a model against a specific base directory.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultModelPathTranslator
-    implements ModelPathTranslator
-{
+public class DefaultModelPathTranslator implements ModelPathTranslator {
 
     private final PathTranslator pathTranslator;
 
     @Inject
-    public DefaultModelPathTranslator( PathTranslator pathTranslator )
-    {
+    public DefaultModelPathTranslator(PathTranslator pathTranslator) {
         this.pathTranslator = pathTranslator;
     }
 
     @Override
-    public void alignToBaseDirectory( Model model, File basedir, ModelBuildingRequest request )
-    {
-        if ( model == null || basedir == null )
-        {
+    public void alignToBaseDirectory(org.apache.maven.model.Model modelV3, File basedir, ModelBuildingRequest request) {
+        if (modelV3 == null || basedir == null) {
             return;
         }
 
+        Model model = modelV3.getDelegate();
         Build build = model.getBuild();
-
-        if ( build != null )
-        {
-            build.setDirectory( alignToBaseDirectory( build.getDirectory(), basedir ) );
-
-            build.setSourceDirectory( alignToBaseDirectory( build.getSourceDirectory(), basedir ) );
-
-            build.setTestSourceDirectory( alignToBaseDirectory( build.getTestSourceDirectory(), basedir ) );
-
-            build.setScriptSourceDirectory( alignToBaseDirectory( build.getScriptSourceDirectory(), basedir ) );
-
-            for ( Resource resource : build.getResources() )
-            {
-                resource.setDirectory( alignToBaseDirectory( resource.getDirectory(), basedir ) );
-            }
-
-            for ( Resource resource : build.getTestResources() )
-            {
-                resource.setDirectory( alignToBaseDirectory( resource.getDirectory(), basedir ) );
-            }
-
-            if ( build.getFilters() != null )
-            {
-                List<String> filters = new ArrayList<>( build.getFilters().size() );
-                for ( String filter : build.getFilters() )
-                {
-                    filters.add( alignToBaseDirectory( filter, basedir ) );
-                }
-                build.setFilters( filters );
-            }
-
-            build.setOutputDirectory( alignToBaseDirectory( build.getOutputDirectory(), basedir ) );
-
-            build.setTestOutputDirectory( alignToBaseDirectory( build.getTestOutputDirectory(), basedir ) );
+        Build newBuild = null;
+        if (build != null) {
+            newBuild = Build.newBuilder(build)
+                    .directory(alignToBaseDirectory(build.getDirectory(), basedir))
+                    .sourceDirectory(alignToBaseDirectory(build.getSourceDirectory(), basedir))
+                    .testSourceDirectory(alignToBaseDirectory(build.getTestSourceDirectory(), basedir))
+                    .scriptSourceDirectory(alignToBaseDirectory(build.getScriptSourceDirectory(), basedir))
+                    .resources(map(build.getResources(), r -> alignToBaseDirectory(r, basedir)))
+                    .testResources(map(build.getTestResources(), r -> alignToBaseDirectory(r, basedir)))
+                    .filters(map(build.getFilters(), s -> alignToBaseDirectory(s, basedir)))
+                    .outputDirectory(alignToBaseDirectory(build.getOutputDirectory(), basedir))
+                    .testOutputDirectory(alignToBaseDirectory(build.getTestOutputDirectory(), basedir))
+                    .build();
         }
 
         Reporting reporting = model.getReporting();
-
-        if ( reporting != null )
-        {
-            reporting.setOutputDirectory( alignToBaseDirectory( reporting.getOutputDirectory(), basedir ) );
+        Reporting newReporting = null;
+        if (reporting != null) {
+            newReporting = Reporting.newBuilder(reporting)
+                    .outputDirectory(alignToBaseDirectory(reporting.getOutputDirectory(), basedir))
+                    .build();
+        }
+        if (newBuild != build || newReporting != reporting) {
+            modelV3.update(Model.newBuilder(model)
+                    .build(newBuild)
+                    .reporting(newReporting)
+                    .build());
         }
     }
 
-    private String alignToBaseDirectory( String path, File basedir )
-    {
-        return pathTranslator.alignToBaseDirectory( path, basedir );
+    private <T> List<T> map(List<T> resources, Function<T, T> mapper) {
+        List<T> newResources = null;
+        if (resources != null) {
+            for (int i = 0; i < resources.size(); i++) {
+                T resource = resources.get(i);
+                T newResource = mapper.apply(resource);
+                if (newResource != null) {
+                    if (newResources == null) {
+                        newResources = new ArrayList<>(resources);
+                    }
+                    newResources.set(i, newResource);
+                }
+            }
+        }
+        return newResources;
     }
 
+    private Resource alignToBaseDirectory(Resource resource, File basedir) {
+        if (resource != null) {
+            String newDir = alignToBaseDirectory(resource.getDirectory(), basedir);
+            if (newDir != null) {
+                return resource.withDirectory(newDir);
+            }
+        }
+        return resource;
+    }
+
+    private String alignToBaseDirectory(String path, File basedir) {
+        String newPath = pathTranslator.alignToBaseDirectory(path, basedir);
+        return Objects.equals(path, newPath) ? null : newPath;
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelUrlNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelUrlNormalizer.java
index 92d7bbd..ca0090e 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelUrlNormalizer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultModelUrlNormalizer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
 import javax.inject.Inject;
 import javax.inject.Named;
@@ -33,54 +32,43 @@
  * Normalizes URLs to remove the ugly parent references "../" that got potentially inserted by URL adjustment during
  * model inheritance.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultModelUrlNormalizer
-    implements ModelUrlNormalizer
-{
+public class DefaultModelUrlNormalizer implements ModelUrlNormalizer {
 
     private final UrlNormalizer urlNormalizer;
 
     @Inject
-    public DefaultModelUrlNormalizer( UrlNormalizer urlNormalizer )
-    {
+    public DefaultModelUrlNormalizer(UrlNormalizer urlNormalizer) {
         this.urlNormalizer = urlNormalizer;
     }
 
     @Override
-    public void normalize( Model model, ModelBuildingRequest request )
-    {
-        if ( model == null )
-        {
+    public void normalize(Model model, ModelBuildingRequest request) {
+        if (model == null) {
             return;
         }
 
-        model.setUrl( normalize( model.getUrl() ) );
+        model.setUrl(normalize(model.getUrl()));
 
         Scm scm = model.getScm();
-        if ( scm != null )
-        {
-            scm.setUrl( normalize( scm.getUrl() ) );
-            scm.setConnection( normalize( scm.getConnection() ) );
-            scm.setDeveloperConnection( normalize( scm.getDeveloperConnection() ) );
+        if (scm != null) {
+            scm.setUrl(normalize(scm.getUrl()));
+            scm.setConnection(normalize(scm.getConnection()));
+            scm.setDeveloperConnection(normalize(scm.getDeveloperConnection()));
         }
 
         DistributionManagement dist = model.getDistributionManagement();
-        if ( dist != null )
-        {
+        if (dist != null) {
             Site site = dist.getSite();
-            if ( site != null )
-            {
-                site.setUrl( normalize( site.getUrl() ) );
+            if (site != null) {
+                site.setUrl(normalize(site.getUrl()));
             }
         }
     }
 
-    private String normalize( String url )
-    {
-        return urlNormalizer.normalize( url );
+    private String normalize(String url) {
+        return urlNormalizer.normalize(url);
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultPathTranslator.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultPathTranslator.java
index f15da53..f5119b9 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultPathTranslator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultPathTranslator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,51 +16,41 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
+package org.apache.maven.model.path;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+
 /**
  * Resolves relative paths against a specific base directory.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultPathTranslator
-    implements PathTranslator
-{
+public class DefaultPathTranslator implements PathTranslator {
 
     @Override
-    public String alignToBaseDirectory( String path, File basedir )
-    {
+    public String alignToBaseDirectory(String path, File basedir) {
         String result = path;
 
-        if ( path != null && basedir != null )
-        {
-            path = path.replace( '\\', File.separatorChar ).replace( '/', File.separatorChar );
+        if (path != null && basedir != null) {
+            path = path.replace('\\', File.separatorChar).replace('/', File.separatorChar);
 
-            File file = new File( path );
-            if ( file.isAbsolute() )
-            {
+            File file = new File(path);
+            if (file.isAbsolute()) {
                 // path was already absolute, just normalize file separator and we're done
                 result = file.getPath();
-            }
-            else if ( file.getPath().startsWith( File.separator ) )
-            {
+            } else if (file.getPath().startsWith(File.separator)) {
                 // drive-relative Windows path, don't align with project directory but with drive root
                 result = file.getAbsolutePath();
-            }
-            else
-            {
+            } else {
                 // an ordinary relative path, align with project directory
-                result = new File( new File( basedir, path ).toURI().normalize() ).getAbsolutePath();
+                result = new File(new File(basedir, path).toURI().normalize()).getAbsolutePath();
             }
         }
 
         return result;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultUrlNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultUrlNormalizer.java
index af445a4..aa97b04 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultUrlNormalizer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/DefaultUrlNormalizer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -25,51 +24,37 @@
 /**
  * Normalizes a URL.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultUrlNormalizer
-    implements UrlNormalizer
-{
+public class DefaultUrlNormalizer implements UrlNormalizer {
 
     @Override
-    public String normalize( String url )
-    {
+    public String normalize(String url) {
         String result = url;
 
-        if ( result != null )
-        {
-            while ( true )
-            {
-                int idx = result.indexOf( "/../" );
-                if ( idx < 0 )
-                {
+        if (result != null) {
+            while (true) {
+                int idx = result.indexOf("/../");
+                if (idx < 0) {
                     break;
-                }
-                else if ( idx == 0 )
-                {
-                    result = result.substring( 3 );
+                } else if (idx == 0) {
+                    result = result.substring(3);
                     continue;
                 }
                 int parent = idx - 1;
-                while ( parent >= 0 && result.charAt( parent ) == '/' )
-                {
+                while (parent >= 0 && result.charAt(parent) == '/') {
                     parent--;
                 }
-                parent = result.lastIndexOf( '/', parent );
-                if ( parent < 0 )
-                {
-                    result = result.substring( idx + 4 );
-                }
-                else
-                {
-                    result = result.substring( 0, parent ) + result.substring( idx + 3 );
+                parent = result.lastIndexOf('/', parent);
+                if (parent < 0) {
+                    result = result.substring(idx + 4);
+                } else {
+                    result = result.substring(0, parent) + result.substring(idx + 3);
                 }
             }
         }
 
         return result;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelPathTranslator.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelPathTranslator.java
index 2bd39c5..a1b3431 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelPathTranslator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelPathTranslator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
 import java.io.File;
 
@@ -27,10 +26,8 @@
 /**
  * Resolves relative paths of a model against a specific base directory.
  *
- * @author Jason van Zyl
  */
-public interface ModelPathTranslator
-{
+public interface ModelPathTranslator {
 
     /**
      * Resolves the well-known paths of the specified model against the given base directory. Paths within plugin
@@ -40,6 +37,5 @@
      * @param basedir The base directory to resolve relative paths against, may be {@code null}.
      * @param request The model building request that holds further settings, must not be {@code null}.
      */
-    void alignToBaseDirectory( Model model, File basedir, ModelBuildingRequest request );
-
+    void alignToBaseDirectory(Model model, File basedir, ModelBuildingRequest request);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelUrlNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelUrlNormalizer.java
index 8325b05..6e363f0 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelUrlNormalizer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/ModelUrlNormalizer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -26,10 +25,8 @@
  * Normalizes URLs to remove the ugly parent references "../" that got potentially inserted by URL adjustment during
  * model inheritance.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelUrlNormalizer
-{
+public interface ModelUrlNormalizer {
 
     /**
      * Normalizes the well-known URLs of the specified model.
@@ -37,6 +34,5 @@
      * @param model The model whose URLs should be normalized, may be {@code null}.
      * @param request The model building request that holds further settings, must not be {@code null}.
      */
-    void normalize( Model model, ModelBuildingRequest request );
-
+    void normalize(Model model, ModelBuildingRequest request);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java
index c416e6a..83b3ae5 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/PathTranslator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
 import java.io.File;
 
 /**
  * Resolves relative paths against a specific base directory.
  *
- * @author Jason van Zyl
  */
-public interface PathTranslator
-{
+public interface PathTranslator {
 
     /**
      * Resolves the specified path against the given base directory. The resolved path will be absolute and uses the
@@ -38,6 +35,5 @@
      * @param basedir The base directory to resolve relative paths against, may be {@code null}.
      * @return The resolved path or {@code null} if the input path was {@code null}.
      */
-    String alignToBaseDirectory( String path, File basedir );
-
+    String alignToBaseDirectory(String path, File basedir);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java
index 41257ac..1ab4e47 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/ProfileActivationFilePathInterpolator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,35 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
-import org.apache.maven.model.ActivationFile;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.nio.file.Path;
+
+import org.apache.maven.api.model.ActivationFile;
 import org.apache.maven.model.profile.ProfileActivationContext;
+import org.apache.maven.model.root.RootLocator;
 import org.codehaus.plexus.interpolation.AbstractValueSource;
 import org.codehaus.plexus.interpolation.InterpolationException;
 import org.codehaus.plexus.interpolation.MapBasedValueSource;
 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.io.File;
-
 /**
  * Finds an absolute path for {@link ActivationFile#getExists()} or {@link ActivationFile#getMissing()}
  *
- * @author Ravil Galeyev
  */
 @Named
 @Singleton
-public class ProfileActivationFilePathInterpolator
-{
+public class ProfileActivationFilePathInterpolator {
 
     private final PathTranslator pathTranslator;
 
+    private final RootLocator rootLocator;
+
     @Inject
-    public ProfileActivationFilePathInterpolator( PathTranslator pathTranslator )
-    {
+    public ProfileActivationFilePathInterpolator(PathTranslator pathTranslator, RootLocator rootLocator) {
         this.pathTranslator = pathTranslator;
+        this.rootLocator = rootLocator;
     }
 
     /**
@@ -54,10 +56,8 @@
      *
      * @return absolute path or {@code null} if the input was {@code null}
      */
-    public String interpolate( String path, ProfileActivationContext context ) throws InterpolationException
-    {
-        if ( path == null )
-        {
+    public String interpolate(String path, ProfileActivationContext context) throws InterpolationException {
+        if (path == null) {
             return null;
         }
 
@@ -65,38 +65,40 @@
 
         final File basedir = context.getProjectDirectory();
 
-        if ( basedir != null )
-        {
-            interpolator.addValueSource( new AbstractValueSource( false )
-            {
+        if (basedir != null) {
+            interpolator.addValueSource(new AbstractValueSource(false) {
                 @Override
-                public Object getValue( String expression )
-                {
-                    /*
-                     * We intentionally only support ${basedir} and not ${project.basedir} as the latter form
-                     * would suggest that other project.* expressions can be used which is beyond the design.
-                     */
-                    if ( "basedir".equals( expression ) )
-                    {
+                public Object getValue(String expression) {
+                    if ("basedir".equals(expression) || "project.basedir".equals(expression)) {
                         return basedir.getAbsolutePath();
                     }
                     return null;
                 }
-            } );
-        }
-        else if ( path.contains( "${basedir}" ) )
-        {
+            });
+        } else if (path.contains("${basedir}")) {
             return null;
         }
 
-        interpolator.addValueSource( new MapBasedValueSource( context.getProjectProperties() ) );
+        interpolator.addValueSource(new AbstractValueSource(false) {
+            @Override
+            public Object getValue(String expression) {
+                if ("rootDirectory".equals(expression)) {
+                    Path base = basedir != null ? basedir.toPath() : null;
+                    Path root = rootLocator.findMandatoryRoot(base);
+                    return root.toFile().getAbsolutePath();
+                }
+                return null;
+            }
+        });
 
-        interpolator.addValueSource( new MapBasedValueSource( context.getUserProperties() ) );
+        interpolator.addValueSource(new MapBasedValueSource(context.getProjectProperties()));
 
-        interpolator.addValueSource( new MapBasedValueSource( context.getSystemProperties() ) );
+        interpolator.addValueSource(new MapBasedValueSource(context.getUserProperties()));
 
-        String absolutePath = interpolator.interpolate( path, "" );
+        interpolator.addValueSource(new MapBasedValueSource(context.getSystemProperties()));
 
-        return pathTranslator.alignToBaseDirectory( absolutePath, basedir );
+        String absolutePath = interpolator.interpolate(path, "");
+
+        return pathTranslator.alignToBaseDirectory(absolutePath, basedir);
     }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/path/UrlNormalizer.java b/maven-model-builder/src/main/java/org/apache/maven/model/path/UrlNormalizer.java
index b2e4a7b..5655772 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/path/UrlNormalizer.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/path/UrlNormalizer.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
 /**
  * Normalizes a URL to remove the ugly parent references "../" that got potentially inserted by URL adjustment during
  * model inheritance.
  *
- * @author Benjamin Bentmann
  */
-public interface UrlNormalizer
-{
+public interface UrlNormalizer {
 
     /**
      * Normalizes the specified URL.
@@ -34,6 +31,5 @@
      * @param url The URL to normalize, may be {@code null}.
      * @return The normalized URL or {@code null} if the input was {@code null}.
      */
-    String normalize( String url );
-
+    String normalize(String url);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultPluginConfigurationExpander.java b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultPluginConfigurationExpander.java
index 012a685..aaabee9 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultPluginConfigurationExpander.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultPluginConfigurationExpander.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.List;
+package org.apache.maven.model.plugin;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.List;
+
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.model.Build;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Plugin;
@@ -31,56 +31,41 @@
 import org.apache.maven.model.PluginManagement;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * Handles expansion of general build plugin configuration into individual executions.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultPluginConfigurationExpander
-    implements PluginConfigurationExpander
-{
+public class DefaultPluginConfigurationExpander implements PluginConfigurationExpander {
 
     @Override
-    public void expandPluginConfiguration( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    public void expandPluginConfiguration(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
         Build build = model.getBuild();
 
-        if ( build != null )
-        {
-            expand( build.getPlugins() );
+        if (build != null) {
+            expand(build.getPlugins());
 
             PluginManagement pluginManagement = build.getPluginManagement();
 
-            if ( pluginManagement != null )
-            {
-                expand( pluginManagement.getPlugins() );
+            if (pluginManagement != null) {
+                expand(pluginManagement.getPlugins());
             }
         }
     }
 
-    private void expand( List<Plugin> plugins )
-    {
-        for ( Plugin plugin : plugins )
-        {
-            Xpp3Dom pluginConfiguration = (Xpp3Dom) plugin.getConfiguration();
+    private void expand(List<Plugin> plugins) {
+        for (Plugin plugin : plugins) {
+            XmlNode pluginConfiguration = plugin.getDelegate().getConfiguration();
 
-            if ( pluginConfiguration != null )
-            {
-                for ( PluginExecution execution : plugin.getExecutions() )
-                {
-                    Xpp3Dom executionConfiguration = (Xpp3Dom) execution.getConfiguration();
-
-                    executionConfiguration =
-                        Xpp3Dom.mergeXpp3Dom( executionConfiguration, new Xpp3Dom( pluginConfiguration ) );
-
-                    execution.setConfiguration( executionConfiguration );
+            if (pluginConfiguration != null) {
+                for (PluginExecution execution : plugin.getExecutions()) {
+                    XmlNode executionConfiguration = execution.getDelegate().getConfiguration();
+                    executionConfiguration = XmlNode.merge(executionConfiguration, pluginConfiguration);
+                    execution.update(execution.getDelegate().withConfiguration(executionConfiguration));
                 }
             }
         }
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportConfigurationExpander.java b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportConfigurationExpander.java
index b221ac2..aaa2eea 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportConfigurationExpander.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportConfigurationExpander.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,51 +16,43 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.plugin;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import org.apache.maven.api.xml.XmlNode;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.ReportPlugin;
 import org.apache.maven.model.ReportSet;
 import org.apache.maven.model.Reporting;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * Handles expansion of general report plugin configuration into individual report sets.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultReportConfigurationExpander
-    implements ReportConfigurationExpander
-{
+public class DefaultReportConfigurationExpander implements ReportConfigurationExpander {
 
     @Override
-    public void expandPluginConfiguration( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    public void expandPluginConfiguration(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
         Reporting reporting = model.getReporting();
 
-        if ( reporting != null )
-        {
-            for ( ReportPlugin reportPlugin : reporting.getPlugins() )
-            {
-                Xpp3Dom parentDom = (Xpp3Dom) reportPlugin.getConfiguration();
+        if (reporting != null) {
+            for (ReportPlugin reportPlugin : reporting.getPlugins()) {
+                XmlNode parentDom = reportPlugin.getDelegate().getConfiguration();
 
-                if ( parentDom != null )
-                {
-                    for ( ReportSet execution : reportPlugin.getReportSets() )
-                    {
-                        Xpp3Dom childDom = (Xpp3Dom) execution.getConfiguration();
-                        childDom = Xpp3Dom.mergeXpp3Dom( childDom, new Xpp3Dom( parentDom ) );
-                        execution.setConfiguration( childDom );
+                if (parentDom != null) {
+                    for (ReportSet execution : reportPlugin.getReportSets()) {
+                        XmlNode childDom = execution.getDelegate().getConfiguration();
+                        childDom = XmlNode.merge(childDom, parentDom);
+                        execution.update(execution.getDelegate().withConfiguration(childDom));
                     }
                 }
             }
         }
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportingConverter.java b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportingConverter.java
index 04b414b..132017e 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportingConverter.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/DefaultReportingConverter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,257 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.plugin;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.maven.model.Build;
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.InputSource;
 import org.apache.maven.model.Model;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginManagement;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Reporting;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
-import org.apache.maven.model.building.ModelProblemCollectorRequest;
-import org.apache.maven.model.building.ModelProblem.Severity;
-import org.apache.maven.model.building.ModelProblem.Version;
-import org.codehaus.plexus.util.StringUtils;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  * Handles conversion of the <code>&lt;reporting&gt;</code> section into the configuration of Maven Site Plugin 3.x,
  * i.e. <code>reportPlugins</code> and <code>outputDirectory</code> parameters.
  *
- * @author Benjamin Bentmann
+ * @deprecated since maven 4.0, this class is now a no-op class and is only here for compatibility
  */
 @Named
 @Singleton
-public class DefaultReportingConverter
-    implements ReportingConverter
-{
-    private final InputLocation location;
-    {
-        String modelId = "org.apache.maven:maven-model-builder:"
-            + this.getClass().getPackage().getImplementationVersion() + ":reporting-converter";
-        InputSource inputSource = new InputSource();
-        inputSource.setModelId( modelId );
-        location = new InputLocation( -1, -1, inputSource );
-        location.setLocation( 0, location );
-    }
+@Deprecated
+public class DefaultReportingConverter implements ReportingConverter {
 
     @Override
-    public void convertReporting( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
-        Reporting reporting = model.getReporting();
-
-        if ( reporting == null )
-        {
-            return;
-        }
-
-        Build build = model.getBuild();
-
-        if ( build == null )
-        {
-            build = new Build();
-            model.setBuild( build );
-            model.setLocation( "build", location );
-        }
-
-        Plugin sitePlugin = findSitePlugin( build );
-
-        if ( sitePlugin == null )
-        {
-            sitePlugin = new Plugin();
-            sitePlugin.setArtifactId( "maven-site-plugin" );
-            sitePlugin.setLocation( "artifactId", location );
-            PluginManagement pluginManagement = build.getPluginManagement();
-            if ( pluginManagement == null )
-            {
-                pluginManagement = new PluginManagement();
-                build.setPluginManagement( pluginManagement );
-            }
-            pluginManagement.addPlugin( sitePlugin );
-        }
-
-        Xpp3Dom configuration = (Xpp3Dom) sitePlugin.getConfiguration();
-
-        if ( configuration == null )
-        {
-            configuration = new Xpp3Dom( "configuration", location );
-            sitePlugin.setConfiguration( configuration );
-        }
-
-        Xpp3Dom reportPlugins = configuration.getChild( "reportPlugins" );
-
-        if ( reportPlugins != null )
-        {
-            // new-style report configuration already present: warn since this new style has been deprecated
-            // in favor of classical reporting section MSITE-647 / MSITE-684
-            problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.BASE )
-                    .setMessage( "Reporting configuration should be done in <reporting> section, "
-                          + "not in maven-site-plugin <configuration> as reportPlugins parameter." )
-                    .setLocation( sitePlugin.getLocation( "configuration" ) ) );
-            return;
-        }
-
-        if ( configuration.getChild( "outputDirectory" ) == null )
-        {
-            addDom( configuration, "outputDirectory", reporting.getOutputDirectory(),
-                    reporting.getLocation( "outputDirectory" ) );
-        }
-
-        reportPlugins = new Xpp3Dom( "reportPlugins", location );
-        configuration.addChild( reportPlugins );
-
-        boolean hasMavenProjectInfoReportsPlugin = false;
-
-        /* waiting for MSITE-484 before deprecating <reporting> section
-        if ( !reporting.getPlugins().isEmpty()
-            && request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 )
-        {
-
-            problems.add( new ModelProblemCollectorRequest( Severity.WARNING, Version.V31 )
-                    .setMessage( "The <reporting> section is deprecated, please move the reports to the <configuration>"
-                                 + " section of the new Maven Site Plugin." )
-                    .setLocation( reporting.getLocation( "" ) ) );
-        }*/
-
-        for ( ReportPlugin plugin : reporting.getPlugins() )
-        {
-            Xpp3Dom reportPlugin = convert( plugin );
-            reportPlugins.addChild( reportPlugin );
-
-            if ( !reporting.isExcludeDefaults() && !hasMavenProjectInfoReportsPlugin
-                && "org.apache.maven.plugins".equals( plugin.getGroupId() )
-                && "maven-project-info-reports-plugin".equals( plugin.getArtifactId() ) )
-            {
-                hasMavenProjectInfoReportsPlugin = true;
-            }
-        }
-
-        if ( !reporting.isExcludeDefaults() && !hasMavenProjectInfoReportsPlugin )
-        {
-            Xpp3Dom dom = new Xpp3Dom( "reportPlugin", location );
-
-            addDom( dom, "groupId", "org.apache.maven.plugins" );
-            addDom( dom, "artifactId", "maven-project-info-reports-plugin" );
-
-            reportPlugins.addChild( dom );
-        }
-    }
-
-    private Plugin findSitePlugin( Build build )
-    {
-        for ( Plugin plugin : build.getPlugins() )
-        {
-            if ( isSitePlugin( plugin ) )
-            {
-                return plugin;
-            }
-        }
-
-        PluginManagement pluginManagement = build.getPluginManagement();
-        if ( pluginManagement != null )
-        {
-            for ( Plugin plugin : pluginManagement.getPlugins() )
-            {
-                if ( isSitePlugin( plugin ) )
-                {
-                    return plugin;
-                }
-            }
-        }
-
-        return null;
-    }
-
-    private boolean isSitePlugin( Plugin plugin )
-    {
-        return "maven-site-plugin".equals( plugin.getArtifactId() )
-            && "org.apache.maven.plugins".equals( plugin.getGroupId() );
-    }
-
-    private Xpp3Dom convert( ReportPlugin plugin )
-    {
-        Xpp3Dom dom = new Xpp3Dom( "reportPlugin", plugin.getLocation( "" ) );
-
-        addDom( dom, "groupId", plugin.getGroupId(), plugin.getLocation( "groupId" ) );
-        addDom( dom, "artifactId", plugin.getArtifactId(), plugin.getLocation( "artifactId" ) );
-        addDom( dom, "version", plugin.getVersion(), plugin.getLocation( "version" ) );
-
-        Xpp3Dom configuration = (Xpp3Dom) plugin.getConfiguration();
-        if ( configuration != null )
-        {
-            configuration = new Xpp3Dom( configuration );
-            dom.addChild( configuration );
-        }
-
-        if ( !plugin.getReportSets().isEmpty() )
-        {
-            Xpp3Dom reportSets = new Xpp3Dom( "reportSets", plugin.getLocation( "reportSets" ) );
-            for ( ReportSet reportSet : plugin.getReportSets() )
-            {
-                Xpp3Dom rs = convert( reportSet );
-                reportSets.addChild( rs );
-            }
-            dom.addChild( reportSets );
-        }
-
-        return dom;
-    }
-
-    private Xpp3Dom convert( ReportSet reportSet )
-    {
-        Xpp3Dom dom = new Xpp3Dom( "reportSet", reportSet.getLocation( "" ) );
-
-        InputLocation idLocation = reportSet.getLocation( "id" );
-        addDom( dom, "id", reportSet.getId(), idLocation == null ? location : idLocation );
-
-        Xpp3Dom configuration = (Xpp3Dom) reportSet.getConfiguration();
-        if ( configuration != null )
-        {
-            configuration = new Xpp3Dom( configuration );
-            dom.addChild( configuration );
-        }
-
-        if ( !reportSet.getReports().isEmpty() )
-        {
-            InputLocation location = reportSet.getLocation( "reports" );
-            Xpp3Dom reports = new Xpp3Dom( "reports", location );
-            int n = 0;
-            for ( String report : reportSet.getReports() )
-            {
-                addDom( reports, "report", report, ( location == null ) ? null : location.getLocation( n++ ) );
-            }
-            dom.addChild( reports );
-        }
-
-        return dom;
-    }
-
-    private void addDom( Xpp3Dom parent, String childName, String childValue )
-    {
-        addDom( parent, childName, childValue, location );
-    }
-
-    private void addDom( Xpp3Dom parent, String childName, String childValue, InputLocation location )
-    {
-        if ( StringUtils.isNotEmpty( childValue ) )
-        {
-            parent.addChild( newDom( childName, childValue, location ) );
-        }
-    }
-
-    private Xpp3Dom newDom( String name, String value, InputLocation location )
-    {
-        Xpp3Dom dom = new Xpp3Dom( name, location );
-        dom.setValue( value );
-        return dom;
-    }
-
+    public void convertReporting(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {}
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/LifecycleBindingsInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/LifecycleBindingsInjector.java
index 9c0f06d..4d77315 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/LifecycleBindingsInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/LifecycleBindingsInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.plugin;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -26,10 +25,8 @@
 /**
  * Handles injection of plugin executions induced by the lifecycle bindings for a packaging.
  *
- * @author Benjamin Bentmann
  */
-public interface LifecycleBindingsInjector
-{
+public interface LifecycleBindingsInjector {
 
     /**
      * Injects plugin executions induced by lifecycle bindings into the specified model. The model has already undergone
@@ -41,6 +38,5 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void injectLifecycleBindings( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
-
+    void injectLifecycleBindings(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/PluginConfigurationExpander.java b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/PluginConfigurationExpander.java
index 23994aa..92c6d5c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/PluginConfigurationExpander.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/PluginConfigurationExpander.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.plugin;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -26,10 +25,8 @@
 /**
  * Handles expansion of general build plugin configuration into individual executions.
  *
- * @author Benjamin Bentmann
  */
-public interface PluginConfigurationExpander
-{
+public interface PluginConfigurationExpander {
 
     /**
      * Merges values from general build plugin configuration into the individual plugin executions of the given model.
@@ -38,6 +35,5 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void expandPluginConfiguration( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
-
+    void expandPluginConfiguration(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportConfigurationExpander.java b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportConfigurationExpander.java
index 28ad596..37e0e41 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportConfigurationExpander.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportConfigurationExpander.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.plugin;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -26,10 +25,8 @@
 /**
  * Handles expansion of general report plugin configuration into individual report sets.
  *
- * @author Benjamin Bentmann
  */
-public interface ReportConfigurationExpander
-{
+public interface ReportConfigurationExpander {
 
     /**
      * Merges values from general report plugin configuration into the individual reports sets of the given model.
@@ -38,6 +35,5 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void expandPluginConfiguration( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
-
+    void expandPluginConfiguration(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportingConverter.java b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportingConverter.java
index e6d8898..52e15a8 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportingConverter.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/plugin/ReportingConverter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.plugin;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -27,10 +26,10 @@
  * Handles conversion of the <code>&lt;reporting&gt;</code> section into the configuration of Maven Site Plugin 3.x,
  * i.e. <code>reportPlugins</code> and <code>outputDirectory</code> parameters.
  *
- * @author Benjamin Bentmann
+ * @deprecated since maven 4.0, this interface is not used anymore and is only here for compatibility
  */
-public interface ReportingConverter
-{
+@Deprecated
+public interface ReportingConverter {
 
     /**
      * Converts values from model's reporting section into the configuration for Maven Site Plugin 3.x.
@@ -39,6 +38,5 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void convertReporting( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
-
+    void convertReporting(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileActivationContext.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileActivationContext.java
index 4fb1b26..eeadb3a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileActivationContext.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileActivationContext.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,24 +16,22 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile;
 
 import java.io.File;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
+import java.util.stream.Collectors;
 
-import static java.util.stream.Collectors.collectingAndThen;
 import static java.util.stream.Collectors.toMap;
 
 /**
  * Describes the environmental context used to determine the activation status of profiles.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultProfileActivationContext
-    implements ProfileActivationContext
-{
+public class DefaultProfileActivationContext implements ProfileActivationContext {
 
     private List<String> activeProfileIds = Collections.emptyList();
 
@@ -50,8 +46,7 @@
     private File projectDirectory;
 
     @Override
-    public List<String> getActiveProfileIds()
-    {
+    public List<String> getActiveProfileIds() {
         return activeProfileIds;
     }
 
@@ -61,23 +56,13 @@
      * @param activeProfileIds The identifiers of those profiles to activate, may be {@code null}.
      * @return This context, never {@code null}.
      */
-    public DefaultProfileActivationContext setActiveProfileIds( List<String> activeProfileIds )
-    {
-        if ( activeProfileIds != null )
-        {
-            this.activeProfileIds = Collections.unmodifiableList( activeProfileIds );
-        }
-        else
-        {
-            this.activeProfileIds = Collections.emptyList();
-        }
-
+    public DefaultProfileActivationContext setActiveProfileIds(List<String> activeProfileIds) {
+        this.activeProfileIds = unmodifiable(activeProfileIds);
         return this;
     }
 
     @Override
-    public List<String> getInactiveProfileIds()
-    {
+    public List<String> getInactiveProfileIds() {
         return inactiveProfileIds;
     }
 
@@ -87,23 +72,13 @@
      * @param inactiveProfileIds The identifiers of those profiles to deactivate, may be {@code null}.
      * @return This context, never {@code null}.
      */
-    public DefaultProfileActivationContext setInactiveProfileIds( List<String> inactiveProfileIds )
-    {
-        if ( inactiveProfileIds != null )
-        {
-            this.inactiveProfileIds = Collections.unmodifiableList( inactiveProfileIds );
-        }
-        else
-        {
-            this.inactiveProfileIds = Collections.emptyList();
-        }
-
+    public DefaultProfileActivationContext setInactiveProfileIds(List<String> inactiveProfileIds) {
+        this.inactiveProfileIds = unmodifiable(inactiveProfileIds);
         return this;
     }
 
     @Override
-    public Map<String, String> getSystemProperties()
-    {
+    public Map<String, String> getSystemProperties() {
         return systemProperties;
     }
 
@@ -114,19 +89,9 @@
      * @param systemProperties The system properties, may be {@code null}.
      * @return This context, never {@code null}.
      */
-    @SuppressWarnings( "unchecked" )
-    public DefaultProfileActivationContext setSystemProperties( Properties systemProperties )
-    {
-        if ( systemProperties != null )
-        {
-            this.systemProperties = Collections.unmodifiableMap( (Map) systemProperties );
-        }
-        else
-        {
-            this.systemProperties = Collections.emptyMap();
-        }
-
-        return this;
+    @SuppressWarnings("unchecked")
+    public DefaultProfileActivationContext setSystemProperties(Properties systemProperties) {
+        return setSystemProperties(toMap(systemProperties));
     }
 
     /**
@@ -136,23 +101,13 @@
      * @param systemProperties The system properties, may be {@code null}.
      * @return This context, never {@code null}.
      */
-    public DefaultProfileActivationContext setSystemProperties( Map<String, String> systemProperties )
-    {
-        if ( systemProperties != null )
-        {
-            this.systemProperties = Collections.unmodifiableMap( systemProperties );
-        }
-        else
-        {
-            this.systemProperties = Collections.emptyMap();
-        }
-
+    public DefaultProfileActivationContext setSystemProperties(Map<String, String> systemProperties) {
+        this.systemProperties = unmodifiable(systemProperties);
         return this;
     }
 
     @Override
-    public Map<String, String> getUserProperties()
-    {
+    public Map<String, String> getUserProperties() {
         return userProperties;
     }
 
@@ -164,19 +119,9 @@
      * @param userProperties The user properties, may be {@code null}.
      * @return This context, never {@code null}.
      */
-    @SuppressWarnings( "unchecked" )
-    public DefaultProfileActivationContext setUserProperties( Properties userProperties )
-    {
-        if ( userProperties != null )
-        {
-            this.userProperties = Collections.unmodifiableMap( (Map) userProperties );
-        }
-        else
-        {
-            this.userProperties = Collections.emptyMap();
-        }
-
-        return this;
+    @SuppressWarnings("unchecked")
+    public DefaultProfileActivationContext setUserProperties(Properties userProperties) {
+        return setUserProperties(toMap(userProperties));
     }
 
     /**
@@ -187,23 +132,13 @@
      * @param userProperties The user properties, may be {@code null}.
      * @return This context, never {@code null}.
      */
-    public DefaultProfileActivationContext setUserProperties( Map<String, String> userProperties )
-    {
-        if ( userProperties != null )
-        {
-            this.userProperties = Collections.unmodifiableMap( userProperties );
-        }
-        else
-        {
-            this.userProperties = Collections.emptyMap();
-        }
-
+    public DefaultProfileActivationContext setUserProperties(Map<String, String> userProperties) {
+        this.userProperties = unmodifiable(userProperties);
         return this;
     }
 
     @Override
-    public File getProjectDirectory()
-    {
+    public File getProjectDirectory() {
         return projectDirectory;
     }
 
@@ -214,35 +149,42 @@
      *                         happens in the context of metadata retrieval rather than project building.
      * @return This context, never {@code null}.
      */
-    public DefaultProfileActivationContext setProjectDirectory( File projectDirectory )
-    {
+    public DefaultProfileActivationContext setProjectDirectory(File projectDirectory) {
         this.projectDirectory = projectDirectory;
 
         return this;
     }
 
     @Override
-    public Map<String, String> getProjectProperties()
-    {
+    public Map<String, String> getProjectProperties() {
         return projectProperties;
     }
 
-    public DefaultProfileActivationContext setProjectProperties( Properties projectProperties )
-    {
-        if ( projectProperties != null )
-        {
-            this.projectProperties = projectProperties.entrySet().stream()
-                    .collect(
-                            collectingAndThen(
-                                    toMap( k -> String.valueOf( k.getKey() ), v -> String.valueOf( v ) ),
-                                    Collections::unmodifiableMap ) );
-        }
-        else
-        {
-            this.projectProperties = Collections.emptyMap();
-        }
+    public DefaultProfileActivationContext setProjectProperties(Properties projectProperties) {
+        return setProjectProperties(toMap(projectProperties));
+    }
+
+    public DefaultProfileActivationContext setProjectProperties(Map<String, String> projectProperties) {
+        this.projectProperties = unmodifiable(projectProperties);
 
         return this;
     }
 
+    private static List<String> unmodifiable(List<String> list) {
+        return list != null ? Collections.unmodifiableList(list) : Collections.emptyList();
+    }
+
+    private static Map<String, String> unmodifiable(Map<String, String> map) {
+        return map != null ? Collections.unmodifiableMap(map) : Collections.emptyMap();
+    }
+
+    private static Map<String, String> toMap(Properties properties) {
+        if (properties != null && !properties.isEmpty()) {
+            return properties.entrySet().stream()
+                    .collect(Collectors.toMap(e -> String.valueOf(e.getKey()), e -> String.valueOf(e.getValue())));
+
+        } else {
+            return null;
+        }
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java
index 2f9553b..a435002 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,27 +16,30 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import org.apache.maven.model.Build;
-import org.apache.maven.model.BuildBase;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.ModelBase;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.Profile;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Reporting;
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.BuildBase;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.ModelBase;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginContainer;
+import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.model.Profile;
+import org.apache.maven.api.model.ReportPlugin;
+import org.apache.maven.api.model.ReportSet;
+import org.apache.maven.api.model.Reporting;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.merge.MavenModelMerger;
@@ -46,211 +47,214 @@
 /**
  * Handles profile injection into the model.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-@SuppressWarnings( { "checkstyle:methodname" } )
-public class DefaultProfileInjector
-    implements ProfileInjector
-{
+@SuppressWarnings({"checkstyle:methodname"})
+public class DefaultProfileInjector implements ProfileInjector {
+
+    private static final Map<Model, Map<List<Profile>, Model>> CACHE = Collections.synchronizedMap(new WeakHashMap<>());
+
+    // In order for the weak hash map to work correctly, we must not hold any reference to
+    // the model used as the key.  So we use a dummy model as a placeholder to indicate that
+    // we want to store the model used as they key.
+    private static final Model KEY = Model.newInstance();
 
     private ProfileModelMerger merger = new ProfileModelMerger();
 
     @Override
-    public void injectProfile( Model model, Profile profile, ModelBuildingRequest request,
-                               ModelProblemCollector problems )
-    {
-        if ( profile != null )
-        {
-            merger.mergeModelBase( model, profile );
+    public void injectProfile(
+            org.apache.maven.model.Model model,
+            org.apache.maven.model.Profile profile,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems) {
+        model.update(
+                injectProfile(model.getDelegate(), profile != null ? profile.getDelegate() : null, request, problems));
+    }
 
-            if ( profile.getBuild() != null )
-            {
-                if ( model.getBuild() == null )
-                {
-                    model.setBuild( new Build() );
+    @Override
+    public Model injectProfile(
+            Model model, Profile profile, ModelBuildingRequest request, ModelProblemCollector problems) {
+        return injectProfiles(model, Collections.singletonList(profile), request, problems);
+    }
+
+    @Override
+    public Model injectProfiles(
+            Model model, List<Profile> profiles, ModelBuildingRequest request, ModelProblemCollector problems) {
+        Model result = CACHE.computeIfAbsent(model, k -> new ConcurrentHashMap<>())
+                .computeIfAbsent(profiles, l -> doInjectProfiles(model, profiles));
+        return result == KEY ? model : result;
+    }
+
+    private Model doInjectProfiles(Model model, List<Profile> profiles) {
+        Model orgModel = model;
+        for (Profile profile : profiles) {
+            if (profile != null) {
+                Model.Builder builder = Model.newBuilder(model);
+                merger.mergeModelBase(builder, model, profile);
+
+                if (profile.getBuild() != null) {
+                    Build build = model.getBuild() != null ? model.getBuild() : Build.newInstance();
+                    Build.Builder bbuilder = Build.newBuilder(build);
+                    merger.mergeBuildBase(bbuilder, build, profile.getBuild());
+                    builder.build(bbuilder.build());
                 }
-                merger.mergeBuildBase( model.getBuild(), profile.getBuild() );
+
+                model = builder.build();
             }
         }
+        return model == orgModel ? KEY : model;
     }
 
     /**
      * ProfileModelMerger
      */
-    protected static class ProfileModelMerger
-        extends MavenModelMerger
-    {
+    protected static class ProfileModelMerger extends MavenModelMerger {
 
-        public void mergeModelBase( ModelBase target, ModelBase source )
-        {
-            mergeModelBase( target, source, true, Collections.emptyMap() );
+        public void mergeModelBase(ModelBase.Builder builder, ModelBase target, ModelBase source) {
+            mergeModelBase(builder, target, source, true, Collections.emptyMap());
         }
 
-        public void mergeBuildBase( BuildBase target, BuildBase source )
-        {
-            mergeBuildBase( target, source, true, Collections.emptyMap() );
+        public void mergeBuildBase(BuildBase.Builder builder, BuildBase target, BuildBase source) {
+            mergeBuildBase(builder, target, source, true, Collections.emptyMap());
         }
 
         @Override
-        protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
-                                                     boolean sourceDominant, Map<Object, Object> context )
-        {
+        protected void mergePluginContainer_Plugins(
+                PluginContainer.Builder builder,
+                PluginContainer target,
+                PluginContainer source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<Plugin> src = source.getPlugins();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<Plugin> tgt = target.getPlugins();
-                Map<Object, Plugin> master = new LinkedHashMap<>( tgt.size() * 2 );
+                Map<Object, Plugin> master = new LinkedHashMap<>(tgt.size() * 2);
 
-                for ( Plugin element : tgt )
-                {
-                    Object key = getPluginKey().apply( element );
-                    master.put( key, element );
+                for (Plugin element : tgt) {
+                    Object key = getPluginKey().apply(element);
+                    master.put(key, element);
                 }
 
                 Map<Object, List<Plugin>> predecessors = new LinkedHashMap<>();
                 List<Plugin> pending = new ArrayList<>();
-                for ( Plugin element : src )
-                {
-                    Object key = getPluginKey().apply( element );
-                    Plugin existing = master.get( key );
-                    if ( existing != null )
-                    {
-                        mergePlugin( existing, element, sourceDominant, context );
-
-                        if ( !pending.isEmpty() )
-                        {
-                            predecessors.put( key, pending );
+                for (Plugin element : src) {
+                    Object key = getPluginKey().apply(element);
+                    Plugin existing = master.get(key);
+                    if (existing != null) {
+                        existing = mergePlugin(existing, element, sourceDominant, context);
+                        master.put(key, existing);
+                        if (!pending.isEmpty()) {
+                            predecessors.put(key, pending);
                             pending = new ArrayList<>();
                         }
-                    }
-                    else
-                    {
-                        pending.add( element );
+                    } else {
+                        pending.add(element);
                     }
                 }
 
-                List<Plugin> result = new ArrayList<>( src.size() + tgt.size() );
-                for ( Map.Entry<Object, Plugin> entry : master.entrySet() )
-                {
-                    List<Plugin> pre = predecessors.get( entry.getKey() );
-                    if ( pre != null )
-                    {
-                        result.addAll( pre );
+                List<Plugin> result = new ArrayList<>(src.size() + tgt.size());
+                for (Map.Entry<Object, Plugin> entry : master.entrySet()) {
+                    List<Plugin> pre = predecessors.get(entry.getKey());
+                    if (pre != null) {
+                        result.addAll(pre);
                     }
-                    result.add( entry.getValue() );
+                    result.add(entry.getValue());
                 }
-                result.addAll( pending );
+                result.addAll(pending);
 
-                target.setPlugins( result );
+                builder.plugins(result);
             }
         }
 
         @Override
-        protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-        {
+        protected void mergePlugin_Executions(
+                Plugin.Builder builder,
+                Plugin target,
+                Plugin source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<PluginExecution> src = source.getExecutions();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<PluginExecution> tgt = target.getExecutions();
-                Map<Object, PluginExecution> merged =
-                    new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+                Map<Object, PluginExecution> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-                for ( PluginExecution element : tgt )
-                {
-                    Object key = getPluginExecutionKey().apply( element );
-                    merged.put( key, element );
+                for (PluginExecution element : tgt) {
+                    Object key = getPluginExecutionKey().apply(element);
+                    merged.put(key, element);
                 }
 
-                for ( PluginExecution element : src )
-                {
-                    Object key = getPluginExecutionKey().apply( element );
-                    PluginExecution existing = merged.get( key );
-                    if ( existing != null )
-                    {
-                        mergePluginExecution( existing, element, sourceDominant, context );
+                for (PluginExecution element : src) {
+                    Object key = getPluginExecutionKey().apply(element);
+                    PluginExecution existing = merged.get(key);
+                    if (existing != null) {
+                        element = mergePluginExecution(existing, element, sourceDominant, context);
                     }
-                    else
-                    {
-                        merged.put( key, element );
-                    }
+                    merged.put(key, element);
                 }
 
-                target.setExecutions( new ArrayList<>( merged.values() ) );
+                builder.executions(merged.values());
             }
         }
 
         @Override
-        protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-        {
+        protected void mergeReporting_Plugins(
+                Reporting.Builder builder,
+                Reporting target,
+                Reporting source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<ReportPlugin> src = source.getPlugins();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<ReportPlugin> tgt = target.getPlugins();
-                Map<Object, ReportPlugin> merged =
-                    new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+                Map<Object, ReportPlugin> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-                for ( ReportPlugin element : tgt )
-                {
-                    Object key = getReportPluginKey().apply( element );
-                    merged.put( key, element );
+                for (ReportPlugin element : tgt) {
+                    Object key = getReportPluginKey().apply(element);
+                    merged.put(key, element);
                 }
 
-                for ( ReportPlugin element : src )
-                {
-                    Object key = getReportPluginKey().apply( element );
-                    ReportPlugin existing = merged.get( key );
-                    if ( existing == null )
-                    {
-                        merged.put( key, element );
+                for (ReportPlugin element : src) {
+                    Object key = getReportPluginKey().apply(element);
+                    ReportPlugin existing = merged.get(key);
+                    if (existing != null) {
+                        element = mergeReportPlugin(existing, element, sourceDominant, context);
                     }
-                    else
-                    {
-                        mergeReportPlugin( existing, element, sourceDominant, context );
-                    }
+                    merged.put(key, element);
                 }
 
-                target.setPlugins( new ArrayList<>( merged.values() ) );
+                builder.plugins(merged.values());
             }
         }
 
         @Override
-        protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                                     Map<Object, Object> context )
-        {
+        protected void mergeReportPlugin_ReportSets(
+                ReportPlugin.Builder builder,
+                ReportPlugin target,
+                ReportPlugin source,
+                boolean sourceDominant,
+                Map<Object, Object> context) {
             List<ReportSet> src = source.getReportSets();
-            if ( !src.isEmpty() )
-            {
+            if (!src.isEmpty()) {
                 List<ReportSet> tgt = target.getReportSets();
-                Map<Object, ReportSet> merged = new LinkedHashMap<>( ( src.size() + tgt.size() ) * 2 );
+                Map<Object, ReportSet> merged = new LinkedHashMap<>((src.size() + tgt.size()) * 2);
 
-                for ( ReportSet element : tgt )
-                {
-                    Object key = getReportSetKey().apply( element );
-                    merged.put( key, element );
+                for (ReportSet element : tgt) {
+                    Object key = getReportSetKey().apply(element);
+                    merged.put(key, element);
                 }
 
-                for ( ReportSet element : src )
-                {
-                    Object key = getReportSetKey().apply( element );
-                    ReportSet existing = merged.get( key );
-                    if ( existing != null )
-                    {
-                        mergeReportSet( existing, element, sourceDominant, context );
+                for (ReportSet element : src) {
+                    Object key = getReportSetKey().apply(element);
+                    ReportSet existing = merged.get(key);
+                    if (existing != null) {
+                        element = mergeReportSet(existing, element, sourceDominant, context);
                     }
-                    else
-                    {
-                        merged.put( key, element );
-                    }
+                    merged.put(key, element);
                 }
 
-                target.setReportSets( new ArrayList<>( merged.values() ) );
+                builder.reportSets(merged.values());
             }
         }
-
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java
index 75dc10f..b2d0e9a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/DefaultProfileSelector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,134 +16,121 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
+package org.apache.maven.model.profile;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.Profile;
-import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblem.Severity;
 import org.apache.maven.model.building.ModelProblem.Version;
+import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblemCollectorRequest;
 import org.apache.maven.model.profile.activation.ProfileActivator;
 
 /**
  * Calculates the active profiles among a given collection of profiles.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultProfileSelector
-    implements ProfileSelector
-{
+public class DefaultProfileSelector implements ProfileSelector {
 
     private final List<ProfileActivator> activators;
 
-    @Inject
-    public DefaultProfileSelector( List<ProfileActivator> activators )
-    {
-        this.activators = activators;
+    public DefaultProfileSelector() {
+        this.activators = new ArrayList<>();
     }
 
-    public DefaultProfileSelector addProfileActivator( ProfileActivator profileActivator )
-    {
-        if ( profileActivator != null )
-        {
-            activators.add( profileActivator );
+    @Inject
+    public DefaultProfileSelector(List<ProfileActivator> activators) {
+        this.activators = new ArrayList<>(activators);
+    }
+
+    public DefaultProfileSelector addProfileActivator(ProfileActivator profileActivator) {
+        if (profileActivator != null) {
+            activators.add(profileActivator);
         }
         return this;
     }
 
     @Override
-    public List<Profile> getActiveProfiles( Collection<Profile> profiles, ProfileActivationContext context,
-                                            ModelProblemCollector problems )
-    {
-        Collection<String> activatedIds = new HashSet<>( context.getActiveProfileIds() );
-        Collection<String> deactivatedIds = new HashSet<>( context.getInactiveProfileIds() );
+    public List<org.apache.maven.api.model.Profile> getActiveProfilesV4(
+            Collection<org.apache.maven.api.model.Profile> profiles,
+            ProfileActivationContext context,
+            ModelProblemCollector problems) {
+        return getActiveProfiles(profiles.stream().map(Profile::new).collect(Collectors.toList()), context, problems)
+                .stream()
+                .map(Profile::getDelegate)
+                .collect(Collectors.toList());
+    }
 
-        List<Profile> activeProfiles = new ArrayList<>( profiles.size() );
+    @Override
+    public List<Profile> getActiveProfiles(
+            Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems) {
+        Collection<String> activatedIds = new HashSet<>(context.getActiveProfileIds());
+        Collection<String> deactivatedIds = new HashSet<>(context.getInactiveProfileIds());
+
+        List<Profile> activeProfiles = new ArrayList<>(profiles.size());
         List<Profile> activePomProfilesByDefault = new ArrayList<>();
         boolean activatedPomProfileNotByDefault = false;
 
-        for ( Profile profile : profiles )
-        {
-            if ( !deactivatedIds.contains( profile.getId() ) )
-            {
-                if ( activatedIds.contains( profile.getId() ) || isActive( profile, context, problems ) )
-                {
-                    activeProfiles.add( profile );
+        for (Profile profile : profiles) {
+            if (!deactivatedIds.contains(profile.getId())) {
+                if (activatedIds.contains(profile.getId()) || isActive(profile, context, problems)) {
+                    activeProfiles.add(profile);
 
-                    if ( Profile.SOURCE_POM.equals( profile.getSource() ) )
-                    {
+                    if (Profile.SOURCE_POM.equals(profile.getSource())) {
                         activatedPomProfileNotByDefault = true;
                     }
-                }
-                else if ( isActiveByDefault( profile ) )
-                {
-                    if ( Profile.SOURCE_POM.equals( profile.getSource() ) )
-                    {
-                        activePomProfilesByDefault.add( profile );
-                    }
-                    else
-                    {
-                        activeProfiles.add( profile );
+                } else if (isActiveByDefault(profile)) {
+                    if (Profile.SOURCE_POM.equals(profile.getSource())) {
+                        activePomProfilesByDefault.add(profile);
+                    } else {
+                        activeProfiles.add(profile);
                     }
                 }
-
             }
         }
 
-        if ( !activatedPomProfileNotByDefault )
-        {
-            activeProfiles.addAll( activePomProfilesByDefault );
+        if (!activatedPomProfileNotByDefault) {
+            activeProfiles.addAll(activePomProfilesByDefault);
         }
 
         return activeProfiles;
     }
 
-    private boolean isActive( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    private boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         boolean isActive = false;
-        for ( ProfileActivator activator : activators )
-        {
-            if ( activator.presentInConfig( profile, context, problems ) )
-            {
+        for (ProfileActivator activator : activators) {
+            if (activator.presentInConfig(profile, context, problems)) {
                 isActive = true;
-            }
-        }
-        for ( ProfileActivator activator : activators )
-        {
-            try
-            {
-                if ( activator.presentInConfig( profile, context, problems ) )
-                {
-                    isActive &=  activator.isActive( profile, context, problems );
+                try {
+                    if (!activator.isActive(profile, context, problems)) {
+                        return false;
+                    }
+                } catch (RuntimeException e) {
+                    problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                            .setMessage("Failed to determine activation for profile " + profile.getId())
+                            .setLocation(profile.getLocation(""))
+                            .setException(e));
+                    return false;
                 }
             }
-            catch ( RuntimeException e )
-            {
-                problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                        .setMessage( "Failed to determine activation for profile " + profile.getId() )
-                        .setLocation( profile.getLocation( "" ) )
-                        .setException( e ) );
-                return false;
-            }
         }
         return isActive;
     }
 
-    private boolean isActiveByDefault( Profile profile )
-    {
+    private boolean isActiveByDefault(Profile profile) {
         Activation activation = profile.getActivation();
         return activation != null && activation.isActiveByDefault();
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileActivationContext.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileActivationContext.java
index d501e66..8692335 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileActivationContext.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileActivationContext.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile;
 
 import java.io.File;
 import java.util.List;
@@ -26,10 +25,14 @@
 /**
  * Describes the environmental context used to determine the activation status of profiles.
  *
- * @author Benjamin Bentmann
  */
-public interface ProfileActivationContext
-{
+public interface ProfileActivationContext {
+    /**
+     * Key of the property containing the project's packaging.
+     * Available in {@link #getUserProperties()}.
+     * @since 4.0.0
+     */
+    String PROPERTY_NAME_PACKAGING = "packaging";
 
     /**
      * Gets the identifiers of those profiles that should be activated by explicit demand.
@@ -75,5 +78,4 @@
      * @return The project properties, never {@code null}.
      */
     Map<String, String> getProjectProperties();
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java
index fbd7ddf..e4ab400 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileInjector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,9 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile;
+
+import java.util.List;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Profile;
@@ -27,10 +28,8 @@
 /**
  * Handles profile injection into the model.
  *
- * @author Benjamin Bentmann
  */
-public interface ProfileInjector
-{
+public interface ProfileInjector {
 
     /**
      * Merges values from the specified profile into the given model. Implementations are expected to keep the profile
@@ -41,6 +40,46 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void injectProfile( Model model, Profile profile, ModelBuildingRequest request, ModelProblemCollector problems );
+    void injectProfile(Model model, Profile profile, ModelBuildingRequest request, ModelProblemCollector problems);
 
+    /**
+     * Merges values from the specified profile into the given model. Implementations are expected to keep the profile
+     * and model completely decoupled by injecting deep copies rather than the original objects from the profile.
+     *
+     * @param model The model into which to merge the values defined by the profile, must not be <code>null</code>.
+     * @param profile The (read-only) profile whose values should be injected, may be <code>null</code>.
+     * @param request The model building request that holds further settings, must not be {@code null}.
+     * @param problems The container used to collect problems that were encountered, must not be {@code null}.
+     */
+    default org.apache.maven.api.model.Model injectProfile(
+            org.apache.maven.api.model.Model model,
+            org.apache.maven.api.model.Profile profile,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems) {
+        Model m = new Model(model);
+        injectProfile(m, profile != null ? new Profile(profile) : null, request, problems);
+        return m.getDelegate();
+    }
+
+    /**
+     * Merges values from the specified profile into the given model. Implementations are expected to keep the profile
+     * and model completely decoupled by injecting deep copies rather than the original objects from the profile.
+     *
+     * @param model The model into which to merge the values defined by the profile, must not be <code>null</code>.
+     * @param profiles The (read-only) list of profiles whose values should be injected, must not be <code>null</code>.
+     * @param request The model building request that holds further settings, must not be {@code null}.
+     * @param problems The container used to collect problems that were encountered, must not be {@code null}.
+     */
+    default org.apache.maven.api.model.Model injectProfiles(
+            org.apache.maven.api.model.Model model,
+            List<org.apache.maven.api.model.Profile> profiles,
+            ModelBuildingRequest request,
+            ModelProblemCollector problems) {
+        for (org.apache.maven.api.model.Profile profile : profiles) {
+            if (profile != null) {
+                model = injectProfile(model, profile, request, problems);
+            }
+        }
+        return model;
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java
index 53ea8d9..a87d695 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/ProfileSelector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile;
 
 import java.util.Collection;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.building.ModelProblemCollector;
@@ -28,10 +28,8 @@
 /**
  * Calculates the active profiles among a given collection of profiles.
  *
- * @author Benjamin Bentmann
  */
-public interface ProfileSelector
-{
+public interface ProfileSelector {
 
     /**
      * Determines the profiles which are active in the specified activation context. Active profiles will eventually be
@@ -43,7 +41,26 @@
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      * @return The profiles that have been activated, never {@code null}.
      */
-    List<Profile> getActiveProfiles( Collection<Profile> profiles, ProfileActivationContext context,
-                                     ModelProblemCollector problems );
+    List<Profile> getActiveProfiles(
+            Collection<Profile> profiles, ProfileActivationContext context, ModelProblemCollector problems);
 
+    /**
+     * Determines the profiles which are active in the specified activation context. Active profiles will eventually be
+     * injected into the model.
+     *
+     * @param profiles The profiles whose activation status should be determined, must not be {@code null}.
+     * @param context The environmental context used to determine the activation status of a profile, must not be
+     *            {@code null}.
+     * @param problems The container used to collect problems that were encountered, must not be {@code null}.
+     * @return The profiles that have been activated, never {@code null}.
+     */
+    default List<org.apache.maven.api.model.Profile> getActiveProfilesV4(
+            Collection<org.apache.maven.api.model.Profile> profiles,
+            ProfileActivationContext context,
+            ModelProblemCollector problems) {
+        return getActiveProfiles(profiles.stream().map(Profile::new).collect(Collectors.toList()), context, problems)
+                .stream()
+                .map(Profile::getDelegate)
+                .collect(Collectors.toList());
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java
index e45b883..f7c7dc9 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/FileProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,13 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
+package org.apache.maven.model.profile.activation;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.ActivationFile;
 import org.apache.maven.model.Profile;
@@ -35,92 +34,71 @@
 import org.apache.maven.model.path.ProfileActivationFilePathInterpolator;
 import org.apache.maven.model.profile.ProfileActivationContext;
 import org.codehaus.plexus.interpolation.InterpolationException;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Determines profile activation based on the existence/absence of some file.
- * File name interpolation support is limited to <code>${basedir}</code> (since Maven 3,
- * see <a href="https://issues.apache.org/jira/browse/MNG-2363">MNG-2363</a>),
- * System properties and request properties.
- * <code>${project.basedir}</code> is intentionally not supported as this form would suggest that other
- * <code>${project.*}</code> expressions can be used, which is however beyond the design.
+ * File name interpolation support is limited to <code>${project.basedir}</code>
+ * system properties and user properties.
  *
- * @author Benjamin Bentmann
  * @see ActivationFile
  * @see org.apache.maven.model.validation.DefaultModelValidator#validateRawModel
  */
-@Named( "file" )
+@Named("file")
 @Singleton
-public class FileProfileActivator
-    implements ProfileActivator
-{
+public class FileProfileActivator implements ProfileActivator {
 
     private final ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator;
 
     @Inject
-    public FileProfileActivator( ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator )
-    {
+    public FileProfileActivator(ProfileActivationFilePathInterpolator profileActivationFilePathInterpolator) {
         this.profileActivationFilePathInterpolator = profileActivationFilePathInterpolator;
     }
 
     @Override
-    public boolean isActive( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
         ActivationFile file = activation.getFile();
 
-        if ( file == null )
-        {
+        if (file == null) {
             return false;
         }
 
         String path;
         boolean missing;
 
-        if ( StringUtils.isNotEmpty( file.getExists() ) )
-        {
+        if (file.getExists() != null && !file.getExists().isEmpty()) {
             path = file.getExists();
             missing = false;
-        }
-        else if ( StringUtils.isNotEmpty( file.getMissing() ) )
-        {
+        } else if (file.getMissing() != null && !file.getMissing().isEmpty()) {
             path = file.getMissing();
             missing = true;
-        }
-        else
-        {
+        } else {
             return false;
         }
 
-        try
-        {
-            path = profileActivationFilePathInterpolator.interpolate( path, context );
-        }
-        catch ( InterpolationException e )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "Failed to interpolate file location " + path + " for profile " + profile.getId()
-                            + ": " + e.getMessage() )
-                    .setLocation( file.getLocation( missing ? "missing" : "exists" ) )
-                    .setException( e ) );
+        try {
+            path = profileActivationFilePathInterpolator.interpolate(path, context);
+        } catch (InterpolationException e) {
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                    .setMessage("Failed to interpolate file location " + path + " for profile " + profile.getId() + ": "
+                            + e.getMessage())
+                    .setLocation(file.getLocation(missing ? "missing" : "exists"))
+                    .setException(e));
             return false;
         }
 
-        if ( path == null )
-        {
+        if (path == null) {
             return false;
         }
 
-        File f = new File( path );
+        File f = new File(path);
 
-        if ( !f.isAbsolute() )
-        {
+        if (!f.isAbsolute()) {
             return false;
         }
 
@@ -130,12 +108,10 @@
     }
 
     @Override
-    public boolean presentInConfig( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean presentInConfig(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
@@ -143,5 +119,4 @@
 
         return file != null;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java
index b21fd81..71f7fa3 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,82 +16,77 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+package org.apache.maven.model.profile.activation;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Pattern;
+
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.Profile;
-import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblem.Severity;
 import org.apache.maven.model.building.ModelProblem.Version;
+import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblemCollectorRequest;
 import org.apache.maven.model.profile.ProfileActivationContext;
 
 /**
  * Determines profile activation based on the version of the current Java runtime.
  *
- * @author Benjamin Bentmann
  * @see Activation#getJdk()
  */
-@Named( "jdk-version" )
+@Named("jdk-version")
 @Singleton
-public class JdkVersionProfileActivator
-    implements ProfileActivator
-{
+public class JdkVersionProfileActivator implements ProfileActivator {
+
+    private static final Pattern FILTER_1 = Pattern.compile("[^\\d._-]");
+    private static final Pattern FILTER_2 = Pattern.compile("[._-]");
+    private static final Pattern FILTER_3 = Pattern.compile("\\."); // used for split now
 
     @Override
-    public boolean isActive( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
         String jdk = activation.getJdk();
 
-        if ( jdk == null )
-        {
+        if (jdk == null) {
             return false;
         }
 
-        String version = context.getSystemProperties().get( "java.version" );
+        String version = context.getSystemProperties().get("java.version");
 
-        if ( version == null || version.length() <= 0 )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "Failed to determine Java version for profile " + profile.getId() )
-                    .setLocation( activation.getLocation( "jdk" ) ) );
+        if (version == null || version.length() <= 0) {
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                    .setMessage("Failed to determine Java version for profile " + profile.getId())
+                    .setLocation(activation.getLocation("jdk")));
             return false;
         }
+        return isJavaVersionCompatible(jdk, version);
+    }
 
-        if ( jdk.startsWith( "!" ) )
-        {
-            return !version.startsWith( jdk.substring( 1 ) );
-        }
-        else if ( isRange( jdk ) )
-        {
-            return isInRange( version, getRange( jdk ) );
-        }
-        else
-        {
-            return version.startsWith( jdk );
+    public static boolean isJavaVersionCompatible(String requiredJdkRange, String currentJavaVersion) {
+        if (requiredJdkRange.startsWith("!")) {
+            return !currentJavaVersion.startsWith(requiredJdkRange.substring(1));
+        } else if (isRange(requiredJdkRange)) {
+            return isInRange(currentJavaVersion, getRange(requiredJdkRange));
+        } else {
+            return currentJavaVersion.startsWith(requiredJdkRange);
         }
     }
 
     @Override
-    public boolean presentInConfig( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean presentInConfig(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
@@ -102,122 +95,93 @@
         return jdk != null;
     }
 
-    private static boolean isInRange( String value, List<RangeValue> range )
-    {
-        int leftRelation = getRelationOrder( value, range.get( 0 ), true );
+    private static boolean isInRange(String value, List<RangeValue> range) {
+        int leftRelation = getRelationOrder(value, range.get(0), true);
 
-        if ( leftRelation == 0 )
-        {
+        if (leftRelation == 0) {
             return true;
         }
 
-        if ( leftRelation < 0 )
-        {
+        if (leftRelation < 0) {
             return false;
         }
 
-        return getRelationOrder( value, range.get( 1 ), false ) <= 0;
+        return getRelationOrder(value, range.get(1), false) <= 0;
     }
 
-    private static int getRelationOrder( String value, RangeValue rangeValue, boolean isLeft )
-    {
-        if ( rangeValue.value.length() <= 0 )
-        {
+    private static int getRelationOrder(String value, RangeValue rangeValue, boolean isLeft) {
+        if (rangeValue.value.length() <= 0) {
             return isLeft ? 1 : -1;
         }
 
-        value = value.replaceAll( "[^0-9\\.\\-\\_]", "" );
+        value = FILTER_1.matcher(value).replaceAll("");
 
-        List<String> valueTokens = new ArrayList<>( Arrays.asList( value.split( "[\\.\\-\\_]" ) ) );
-        List<String> rangeValueTokens = new ArrayList<>( Arrays.asList( rangeValue.value.split( "\\." ) ) );
+        List<String> valueTokens = new ArrayList<>(Arrays.asList(FILTER_2.split(value)));
+        List<String> rangeValueTokens = new ArrayList<>(Arrays.asList(FILTER_3.split(rangeValue.value)));
 
-        addZeroTokens( valueTokens, 3 );
-        addZeroTokens( rangeValueTokens, 3 );
+        addZeroTokens(valueTokens, 3);
+        addZeroTokens(rangeValueTokens, 3);
 
-        for ( int i = 0; i < 3; i++ )
-        {
-            int x = Integer.parseInt( valueTokens.get( i ) );
-            int y = Integer.parseInt( rangeValueTokens.get( i ) );
-            if ( x < y )
-            {
+        for (int i = 0; i < 3; i++) {
+            int x = Integer.parseInt(valueTokens.get(i));
+            int y = Integer.parseInt(rangeValueTokens.get(i));
+            if (x < y) {
                 return -1;
-            }
-            else if ( x > y )
-            {
+            } else if (x > y) {
                 return 1;
             }
         }
-        if ( !rangeValue.closed )
-        {
+        if (!rangeValue.closed) {
             return isLeft ? -1 : 1;
         }
         return 0;
     }
 
-    private static void addZeroTokens( List<String> tokens, int max )
-    {
-        while ( tokens.size() < max )
-        {
-            tokens.add( "0" );
+    private static void addZeroTokens(List<String> tokens, int max) {
+        while (tokens.size() < max) {
+            tokens.add("0");
         }
     }
 
-    private static boolean isRange( String value )
-    {
-        return value.startsWith( "[" ) || value.startsWith( "(" );
+    private static boolean isRange(String value) {
+        return value.startsWith("[") || value.startsWith("(");
     }
 
-    private static List<RangeValue> getRange( String range )
-    {
+    private static List<RangeValue> getRange(String range) {
         List<RangeValue> ranges = new ArrayList<>();
 
-        for ( String token : range.split( "," ) )
-        {
-            if ( token.startsWith( "[" ) )
-            {
-                ranges.add( new RangeValue( token.replace( "[", "" ), true ) );
-            }
-            else if ( token.startsWith( "(" ) )
-            {
-                ranges.add( new RangeValue( token.replace( "(", "" ), false ) );
-            }
-            else if ( token.endsWith( "]" ) )
-            {
-                ranges.add( new RangeValue( token.replace( "]", "" ), true ) );
-            }
-            else if ( token.endsWith( ")" ) )
-            {
-                ranges.add( new RangeValue( token.replace( ")", "" ), false ) );
-            }
-            else if ( token.length() <= 0 )
-            {
-                ranges.add( new RangeValue( "", false ) );
+        for (String token : range.split(",")) {
+            if (token.startsWith("[")) {
+                ranges.add(new RangeValue(token.replace("[", ""), true));
+            } else if (token.startsWith("(")) {
+                ranges.add(new RangeValue(token.replace("(", ""), false));
+            } else if (token.endsWith("]")) {
+                ranges.add(new RangeValue(token.replace("]", ""), true));
+            } else if (token.endsWith(")")) {
+                ranges.add(new RangeValue(token.replace(")", ""), false));
+            } else if (token.length() <= 0) {
+                ranges.add(new RangeValue("", false));
             }
         }
-        if ( ranges.size() < 2 )
-        {
-            ranges.add( new RangeValue( "99999999", false ) );
+        if (ranges.size() < 2) {
+            ranges.add(new RangeValue("99999999", false));
         }
         return ranges;
     }
 
-    private static class RangeValue
-    {
+    private static class RangeValue {
         private String value;
 
         private boolean closed;
 
-        RangeValue( String value, boolean closed )
-        {
+        RangeValue(String value, boolean closed) {
             this.value = value.trim();
             this.closed = closed;
         }
 
         @Override
-        public String toString()
-        {
+        public String toString() {
             return value;
         }
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/OperatingSystemProfileActivator.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/OperatingSystemProfileActivator.java
index b3b21fa..8f0af6a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/OperatingSystemProfileActivator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/OperatingSystemProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile.activation;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -27,66 +26,54 @@
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.profile.ProfileActivationContext;
-import org.codehaus.plexus.util.Os;
+import org.apache.maven.utils.Os;
 
 /**
  * Determines profile activation based on the operating system of the current runtime platform.
  *
- * @author Benjamin Bentmann
  * @see ActivationOS
  */
-@Named( "os" )
+@Named("os")
 @Singleton
-public class OperatingSystemProfileActivator
-    implements ProfileActivator
-{
+public class OperatingSystemProfileActivator implements ProfileActivator {
 
     @Override
-    public boolean isActive( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
         ActivationOS os = activation.getOs();
 
-        if ( os == null )
-        {
+        if (os == null) {
             return false;
         }
 
-        boolean active = ensureAtLeastOneNonNull( os );
+        boolean active = ensureAtLeastOneNonNull(os);
 
-        if ( active && os.getFamily() != null )
-        {
-            active = determineFamilyMatch( os.getFamily() );
+        if (active && os.getFamily() != null) {
+            active = determineFamilyMatch(os.getFamily());
         }
-        if ( active && os.getName() != null )
-        {
-            active = determineNameMatch( os.getName() );
+        if (active && os.getName() != null) {
+            active = determineNameMatch(os.getName());
         }
-        if ( active && os.getArch() != null )
-        {
-            active = determineArchMatch( os.getArch() );
+        if (active && os.getArch() != null) {
+            active = determineArchMatch(os.getArch());
         }
-        if ( active && os.getVersion() != null )
-        {
-            active = determineVersionMatch( os.getVersion() );
+        if (active && os.getVersion() != null) {
+            active = determineVersionMatch(os.getVersion());
         }
 
         return active;
     }
 
     @Override
-    public boolean presentInConfig( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean presentInConfig(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
@@ -95,73 +82,63 @@
         return os != null;
     }
 
-    private boolean ensureAtLeastOneNonNull( ActivationOS os )
-    {
+    private boolean ensureAtLeastOneNonNull(ActivationOS os) {
         return os.getArch() != null || os.getFamily() != null || os.getName() != null || os.getVersion() != null;
     }
 
-    private boolean determineVersionMatch( String version )
-    {
+    private boolean determineVersionMatch(String version) {
         String test = version;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isVersion( test );
+        boolean result = Os.OS_VERSION.equals(test);
 
         return reverse != result;
     }
 
-    private boolean determineArchMatch( String arch )
-    {
+    private boolean determineArchMatch(String arch) {
         String test = arch;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isArch( test );
+        boolean result = Os.OS_ARCH.equals(test);
 
         return reverse != result;
     }
 
-    private boolean determineNameMatch( String name )
-    {
+    private boolean determineNameMatch(String name) {
         String test = name;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isName( test );
+        boolean result = Os.OS_NAME.equals(test);
 
         return reverse != result;
     }
 
-    private boolean determineFamilyMatch( String family )
-    {
+    private boolean determineFamilyMatch(String family) {
         String test = family;
         boolean reverse = false;
 
-        if ( test.startsWith( "!" ) )
-        {
+        if (test.startsWith("!")) {
             reverse = true;
-            test = test.substring( 1 );
+            test = test.substring(1);
         }
 
-        boolean result = Os.isFamily( test );
+        boolean result = Os.isFamily(test);
 
         return reverse != result;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/ProfileActivator.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/ProfileActivator.java
index 1779147..e3226ec 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/ProfileActivator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/ProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile.activation;
 
 import org.apache.maven.model.Profile;
 import org.apache.maven.model.building.ModelProblemCollector;
@@ -26,10 +25,8 @@
 /**
  * Determines whether a profile should be activated.
  *
- * @author Benjamin Bentmann
  */
-public interface ProfileActivator
-{
+public interface ProfileActivator {
 
     /**
      * Determines whether the specified profile is active in the given activator context.
@@ -41,7 +38,7 @@
      *            {@code null}.
      * @return {@code true} if the profile is active, {@code false} otherwise.
      */
-    boolean isActive( Profile profile, ProfileActivationContext context, ModelProblemCollector problems );
+    boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems);
 
     /**
      * Determines whether specified activation method is present in configuration or not. It should help to have AND
@@ -54,6 +51,5 @@
      *            {@code null}.
      * @return {@code true} if the profile is active, {@code false} otherwise.
      */
-    boolean presentInConfig( Profile profile, ProfileActivationContext context, ModelProblemCollector problems );
-
+    boolean presentInConfig(Profile profile, ProfileActivationContext context, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/PropertyProfileActivator.java b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/PropertyProfileActivator.java
index 1668443..3941655 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/PropertyProfileActivator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/profile/activation/PropertyProfileActivator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile.activation;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -25,91 +24,75 @@
 import org.apache.maven.model.Activation;
 import org.apache.maven.model.ActivationProperty;
 import org.apache.maven.model.Profile;
-import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblem.Severity;
 import org.apache.maven.model.building.ModelProblem.Version;
+import org.apache.maven.model.building.ModelProblemCollector;
 import org.apache.maven.model.building.ModelProblemCollectorRequest;
 import org.apache.maven.model.profile.ProfileActivationContext;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
  * Determines profile activation based on the existence or value of some execution property.
  *
- * @author Benjamin Bentmann
  * @see ActivationProperty
  */
-@Named( "property" )
+@Named("property")
 @Singleton
-public class PropertyProfileActivator
-    implements ProfileActivator
-{
+public class PropertyProfileActivator implements ProfileActivator {
 
     @Override
-    public boolean isActive( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean isActive(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
         ActivationProperty property = activation.getProperty();
 
-        if ( property == null )
-        {
+        if (property == null) {
             return false;
         }
 
         String name = property.getName();
         boolean reverseName = false;
 
-        if ( name != null && name.startsWith( "!" ) )
-        {
+        if (name != null && name.startsWith("!")) {
             reverseName = true;
-            name = name.substring( 1 );
+            name = name.substring(1);
         }
 
-        if ( name == null || name.length() <= 0 )
-        {
-            problems.add( new ModelProblemCollectorRequest( Severity.ERROR, Version.BASE )
-                    .setMessage( "The property name is required to activate the profile " + profile.getId() )
-                    .setLocation( property.getLocation( "" ) ) );
+        if (name == null || name.length() <= 0) {
+            problems.add(new ModelProblemCollectorRequest(Severity.ERROR, Version.BASE)
+                    .setMessage("The property name is required to activate the profile " + profile.getId())
+                    .setLocation(property.getLocation("")));
             return false;
         }
 
-        String sysValue = context.getUserProperties().get( name );
-        if ( sysValue == null )
-        {
-            sysValue = context.getSystemProperties().get( name );
+        String sysValue = context.getUserProperties().get(name);
+        if (sysValue == null) {
+            sysValue = context.getSystemProperties().get(name);
         }
 
         String propValue = property.getValue();
-        if ( StringUtils.isNotEmpty( propValue ) )
-        {
+        if (propValue != null && !propValue.isEmpty()) {
             boolean reverseValue = false;
-            if ( propValue.startsWith( "!" ) )
-            {
+            if (propValue.startsWith("!")) {
                 reverseValue = true;
-                propValue = propValue.substring( 1 );
+                propValue = propValue.substring(1);
             }
 
             // we have a value, so it has to match the system value...
-            return reverseValue != propValue.equals( sysValue );
-        }
-        else
-        {
-            return reverseName != StringUtils.isNotEmpty( sysValue );
+            return reverseValue != propValue.equals(sysValue);
+        } else {
+            return reverseName != (sysValue != null && !sysValue.isEmpty());
         }
     }
 
     @Override
-    public boolean presentInConfig( Profile profile, ProfileActivationContext context, ModelProblemCollector problems )
-    {
+    public boolean presentInConfig(Profile profile, ProfileActivationContext context, ModelProblemCollector problems) {
         Activation activation = profile.getActivation();
 
-        if ( activation == null )
-        {
+        if (activation == null) {
             return false;
         }
 
@@ -117,5 +100,4 @@
 
         return property != null;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/InvalidRepositoryException.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/InvalidRepositoryException.java
index 303aff0..8d6087a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/InvalidRepositoryException.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/InvalidRepositoryException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.resolution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.resolution;
 
-import org.apache.maven.model.Repository;
+import org.apache.maven.api.model.Repository;
 
 /**
  * Signals an error when adding a repository to the model resolver.
  *
- * @author Benjamin Bentmann
  */
-public class InvalidRepositoryException
-    extends Exception
-{
+public class InvalidRepositoryException extends Exception {
 
     /**
      * The repository that raised this error, can be {@code null}.
@@ -42,9 +38,8 @@
      * @param repository The repository that caused the error, may be {@code null}.
      * @param cause The cause, may be {@code null}.
      */
-    public InvalidRepositoryException( String message, Repository repository, Throwable cause )
-    {
-        super( message, cause );
+    public InvalidRepositoryException(String message, Repository repository, Throwable cause) {
+        super(message, cause);
         this.repository = repository;
     }
 
@@ -54,9 +49,8 @@
      * @param message The detail message, may be {@code null}.
      * @param repository The repository that caused the error, may be {@code null}.
      */
-    public InvalidRepositoryException( String message, Repository repository )
-    {
-        super( message );
+    public InvalidRepositoryException(String message, Repository repository) {
+        super(message);
         this.repository = repository;
     }
 
@@ -65,9 +59,7 @@
      *
      * @return The repository that causes this error or {@code null} if not known.
      */
-    public Repository getRepository()
-    {
+    public Repository getRepository() {
         return repository;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/ModelResolver.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/ModelResolver.java
index a07eaf6..0b489c0 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/ModelResolver.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/ModelResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.resolution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,10 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.resolution;
 
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.Repository;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Parent;
+import org.apache.maven.api.model.Repository;
 import org.apache.maven.model.building.ModelSource;
 
 /**
@@ -29,10 +30,8 @@
  * {@link org.apache.maven.model.building.ModelBuilder} will add any relevant repositories to the model resolver. In
  * other words, the model resolver is stateful and should not be reused across multiple model building requests.
  *
- * @author Benjamin Bentmann
  */
-public interface ModelResolver
-{
+public interface ModelResolver {
 
     /**
      * Tries to resolve the POM for the specified coordinates.
@@ -43,8 +42,7 @@
      * @return The source of the requested POM, never {@code null}.
      * @throws UnresolvableModelException If the POM could not be resolved from any configured repository.
      */
-    ModelSource resolveModel( String groupId, String artifactId, String version )
-        throws UnresolvableModelException;
+    ModelSource resolveModel(String groupId, String artifactId, String version) throws UnresolvableModelException;
 
     /**
      * Tries to resolve the POM for the specified parent coordinates possibly updating {@code parent}.
@@ -64,8 +62,7 @@
      *
      * @see Parent#clone()
      */
-    ModelSource resolveModel( Parent parent )
-        throws UnresolvableModelException;
+    ModelSource resolveModel(org.apache.maven.model.Parent parent) throws UnresolvableModelException;
 
     /**
      * Tries to resolve the POM for the specified dependency coordinates possibly updating {@code dependency}.
@@ -85,8 +82,7 @@
      *
      * @see Dependency#clone()
      */
-    ModelSource resolveModel( Dependency dependency )
-        throws UnresolvableModelException;
+    ModelSource resolveModel(org.apache.maven.model.Dependency dependency) throws UnresolvableModelException;
 
     /**
      * Adds a repository to use for subsequent resolution requests. The order in which repositories are added matters,
@@ -96,8 +92,7 @@
      * @param repository The repository to add to the internal search chain, must not be {@code null}.
      * @throws InvalidRepositoryException If the repository could not be added (e.g. due to invalid URL or layout).
      */
-    void addRepository( Repository repository )
-        throws InvalidRepositoryException;
+    void addRepository(org.apache.maven.model.Repository repository) throws InvalidRepositoryException;
 
     /**
      * Adds a repository to use for subsequent resolution requests. The order in which repositories are added matters,
@@ -110,8 +105,7 @@
      * @param repository The repository to add to the internal search chain, must not be {@code null}.
      * @throws InvalidRepositoryException If the repository could not be added (e.g. due to invalid URL or layout).
      */
-    void addRepository( Repository repository, boolean replace )
-            throws InvalidRepositoryException;
+    void addRepository(org.apache.maven.model.Repository repository, boolean replace) throws InvalidRepositoryException;
 
     /**
      * Clones this resolver for usage in a forked resolution process. In general, implementors need not provide a deep
@@ -122,4 +116,31 @@
      */
     ModelResolver newCopy();
 
+    default ModelSource resolveModel(Parent parent, AtomicReference<Parent> modified)
+            throws UnresolvableModelException {
+        org.apache.maven.model.Parent p = new org.apache.maven.model.Parent(parent);
+        ModelSource result = resolveModel(p);
+        if (p.getDelegate() != parent) {
+            modified.set(p.getDelegate());
+        }
+        return result;
+    }
+
+    default ModelSource resolveModel(Dependency dependency, AtomicReference<Dependency> modified)
+            throws UnresolvableModelException {
+        org.apache.maven.model.Dependency d = new org.apache.maven.model.Dependency(dependency);
+        ModelSource result = resolveModel(d);
+        if (d.getDelegate() != dependency) {
+            modified.set(d.getDelegate());
+        }
+        return result;
+    }
+
+    default void addRepository(Repository repository) throws InvalidRepositoryException {
+        addRepository(new org.apache.maven.model.Repository(repository));
+    }
+
+    default void addRepository(Repository repository, boolean replace) throws InvalidRepositoryException {
+        addRepository(new org.apache.maven.model.Repository(repository), replace);
+    }
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java
index bdb623a..4438bb7 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/UnresolvableModelException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.resolution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.resolution;
 
 /**
  * Signals an error when resolving the path to an external model.
  *
- * @author Benjamin Bentmann
  */
-public class UnresolvableModelException
-    extends Exception
-{
+public class UnresolvableModelException extends Exception {
 
     /**
      * The group id of the unresolvable model.
@@ -52,13 +48,12 @@
      * @param version The version of the unresolvable model, may be {@code null}.
      * @param cause The cause, may be {@code null}.
      */
-    public UnresolvableModelException( String message, String groupId, String artifactId, String version,
-                                       Throwable cause )
-    {
-        super( message, cause );
-        this.groupId = ( groupId != null ) ? groupId : "";
-        this.artifactId = ( artifactId != null ) ? artifactId : "";
-        this.version = ( version != null ) ? version : "";
+    public UnresolvableModelException(
+            String message, String groupId, String artifactId, String version, Throwable cause) {
+        super(message, cause);
+        this.groupId = (groupId != null) ? groupId : "";
+        this.artifactId = (artifactId != null) ? artifactId : "";
+        this.version = (version != null) ? version : "";
     }
 
     /**
@@ -69,12 +64,11 @@
      * @param artifactId The artifact id of the unresolvable model, may be {@code null}.
      * @param version The version of the unresolvable model, may be {@code null}.
      */
-    public UnresolvableModelException( String message, String groupId, String artifactId, String version )
-    {
-        super( message );
-        this.groupId = ( groupId != null ) ? groupId : "";
-        this.artifactId = ( artifactId != null ) ? artifactId : "";
-        this.version = ( version != null ) ? version : "";
+    public UnresolvableModelException(String message, String groupId, String artifactId, String version) {
+        super(message);
+        this.groupId = (groupId != null) ? groupId : "";
+        this.artifactId = (artifactId != null) ? artifactId : "";
+        this.version = (version != null) ? version : "";
     }
 
     /**
@@ -85,9 +79,8 @@
      * @param artifactId
      * @param version
      */
-    public UnresolvableModelException( Throwable cause, String groupId, String artifactId, String version )
-    {
-        super( cause );
+    public UnresolvableModelException(Throwable cause, String groupId, String artifactId, String version) {
+        super(cause);
         this.groupId = groupId;
         this.artifactId = artifactId;
         this.version = version;
@@ -98,8 +91,7 @@
      *
      * @return The group id of the unresolvable model, can be empty but never {@code null}.
      */
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
@@ -108,8 +100,7 @@
      *
      * @return The artifact id of the unresolvable model, can be empty but never {@code null}.
      */
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
@@ -118,9 +109,7 @@
      *
      * @return The version of the unresolvable model, can be empty but never {@code null}.
      */
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java
index 8264ed7..bf4797c 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/resolution/WorkspaceModelResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.resolution;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,19 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.resolution;
 
 import org.apache.maven.model.Model;
 
 /**
  * WorkspaceModelResolver
  */
-public interface WorkspaceModelResolver
-{
+public interface WorkspaceModelResolver {
 
-    Model resolveRawModel( String groupId, String artifactId, String versionConstraint )
-        throws UnresolvableModelException;
+    Model resolveRawModel(String groupId, String artifactId, String versionConstraint)
+            throws UnresolvableModelException;
 
-    Model resolveEffectiveModel( String groupId, String artifactId, String versionConstraint )
-        throws UnresolvableModelException;
-
-}
\ No newline at end of file
+    Model resolveEffectiveModel(String groupId, String artifactId, String versionConstraint)
+            throws UnresolvableModelException;
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/root/DefaultRootLocator.java b/maven-model-builder/src/main/java/org/apache/maven/model/root/DefaultRootLocator.java
new file mode 100644
index 0000000..0321e7b
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/root/DefaultRootLocator.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.root;
+
+import javax.inject.Named;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import com.ctc.wstx.stax.WstxInputFactory;
+
+@Named
+public class DefaultRootLocator implements RootLocator {
+
+    public boolean isRootDirectory(Path dir) {
+        if (Files.isDirectory(dir.resolve(".mvn"))) {
+            return true;
+        }
+        // we're too early to use the modelProcessor ...
+        Path pom = dir.resolve("pom.xml");
+        try (InputStream is = Files.newInputStream(pom)) {
+            XMLStreamReader parser = new WstxInputFactory().createXMLStreamReader(is);
+            if (parser.nextTag() == XMLStreamReader.START_ELEMENT
+                    && parser.getLocalName().equals("project")) {
+                for (int i = 0; i < parser.getAttributeCount(); i++) {
+                    if ("root".equals(parser.getAttributeLocalName(i))) {
+                        return Boolean.parseBoolean(parser.getAttributeValue(i));
+                    }
+                }
+            }
+        } catch (IOException | XMLStreamException e) {
+            // The root locator can be used very early during the setup of Maven,
+            // even before the arguments from the command line are parsed.  Any exception
+            // that would happen here should cause the build to fail at a later stage
+            // (when actually parsing the POM) and will lead to a better exception being
+            // displayed to the user, so just bail out and return false.
+        }
+        return false;
+    }
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/root/RootLocator.java b/maven-model-builder/src/main/java/org/apache/maven/model/root/RootLocator.java
new file mode 100644
index 0000000..c1b458d
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/root/RootLocator.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.root;
+
+import java.nio.file.Path;
+
+import org.apache.maven.api.annotations.Nonnull;
+import org.apache.maven.api.annotations.Nullable;
+
+/**
+ * Interface used to locate the root directory for a given project.
+ *
+ * The root locator is usually looked up from the plexus container.
+ * One notable exception is the computation of the early {@code session.rootDirectory}
+ * property which happens very early.  The implementation used in this case
+ * will be discovered using the JDK service mechanism.
+ *
+ * The default implementation will look for a {@code .mvn} child directory
+ * or a {@code pom.xml} containing the {@code root="true"} attribute.
+ *
+ * @see DefaultRootLocator
+ */
+public interface RootLocator {
+
+    String UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE = "Unable to find the root directory. "
+            + "Create a .mvn directory in the root directory or add the root=\"true\""
+            + " attribute on the root project's model to identify it.";
+
+    @Nonnull
+    default Path findMandatoryRoot(Path basedir) {
+        Path rootDirectory = findRoot(basedir);
+        if (rootDirectory == null) {
+            throw new IllegalStateException(getNoRootMessage());
+        }
+        return rootDirectory;
+    }
+
+    @Nullable
+    default Path findRoot(Path basedir) {
+        Path rootDirectory = basedir;
+        while (rootDirectory != null && !isRootDirectory(rootDirectory)) {
+            rootDirectory = rootDirectory.getParent();
+        }
+        return rootDirectory;
+    }
+
+    @Nonnull
+    default String getNoRootMessage() {
+        return UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE;
+    }
+
+    boolean isRootDirectory(Path dir);
+}
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/superpom/DefaultSuperPomProvider.java b/maven-model-builder/src/main/java/org/apache/maven/model/superpom/DefaultSuperPomProvider.java
index 31df92f..d7180c9 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/superpom/DefaultSuperPomProvider.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/superpom/DefaultSuperPomProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.superpom;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,81 +16,72 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
+package org.apache.maven.model.superpom;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
-import org.apache.maven.model.InputSource;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.api.model.InputSource;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelProcessor;
 
 /**
  * Provides the super POM that all models implicitly inherit from.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultSuperPomProvider
-    implements SuperPomProvider
-{
+public class DefaultSuperPomProvider implements SuperPomProvider {
 
     private final ModelProcessor modelProcessor;
 
     /**
      * The cached super POM, lazily created.
      */
-    private Model superModel;
+    private static final Map<String, Model> SUPER_MODELS = new ConcurrentHashMap<>();
 
     @Inject
-    public DefaultSuperPomProvider( ModelProcessor modelProcessor )
-    {
+    public DefaultSuperPomProvider(ModelProcessor modelProcessor) {
         this.modelProcessor = modelProcessor;
     }
 
     @Override
-    public Model getSuperModel( String version )
-    {
-        if ( superModel == null )
-        {
-            String resource = "/org/apache/maven/model/pom-" + version + ".xml";
+    public Model getSuperModel(String version) {
+        return SUPER_MODELS.computeIfAbsent(Objects.requireNonNull(version), v -> {
+            String resource = "/org/apache/maven/model/pom-" + v + ".xml";
 
-            InputStream is = getClass().getResourceAsStream( resource );
+            InputStream is = getClass().getResourceAsStream(resource);
 
-            if ( is == null )
-            {
-                throw new IllegalStateException( "The super POM " + resource + " was not found"
-                    + ", please verify the integrity of your Maven installation" );
+            if (is == null) {
+                throw new IllegalStateException("The super POM " + resource + " was not found"
+                        + ", please verify the integrity of your Maven installation");
             }
 
-            try
-            {
-                Map<String, Object> options = new HashMap<>( 2 );
-                options.put( "xml:4.0.0", "xml:4.0.0" );
+            try {
+                Map<String, Object> options = new HashMap<>(2);
+                options.put("xml:" + version, "xml:" + version);
 
-                String modelId = "org.apache.maven:maven-model-builder:"
-                    + this.getClass().getPackage().getImplementationVersion() + ":super-pom";
-                InputSource inputSource = new InputSource();
-                inputSource.setModelId( modelId );
-                inputSource.setLocation( getClass().getResource( resource ).toExternalForm() );
-                options.put( ModelProcessor.INPUT_SOURCE, inputSource );
+                String modelId = "org.apache.maven:maven-model-builder:" + version + "-"
+                        + this.getClass().getPackage().getImplementationVersion() + ":super-pom";
+                InputSource inputSource = new InputSource(
+                        modelId, getClass().getResource(resource).toExternalForm());
+                options.put(ModelProcessor.INPUT_SOURCE, new org.apache.maven.model.InputSource(inputSource));
 
-                superModel = modelProcessor.read( is, options );
+                return modelProcessor.read(is, options);
+            } catch (IOException e) {
+                throw new IllegalStateException(
+                        "The super POM " + resource + " is damaged"
+                                + ", please verify the integrity of your Maven installation",
+                        e);
             }
-            catch ( IOException e )
-            {
-                throw new IllegalStateException( "The super POM " + resource + " is damaged"
-                    + ", please verify the integrity of your Maven installation", e );
-            }
-        }
-
-        return superModel;
+        });
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/superpom/SuperPomProvider.java b/maven-model-builder/src/main/java/org/apache/maven/model/superpom/SuperPomProvider.java
index 3f44fb7..50ffc9a 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/superpom/SuperPomProvider.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/superpom/SuperPomProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.superpom;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.superpom;
 
 import org.apache.maven.model.Model;
 
 /**
  * Provides the super POM that all models implicitly inherit from.
  *
- * @author Benjamin Bentmann
  */
-public interface SuperPomProvider
-{
+public interface SuperPomProvider {
 
     /**
      * Gets the super POM for the specified model version. The returned model is supposed to be read-only, i.e. if the
@@ -37,6 +34,5 @@
      * @param version The model version to retrieve the super POM for (e.g. "4.0.0"), must not be {@code null}.
      * @return The super POM, never {@code null}.
      */
-    Model getSuperModel( String version );
-
+    Model getSuperModel(String version);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
index 93a99cc..25f4328 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/validation/DefaultModelValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,37 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.validation;
 
-import org.apache.maven.model.Activation;
-import org.apache.maven.model.ActivationFile;
-import org.apache.maven.model.Build;
-import org.apache.maven.model.BuildBase;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Exclusion;
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.InputLocationTracker;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.PluginManagement;
-import org.apache.maven.model.Profile;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.Reporting;
-import org.apache.maven.model.Repository;
-import org.apache.maven.model.Resource;
-import org.apache.maven.model.building.ModelBuildingRequest;
-import org.apache.maven.model.building.ModelProblem.Severity;
-import org.apache.maven.model.building.ModelProblem.Version;
-import org.apache.maven.model.building.ModelProblemCollector;
-import org.apache.maven.model.building.ModelProblemCollectorRequest;
-import org.apache.maven.model.interpolation.ModelVersionProcessor;
-import org.codehaus.plexus.util.StringUtils;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.io.File;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -58,20 +34,45 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
+import org.apache.maven.api.model.Activation;
+import org.apache.maven.api.model.ActivationFile;
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.BuildBase;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.DependencyManagement;
+import org.apache.maven.api.model.DistributionManagement;
+import org.apache.maven.api.model.Exclusion;
+import org.apache.maven.api.model.InputLocation;
+import org.apache.maven.api.model.InputLocationTracker;
+import org.apache.maven.api.model.Parent;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginExecution;
+import org.apache.maven.api.model.PluginManagement;
+import org.apache.maven.api.model.Profile;
+import org.apache.maven.api.model.ReportPlugin;
+import org.apache.maven.api.model.Reporting;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.api.model.Resource;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.building.ModelBuildingRequest;
+import org.apache.maven.model.building.ModelProblem.Severity;
+import org.apache.maven.model.building.ModelProblem.Version;
+import org.apache.maven.model.building.ModelProblemCollector;
+import org.apache.maven.model.building.ModelProblemCollectorRequest;
+import org.apache.maven.model.interpolation.ModelVersionProcessor;
+import org.apache.maven.model.v4.MavenModelVersion;
 
 /**
- * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
  */
 @Named
 @Singleton
-public class DefaultModelValidator
-    implements ModelValidator
-{
+public class DefaultModelValidator implements ModelValidator {
 
-    private static final Pattern EXPRESSION_NAME_PATTERN = Pattern.compile( "\\$\\{(.+?)\\}" );
+    public static final List<String> VALID_MODEL_VERSIONS =
+            Collections.unmodifiableList(Arrays.asList("4.0.0", "4.1.0"));
+
+    private static final Pattern EXPRESSION_NAME_PATTERN = Pattern.compile("\\$\\{(.+?)}");
+    private static final Pattern EXPRESSION_PROJECT_NAME_PATTERN = Pattern.compile("\\$\\{(project.+?)}");
 
     private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*";
 
@@ -88,150 +89,164 @@
     private final ModelVersionProcessor versionProcessor;
 
     @Inject
-    public DefaultModelValidator( ModelVersionProcessor versionProcessor )
-    {
+    public DefaultModelValidator(ModelVersionProcessor versionProcessor) {
         this.versionProcessor = versionProcessor;
     }
 
     @Override
-    public void validateFileModel( Model m, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    public void validateFileModel(Model ma, ModelBuildingRequest request, ModelProblemCollector problems) {
+
+        org.apache.maven.api.model.Model m = ma.getDelegate();
+
         Parent parent = m.getParent();
-        if ( parent != null )
-        {
-            validateStringNotEmpty( "parent.groupId", problems, Severity.FATAL, Version.BASE, parent.getGroupId(),
-                                    parent );
+        if (parent != null) {
+            validateStringNotEmpty(
+                    "parent.groupId", problems, Severity.FATAL, Version.BASE, parent.getGroupId(), parent);
 
-            validateStringNotEmpty( "parent.artifactId", problems, Severity.FATAL, Version.BASE, parent.getArtifactId(),
-                                    parent );
+            validateStringNotEmpty(
+                    "parent.artifactId", problems, Severity.FATAL, Version.BASE, parent.getArtifactId(), parent);
 
-            if ( equals( parent.getGroupId(), m.getGroupId() ) && equals( parent.getArtifactId(), m.getArtifactId() ) )
-            {
-                addViolation( problems, Severity.FATAL, Version.BASE, "parent.artifactId", null,
-                              "must be changed"
-                                  + ", the parent element cannot have the same groupId:artifactId as the project.",
-                              parent );
+            if (equals(parent.getGroupId(), m.getGroupId()) && equals(parent.getArtifactId(), m.getArtifactId())) {
+                addViolation(
+                        problems,
+                        Severity.FATAL,
+                        Version.BASE,
+                        "parent.artifactId",
+                        null,
+                        "must be changed"
+                                + ", the parent element cannot have the same groupId:artifactId as the project.",
+                        parent);
             }
 
-            if ( equals( "LATEST", parent.getVersion() ) || equals( "RELEASE", parent.getVersion() ) )
-            {
-                addViolation( problems, Severity.WARNING, Version.BASE, "parent.version", null,
-                              "is either LATEST or RELEASE (both of them are being deprecated)", parent );
+            if (equals("LATEST", parent.getVersion()) || equals("RELEASE", parent.getVersion())) {
+                addViolation(
+                        problems,
+                        Severity.WARNING,
+                        Version.BASE,
+                        "parent.version",
+                        null,
+                        "is either LATEST or RELEASE (both of them are being deprecated)",
+                        parent);
             }
-
         }
 
-        if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
-        {
+        if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
             Set<String> modules = new HashSet<>();
-            for ( int i = 0, n = m.getModules().size(); i < n; i++ )
-            {
-                String module = m.getModules().get( i );
-                if ( !modules.add( module ) )
-                {
-                    addViolation( problems, Severity.ERROR, Version.V20, "modules.module[" + i + "]", null,
-                                  "specifies duplicate child module " + module, m.getLocation( "modules" ) );
+            for (int i = 0, n = m.getModules().size(); i < n; i++) {
+                String module = m.getModules().get(i);
+                if (!modules.add(module)) {
+                    addViolation(
+                            problems,
+                            Severity.ERROR,
+                            Version.V20,
+                            "modules.module[" + i + "]",
+                            null,
+                            "specifies duplicate child module " + module,
+                            m.getLocation("modules"));
                 }
             }
 
-            Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
+            Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
 
-            // [MNG-6074] Maven should produce an error if no model version has been set in a POM file used to build an
-            // effective model.
-            //
-            // As of 3.4, the model version is mandatory even in raw models. The XML element still is optional in the
-            // XML schema and this will not change anytime soon. We do not want to build effective models based on
-            // models without a version starting with 3.4.
-            validateStringNotEmpty( "modelVersion", problems, Severity.ERROR, Version.V20, m.getModelVersion(), m );
-
-            validateModelVersion( problems, m.getModelVersion(), m, "4.0.0" );
-
-            validateStringNoExpression( "groupId", problems, Severity.WARNING, Version.V20, m.getGroupId(), m );
-            if ( parent == null )
-            {
-                validateStringNotEmpty( "groupId", problems, Severity.FATAL, Version.V20, m.getGroupId(), m );
+            // The file pom may not contain the modelVersion yet, as it may be set later by the
+            // ModelVersionXMLFilter.
+            if (m.getModelVersion() != null && !m.getModelVersion().isEmpty()) {
+                validateModelVersion(problems, m.getModelVersion(), m, VALID_MODEL_VERSIONS);
             }
 
-            validateStringNoExpression( "artifactId", problems, Severity.WARNING, Version.V20, m.getArtifactId(), m );
-            validateStringNotEmpty( "artifactId", problems, Severity.FATAL, Version.V20, m.getArtifactId(), m );
-
-            validateVersionNoExpression( "version", problems, Severity.WARNING, Version.V20, m.getVersion(), m );
-            if ( parent == null )
-            {
-                validateStringNotEmpty( "version", problems, Severity.FATAL, Version.V20, m.getVersion(), m );
+            validateStringNoExpression("groupId", problems, Severity.WARNING, Version.V20, m.getGroupId(), m);
+            if (parent == null) {
+                validateStringNotEmpty("groupId", problems, Severity.FATAL, Version.V20, m.getGroupId(), m);
             }
 
-            validate20RawDependencies( problems, m.getDependencies(), "dependencies.dependency.", EMPTY, request );
+            validateStringNoExpression("artifactId", problems, Severity.WARNING, Version.V20, m.getArtifactId(), m);
+            validateStringNotEmpty("artifactId", problems, Severity.FATAL, Version.V20, m.getArtifactId(), m);
 
-            validate20RawDependenciesSelfReferencing( problems, m, m.getDependencies(), "dependencies.dependency",
-                                                      request );
-
-            if ( m.getDependencyManagement() != null )
-            {
-                validate20RawDependencies( problems, m.getDependencyManagement().getDependencies(),
-                                           "dependencyManagement.dependencies.dependency.", EMPTY, request );
+            validateVersionNoExpression("version", problems, Severity.WARNING, Version.V20, m.getVersion(), m);
+            if (parent == null) {
+                validateStringNotEmpty("version", problems, Severity.FATAL, Version.V20, m.getVersion(), m);
             }
 
-            validateRawRepositories( problems, m.getRepositories(), "repositories.repository.", EMPTY, request );
+            validate20RawDependencies(problems, m.getDependencies(), "dependencies.dependency.", EMPTY, request);
 
-            validateRawRepositories( problems, m.getPluginRepositories(), "pluginRepositories.pluginRepository.",
-                                     EMPTY, request );
+            validate20RawDependenciesSelfReferencing(
+                    problems, m, m.getDependencies(), "dependencies.dependency", request);
+
+            if (m.getDependencyManagement() != null) {
+                validate20RawDependencies(
+                        problems,
+                        m.getDependencyManagement().getDependencies(),
+                        "dependencyManagement.dependencies.dependency.",
+                        EMPTY,
+                        request);
+            }
+
+            validateRawRepositories(problems, m.getRepositories(), "repositories.repository.", EMPTY, request);
+
+            validateRawRepositories(
+                    problems, m.getPluginRepositories(), "pluginRepositories.pluginRepository.", EMPTY, request);
 
             Build build = m.getBuild();
-            if ( build != null )
-            {
-                validate20RawPlugins( problems, build.getPlugins(), "build.plugins.plugin.", EMPTY, request );
+            if (build != null) {
+                validate20RawPlugins(problems, build.getPlugins(), "build.plugins.plugin.", EMPTY, request);
 
                 PluginManagement mgmt = build.getPluginManagement();
-                if ( mgmt != null )
-                {
-                    validate20RawPlugins( problems, mgmt.getPlugins(), "build.pluginManagement.plugins.plugin.",
-                                          EMPTY, request );
+                if (mgmt != null) {
+                    validate20RawPlugins(
+                            problems, mgmt.getPlugins(), "build.pluginManagement.plugins.plugin.", EMPTY, request);
                 }
             }
 
             Set<String> profileIds = new HashSet<>();
 
-            for ( Profile profile : m.getProfiles() )
-            {
+            for (Profile profile : m.getProfiles()) {
                 String prefix = "profiles.profile[" + profile.getId() + "].";
 
-                validateProfileId( prefix, "id", problems, Severity.ERROR, Version.V40, profile.getId(), null, m );
+                validateProfileId(prefix, "id", problems, Severity.ERROR, Version.V40, profile.getId(), null, m);
 
-                if ( !profileIds.add( profile.getId() ) )
-                {
-                    addViolation( problems, errOn30, Version.V20, "profiles.profile.id", null,
-                                  "must be unique but found duplicate profile with id " + profile.getId(), profile );
+                if (!profileIds.add(profile.getId())) {
+                    addViolation(
+                            problems,
+                            errOn30,
+                            Version.V20,
+                            "profiles.profile.id",
+                            null,
+                            "must be unique but found duplicate profile with id " + profile.getId(),
+                            profile);
                 }
 
-                validate30RawProfileActivation( problems, profile.getActivation(), profile.getId(),
-                                                prefix, "activation", request );
+                validate30RawProfileActivation(problems, profile.getActivation(), prefix);
 
-                validate20RawDependencies( problems, profile.getDependencies(), prefix, "dependencies.dependency.",
-                                           request );
+                validate20RawDependencies(
+                        problems, profile.getDependencies(), prefix, "dependencies.dependency.", request);
 
-                if ( profile.getDependencyManagement() != null )
-                {
-                    validate20RawDependencies( problems, profile.getDependencyManagement().getDependencies(),
-                                               prefix, "dependencyManagement.dependencies.dependency.", request );
+                if (profile.getDependencyManagement() != null) {
+                    validate20RawDependencies(
+                            problems,
+                            profile.getDependencyManagement().getDependencies(),
+                            prefix,
+                            "dependencyManagement.dependencies.dependency.",
+                            request);
                 }
 
-                validateRawRepositories( problems, profile.getRepositories(), prefix, "repositories.repository.",
-                                         request );
+                validateRawRepositories(
+                        problems, profile.getRepositories(), prefix, "repositories.repository.", request);
 
-                validateRawRepositories( problems, profile.getPluginRepositories(),
-                                         prefix, "pluginRepositories.pluginRepository.", request );
+                validateRawRepositories(
+                        problems,
+                        profile.getPluginRepositories(),
+                        prefix,
+                        "pluginRepositories.pluginRepository.",
+                        request);
 
                 BuildBase buildBase = profile.getBuild();
-                if ( buildBase != null )
-                {
-                    validate20RawPlugins( problems, buildBase.getPlugins(), prefix, "plugins.plugin.", request );
+                if (buildBase != null) {
+                    validate20RawPlugins(problems, buildBase.getPlugins(), prefix, "plugins.plugin.", request);
 
                     PluginManagement mgmt = buildBase.getPluginManagement();
-                    if ( mgmt != null )
-                    {
-                        validate20RawPlugins( problems, mgmt.getPlugins(), prefix, "pluginManagement.plugins.plugin.",
-                                              request );
+                    if (mgmt != null) {
+                        validate20RawPlugins(
+                                problems, mgmt.getPlugins(), prefix, "pluginManagement.plugins.plugin.", request);
                     }
                 }
             }
@@ -239,515 +254,699 @@
     }
 
     @Override
-    public void validateRawModel( Model m, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    public void validateRawModel(Model ma, ModelBuildingRequest request, ModelProblemCollector problems) {
+        org.apache.maven.api.model.Model m = ma.getDelegate();
+
+        // [MNG-6074] Maven should produce an error if no model version has been set in a POM file used to build an
+        // effective model.
+        //
+        // As of 3.4, the model version is mandatory even in raw models. The XML element still is optional in the
+        // XML schema and this will not change anytime soon. We do not want to build effective models based on
+        // models without a version starting with 3.4.
+        validateStringNotEmpty("modelVersion", problems, Severity.ERROR, Version.V20, m.getModelVersion(), m);
+
+        validateModelVersion(problems, m.getModelVersion(), m, VALID_MODEL_VERSIONS);
+
+        String minVersion = new MavenModelVersion().getModelVersion(m);
+        if (m.getModelVersion() != null && compareModelVersions(minVersion, m.getModelVersion()) > 0) {
+            addViolation(
+                    problems,
+                    Severity.FATAL,
+                    Version.V40,
+                    "model",
+                    null,
+                    "the model contains elements that require a model version of " + minVersion,
+                    m);
+        }
+
         Parent parent = m.getParent();
 
-        if ( parent != null )
-        {
-            validateStringNotEmpty( "parent.version", problems, Severity.FATAL, Version.BASE, parent.getVersion(),
-                                    parent );
+        if (parent != null) {
+            validateStringNotEmpty(
+                    "parent.version", problems, Severity.FATAL, Version.BASE, parent.getVersion(), parent);
         }
     }
 
-    private void validate30RawProfileActivation( ModelProblemCollector problems, Activation activation,
-                                                 String sourceHint, String prefix, String fieldName,
-                                                 ModelBuildingRequest request )
-    {
-        if ( activation == null )
-        {
+    private void validate30RawProfileActivation(ModelProblemCollector problems, Activation activation, String prefix) {
+        if (activation == null || activation.getFile() == null) {
             return;
         }
 
         ActivationFile file = activation.getFile();
 
-        if ( file != null )
-        {
-            String path;
-            boolean missing;
+        String path;
+        String location;
 
-            if ( StringUtils.isNotEmpty( file.getExists() ) )
-            {
-                path = file.getExists();
-                missing = false;
-            }
-            else if ( StringUtils.isNotEmpty( file.getMissing() ) )
-            {
-                path = file.getMissing();
-                missing = true;
-            }
-            else
-            {
-                return;
-            }
+        if (file.getExists() != null && !file.getExists().isEmpty()) {
+            path = file.getExists();
+            location = "exists";
+        } else if (file.getMissing() != null && !file.getMissing().isEmpty()) {
+            path = file.getMissing();
+            location = "missing";
+        } else {
+            return;
+        }
 
-            if ( path.contains( "${project.basedir}" ) )
-            {
-                addViolation( problems, Severity.WARNING, Version.V30,
-                              prefix + fieldName + ( missing ? ".file.missing" : ".file.exists" ), null,
-                              "Failed to interpolate file location " + path + " for profile " + sourceHint
-                                  + ": ${project.basedir} expression not supported during profile activation, "
-                                  + "use ${basedir} instead",
-                              file.getLocation( missing ? "missing" : "exists" ) );
-            }
-            else if ( hasProjectExpression( path ) )
-            {
-                addViolation( problems, Severity.WARNING, Version.V30,
-                              prefix + fieldName + ( missing ? ".file.missing" : ".file.exists" ), null,
-                              "Failed to interpolate file location " + path + " for profile " + sourceHint
-                                  + ": ${project.*} expressions are not supported during profile activation",
-                              file.getLocation( missing ? "missing" : "exists" ) );
+        if (hasProjectExpression(path)) {
+            Matcher matcher = EXPRESSION_PROJECT_NAME_PATTERN.matcher(path);
+            while (matcher.find()) {
+                String propertyName = matcher.group(0);
+                if (!"${project.basedir}".equals(propertyName)) {
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            Version.V30,
+                            prefix + "activation.file." + location,
+                            null,
+                            "Failed to interpolate file location " + path + ": " + propertyName
+                                    + " expressions are not supported during profile activation.",
+                            file.getLocation(location));
+                }
             }
         }
     }
 
-    private void validate20RawPlugins( ModelProblemCollector problems, List<Plugin> plugins, String prefix,
-                                       String prefix2, ModelBuildingRequest request )
-    {
-        Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
+    private void validate20RawPlugins(
+            ModelProblemCollector problems,
+            List<Plugin> plugins,
+            String prefix,
+            String prefix2,
+            ModelBuildingRequest request) {
+        Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
 
         Map<String, Plugin> index = new HashMap<>();
 
-        for ( Plugin plugin : plugins )
-        {
-            if ( plugin.getGroupId() == null
-                || ( plugin.getGroupId() != null && plugin.getGroupId().trim().isEmpty() ) )
-            {
-                addViolation( problems, Severity.FATAL, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null,
-                              "groupId of a plugin must be defined. ", plugin );
+        for (Plugin plugin : plugins) {
+            if (plugin.getGroupId() == null
+                    || (plugin.getGroupId() != null
+                            && plugin.getGroupId().trim().isEmpty())) {
+                addViolation(
+                        problems,
+                        Severity.FATAL,
+                        Version.V20,
+                        prefix + prefix2 + "(groupId:artifactId)",
+                        null,
+                        "groupId of a plugin must be defined. ",
+                        plugin);
             }
 
-            if ( plugin.getArtifactId() == null
-                || ( plugin.getArtifactId() != null && plugin.getArtifactId().trim().isEmpty() ) )
-            {
-                addViolation( problems, Severity.FATAL, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null,
-                              "artifactId of a plugin must be defined. ", plugin );
+            if (plugin.getArtifactId() == null
+                    || (plugin.getArtifactId() != null
+                            && plugin.getArtifactId().trim().isEmpty())) {
+                addViolation(
+                        problems,
+                        Severity.FATAL,
+                        Version.V20,
+                        prefix + prefix2 + "(groupId:artifactId)",
+                        null,
+                        "artifactId of a plugin must be defined. ",
+                        plugin);
             }
 
             // This will catch cases like <version></version> or <version/>
-            if ( plugin.getVersion() != null && plugin.getVersion().trim().isEmpty() )
-            {
-                addViolation( problems, Severity.FATAL, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null,
-                              "version of a plugin must be defined. ", plugin );
+            if (plugin.getVersion() != null && plugin.getVersion().trim().isEmpty()) {
+                addViolation(
+                        problems,
+                        Severity.FATAL,
+                        Version.V20,
+                        prefix + prefix2 + "(groupId:artifactId)",
+                        null,
+                        "version of a plugin must be defined. ",
+                        plugin);
             }
 
             String key = plugin.getKey();
 
-            Plugin existing = index.get( key );
+            Plugin existing = index.get(key);
 
-            if ( existing != null )
-            {
-                addViolation( problems, errOn31, Version.V20, prefix + prefix2 + "(groupId:artifactId)", null,
-                              "must be unique but found duplicate declaration of plugin " + key, plugin );
-            }
-            else
-            {
-                index.put( key, plugin );
+            if (existing != null) {
+                addViolation(
+                        problems,
+                        errOn31,
+                        Version.V20,
+                        prefix + prefix2 + "(groupId:artifactId)",
+                        null,
+                        "must be unique but found duplicate declaration of plugin " + key,
+                        plugin);
+            } else {
+                index.put(key, plugin);
             }
 
             Set<String> executionIds = new HashSet<>();
 
-            for ( PluginExecution exec : plugin.getExecutions() )
-            {
-                if ( !executionIds.add( exec.getId() ) )
-                {
-                    addViolation( problems, Severity.ERROR, Version.V20,
-                                  prefix + prefix2 + "[" + plugin.getKey() + "].executions.execution.id", null,
-                                  "must be unique but found duplicate execution with id " + exec.getId(), exec );
+            for (PluginExecution exec : plugin.getExecutions()) {
+                if (!executionIds.add(exec.getId())) {
+                    addViolation(
+                            problems,
+                            Severity.ERROR,
+                            Version.V20,
+                            prefix + prefix2 + "[" + plugin.getKey() + "].executions.execution.id",
+                            null,
+                            "must be unique but found duplicate execution with id " + exec.getId(),
+                            exec);
                 }
             }
         }
     }
 
     @Override
-    public void validateEffectiveModel( Model m, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
-        validateStringNotEmpty( "modelVersion", problems, Severity.ERROR, Version.BASE, m.getModelVersion(), m );
+    public void validateEffectiveModel(Model ma, ModelBuildingRequest request, ModelProblemCollector problems) {
+        org.apache.maven.api.model.Model m = ma.getDelegate();
 
-        validateCoordinateId( "groupId", problems, m.getGroupId(), m );
+        validateStringNotEmpty("modelVersion", problems, Severity.ERROR, Version.BASE, m.getModelVersion(), m);
 
-        validateCoordinateId( "artifactId", problems, m.getArtifactId(), m );
+        validateCoordinateId("groupId", problems, m.getGroupId(), m);
 
-        validateStringNotEmpty( "packaging", problems, Severity.ERROR, Version.BASE, m.getPackaging(), m );
+        validateCoordinateId("artifactId", problems, m.getArtifactId(), m);
 
-        if ( !m.getModules().isEmpty() )
-        {
-            if ( !"pom".equals( m.getPackaging() ) )
-            {
-                addViolation( problems, Severity.ERROR, Version.BASE, "packaging", null, "with value '"
-                    + m.getPackaging() + "' is invalid. Aggregator projects " + "require 'pom' as packaging.", m );
+        validateStringNotEmpty("packaging", problems, Severity.ERROR, Version.BASE, m.getPackaging(), m);
+
+        if (!m.getModules().isEmpty()) {
+            if (!"pom".equals(m.getPackaging())) {
+                addViolation(
+                        problems,
+                        Severity.ERROR,
+                        Version.BASE,
+                        "packaging",
+                        null,
+                        "with value '" + m.getPackaging() + "' is invalid. Aggregator projects "
+                                + "require 'pom' as packaging.",
+                        m);
             }
 
-            for ( int i = 0, n = m.getModules().size(); i < n; i++ )
-            {
-                String module = m.getModules().get( i );
-                if ( StringUtils.isBlank( module ) )
-                {
-                    addViolation( problems, Severity.ERROR, Version.BASE, "modules.module[" + i + "]", null,
-                                  "has been specified without a path to the project directory.",
-                                  m.getLocation( "modules" ) );
+            for (int i = 0, n = m.getModules().size(); i < n; i++) {
+                String module = m.getModules().get(i);
+
+                boolean isBlankModule = true;
+                if (module != null) {
+                    for (int j = 0; j < module.length(); j++) {
+                        if (!Character.isWhitespace(module.charAt(j))) {
+                            isBlankModule = false;
+                        }
+                    }
+                }
+
+                if (isBlankModule) {
+                    addViolation(
+                            problems,
+                            Severity.ERROR,
+                            Version.BASE,
+                            "modules.module[" + i + "]",
+                            null,
+                            "has been specified without a path to the project directory.",
+                            m.getLocation("modules"));
                 }
             }
         }
 
-        validateStringNotEmpty( "version", problems, Severity.ERROR, Version.BASE, m.getVersion(), m );
+        validateStringNotEmpty("version", problems, Severity.ERROR, Version.BASE, m.getVersion(), m);
 
-        Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
+        Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
 
-        validateEffectiveDependencies( problems, m, m.getDependencies(), false, request );
+        validateEffectiveDependencies(problems, m, m.getDependencies(), false, request);
 
         DependencyManagement mgmt = m.getDependencyManagement();
-        if ( mgmt != null )
-        {
-            validateEffectiveDependencies( problems, m, mgmt.getDependencies(), true, request );
+        if (mgmt != null) {
+            validateEffectiveDependencies(problems, m, mgmt.getDependencies(), true, request);
         }
 
-        if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
-        {
-            Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
+        if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
+            Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
 
-            validateBannedCharacters( EMPTY, "version", problems, errOn31, Version.V20, m.getVersion(), null, m,
-                                      ILLEGAL_VERSION_CHARS );
-            validate20ProperSnapshotVersion( "version", problems, errOn31, Version.V20, m.getVersion(), null, m );
+            validateBannedCharacters(
+                    EMPTY, "version", problems, errOn31, Version.V20, m.getVersion(), null, m, ILLEGAL_VERSION_CHARS);
+            validate20ProperSnapshotVersion("version", problems, errOn31, Version.V20, m.getVersion(), null, m);
 
             Build build = m.getBuild();
-            if ( build != null )
-            {
-                for ( Plugin p : build.getPlugins() )
-                {
-                    validateStringNotEmpty( "build.plugins.plugin.artifactId", problems, Severity.ERROR, Version.V20,
-                                            p.getArtifactId(), p );
+            if (build != null) {
+                for (Plugin p : build.getPlugins()) {
+                    validateStringNotEmpty(
+                            "build.plugins.plugin.artifactId",
+                            problems,
+                            Severity.ERROR,
+                            Version.V20,
+                            p.getArtifactId(),
+                            p);
 
-                    validateStringNotEmpty( "build.plugins.plugin.groupId", problems, Severity.ERROR, Version.V20,
-                                            p.getGroupId(), p );
+                    validateStringNotEmpty(
+                            "build.plugins.plugin.groupId", problems, Severity.ERROR, Version.V20, p.getGroupId(), p);
 
-                    validate20PluginVersion( "build.plugins.plugin.version", problems, p.getVersion(), p.getKey(), p,
-                                             request );
+                    validate20PluginVersion(
+                            "build.plugins.plugin.version", problems, p.getVersion(), p.getKey(), p, request);
 
-                    validateBoolean( "build.plugins.plugin.inherited", EMPTY, problems, errOn30, Version.V20,
-                                     p.getInherited(), p.getKey(), p );
+                    validateBoolean(
+                            "build.plugins.plugin.inherited",
+                            EMPTY,
+                            problems,
+                            errOn30,
+                            Version.V20,
+                            p.getInherited(),
+                            p.getKey(),
+                            p);
 
-                    validateBoolean( "build.plugins.plugin.extensions", EMPTY, problems, errOn30, Version.V20,
-                                     p.getExtensions(), p.getKey(), p );
+                    validateBoolean(
+                            "build.plugins.plugin.extensions",
+                            EMPTY,
+                            problems,
+                            errOn30,
+                            Version.V20,
+                            p.getExtensions(),
+                            p.getKey(),
+                            p);
 
-                    validate20EffectivePluginDependencies( problems, p, request );
+                    validate20EffectivePluginDependencies(problems, p, request);
                 }
 
-                validate20RawResources( problems, build.getResources(), "build.resources.resource.", request );
+                validate20RawResources(problems, build.getResources(), "build.resources.resource.", request);
 
-                validate20RawResources( problems, build.getTestResources(), "build.testResources.testResource.",
-                                        request );
+                validate20RawResources(
+                        problems, build.getTestResources(), "build.testResources.testResource.", request);
             }
 
             Reporting reporting = m.getReporting();
-            if ( reporting != null )
-            {
-                for ( ReportPlugin p : reporting.getPlugins() )
-                {
-                    validateStringNotEmpty( "reporting.plugins.plugin.artifactId", problems, Severity.ERROR,
-                                            Version.V20, p.getArtifactId(), p );
+            if (reporting != null) {
+                for (ReportPlugin p : reporting.getPlugins()) {
+                    validateStringNotEmpty(
+                            "reporting.plugins.plugin.artifactId",
+                            problems,
+                            Severity.ERROR,
+                            Version.V20,
+                            p.getArtifactId(),
+                            p);
 
-                    validateStringNotEmpty( "reporting.plugins.plugin.groupId", problems, Severity.ERROR, Version.V20,
-                                            p.getGroupId(), p );
+                    validateStringNotEmpty(
+                            "reporting.plugins.plugin.groupId",
+                            problems,
+                            Severity.ERROR,
+                            Version.V20,
+                            p.getGroupId(),
+                            p);
                 }
             }
 
-            for ( Repository repository : m.getRepositories() )
-            {
-                validate20EffectiveRepository( problems, repository, "repositories.repository.", request );
+            for (Repository repository : m.getRepositories()) {
+                validate20EffectiveRepository(problems, repository, "repositories.repository.", request);
             }
 
-            for ( Repository repository : m.getPluginRepositories() )
-            {
-                validate20EffectiveRepository( problems, repository, "pluginRepositories.pluginRepository.", request );
+            for (Repository repository : m.getPluginRepositories()) {
+                validate20EffectiveRepository(problems, repository, "pluginRepositories.pluginRepository.", request);
             }
 
             DistributionManagement distMgmt = m.getDistributionManagement();
-            if ( distMgmt != null )
-            {
-                if ( distMgmt.getStatus() != null )
-                {
-                    addViolation( problems, Severity.ERROR, Version.V20, "distributionManagement.status", null,
-                                  "must not be specified.", distMgmt );
+            if (distMgmt != null) {
+                if (distMgmt.getStatus() != null) {
+                    addViolation(
+                            problems,
+                            Severity.ERROR,
+                            Version.V20,
+                            "distributionManagement.status",
+                            null,
+                            "must not be specified.",
+                            distMgmt);
                 }
 
-                validate20EffectiveRepository( problems, distMgmt.getRepository(), "distributionManagement.repository.",
-                                               request );
-                validate20EffectiveRepository( problems, distMgmt.getSnapshotRepository(),
-                                               "distributionManagement.snapshotRepository.", request );
+                validate20EffectiveRepository(
+                        problems, distMgmt.getRepository(), "distributionManagement.repository.", request);
+                validate20EffectiveRepository(
+                        problems,
+                        distMgmt.getSnapshotRepository(),
+                        "distributionManagement.snapshotRepository.",
+                        request);
             }
         }
     }
 
-    private void validate20RawDependencies( ModelProblemCollector problems, List<Dependency> dependencies,
-                                            String prefix, String prefix2, ModelBuildingRequest request )
-    {
-        Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
-        Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
+    private void validate20RawDependencies(
+            ModelProblemCollector problems,
+            List<Dependency> dependencies,
+            String prefix,
+            String prefix2,
+            ModelBuildingRequest request) {
+        Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
+        Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
 
         Map<String, Dependency> index = new HashMap<>();
 
-        for ( Dependency dependency : dependencies )
-        {
+        for (Dependency dependency : dependencies) {
             String key = dependency.getManagementKey();
 
-            if ( "import".equals( dependency.getScope() ) )
-            {
-                if ( !"pom".equals( dependency.getType() ) )
-                {
-                    addViolation( problems, Severity.WARNING, Version.V20, prefix + prefix2 + "type", key,
-                                  "must be 'pom' to import the managed dependencies.", dependency );
+            if ("import".equals(dependency.getScope())) {
+                if (!"pom".equals(dependency.getType())) {
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            Version.V20,
+                            prefix + prefix2 + "type",
+                            key,
+                            "must be 'pom' to import the managed dependencies.",
+                            dependency);
+                } else if (dependency.getClassifier() != null
+                        && !dependency.getClassifier().isEmpty()) {
+                    addViolation(
+                            problems,
+                            errOn30,
+                            Version.V20,
+                            prefix + prefix2 + "classifier",
+                            key,
+                            "must be empty, imported POM cannot have a classifier.",
+                            dependency);
                 }
-                else if ( StringUtils.isNotEmpty( dependency.getClassifier() ) )
-                {
-                    addViolation( problems, errOn30, Version.V20, prefix + prefix2 + "classifier", key,
-                                  "must be empty, imported POM cannot have a classifier.", dependency );
-                }
-            }
-            else if ( "system".equals( dependency.getScope() ) )
-            {
+            } else if ("system".equals(dependency.getScope())) {
 
-                if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 )
-                {
-                    addViolation( problems, Severity.WARNING, Version.V31, prefix + prefix2 + "scope", key,
-                                  "declares usage of deprecated 'system' scope ", dependency );
+                if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1) {
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            Version.V31,
+                            prefix + prefix2 + "scope",
+                            key,
+                            "declares usage of deprecated 'system' scope ",
+                            dependency);
                 }
 
                 String sysPath = dependency.getSystemPath();
-                if ( StringUtils.isNotEmpty( sysPath ) )
-                {
-                    if ( !hasExpression( sysPath ) )
-                    {
-                        addViolation( problems, Severity.WARNING, Version.V20, prefix + prefix2 + "systemPath", key,
-                                      "should use a variable instead of a hard-coded path " + sysPath, dependency );
-                    }
-                    else if ( sysPath.contains( "${basedir}" ) || sysPath.contains( "${project.basedir}" ) )
-                    {
-                        addViolation( problems, Severity.WARNING, Version.V20, prefix + prefix2 + "systemPath", key,
-                                      "should not point at files within the project directory, " + sysPath
-                                          + " will be unresolvable by dependent projects",
-                                      dependency );
+                if (sysPath != null && !sysPath.isEmpty()) {
+                    if (!hasExpression(sysPath)) {
+                        addViolation(
+                                problems,
+                                Severity.WARNING,
+                                Version.V20,
+                                prefix + prefix2 + "systemPath",
+                                key,
+                                "should use a variable instead of a hard-coded path " + sysPath,
+                                dependency);
+                    } else if (sysPath.contains("${basedir}") || sysPath.contains("${project.basedir}")) {
+                        addViolation(
+                                problems,
+                                Severity.WARNING,
+                                Version.V20,
+                                prefix + prefix2 + "systemPath",
+                                key,
+                                "should not point at files within the project directory, " + sysPath
+                                        + " will be unresolvable by dependent projects",
+                                dependency);
                     }
                 }
             }
 
-            if ( equals( "LATEST", dependency.getVersion() ) || equals( "RELEASE", dependency.getVersion() ) )
-            {
-                addViolation( problems, Severity.WARNING, Version.BASE, prefix + prefix2 + "version", key,
-                              "is either LATEST or RELEASE (both of them are being deprecated)", dependency );
+            if (equals("LATEST", dependency.getVersion()) || equals("RELEASE", dependency.getVersion())) {
+                addViolation(
+                        problems,
+                        Severity.WARNING,
+                        Version.BASE,
+                        prefix + prefix2 + "version",
+                        key,
+                        "is either LATEST or RELEASE (both of them are being deprecated)",
+                        dependency);
             }
 
-            Dependency existing = index.get( key );
+            Dependency existing = index.get(key);
 
-            if ( existing != null )
-            {
+            if (existing != null) {
                 String msg;
-                if ( equals( existing.getVersion(), dependency.getVersion() ) )
-                {
-                    msg = "duplicate declaration of version "
-                        + Objects.toString( dependency.getVersion(), "(?)" );
-                }
-                else
-                {
-                    msg = "version " + Objects.toString( existing.getVersion(), "(?)" ) + " vs "
-                        + Objects.toString( dependency.getVersion(), "(?)" );
+                if (equals(existing.getVersion(), dependency.getVersion())) {
+                    msg = "duplicate declaration of version " + Objects.toString(dependency.getVersion(), "(?)");
+                } else {
+                    msg = "version " + Objects.toString(existing.getVersion(), "(?)") + " vs "
+                            + Objects.toString(dependency.getVersion(), "(?)");
                 }
 
-                addViolation( problems, errOn31, Version.V20, prefix + prefix2 + "(groupId:artifactId:type:classifier)",
-                              null, "must be unique: " + key + " -> " + msg, dependency );
-            }
-            else
-            {
-                index.put( key, dependency );
+                addViolation(
+                        problems,
+                        errOn31,
+                        Version.V20,
+                        prefix + prefix2 + "(groupId:artifactId:type:classifier)",
+                        null,
+                        "must be unique: " + key + " -> " + msg,
+                        dependency);
+            } else {
+                index.put(key, dependency);
             }
         }
     }
 
-    private void validate20RawDependenciesSelfReferencing( ModelProblemCollector problems, Model m,
-                                                           List<Dependency> dependencies, String prefix,
-                                                           ModelBuildingRequest request )
-    {
+    private void validate20RawDependenciesSelfReferencing(
+            ModelProblemCollector problems,
+            org.apache.maven.api.model.Model m,
+            List<Dependency> dependencies,
+            String prefix,
+            ModelBuildingRequest request) {
         // We only check for groupId/artifactId/version/classifier cause if there is another
         // module with the same groupId/artifactId/version/classifier this will fail the build
         // earlier like "Project '...' is duplicated in the reactor.
         // So it is sufficient to check only groupId/artifactId/version/classifier and not the
         // packaging type.
-        for ( Dependency dependency : dependencies )
-        {
+        for (Dependency dependency : dependencies) {
             String key = dependency.getGroupId() + ":" + dependency.getArtifactId() + ":" + dependency.getVersion()
-                    + ( dependency.getClassifier() != null ? ":" + dependency.getClassifier() : EMPTY  );
+                    + (dependency.getClassifier() != null ? ":" + dependency.getClassifier() : EMPTY);
             String mKey = m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion();
-            if ( key.equals( mKey ) )
-            {
+            if (key.equals(mKey)) {
                 // This means a module which is build has a dependency which has the same
                 // groupId, artifactId, version and classifier coordinates. This is in consequence
                 // a self reference or in other words a circular reference which can not being resolved.
-                addViolation( problems, Severity.FATAL, Version.V31, prefix + "[" + key + "]", key,
-                              "is referencing itself.", dependency );
-
+                addViolation(
+                        problems,
+                        Severity.FATAL,
+                        Version.V31,
+                        prefix + "[" + key + "]",
+                        key,
+                        "is referencing itself.",
+                        dependency);
             }
         }
     }
 
-    private void validateEffectiveDependencies( ModelProblemCollector problems, Model m, List<Dependency> dependencies,
-                                                boolean management, ModelBuildingRequest request )
-    {
-        Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
+    private void validateEffectiveDependencies(
+            ModelProblemCollector problems,
+            org.apache.maven.api.model.Model m,
+            List<Dependency> dependencies,
+            boolean management,
+            ModelBuildingRequest request) {
+        Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
 
         String prefix = management ? "dependencyManagement.dependencies.dependency." : "dependencies.dependency.";
 
-        for ( Dependency d : dependencies )
-        {
-            validateEffectiveDependency( problems, d, management, prefix, request );
+        for (Dependency d : dependencies) {
+            validateEffectiveDependency(problems, d, management, prefix, request);
 
-            if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
-            {
-                validateBoolean( prefix, "optional", problems, errOn30, Version.V20, d.getOptional(),
-                                 d.getManagementKey(), d );
+            if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
+                validateBoolean(
+                        prefix, "optional", problems, errOn30, Version.V20, d.getOptional(), d.getManagementKey(), d);
 
-                if ( !management )
-                {
-                    validateVersion( prefix, "version", problems, errOn30, Version.V20, d.getVersion(),
-                                     d.getManagementKey(), d );
+                if (!management) {
+                    validateVersion(
+                            prefix, "version", problems, errOn30, Version.V20, d.getVersion(), d.getManagementKey(), d);
 
                     /*
                      * TODO Extensions like Flex Mojos use custom scopes like "merged", "internal", "external", etc. In
                      * order to don't break backward-compat with those, only warn but don't error out.
                      */
-                    validateEnum( prefix, "scope", problems, Severity.WARNING, Version.V20, d.getScope(),
-                                  d.getManagementKey(), d, "provided", "compile", "runtime", "test", "system" );
+                    validateEnum(
+                            prefix,
+                            "scope",
+                            problems,
+                            Severity.WARNING,
+                            Version.V20,
+                            d.getScope(),
+                            d.getManagementKey(),
+                            d,
+                            "provided",
+                            "compile",
+                            "runtime",
+                            "test",
+                            "system");
 
-                    validateEffectiveModelAgainstDependency( prefix, problems, m, d, request );
-                }
-                else
-                {
-                    validateEnum( prefix, "scope", problems, Severity.WARNING, Version.V20, d.getScope(),
-                                  d.getManagementKey(), d, "provided", "compile", "runtime", "test", "system",
-                                  "import" );
+                    validateEffectiveModelAgainstDependency(prefix, problems, m, d, request);
+                } else {
+                    validateEnum(
+                            prefix,
+                            "scope",
+                            problems,
+                            Severity.WARNING,
+                            Version.V20,
+                            d.getScope(),
+                            d.getManagementKey(),
+                            d,
+                            "provided",
+                            "compile",
+                            "runtime",
+                            "test",
+                            "system",
+                            "import");
                 }
             }
         }
     }
 
-    private void validateEffectiveModelAgainstDependency( String prefix, ModelProblemCollector problems, Model m,
-                                                          Dependency d, ModelBuildingRequest request )
-    {
+    private void validateEffectiveModelAgainstDependency(
+            String prefix,
+            ModelProblemCollector problems,
+            org.apache.maven.api.model.Model m,
+            Dependency d,
+            ModelBuildingRequest request) {
         String key = d.getGroupId() + ":" + d.getArtifactId() + ":" + d.getVersion()
-                + ( d.getClassifier() != null ? ":" + d.getClassifier() : EMPTY  );
+                + (d.getClassifier() != null ? ":" + d.getClassifier() : EMPTY);
         String mKey = m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion();
-        if ( key.equals( mKey ) )
-        {
+        if (key.equals(mKey)) {
             // This means a module which is build has a dependency which has the same
             // groupId, artifactId, version and classifier coordinates. This is in consequence
             // a self reference or in other words a circular reference which can not being resolved.
-            addViolation( problems, Severity.FATAL, Version.V31, prefix + "[" + key + "]", key,
-                          "is referencing itself.", d );
-
+            addViolation(
+                    problems, Severity.FATAL, Version.V31, prefix + "[" + key + "]", key, "is referencing itself.", d);
         }
-
     }
 
-    private void validate20EffectivePluginDependencies( ModelProblemCollector problems, Plugin plugin,
-                                                        ModelBuildingRequest request )
-    {
+    private void validate20EffectivePluginDependencies(
+            ModelProblemCollector problems, Plugin plugin, ModelBuildingRequest request) {
         List<Dependency> dependencies = plugin.getDependencies();
 
-        if ( !dependencies.isEmpty() )
-        {
+        if (!dependencies.isEmpty()) {
             String prefix = "build.plugins.plugin[" + plugin.getKey() + "].dependencies.dependency.";
 
-            Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
+            Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
 
-            for ( Dependency d : dependencies )
-            {
-                validateEffectiveDependency( problems, d, false, prefix, request );
+            for (Dependency d : dependencies) {
+                validateEffectiveDependency(problems, d, false, prefix, request);
 
-                validateVersion( prefix, "version", problems, errOn30, Version.BASE, d.getVersion(),
-                                 d.getManagementKey(), d );
+                validateVersion(
+                        prefix, "version", problems, errOn30, Version.BASE, d.getVersion(), d.getManagementKey(), d);
 
-                validateEnum( prefix, "scope", problems, errOn30, Version.BASE, d.getScope(), d.getManagementKey(), d,
-                              "compile", "runtime", "system" );
+                validateEnum(
+                        prefix,
+                        "scope",
+                        problems,
+                        errOn30,
+                        Version.BASE,
+                        d.getScope(),
+                        d.getManagementKey(),
+                        d,
+                        "compile",
+                        "runtime",
+                        "system");
             }
         }
     }
 
-    private void validateEffectiveDependency( ModelProblemCollector problems, Dependency d, boolean management,
-                                              String prefix, ModelBuildingRequest request )
-    {
-        validateCoordinateId( prefix, "artifactId", problems, Severity.ERROR, Version.BASE, d.getArtifactId(),
-                    d.getManagementKey(), d );
+    private void validateEffectiveDependency(
+            ModelProblemCollector problems,
+            Dependency d,
+            boolean management,
+            String prefix,
+            ModelBuildingRequest request) {
+        validateCoordinateId(
+                prefix,
+                "artifactId",
+                problems,
+                Severity.ERROR,
+                Version.BASE,
+                d.getArtifactId(),
+                d.getManagementKey(),
+                d);
 
-        validateCoordinateId( prefix, "groupId", problems, Severity.ERROR, Version.BASE, d.getGroupId(),
-                    d.getManagementKey(), d );
+        validateCoordinateId(
+                prefix, "groupId", problems, Severity.ERROR, Version.BASE, d.getGroupId(), d.getManagementKey(), d);
 
-        if ( !management )
-        {
-            validateStringNotEmpty( prefix, "type", problems, Severity.ERROR, Version.BASE, d.getType(),
-                                    d.getManagementKey(), d );
+        if (!management) {
+            validateStringNotEmpty(
+                    prefix, "type", problems, Severity.ERROR, Version.BASE, d.getType(), d.getManagementKey(), d);
 
-            validateDependencyVersion( problems, d, prefix );
+            validateDependencyVersion(problems, d, prefix);
         }
 
-        if ( "system".equals( d.getScope() ) )
-        {
+        if ("system".equals(d.getScope())) {
             String systemPath = d.getSystemPath();
 
-            if ( StringUtils.isEmpty( systemPath ) )
-            {
-                addViolation( problems, Severity.ERROR, Version.BASE, prefix + "systemPath", d.getManagementKey(),
-                              "is missing.", d );
-            }
-            else
-            {
-                File sysFile = new File( systemPath );
-                if ( !sysFile.isAbsolute() )
-                {
-                    addViolation( problems, Severity.ERROR, Version.BASE, prefix + "systemPath", d.getManagementKey(),
-                                  "must specify an absolute path but is " + systemPath, d );
-                }
-                else if ( !sysFile.isFile() )
-                {
+            if (systemPath == null || systemPath.isEmpty()) {
+                addViolation(
+                        problems,
+                        Severity.ERROR,
+                        Version.BASE,
+                        prefix + "systemPath",
+                        d.getManagementKey(),
+                        "is missing.",
+                        d);
+            } else {
+                File sysFile = new File(systemPath);
+                if (!sysFile.isAbsolute()) {
+                    addViolation(
+                            problems,
+                            Severity.ERROR,
+                            Version.BASE,
+                            prefix + "systemPath",
+                            d.getManagementKey(),
+                            "must specify an absolute path but is " + systemPath,
+                            d);
+                } else if (!sysFile.isFile()) {
                     String msg = "refers to a non-existing file " + sysFile.getAbsolutePath();
-                    systemPath = systemPath.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
+                    systemPath = systemPath.replace('/', File.separatorChar).replace('\\', File.separatorChar);
                     String jdkHome =
-                        request.getSystemProperties().getProperty( "java.home", EMPTY ) + File.separator + "..";
-                    if ( systemPath.startsWith( jdkHome ) )
-                    {
+                            request.getSystemProperties().getProperty("java.home", EMPTY) + File.separator + "..";
+                    if (systemPath.startsWith(jdkHome)) {
                         msg += ". Please verify that you run Maven using a JDK and not just a JRE.";
                     }
-                    addViolation( problems, Severity.WARNING, Version.BASE, prefix + "systemPath", d.getManagementKey(),
-                                  msg, d );
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            Version.BASE,
+                            prefix + "systemPath",
+                            d.getManagementKey(),
+                            msg,
+                            d);
                 }
             }
-        }
-        else if ( StringUtils.isNotEmpty( d.getSystemPath() ) )
-        {
-            addViolation( problems, Severity.ERROR, Version.BASE, prefix + "systemPath", d.getManagementKey(),
-                          "must be omitted." + " This field may only be specified for a dependency with system scope.",
-                          d );
+        } else if (d.getSystemPath() != null && !d.getSystemPath().isEmpty()) {
+            addViolation(
+                    problems,
+                    Severity.ERROR,
+                    Version.BASE,
+                    prefix + "systemPath",
+                    d.getManagementKey(),
+                    "must be omitted. This field may only be specified for a dependency with system scope.",
+                    d);
         }
 
-        if ( request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 )
-        {
-            for ( Exclusion exclusion : d.getExclusions() )
-            {
-                if ( request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 )
-                {
-                    validateCoordinateId( prefix, "exclusions.exclusion.groupId", problems, Severity.WARNING,
-                                          Version.V20, exclusion.getGroupId(), d.getManagementKey(), exclusion );
+        if (request.getValidationLevel() >= ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0) {
+            for (Exclusion exclusion : d.getExclusions()) {
+                if (request.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0) {
+                    validateCoordinateId(
+                            prefix,
+                            "exclusions.exclusion.groupId",
+                            problems,
+                            Severity.WARNING,
+                            Version.V20,
+                            exclusion.getGroupId(),
+                            d.getManagementKey(),
+                            exclusion);
 
-                    validateCoordinateId( prefix, "exclusions.exclusion.artifactId", problems, Severity.WARNING,
-                                          Version.V20, exclusion.getArtifactId(), d.getManagementKey(), exclusion );
-                }
-                else
-                {
-                    validateCoordinateIdWithWildcards( prefix, "exclusions.exclusion.groupId", problems,
-                                                       Severity.WARNING, Version.V30, exclusion.getGroupId(),
-                                                       d.getManagementKey(), exclusion );
+                    validateCoordinateId(
+                            prefix,
+                            "exclusions.exclusion.artifactId",
+                            problems,
+                            Severity.WARNING,
+                            Version.V20,
+                            exclusion.getArtifactId(),
+                            d.getManagementKey(),
+                            exclusion);
+                } else {
+                    validateCoordinateIdWithWildcards(
+                            prefix,
+                            "exclusions.exclusion.groupId",
+                            problems,
+                            Severity.WARNING,
+                            Version.V30,
+                            exclusion.getGroupId(),
+                            d.getManagementKey(),
+                            exclusion);
 
-                    validateCoordinateIdWithWildcards( prefix, "exclusions.exclusion.artifactId", problems,
-                                                       Severity.WARNING, Version.V30, exclusion.getArtifactId(),
-                                                       d.getManagementKey(), exclusion );
+                    validateCoordinateIdWithWildcards(
+                            prefix,
+                            "exclusions.exclusion.artifactId",
+                            problems,
+                            Severity.WARNING,
+                            Version.V30,
+                            exclusion.getArtifactId(),
+                            d.getManagementKey(),
+                            exclusion);
                 }
             }
         }
@@ -756,33 +955,44 @@
     /**
      * @since 3.2.4
      */
-    protected void validateDependencyVersion( ModelProblemCollector problems, Dependency d, String prefix )
-    {
-        validateStringNotEmpty( prefix, "version", problems, Severity.ERROR, Version.BASE, d.getVersion(),
-                                d.getManagementKey(), d );
+    protected void validateDependencyVersion(ModelProblemCollector problems, Dependency d, String prefix) {
+        validateStringNotEmpty(
+                prefix, "version", problems, Severity.ERROR, Version.BASE, d.getVersion(), d.getManagementKey(), d);
     }
 
-    private void validateRawRepositories( ModelProblemCollector problems, List<Repository> repositories, String prefix,
-                                          String prefix2, ModelBuildingRequest request )
-    {
+    private void validateRawRepositories(
+            ModelProblemCollector problems,
+            List<Repository> repositories,
+            String prefix,
+            String prefix2,
+            ModelBuildingRequest request) {
         Map<String, Repository> index = new HashMap<>();
 
-        for ( Repository repository : repositories )
-        {
-            validateStringNotEmpty( prefix, prefix2, "id", problems, Severity.ERROR, Version.V20, repository.getId(),
-                                    null, repository );
+        for (Repository repository : repositories) {
+            validateStringNotEmpty(
+                    prefix, prefix2, "id", problems, Severity.ERROR, Version.V20, repository.getId(), null, repository);
 
-            if ( validateStringNotEmpty( prefix, prefix2, "[" + repository.getId() + "].url", problems, Severity.ERROR,
-                                         Version.V20, repository.getUrl(), null, repository ) )
-            {
+            if (validateStringNotEmpty(
+                    prefix,
+                    prefix2,
+                    "[" + repository.getId() + "].url",
+                    problems,
+                    Severity.ERROR,
+                    Version.V20,
+                    repository.getUrl(),
+                    null,
+                    repository)) {
                 // only allow ${basedir} and ${project.basedir}
-                Matcher m = EXPRESSION_NAME_PATTERN.matcher( repository.getUrl() );
-                while ( m.find() )
-                {
-                    if ( !( "basedir".equals( m.group( 1 ) ) || "project.basedir".equals( m.group( 1 ) ) ) )
-                    {
-                        validateStringNoExpression( prefix + prefix2 + "[" + repository.getId() + "].url", problems,
-                                                    Severity.ERROR, Version.V40, repository.getUrl(), repository );
+                Matcher m = EXPRESSION_NAME_PATTERN.matcher(repository.getUrl());
+                while (m.find()) {
+                    if (!("basedir".equals(m.group(1)) || "project.basedir".equals(m.group(1)))) {
+                        validateStringNoExpression(
+                                prefix + prefix2 + "[" + repository.getId() + "].url",
+                                problems,
+                                Severity.ERROR,
+                                Version.V40,
+                                repository.getUrl(),
+                                repository);
                         break;
                     }
                 }
@@ -790,60 +1000,91 @@
 
             String key = repository.getId();
 
-            Repository existing = index.get( key );
+            Repository existing = index.get(key);
 
-            if ( existing != null )
-            {
-                Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
+            if (existing != null) {
+                Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
 
-                addViolation( problems, errOn30, Version.V20, prefix + prefix2 + "id", null, "must be unique: "
-                    + repository.getId() + " -> " + existing.getUrl() + " vs " + repository.getUrl(), repository );
-            }
-            else
-            {
-                index.put( key, repository );
+                addViolation(
+                        problems,
+                        errOn30,
+                        Version.V20,
+                        prefix + prefix2 + "id",
+                        null,
+                        "must be unique: " + repository.getId() + " -> " + existing.getUrl() + " vs "
+                                + repository.getUrl(),
+                        repository);
+            } else {
+                index.put(key, repository);
             }
         }
     }
 
-    private void validate20EffectiveRepository( ModelProblemCollector problems, Repository repository, String prefix,
-                                                ModelBuildingRequest request )
-    {
-        if ( repository != null )
-        {
-            Severity errOn31 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1 );
+    private void validate20EffectiveRepository(
+            ModelProblemCollector problems, Repository repository, String prefix, ModelBuildingRequest request) {
+        if (repository != null) {
+            Severity errOn31 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1);
 
-            validateBannedCharacters( prefix, "id", problems, errOn31, Version.V20, repository.getId(), null,
-                                      repository, ILLEGAL_REPO_ID_CHARS );
+            validateBannedCharacters(
+                    prefix,
+                    "id",
+                    problems,
+                    errOn31,
+                    Version.V20,
+                    repository.getId(),
+                    null,
+                    repository,
+                    ILLEGAL_REPO_ID_CHARS);
 
-            if ( "local".equals( repository.getId() ) )
-            {
-                addViolation( problems, errOn31, Version.V20, prefix + "id", null,
-                              "must not be 'local'" + ", this identifier is reserved for the local repository"
-                                  + ", using it for other repositories will corrupt your repository metadata.",
-                              repository );
+            if ("local".equals(repository.getId())) {
+                addViolation(
+                        problems,
+                        errOn31,
+                        Version.V20,
+                        prefix + "id",
+                        null,
+                        "must not be 'local'" + ", this identifier is reserved for the local repository"
+                                + ", using it for other repositories will corrupt your repository metadata.",
+                        repository);
             }
 
-            if ( "legacy".equals( repository.getLayout() ) )
-            {
-                addViolation( problems, Severity.WARNING, Version.V20, prefix + "layout", repository.getId(),
-                              "uses the unsupported value 'legacy', artifact resolution might fail.", repository );
+            if ("legacy".equals(repository.getLayout())) {
+                addViolation(
+                        problems,
+                        Severity.WARNING,
+                        Version.V20,
+                        prefix + "layout",
+                        repository.getId(),
+                        "uses the unsupported value 'legacy', artifact resolution might fail.",
+                        repository);
             }
         }
     }
 
-    private void validate20RawResources( ModelProblemCollector problems, List<Resource> resources, String prefix,
-                                         ModelBuildingRequest request )
-    {
-        Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
+    private void validate20RawResources(
+            ModelProblemCollector problems, List<Resource> resources, String prefix, ModelBuildingRequest request) {
+        Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
 
-        for ( Resource resource : resources )
-        {
-            validateStringNotEmpty( prefix, "directory", problems, Severity.ERROR, Version.V20,
-                                    resource.getDirectory(), null, resource );
+        for (Resource resource : resources) {
+            validateStringNotEmpty(
+                    prefix,
+                    "directory",
+                    problems,
+                    Severity.ERROR,
+                    Version.V20,
+                    resource.getDirectory(),
+                    null,
+                    resource);
 
-            validateBoolean( prefix, "filtering", problems, errOn30, Version.V20, resource.getFiltering(),
-                             resource.getDirectory(), resource );
+            validateBoolean(
+                    prefix,
+                    "filtering",
+                    problems,
+                    errOn30,
+                    Version.V20,
+                    resource.getFiltering(),
+                    resource.getDirectory(),
+                    resource);
         }
     }
 
@@ -851,86 +1092,91 @@
     // Field validation
     // ----------------------------------------------------------------------
 
-    private boolean validateCoordinateId( String fieldName, ModelProblemCollector problems, String id,
-                                          InputLocationTracker tracker )
-    {
-        return validateCoordinateId( EMPTY, fieldName, problems, Severity.ERROR, Version.BASE, id, null, tracker );
+    private boolean validateCoordinateId(
+            String fieldName, ModelProblemCollector problems, String id, InputLocationTracker tracker) {
+        return validateCoordinateId(EMPTY, fieldName, problems, Severity.ERROR, Version.BASE, id, null, tracker);
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateCoordinateId( String prefix, String fieldName, ModelProblemCollector problems,
-                                          Severity severity, Version version, String id, String sourceHint,
-                                          InputLocationTracker tracker )
-    {
-        if ( validCoordinateIds.contains( id ) )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateCoordinateId(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String id,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (validCoordinateIds.contains(id)) {
             return true;
         }
-        if ( !validateStringNotEmpty( prefix, fieldName, problems, severity, version, id, sourceHint, tracker ) )
-        {
+        if (!validateStringNotEmpty(prefix, fieldName, problems, severity, version, id, sourceHint, tracker)) {
             return false;
-        }
-        else
-        {
-            if ( !isValidCoordinateId( id ) )
-            {
-                addViolation( problems, severity, version, prefix + fieldName, sourceHint,
-                              "with value '" + id + "' does not match a valid coordinate id pattern.", tracker );
+        } else {
+            if (!isValidCoordinateId(id)) {
+                addViolation(
+                        problems,
+                        severity,
+                        version,
+                        prefix + fieldName,
+                        sourceHint,
+                        "with value '" + id + "' does not match a valid coordinate id pattern.",
+                        tracker);
                 return false;
             }
-            validCoordinateIds.add( id );
+            validCoordinateIds.add(id);
             return true;
         }
     }
 
-    private boolean isValidCoordinateId( String id )
-    {
-        for ( int i = 0; i < id.length(); i++ )
-        {
-            char c = id.charAt( i );
-            if ( !isValidCoordinateIdCharacter( c ) )
-            {
+    private boolean isValidCoordinateId(String id) {
+        for (int i = 0; i < id.length(); i++) {
+            char c = id.charAt(i);
+            if (!isValidCoordinateIdCharacter(c)) {
                 return false;
             }
         }
         return true;
     }
 
-    private boolean isValidCoordinateIdCharacter( char c )
-    {
+    private boolean isValidCoordinateIdCharacter(char c) {
         return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c >= '0' && c <= '9' || c == '-' || c == '_' || c == '.';
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateProfileId( String prefix, String fieldName, ModelProblemCollector problems,
-                                       Severity severity, Version version, String id, String sourceHint,
-                                       InputLocationTracker tracker )
-    {
-        if ( validProfileIds.contains( id ) )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateProfileId(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String id,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (validProfileIds.contains(id)) {
             return true;
         }
-        if ( !validateStringNotEmpty( prefix, fieldName, problems, severity, version, id, sourceHint, tracker ) )
-        {
+        if (!validateStringNotEmpty(prefix, fieldName, problems, severity, version, id, sourceHint, tracker)) {
             return false;
-        }
-        else
-        {
-            if ( !isValidProfileId( id ) )
-            {
-                addViolation( problems, severity, version, prefix + fieldName, sourceHint,
-                              "with value '" + id + "' does not match a valid profile id pattern.", tracker );
+        } else {
+            if (!isValidProfileId(id)) {
+                addViolation(
+                        problems,
+                        severity,
+                        version,
+                        prefix + fieldName,
+                        sourceHint,
+                        "with value '" + id + "' does not match a valid profile id pattern.",
+                        tracker);
                 return false;
             }
-            validProfileIds.add( id );
+            validProfileIds.add(id);
             return true;
         }
     }
 
-    private boolean isValidProfileId( String id )
-    {
-        switch ( id.charAt( 0 ) )
-        { // avoid first character that has special CLI meaning in "mvn -P xxx"
+    private boolean isValidProfileId(String id) {
+        switch (id.charAt(0)) { // avoid first character that has special CLI meaning in "mvn -P xxx"
             case '+': // activate
             case '-': // deactivate
             case '!': // deactivate
@@ -941,75 +1187,94 @@
         return true;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateCoordinateIdWithWildcards( String prefix, String fieldName, ModelProblemCollector problems,
-                                                       Severity severity, Version version, String id, String sourceHint,
-                                                       InputLocationTracker tracker )
-    {
-        if ( !validateStringNotEmpty( prefix, fieldName, problems, severity, version, id, sourceHint, tracker ) )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateCoordinateIdWithWildcards(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String id,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (!validateStringNotEmpty(prefix, fieldName, problems, severity, version, id, sourceHint, tracker)) {
             return false;
-        }
-        else
-        {
-            if ( !isValidCoordinateIdWithWildCards( id ) )
-            {
-                addViolation( problems, severity, version, prefix + fieldName, sourceHint,
-                              "with value '" + id + "' does not match a valid coordinate id pattern.", tracker );
+        } else {
+            if (!isValidCoordinateIdWithWildCards(id)) {
+                addViolation(
+                        problems,
+                        severity,
+                        version,
+                        prefix + fieldName,
+                        sourceHint,
+                        "with value '" + id + "' does not match a valid coordinate id pattern.",
+                        tracker);
                 return false;
             }
             return true;
         }
     }
 
-    private boolean isValidCoordinateIdWithWildCards( String id )
-    {
-        for ( int i = 0; i < id.length(); i++ )
-        {
-            char c = id.charAt( i );
-            if ( !isValidCoordinateIdWithWildCardCharacter( c ) )
-            {
+    private boolean isValidCoordinateIdWithWildCards(String id) {
+        for (int i = 0; i < id.length(); i++) {
+            char c = id.charAt(i);
+            if (!isValidCoordinateIdWithWildCardCharacter(c)) {
                 return false;
             }
         }
         return true;
     }
 
-    private boolean isValidCoordinateIdWithWildCardCharacter( char c )
-    {
-        return isValidCoordinateIdCharacter( c ) || c == '?' || c == '*';
+    private boolean isValidCoordinateIdWithWildCardCharacter(char c) {
+        return isValidCoordinateIdCharacter(c) || c == '?' || c == '*';
     }
 
-    private boolean validateStringNoExpression( String fieldName, ModelProblemCollector problems, Severity severity,
-                                                Version version, String string, InputLocationTracker tracker )
-    {
-        if ( !hasExpression( string ) )
-        {
+    private boolean validateStringNoExpression(
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            InputLocationTracker tracker) {
+        if (!hasExpression(string)) {
             return true;
         }
 
-        addViolation( problems, severity, version, fieldName, null, "contains an expression but should be a constant.",
-                      tracker );
+        addViolation(
+                problems,
+                severity,
+                version,
+                fieldName,
+                null,
+                "contains an expression but should be a constant.",
+                tracker);
 
         return false;
     }
 
-    private boolean validateVersionNoExpression( String fieldName, ModelProblemCollector problems, Severity severity,
-                                                 Version version, String string, InputLocationTracker tracker )
-    {
-        if ( !hasExpression( string ) )
-        {
+    private boolean validateVersionNoExpression(
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            InputLocationTracker tracker) {
+        if (!hasExpression(string)) {
             return true;
         }
 
-        Matcher m = EXPRESSION_NAME_PATTERN.matcher( string.trim() );
-        while ( m.find() )
-        {
-            String property = m.group( 1 );
-            if ( !versionProcessor.isValidProperty( property ) )
-            {
-                addViolation( problems, severity, version, fieldName, null,
-                              "contains an expression but should be a constant.", tracker );
+        Matcher m = EXPRESSION_NAME_PATTERN.matcher(string.trim());
+        while (m.find()) {
+            String property = m.group(1);
+            if (!versionProcessor.isValidProperty(property)) {
+                addViolation(
+                        problems,
+                        severity,
+                        version,
+                        fieldName,
+                        null,
+                        "contains an expression but should be a constant.",
+                        tracker);
 
                 return false;
             }
@@ -1018,20 +1283,22 @@
         return true;
     }
 
-    private boolean hasExpression( String value )
-    {
-        return value != null && value.contains( "${" );
+    private boolean hasExpression(String value) {
+        return value != null && value.contains("${");
     }
 
-    private boolean hasProjectExpression( String value )
-    {
-        return value != null && value.contains( "${project." );
+    private boolean hasProjectExpression(String value) {
+        return value != null && value.contains("${project.");
     }
 
-    private boolean validateStringNotEmpty( String fieldName, ModelProblemCollector problems, Severity severity,
-                                            Version version, String string, InputLocationTracker tracker )
-    {
-        return validateStringNotEmpty( EMPTY, fieldName, problems, severity, version, string, null, tracker );
+    private boolean validateStringNotEmpty(
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            InputLocationTracker tracker) {
+        return validateStringNotEmpty(EMPTY, fieldName, problems, severity, version, string, null, tracker);
     }
 
     /**
@@ -1042,22 +1309,26 @@
      * <li><code>string.length > 0</code>
      * </ul>
      */
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateStringNotEmpty( String prefix, String prefix2, String fieldName,
-                                            ModelProblemCollector problems, Severity severity, Version version,
-                                            String string, String sourceHint, InputLocationTracker tracker )
-    {
-        if ( !validateNotNull( prefix, prefix2, fieldName, problems, severity, version, string, sourceHint, tracker ) )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateStringNotEmpty(
+            String prefix,
+            String prefix2,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (!validateNotNull(prefix, prefix2, fieldName, problems, severity, version, string, sourceHint, tracker)) {
             return false;
         }
 
-        if ( !string.isEmpty() )
-        {
+        if (!string.isEmpty()) {
             return true;
         }
 
-        addViolation( problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker );
+        addViolation(problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker);
 
         return false;
     }
@@ -1070,22 +1341,25 @@
      * <li><code>string.length > 0</code>
      * </ul>
      */
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateStringNotEmpty( String prefix, String fieldName, ModelProblemCollector problems,
-                                            Severity severity, Version version, String string, String sourceHint,
-                                            InputLocationTracker tracker )
-    {
-        if ( !validateNotNull( prefix, fieldName, problems, severity, version, string, sourceHint, tracker ) )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateStringNotEmpty(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (!validateNotNull(prefix, fieldName, problems, severity, version, string, sourceHint, tracker)) {
             return false;
         }
 
-        if ( string.length() > 0 )
-        {
+        if (string.length() > 0) {
             return true;
         }
 
-        addViolation( problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker );
+        addViolation(problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker);
 
         return false;
     }
@@ -1097,16 +1371,21 @@
      * <li><code>string != null</code>
      * </ul>
      */
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateNotNull( String prefix, String fieldName, ModelProblemCollector problems, Severity severity,
-                                     Version version, Object object, String sourceHint, InputLocationTracker tracker )
-    {
-        if ( object != null )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateNotNull(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            Object object,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (object != null) {
             return true;
         }
 
-        addViolation( problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker );
+        addViolation(problems, severity, version, prefix + fieldName, sourceHint, "is missing.", tracker);
 
         return false;
     }
@@ -1118,108 +1397,140 @@
      * <li><code>string != null</code>
      * </ul>
      */
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateNotNull( String prefix, String prefix2, String fieldName,
-                                     ModelProblemCollector problems, Severity severity, Version version,
-                                     Object object, String sourceHint, InputLocationTracker tracker )
-    {
-        if ( object != null )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateNotNull(
+            String prefix,
+            String prefix2,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            Object object,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (object != null) {
             return true;
         }
 
-        addViolation( problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker );
+        addViolation(problems, severity, version, prefix + prefix2 + fieldName, sourceHint, "is missing.", tracker);
 
         return false;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateBoolean( String prefix, String fieldName, ModelProblemCollector problems, Severity severity,
-                                     Version version, String string, String sourceHint, InputLocationTracker tracker )
-    {
-        if ( string == null || string.length() <= 0 )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateBoolean(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (string == null || string.length() <= 0) {
             return true;
         }
 
-        if ( "true".equalsIgnoreCase( string ) || "false".equalsIgnoreCase( string ) )
-        {
+        if ("true".equalsIgnoreCase(string) || "false".equalsIgnoreCase(string)) {
             return true;
         }
 
-        addViolation( problems, severity, version, prefix + fieldName, sourceHint,
-                      "must be 'true' or 'false' but is '" + string + "'.", tracker );
+        addViolation(
+                problems,
+                severity,
+                version,
+                prefix + fieldName,
+                sourceHint,
+                "must be 'true' or 'false' but is '" + string + "'.",
+                tracker);
 
         return false;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateEnum( String prefix, String fieldName, ModelProblemCollector problems, Severity severity,
-                                  Version version, String string, String sourceHint, InputLocationTracker tracker,
-                                  String... validValues )
-    {
-        if ( string == null || string.length() <= 0 )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateEnum(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker,
+            String... validValues) {
+        if (string == null || string.length() <= 0) {
             return true;
         }
 
-        List<String> values = Arrays.asList( validValues );
+        List<String> values = Arrays.asList(validValues);
 
-        if ( values.contains( string ) )
-        {
+        if (values.contains(string)) {
             return true;
         }
 
-        addViolation( problems, severity, version, prefix + fieldName, sourceHint,
-                      "must be one of " + values + " but is '" + string + "'.", tracker );
+        addViolation(
+                problems,
+                severity,
+                version,
+                prefix + fieldName,
+                sourceHint,
+                "must be one of " + values + " but is '" + string + "'.",
+                tracker);
 
         return false;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateModelVersion( ModelProblemCollector problems, String string, InputLocationTracker tracker,
-                                          String... validVersions )
-    {
-        if ( string == null || string.length() <= 0 )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateModelVersion(
+            ModelProblemCollector problems, String string, InputLocationTracker tracker, List<String> validVersions) {
+        if (string == null || string.length() <= 0) {
             return true;
         }
 
-        List<String> values = Arrays.asList( validVersions );
-
-        if ( values.contains( string ) )
-        {
+        if (validVersions.contains(string)) {
             return true;
         }
 
         boolean newerThanAll = true;
         boolean olderThanAll = true;
-        for ( String validValue : validVersions )
-        {
-            final int comparison = compareModelVersions( validValue, string );
+        for (String validValue : validVersions) {
+            final int comparison = compareModelVersions(validValue, string);
             newerThanAll = newerThanAll && comparison < 0;
             olderThanAll = olderThanAll && comparison > 0;
         }
 
-        if ( newerThanAll )
-        {
-            addViolation( problems, Severity.FATAL, Version.V20, "modelVersion", null,
-                          "of '" + string + "' is newer than the versions supported by this version of Maven: " + values
-                              + ". Building this project requires a newer version of Maven.", tracker );
+        if (newerThanAll) {
+            addViolation(
+                    problems,
+                    Severity.FATAL,
+                    Version.V20,
+                    "modelVersion",
+                    null,
+                    "of '" + string + "' is newer than the versions supported by this version of Maven: "
+                            + validVersions + ". Building this project requires a newer version of Maven.",
+                    tracker);
 
-        }
-        else if ( olderThanAll )
-        {
+        } else if (olderThanAll) {
             // note this will not be hit for Maven 1.x project.xml as it is an incompatible schema
-            addViolation( problems, Severity.FATAL, Version.V20, "modelVersion", null,
-                          "of '" + string + "' is older than the versions supported by this version of Maven: " + values
-                              + ". Building this project requires an older version of Maven.", tracker );
+            addViolation(
+                    problems,
+                    Severity.FATAL,
+                    Version.V20,
+                    "modelVersion",
+                    null,
+                    "of '" + string + "' is older than the versions supported by this version of Maven: "
+                            + validVersions + ". Building this project requires an older version of Maven.",
+                    tracker);
 
-        }
-        else
-        {
-            addViolation( problems, Severity.ERROR, Version.V20, "modelVersion", null,
-                          "must be one of " + values + " but is '" + string + "'.", tracker );
+        } else {
+            addViolation(
+                    problems,
+                    Severity.ERROR,
+                    Version.V20,
+                    "modelVersion",
+                    null,
+                    "must be one of " + validVersions + " but is '" + string + "'.",
+                    tracker);
         }
 
         return false;
@@ -1233,41 +1544,42 @@
      * @return negative if the first version is newer than the second version, zero if they are the same or positive if
      * the second version is the newer.
      */
-    private static int compareModelVersions( String first, String second )
-    {
+    private static int compareModelVersions(String first, String second) {
         // we use a dedicated comparator because we control our model version scheme.
-        String[] firstSegments = StringUtils.split( first, "." );
-        String[] secondSegments = StringUtils.split( second, "." );
-        for ( int i = 0; i < Math.min( firstSegments.length, secondSegments.length ); i++ )
-        {
-            int result = Long.valueOf( firstSegments[i] ).compareTo( Long.valueOf( secondSegments[i] ) );
-            if ( result != 0 )
-            {
+        String[] firstSegments = first.split("\\.");
+        String[] secondSegments = second.split("\\.");
+        for (int i = 0; i < Math.max(firstSegments.length, secondSegments.length); i++) {
+            int result = Long.valueOf(i < firstSegments.length ? firstSegments[i] : "0")
+                    .compareTo(Long.valueOf(i < secondSegments.length ? secondSegments[i] : "0"));
+            if (result != 0) {
                 return result;
             }
         }
-        if ( firstSegments.length == secondSegments.length )
-        {
-            return 0;
-        }
-        return firstSegments.length > secondSegments.length ? -1 : 1;
+        return 0;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateBannedCharacters( String prefix, String fieldName, ModelProblemCollector problems,
-                                              Severity severity, Version version, String string, String sourceHint,
-                                              InputLocationTracker tracker, String banned )
-    {
-        if ( string != null )
-        {
-            for ( int i = string.length() - 1; i >= 0; i-- )
-            {
-                if ( banned.indexOf( string.charAt( i ) ) >= 0 )
-                {
-                    addViolation( problems, severity, version, prefix + fieldName, sourceHint,
-                                  "must not contain any of these characters " + banned + " but found "
-                                      + string.charAt( i ),
-                                  tracker );
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateBannedCharacters(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker,
+            String banned) {
+        if (string != null) {
+            for (int i = string.length() - 1; i >= 0; i--) {
+                if (banned.indexOf(string.charAt(i)) >= 0) {
+                    addViolation(
+                            problems,
+                            severity,
+                            version,
+                            prefix + fieldName,
+                            sourceHint,
+                            "must not contain any of these characters " + banned + " but found " + string.charAt(i),
+                            tracker);
                     return false;
                 }
             }
@@ -1276,155 +1588,166 @@
         return true;
     }
 
-    @SuppressWarnings( "checkstyle:parameternumber" )
-    private boolean validateVersion( String prefix, String fieldName, ModelProblemCollector problems, Severity severity,
-                                     Version version, String string, String sourceHint, InputLocationTracker tracker )
-    {
-        if ( string == null || string.length() <= 0 )
-        {
+    @SuppressWarnings("checkstyle:parameternumber")
+    private boolean validateVersion(
+            String prefix,
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (string == null || string.length() <= 0) {
             return true;
         }
 
-        if ( hasExpression( string ) )
-        {
-            addViolation( problems, severity, version, prefix + fieldName, sourceHint,
-                          "must be a valid version but is '" + string + "'.", tracker );
+        if (hasExpression(string)) {
+            addViolation(
+                    problems,
+                    severity,
+                    version,
+                    prefix + fieldName,
+                    sourceHint,
+                    "must be a valid version but is '" + string + "'.",
+                    tracker);
             return false;
         }
 
-        return validateBannedCharacters( prefix, fieldName, problems, severity, version, string, sourceHint, tracker,
-                                         ILLEGAL_VERSION_CHARS );
-
+        return validateBannedCharacters(
+                prefix, fieldName, problems, severity, version, string, sourceHint, tracker, ILLEGAL_VERSION_CHARS);
     }
 
-    private boolean validate20ProperSnapshotVersion( String fieldName, ModelProblemCollector problems,
-                                                     Severity severity, Version version, String string,
-                                                     String sourceHint, InputLocationTracker tracker )
-    {
-        if ( string == null || string.length() <= 0 )
-        {
+    private boolean validate20ProperSnapshotVersion(
+            String fieldName,
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker) {
+        if (string == null || string.length() <= 0) {
             return true;
         }
 
-        if ( string.endsWith( "SNAPSHOT" ) && !string.endsWith( "-SNAPSHOT" ) )
-        {
-            addViolation( problems, severity, version, fieldName, sourceHint,
-                          "uses an unsupported snapshot version format, should be '*-SNAPSHOT' instead.", tracker );
+        if (string.endsWith("SNAPSHOT") && !string.endsWith("-SNAPSHOT")) {
+            addViolation(
+                    problems,
+                    severity,
+                    version,
+                    fieldName,
+                    sourceHint,
+                    "uses an unsupported snapshot version format, should be '*-SNAPSHOT' instead.",
+                    tracker);
             return false;
         }
 
         return true;
     }
 
-    private boolean validate20PluginVersion( String fieldName, ModelProblemCollector problems, String string,
-                                             String sourceHint, InputLocationTracker tracker,
-                                             ModelBuildingRequest request )
-    {
-        if ( string == null )
-        {
+    private boolean validate20PluginVersion(
+            String fieldName,
+            ModelProblemCollector problems,
+            String string,
+            String sourceHint,
+            InputLocationTracker tracker,
+            ModelBuildingRequest request) {
+        if (string == null) {
             // NOTE: The check for missing plugin versions is handled directly by the model builder
             return true;
         }
 
-        Severity errOn30 = getSeverity( request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0 );
+        Severity errOn30 = getSeverity(request, ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_0);
 
-        if ( !validateVersion( EMPTY, fieldName, problems, errOn30, Version.V20, string, sourceHint, tracker ) )
-        {
+        if (!validateVersion(EMPTY, fieldName, problems, errOn30, Version.V20, string, sourceHint, tracker)) {
             return false;
         }
 
-        if ( string.length() <= 0 || "RELEASE".equals( string ) || "LATEST".equals( string ) )
-        {
-            addViolation( problems, errOn30, Version.V20, fieldName, sourceHint,
-                          "must be a valid version but is '" + string + "'.", tracker );
+        if (string.length() <= 0 || "RELEASE".equals(string) || "LATEST".equals(string)) {
+            addViolation(
+                    problems,
+                    errOn30,
+                    Version.V20,
+                    fieldName,
+                    sourceHint,
+                    "must be a valid version but is '" + string + "'.",
+                    tracker);
             return false;
         }
 
         return true;
     }
 
-    private static void addViolation( ModelProblemCollector problems, Severity severity, Version version,
-                                      String fieldName, String sourceHint, String message,
-                                      InputLocationTracker tracker )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-        buffer.append( '\'' ).append( fieldName ).append( '\'' );
+    private static void addViolation(
+            ModelProblemCollector problems,
+            Severity severity,
+            Version version,
+            String fieldName,
+            String sourceHint,
+            String message,
+            InputLocationTracker tracker) {
+        StringBuilder buffer = new StringBuilder(256);
+        buffer.append('\'').append(fieldName).append('\'');
 
-        if ( sourceHint != null )
-        {
-            buffer.append( " for " ).append( sourceHint );
+        if (sourceHint != null) {
+            buffer.append(" for ").append(sourceHint);
         }
 
-        buffer.append( ' ' ).append( message );
+        buffer.append(' ').append(message);
 
-        // CHECKSTYLE_OFF: LineLength
-        problems.add( new ModelProblemCollectorRequest( severity, version ).setMessage(
-                                                                                        buffer.toString() ).setLocation( getLocation( fieldName, tracker ) ) );
-        // CHECKSTYLE_ON: LineLength
+        problems.add(new ModelProblemCollectorRequest(severity, version)
+                .setMessage(buffer.toString())
+                .setLocation(getLocation(fieldName, tracker)));
     }
 
-    private static InputLocation getLocation( String fieldName, InputLocationTracker tracker )
-    {
+    private static org.apache.maven.model.InputLocation getLocation(String fieldName, InputLocationTracker tracker) {
         InputLocation location = null;
 
-        if ( tracker != null )
-        {
-            if ( fieldName != null )
-            {
+        if (tracker != null) {
+            if (fieldName != null) {
                 Object key = fieldName;
 
-                int idx = fieldName.lastIndexOf( '.' );
-                if ( idx >= 0 )
-                {
-                    fieldName = fieldName.substring( idx + 1 );
+                int idx = fieldName.lastIndexOf('.');
+                if (idx >= 0) {
+                    fieldName = fieldName.substring(idx + 1);
                     key = fieldName;
                 }
 
-                if ( fieldName.endsWith( "]" ) )
-                {
-                    key = fieldName.substring( fieldName.lastIndexOf( '[' ) + 1, fieldName.length() - 1 );
-                    try
-                    {
-                        key = Integer.valueOf( key.toString() );
-                    }
-                    catch ( NumberFormatException e )
-                    {
+                if (fieldName.endsWith("]")) {
+                    key = fieldName.substring(fieldName.lastIndexOf('[') + 1, fieldName.length() - 1);
+                    try {
+                        key = Integer.valueOf(key.toString());
+                    } catch (NumberFormatException e) {
                         // use key as is
                     }
                 }
 
-                location = tracker.getLocation( key );
+                location = tracker.getLocation(key);
             }
 
-            if ( location == null )
-            {
-                location = tracker.getLocation( EMPTY );
+            if (location == null) {
+                location = tracker.getLocation(EMPTY);
             }
         }
 
-        return location;
+        return location != null ? new org.apache.maven.model.InputLocation(location) : null;
     }
 
-    private static boolean equals( String s1, String s2 )
-    {
-        return StringUtils.clean( s1 ).equals( StringUtils.clean( s2 ) );
+    private static boolean equals(String s1, String s2) {
+        String c1 = s1 == null ? "" : s1.trim();
+        String c2 = s2 == null ? "" : s2.trim();
+        return c1.equals(c2);
     }
 
-    private static Severity getSeverity( ModelBuildingRequest request, int errorThreshold )
-    {
-        return getSeverity( request.getValidationLevel(), errorThreshold );
+    private static Severity getSeverity(ModelBuildingRequest request, int errorThreshold) {
+        return getSeverity(request.getValidationLevel(), errorThreshold);
     }
 
-    private static Severity getSeverity( int validationLevel, int errorThreshold )
-    {
-        if ( validationLevel < errorThreshold )
-        {
+    private static Severity getSeverity(int validationLevel, int errorThreshold) {
+        if (validationLevel < errorThreshold) {
             return Severity.WARNING;
-        }
-        else
-        {
+        } else {
             return Severity.ERROR;
         }
     }
-
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/model/validation/ModelValidator.java b/maven-model-builder/src/main/java/org/apache/maven/model/validation/ModelValidator.java
index 198ba5a..2817d95 100644
--- a/maven-model-builder/src/main/java/org/apache/maven/model/validation/ModelValidator.java
+++ b/maven-model-builder/src/main/java/org/apache/maven/model/validation/ModelValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.validation;
 
 import org.apache.maven.model.Model;
 import org.apache.maven.model.building.ModelBuildingRequest;
@@ -26,10 +25,8 @@
 /**
  * Checks the model for missing or invalid values.
  *
- * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
  */
-public interface ModelValidator
-{
+public interface ModelValidator {
     /**
      * Checks the specified file model for missing or invalid values. This model is directly created from the POM
      * file and has not been subjected to inheritance, interpolation or profile/default injection.
@@ -38,8 +35,7 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    default void validateFileModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems )
-    {
+    default void validateFileModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems) {
         // do nothing
     }
 
@@ -51,7 +47,7 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void validateRawModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
+    void validateRawModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 
     /**
      * Checks the specified (effective) model for missing or invalid values. The effective model is fully assembled and
@@ -61,6 +57,5 @@
      * @param request The model building request that holds further settings, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void validateEffectiveModel( Model model, ModelBuildingRequest request, ModelProblemCollector problems );
-
+    void validateEffectiveModel(Model model, ModelBuildingRequest request, ModelProblemCollector problems);
 }
diff --git a/maven-model-builder/src/main/java/org/apache/maven/utils/Os.java b/maven-model-builder/src/main/java/org/apache/maven/utils/Os.java
new file mode 100644
index 0000000..7f64737
--- /dev/null
+++ b/maven-model-builder/src/main/java/org/apache/maven/utils/Os.java
@@ -0,0 +1,215 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.utils;
+
+import java.util.Locale;
+import java.util.stream.Stream;
+
+/**
+ * OS support
+ */
+public class Os {
+
+    /**
+     * The OS Name.
+     */
+    public static final String OS_NAME = System.getProperty("os.name").toLowerCase(Locale.ENGLISH);
+
+    /**
+     * The OA architecture.
+     */
+    public static final String OS_ARCH = System.getProperty("os.arch").toLowerCase(Locale.ENGLISH);
+
+    /**
+     * The OS version.
+     */
+    public static final String OS_VERSION = System.getProperty("os.version").toLowerCase(Locale.ENGLISH);
+
+    /**
+     * OS Family
+     */
+    public static final String OS_FAMILY;
+
+    /**
+     * Boolean indicating if the running OS is a Windows system.
+     */
+    public static final boolean IS_WINDOWS;
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_WINDOWS = "windows";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_WIN9X = "win9x";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    public static final String FAMILY_NT = "winnt";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_OS2 = "os/2";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_NETWARE = "netware";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_DOS = "dos";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_MAC = "mac";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_TANDEM = "tandem";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_UNIX = "unix";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_OPENVMS = "openvms";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_ZOS = "z/os";
+
+    /**
+     * OS family that can be tested for. {@value}
+     */
+    private static final String FAMILY_OS400 = "os/400";
+
+    /**
+     * OpenJDK is reported to call MacOS X "Darwin"
+     *
+     * @see <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=44889">bugzilla issue</a>
+     * @see <a href="https://issues.apache.org/jira/browse/HADOOP-3318">HADOOP-3318</a>
+     */
+    private static final String DARWIN = "darwin";
+
+    /**
+     * The path separator.
+     */
+    private static final String PATH_SEP = System.getProperty("path.separator");
+
+    static {
+        // Those two public constants are initialized here, as they need all the private constants
+        // above to be initialized first, but the code style imposes the public constants to be
+        // defined above the private ones...
+        OS_FAMILY = getOsFamily();
+        IS_WINDOWS = isFamily(FAMILY_WINDOWS);
+    }
+
+    private Os() {}
+
+    /**
+     * Determines if the OS on which Maven is executing matches the
+     * given OS family.
+     *
+     * @param family the family to check for
+     * @return true if the OS matches
+     *
+     */
+    public static boolean isFamily(String family) {
+        // windows probing logic relies on the word 'windows' in the OS
+        boolean isWindows = OS_NAME.contains(FAMILY_WINDOWS);
+        boolean is9x = false;
+        boolean isNT = false;
+        if (isWindows) {
+            // there are only four 9x platforms that we look for
+            is9x = (OS_NAME.contains("95")
+                    || OS_NAME.contains("98")
+                    || OS_NAME.contains("me")
+                    // wince isn't really 9x, but crippled enough to
+                    // be a muchness. Maven doesnt run on CE, anyway.
+                    || OS_NAME.contains("ce"));
+            isNT = !is9x;
+        }
+        switch (family) {
+            case FAMILY_WINDOWS:
+                return isWindows;
+            case FAMILY_WIN9X:
+                return isWindows && is9x;
+            case FAMILY_NT:
+                return isWindows && isNT;
+            case FAMILY_OS2:
+                return OS_NAME.contains(FAMILY_OS2);
+            case FAMILY_NETWARE:
+                return OS_NAME.contains(FAMILY_NETWARE);
+            case FAMILY_DOS:
+                return PATH_SEP.equals(";") && !isFamily(FAMILY_NETWARE);
+            case FAMILY_MAC:
+                return OS_NAME.contains(FAMILY_MAC) || OS_NAME.contains(DARWIN);
+            case FAMILY_TANDEM:
+                return OS_NAME.contains("nonstop_kernel");
+            case FAMILY_UNIX:
+                return PATH_SEP.equals(":")
+                        && !isFamily(FAMILY_OPENVMS)
+                        && (!isFamily(FAMILY_MAC) || OS_NAME.endsWith("x") || OS_NAME.contains(DARWIN));
+            case FAMILY_ZOS:
+                return OS_NAME.contains(FAMILY_ZOS) || OS_NAME.contains("os/390");
+            case FAMILY_OS400:
+                return OS_NAME.contains(FAMILY_OS400);
+            case FAMILY_OPENVMS:
+                return OS_NAME.contains(FAMILY_OPENVMS);
+            default:
+                return OS_NAME.contains(family.toLowerCase(Locale.US));
+        }
+    }
+
+    /**
+     * Helper method to determine the current OS family.
+     *
+     * @return name of current OS family.
+     */
+    private static String getOsFamily() {
+        return Stream.of(
+                        FAMILY_DOS,
+                        FAMILY_MAC,
+                        FAMILY_NETWARE,
+                        FAMILY_NT,
+                        FAMILY_OPENVMS,
+                        FAMILY_OS2,
+                        FAMILY_OS400,
+                        FAMILY_TANDEM,
+                        FAMILY_UNIX,
+                        FAMILY_WIN9X,
+                        FAMILY_WINDOWS,
+                        FAMILY_ZOS)
+                .filter(Os::isFamily)
+                .findFirst()
+                .orElse(null);
+    }
+}
diff --git a/maven-model-builder/src/main/resources/META-INF/services/org.apache.maven.model.root.RootLocator b/maven-model-builder/src/main/resources/META-INF/services/org.apache.maven.model.root.RootLocator
new file mode 100644
index 0000000..4b81cf5
--- /dev/null
+++ b/maven-model-builder/src/main/resources/META-INF/services/org.apache.maven.model.root.RootLocator
@@ -0,0 +1 @@
+org.apache.maven.model.root.DefaultRootLocator
diff --git a/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml b/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml
index 1c5db28..85f8334 100644
--- a/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml
+++ b/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.0.0.xml
@@ -23,32 +23,10 @@
 <project>
   <modelVersion>4.0.0</modelVersion>
 
-  <repositories>
-    <repository>
-      <id>central</id>
-      <name>Maven Central Repository</name>
-      <url>https://repo.maven.apache.org/maven2</url>
-      <layout>default</layout>
-      <snapshots>
-        <enabled>false</enabled>
-      </snapshots>
-    </repository>
-  </repositories>
-
-  <pluginRepositories>
-    <pluginRepository>
-      <id>central</id>
-      <name>Maven Central Repository</name>
-      <url>https://repo.maven.apache.org/maven2</url>
-      <layout>default</layout>
-      <snapshots>
-        <enabled>false</enabled>
-      </snapshots>
-      <releases>
-        <updatePolicy>never</updatePolicy>
-      </releases>
-    </pluginRepository>
-  </pluginRepositories>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+  </properties>
 
   <build>
     <directory>${project.basedir}/target</directory>
diff --git a/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.1.0.xml b/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.1.0.xml
new file mode 100644
index 0000000..85f8334
--- /dev/null
+++ b/maven-model-builder/src/main/resources/org/apache/maven/model/pom-4.1.0.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<!-- START SNIPPET: superpom -->
+<project>
+  <modelVersion>4.0.0</modelVersion>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+  </properties>
+
+  <build>
+    <directory>${project.basedir}/target</directory>
+    <outputDirectory>${project.build.directory}/classes</outputDirectory>
+    <finalName>${project.artifactId}-${project.version}</finalName>
+    <testOutputDirectory>${project.build.directory}/test-classes</testOutputDirectory>
+    <sourceDirectory>${project.basedir}/src/main/java</sourceDirectory>
+    <scriptSourceDirectory>${project.basedir}/src/main/scripts</scriptSourceDirectory>
+    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>
+    <resources>
+      <resource>
+        <directory>${project.basedir}/src/main/resources</directory>
+      </resource>
+      <resource>
+        <directory>${project.basedir}/src/main/resources-filtered</directory>
+        <filtering>true</filtering>
+      </resource>
+    </resources>
+    <testResources>
+      <testResource>
+        <directory>${project.basedir}/src/test/resources</directory>
+      </testResource>
+      <testResource>
+        <directory>${project.basedir}/src/test/resources-filtered</directory>
+        <filtering>true</filtering>
+      </testResource>
+    </testResources>
+  </build>
+
+  <reporting>
+    <outputDirectory>${project.build.directory}/site</outputDirectory>
+  </reporting>
+
+</project>
+<!-- END SNIPPET: superpom -->
diff --git a/maven-model-builder/src/site/apt/index.apt b/maven-model-builder/src/site/apt/index.apt
index 5eb2374..38faeff 100644
--- a/maven-model-builder/src/site/apt/index.apt
+++ b/maven-model-builder/src/site/apt/index.apt
@@ -41,7 +41,7 @@
 
    ** profile activation: see {{{./apidocs/org/apache/maven/model/profile/activation/package-summary.html}available activators}}.
    Notice that model interpolation hasn't happened yet, then interpolation for file-based activation is limited to
-   <<<$\{basedir}>>> (since Maven 3), System properties and request properties
+   <<<$\{basedir}>>> (since Maven 3), <<<$\{rootDirectory}>>> (since Maven 4), system properties and user properties
 
    ** file model validation: <<<ModelValidator>>> ({{{./apidocs/org/apache/maven/model/validation/ModelValidator.html}javadoc}}),
    with its <<<DefaultModelValidator>>> implementation
@@ -51,7 +51,7 @@
 
  * phase 2, with optional plugin processing
 
-   ** Build up a raw model by re-reading the file and enrich it based on information available in the reactor. Some features:
+   ** Build up a raw model by re-reading the file and enriching it based on information available in the reactor. Some features:
 
       *** Resolve version of versionless parents based on relativePath (including ci-friendly versions)
 
@@ -156,13 +156,13 @@
 
 * Model Interpolation
 
-  Model Interpolation consists in replacing <<<$\{...\}>>> with calculated value. It is done in <<<StringSearchModelInterpolator>>>
-  ({{{./apidocs/org/apache/maven/model/interpolation/StringSearchModelInterpolator.html}javadoc}},
-  {{{./xref/org/apache/maven/model/interpolation/StringSearchModelInterpolator.html}source}}).
+  Model Interpolation consists in replacing <<<$\{...\}>>> with calculated value. It is done in <<<StringVisitorModelInterpolator>>>
+  ({{{./apidocs/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.html}javadoc}},
+  {{{./xref/org/apache/maven/model/interpolation/StringVisitorModelInterpolator.html}source}}).
 
-  Notice that model interpolation happens <after> profile activation, then profile activation doesn't benefit from every values:
+  Notice that model interpolation happens <after> profile activation, and that profile activation doesn't benefit from every values:
   interpolation for file-based activation is limited to <<<$\{basedir}>>> (which was introduced in Maven 3 and is not deprecated
-  in this context), System properties and request properties.
+  in this context) and <<<$\{rootDirectory}>>> (introduced in Maven 4), system properties and user properties.
 
   Values are evaluated in sequence from different syntaxes:
 
@@ -183,6 +183,8 @@
 | <<<project.baseUri>>>\
 <<<pom.baseUri>>> (<deprecated>) | the directory containing the <<<pom.xml>>> file as URI | <<<$\{project.baseUri\}>>> |
 *----+------+------+
+| <<<project.rootDirectory>>> | the project's root directory (containing a <<<.mvn>>> directory or with the <<<root="true">>> xml attribute) | <<<$\{project.rootDirectory\}>>> |
+*----+------+------+
 | <<<build.timestamp>>>\
 <<<maven.build.timestamp>>> | the UTC timestamp of build start, in <<<yyyy-MM-dd'T'HH:mm:ss'Z'>>> default format, which can be overridden with <<<maven.build.timestamp.format>>> POM property | <<<$\{maven.build.timestamp\}>>> |
 *----+------+------+
@@ -198,9 +200,11 @@
 *----+------+------+
 | <<<maven.repo.local>>> | The repository on the local machine Maven shall use to store installed and downloaded artifacts (POMs, JARs, etc). | <<<$\{user.home\}/.m2/repository>>> |
 *----+------+------+
-| <<<*>>> | Java system properties (see {{{http://download.oracle.com/javase/6/docs/api/java/lang/System.html#getProperties()}JDK reference}}) | <<<$\{user.home\}>>>\
+| <<<*>>> | Java system properties (see {{{https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getProperties()}JDK reference}}) | <<<$\{user.home\}>>>\
  | | <<<$\{java.home\}>>> |
 *----+------+------+
+| <<<*>>> | User properties | <<<$\{foo\}>>> |
+*----+------+------+
 | <<<env.*>>>\
 <<<*>>> | environment variables | <<<$\{env.PATH\}>>> |
 *----+------+------+
@@ -223,11 +227,13 @@
 
     * <<<$\{project.build.sourceEncoding\}>>> for
     {{{https://cwiki.apache.org/confluence/display/MAVEN/POM+Element+for+Source+File+Encoding}source files encoding}}
-    (defaults to platform encoding)
+    (defaults to <<<UTF-8>>> since Maven 4.0.0, no default value was provided in Maven 3.x, meaning that the platform
+    encoding was used by plugins)
 
     * <<<$\{project.reporting.outputEncoding\}>>> for
     {{{https://cwiki.apache.org/confluence/display/MAVENOLD/Reporting+Encoding+Configuration}reporting output files encoding}}
-    (defaults to <<<UTF-8>>>)
+    (defaults to <<<UTF-8>>> since Maven 4.0.0, no default value was provided in Maven 3.x, plugins usually defaulting
+    to <<<UTF-8>>>)
 
     []
 
diff --git a/maven-model-builder/src/site/site.xml b/maven-model-builder/src/site/site.xml
index 7aaee5a..61e47a6 100644
--- a/maven-model-builder/src/site/site.xml
+++ b/maven-model-builder/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/BuildModelSourceTransformerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/BuildModelSourceTransformerTest.java
new file mode 100644
index 0000000..7784cb4
--- /dev/null
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/BuildModelSourceTransformerTest.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.building;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+import org.apache.maven.model.Model;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class BuildModelSourceTransformerTest {
+
+    Path pomFile;
+    TransformerContext context = org.mockito.Mockito.mock(TransformerContext.class);
+
+    @Test
+    void testModelVersion() {
+        Model initial = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .namespaceUri("http://maven.apache.org/POM/4.0.0")
+                .build());
+        Model expected = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .namespaceUri("http://maven.apache.org/POM/4.0.0")
+                .modelVersion("4.0.0")
+                .build());
+        Model actual = transform(initial);
+        assertTrue(equalsDeep(expected, actual));
+    }
+
+    @Test
+    void testParent() {
+        Path root = Paths.get(".").toAbsolutePath().normalize();
+        pomFile = root.resolve("child/pom.xml");
+        Model parent = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .groupId("GROUPID")
+                .artifactId("ARTIFACTID")
+                .version("1.0-SNAPSHOT")
+                .build());
+        Mockito.when(context.getRawModel(pomFile, root.resolve("pom.xml"))).thenReturn(parent);
+        Mockito.when(context.locate(root)).thenReturn(root.resolve("pom.xml"));
+        Model initial = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .parent(org.apache.maven.api.model.Parent.newBuilder()
+                        .groupId("GROUPID")
+                        .artifactId("ARTIFACTID")
+                        .build())
+                .build());
+        Model expected = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .parent(org.apache.maven.api.model.Parent.newBuilder()
+                        .groupId("GROUPID")
+                        .artifactId("ARTIFACTID")
+                        .version("1.0-SNAPSHOT")
+                        .build())
+                .build());
+        Model actual = transform(initial);
+        assertTrue(equalsDeep(expected, actual));
+    }
+
+    @Test
+    void testReactorDependencies() {
+        Model dep = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .groupId("GROUPID")
+                .artifactId("ARTIFACTID")
+                .version("1.0-SNAPSHOT")
+                .build());
+        Mockito.when(context.getRawModel(pomFile, "GROUPID", "ARTIFACTID")).thenReturn(dep);
+        Model initial = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .dependencies(Collections.singleton(org.apache.maven.api.model.Dependency.newBuilder()
+                        .groupId("GROUPID")
+                        .artifactId("ARTIFACTID")
+                        .build()))
+                .build());
+        Model expected = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .dependencies(Collections.singleton(org.apache.maven.api.model.Dependency.newBuilder()
+                        .groupId("GROUPID")
+                        .artifactId("ARTIFACTID")
+                        .version("1.0-SNAPSHOT")
+                        .build()))
+                .build());
+        Model actual = transform(initial);
+        assertTrue(equalsDeep(expected, actual));
+    }
+
+    @Test
+    void testCiFriendlyVersion() {
+        Model initial = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .version("${revision}-${sha1}")
+                .build());
+        Mockito.when(context.getUserProperty("revision")).thenReturn("therev");
+        Mockito.when(context.getUserProperty("sha1")).thenReturn("thesha");
+        Model expected = new Model(org.apache.maven.api.model.Model.newBuilder()
+                .version("therev-thesha")
+                .build());
+        Model actual = transform(initial);
+        assertTrue(equalsDeep(expected, actual));
+    }
+
+    Model transform(Model model) {
+        Model transformed = model.clone();
+        new BuildModelSourceTransformer().transform(pomFile, context, transformed);
+        return transformed;
+    }
+
+    public static boolean equalsDeep(Object m1, Object m2) {
+        try {
+            if (m1 == m2) {
+                return true;
+            }
+            if (m1 == null || m2 == null) {
+                return false;
+            }
+            if (!Objects.equals(m1.getClass(), m2.getClass())) {
+                return false;
+            }
+            BeanInfo bean = Introspector.getBeanInfo(m1.getClass());
+            for (PropertyDescriptor prop : bean.getPropertyDescriptors()) {
+                if (("first".equals(prop.getName()) || "last".equals(prop.getName()))
+                        && List.class.equals(prop.getReadMethod().getDeclaringClass())) {
+                    continue;
+                }
+                Object p1 = prop.getReadMethod().invoke(m1);
+                Object p2 = prop.getReadMethod().invoke(m2);
+                if (!equalsDeep(p1, p2)) {
+                    return false;
+                }
+            }
+            return true;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/ComplexActivationTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/ComplexActivationTest.java
index 1401652..de0963e 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/ComplexActivationTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/ComplexActivationTest.java
@@ -1,6 +1,4 @@
-package org.apache.maven.model.building;
-
-  /*
+/*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
 import java.util.Properties;
@@ -29,36 +28,30 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 
 /**
- * @author Konstantin Perikov
  */
-public class ComplexActivationTest
-{
+class ComplexActivationTest {
 
-    private File getPom( String name )
-    {
-        return new File( "src/test/resources/poms/factory/" + name + ".xml" ).getAbsoluteFile();
+    private File getPom(String name) {
+        return new File("src/test/resources/poms/factory/" + name + ".xml").getAbsoluteFile();
     }
 
     @Test
-    public void testAndConditionInActivation()
-            throws Exception
-    {
+    void testAndConditionInActivation() throws Exception {
         Properties sysProperties = new Properties();
-        sysProperties.setProperty( "myproperty", "test" );
+        sysProperties.setProperty("myproperty", "test");
 
         ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
-        assertNotNull( builder );
+        assertNotNull(builder);
 
         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
-        request.setProcessPlugins( true );
-        request.setPomFile( getPom( "complex" ) );
-        request.setSystemProperties( sysProperties );
+        request.setProcessPlugins(true);
+        request.setPomFile(getPom("complex"));
+        request.setSystemProperties(sysProperties);
 
-        ModelBuildingResult result = builder.build( request );
-        assertNotNull( result );
-        assertNotNull( result.getEffectiveModel() );
-        assertEquals( "activated-1", result.getEffectiveModel().getProperties().get( "profile.file" ) );
-        assertNull( result.getEffectiveModel().getProperties().get( "profile.miss" ) );
+        ModelBuildingResult result = builder.build(request);
+        assertNotNull(result);
+        assertNotNull(result.getEffectiveModel());
+        assertEquals("activated-1", result.getEffectiveModel().getProperties().get("profile.file"));
+        assertNull(result.getEffectiveModel().getProperties().get("profile.miss"));
     }
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java
index 98e2773..08ef207 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderFactoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,77 +16,86 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
-import java.io.FileInputStream;
+import java.io.InputStream;
+import java.nio.file.Files;
 import java.nio.file.Paths;
 
-import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.model.v4.MavenStaxReader;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.junit.jupiter.api.Test;
 
-import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author Benjamin Bentmann
  */
-public class DefaultModelBuilderFactoryTest
-{
+class DefaultModelBuilderFactoryTest {
 
-    private static final String BASE_DIR = Paths.get( "src", "test", "resources", "poms", "factory" ).toString();
+    private static final String BASE_DIR =
+            Paths.get("src", "test", "resources", "poms", "factory").toString();
 
-    private File getPom( String name )
-    {
-        return new File( Paths.get( BASE_DIR, name + ".xml"  ).toString() ).getAbsoluteFile();
+    private File getPom(String name) {
+        return new File(Paths.get(BASE_DIR, name + ".xml").toString()).getAbsoluteFile();
     }
 
     @Test
-    public void testCompleteWiring()
-        throws Exception
-    {
+    void testCompleteWiring() throws Exception {
         ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
-        assertNotNull( builder );
+        assertNotNull(builder);
 
         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
-        request.setProcessPlugins( true );
-        request.setPomFile( getPom( "simple" ) );
+        request.setProcessPlugins(true);
+        request.setPomFile(getPom("simple"));
 
-        ModelBuildingResult result = builder.build( request );
-        assertNotNull( result );
-        assertNotNull( result.getEffectiveModel() );
-        assertEquals( "activated", result.getEffectiveModel().getProperties().get( "profile.file" ) );
-        Xpp3Dom conf = (Xpp3Dom) result.getEffectiveModel().getBuild().getPlugins().get( 0 ).getConfiguration();
-        assertEquals( "1.5", conf.getChild( "source" ).getValue() );
-        assertEquals( "  1.5  ", conf.getChild( "target" ).getValue() );
+        ModelBuildingResult result = builder.build(request);
+        assertNotNull(result);
+        assertNotNull(result.getEffectiveModel());
+        assertEquals("activated", result.getEffectiveModel().getProperties().get("profile.file"));
+        Xpp3Dom conf = (Xpp3Dom)
+                result.getEffectiveModel().getBuild().getPlugins().get(0).getConfiguration();
+        assertNotNull(conf);
+        assertEquals("1.5", conf.getChild("source").getValue());
+        assertEquals("  1.5  ", conf.getChild("target").getValue());
     }
 
     @Test
-    public void testPomChanges() throws Exception
-    {
+    void testPomChanges() throws Exception {
         ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
-        assertNotNull( builder );
-        File pom = getPom( "simple" );
+        assertNotNull(builder);
+        File pom = getPom("simple");
 
-        String originalExists = readPom( pom ).getProfiles().get( 1 ).getActivation().getFile().getExists();
+        String originalExists =
+                readPom(pom).getProfiles().get(1).getActivation().getFile().getExists();
 
         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
-        request.setProcessPlugins( true );
-        request.setPomFile( pom );
-        ModelBuildingResult result = builder.build( request );
-        String resultExists = result.getRawModel().getProfiles().get( 1 ).getActivation().getFile().getExists();
+        request.setProcessPlugins(true);
+        request.setPomFile(pom);
+        ModelBuildingResult result = builder.build(request);
+        String resultExists = result.getRawModel()
+                .getProfiles()
+                .get(1)
+                .getActivation()
+                .getFile()
+                .getExists();
 
-        assertEquals( originalExists, resultExists );
-        assertTrue( result.getEffectiveModel().getProfiles().get( 1 ).getActivation().getFile().getExists()
-                .contains( BASE_DIR ) );
+        assertEquals(originalExists, resultExists);
+        assertTrue(result.getEffectiveModel()
+                .getProfiles()
+                .get(1)
+                .getActivation()
+                .getFile()
+                .getExists()
+                .contains(BASE_DIR));
     }
 
-    private static Model readPom( File file ) throws Exception
-    {
-        MavenXpp3Reader reader = new MavenXpp3Reader();
-
-        return reader.read( new FileInputStream( file ) );
+    private static Model readPom(File file) throws Exception {
+        try (InputStream is = Files.newInputStream(file.toPath())) {
+            return new MavenStaxReader().read(is);
+        }
     }
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
index 767f5fb..0c2d783 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/DefaultModelBuilderTest.java
@@ -1,10 +1,3 @@
-package org.apache.maven.model.building;
-
-  import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import java.io.File;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -23,138 +16,151 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
-import org.apache.maven.model.Dependency;
+import java.io.File;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Parent;
+import org.apache.maven.api.model.Repository;
 import org.apache.maven.model.Model;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.Repository;
 import org.apache.maven.model.resolution.InvalidRepositoryException;
 import org.apache.maven.model.resolution.ModelResolver;
 import org.apache.maven.model.resolution.UnresolvableModelException;
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
 /**
- * @author Guillaume Nodet
  */
-public class DefaultModelBuilderTest
-{
+class DefaultModelBuilderTest {
 
     private static final String BASE1_ID = "thegroup:base1:pom";
 
-    private static final String BASE1 = "<project>\n" +
-            "  <modelVersion>4.0.0</modelVersion>\n" +
-            "  <groupId>thegroup</groupId>\n" +
-            "  <artifactId>base1</artifactId>\n" +
-            "  <version>1</version>\n" +
-            "  <packaging>pom</packaging>\n" +
-            "  <dependencyManagement>\n" +
-            "    <dependencies>\n" +
-            "      <dependency>\n" +
-            "        <groupId>thegroup</groupId>\n" +
-            "        <artifactId>base2</artifactId>\n" +
-            "        <version>1</version>\n" +
-            "        <type>pom</type>\n" +
-            "        <scope>import</scope>\n" +
-            "      </dependency>\n" +
-            "    </dependencies>\n" +
-            "  </dependencyManagement>\n" +
-            "</project>\n";
+    private static final String BASE1 = "<project>\n" + "  <modelVersion>4.0.0</modelVersion>\n"
+            + "  <groupId>thegroup</groupId>\n"
+            + "  <artifactId>base1</artifactId>\n"
+            + "  <version>1</version>\n"
+            + "  <packaging>pom</packaging>\n"
+            + "  <dependencyManagement>\n"
+            + "    <dependencies>\n"
+            + "      <dependency>\n"
+            + "        <groupId>thegroup</groupId>\n"
+            + "        <artifactId>base2</artifactId>\n"
+            + "        <version>1</version>\n"
+            + "        <type>pom</type>\n"
+            + "        <scope>import</scope>\n"
+            + "      </dependency>\n"
+            + "    </dependencies>\n"
+            + "  </dependencyManagement>\n"
+            + "</project>\n";
 
     private static final String BASE2_ID = "thegroup:base2:pom";
 
-    private static final String BASE2 = "<project>\n" +
-            "  <modelVersion>4.0.0</modelVersion>\n" +
-            "  <groupId>thegroup</groupId>\n" +
-            "  <artifactId>base2</artifactId>\n" +
-            "  <version>1</version>\n" +
-            "  <packaging>pom</packaging>\n" +
-            "  <dependencyManagement>\n" +
-            "    <dependencies>\n" +
-            "      <dependency>\n" +
-            "        <groupId>thegroup</groupId>\n" +
-            "        <artifactId>base1</artifactId>\n" +
-            "        <version>1</version>\n" +
-            "        <type>pom</type>\n" +
-            "        <scope>import</scope>\n" +
-            "      </dependency>\n" +
-            "    </dependencies>\n" +
-            "  </dependencyManagement>\n" +
-            "</project>\n";
+    private static final String BASE2 = "<project>\n" + "  <modelVersion>4.0.0</modelVersion>\n"
+            + "  <groupId>thegroup</groupId>\n"
+            + "  <artifactId>base2</artifactId>\n"
+            + "  <version>1</version>\n"
+            + "  <packaging>pom</packaging>\n"
+            + "  <dependencyManagement>\n"
+            + "    <dependencies>\n"
+            + "      <dependency>\n"
+            + "        <groupId>thegroup</groupId>\n"
+            + "        <artifactId>base1</artifactId>\n"
+            + "        <version>1</version>\n"
+            + "        <type>pom</type>\n"
+            + "        <scope>import</scope>\n"
+            + "      </dependency>\n"
+            + "    </dependencies>\n"
+            + "  </dependencyManagement>\n"
+            + "</project>\n";
 
     @Test
-    public void testCycleInImports()
-            throws Exception
-    {
+    void testCycleInImports() throws Exception {
         ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
-        assertNotNull( builder );
+        assertNotNull(builder);
 
         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
-        request.setModelSource( new StringModelSource( BASE1 ) );
-        request.setModelResolver( new CycleInImportsResolver() );
+        request.setModelSource(new StringModelSource(BASE1));
+        request.setModelResolver(new CycleInImportsResolver());
 
-        assertThrows( ModelBuildingException.class, () -> builder.build( request ) );
+        assertThrows(ModelBuildingException.class, () -> builder.build(request));
     }
 
-    static class CycleInImportsResolver extends BaseModelResolver
-    {
+    static class CycleInImportsResolver extends BaseModelResolver {
         @Override
-        public ModelSource resolveModel(Dependency dependency) throws UnresolvableModelException
-        {
-            switch ( dependency.getManagementKey() )
-            {
-                case BASE1_ID: return new StringModelSource( BASE1 );
-                case BASE2_ID: return new StringModelSource( BASE2 );
+        public ModelSource resolveModel(org.apache.maven.model.Dependency dependency)
+                throws UnresolvableModelException {
+            switch (dependency.getManagementKey()) {
+                case BASE1_ID:
+                    return new StringModelSource(BASE1);
+                case BASE2_ID:
+                    return new StringModelSource(BASE2);
             }
             return null;
         }
     }
 
-    static class BaseModelResolver implements ModelResolver
-    {
+    static class BaseModelResolver implements ModelResolver {
         @Override
-        public ModelSource resolveModel( String groupId, String artifactId, String version )
-                throws UnresolvableModelException
-        {
+        public ModelSource resolveModel(String groupId, String artifactId, String version)
+                throws UnresolvableModelException {
             return null;
         }
 
         @Override
-        public ModelSource resolveModel( Parent parent ) throws UnresolvableModelException
-        {
+        public ModelSource resolveModel(Parent parent, AtomicReference<Parent> modified)
+                throws UnresolvableModelException {
             return null;
         }
 
         @Override
-        public ModelSource resolveModel( Dependency dependency ) throws UnresolvableModelException
-        {
+        public ModelSource resolveModel(Dependency dependency, AtomicReference<Dependency> modified)
+                throws UnresolvableModelException {
             return null;
         }
 
         @Override
-        public void addRepository( Repository repository ) throws InvalidRepositoryException
-        {
-        }
+        public void addRepository(Repository repository) throws InvalidRepositoryException {}
 
         @Override
-        public void addRepository(Repository repository, boolean replace) throws InvalidRepositoryException
-        {
-        }
+        public void addRepository(Repository repository, boolean replace) throws InvalidRepositoryException {}
 
         @Override
-        public ModelResolver newCopy()
-        {
+        public ModelResolver newCopy() {
             return this;
         }
+
+        @Override
+        public ModelSource resolveModel(org.apache.maven.model.Parent parent) throws UnresolvableModelException {
+            return null;
+        }
+
+        @Override
+        public ModelSource resolveModel(org.apache.maven.model.Dependency dependency)
+                throws UnresolvableModelException {
+            return null;
+        }
+
+        @Override
+        public void addRepository(org.apache.maven.model.Repository repository) throws InvalidRepositoryException {}
+
+        @Override
+        public void addRepository(org.apache.maven.model.Repository repository, boolean replace)
+                throws InvalidRepositoryException {}
     }
 
     @Test
-    public void testBuildRawModel()
-            throws Exception
-    {
+    void testBuildRawModel() throws Exception {
         ModelBuilder builder = new DefaultModelBuilderFactory().newInstance();
-        assertNotNull( builder );
+        assertNotNull(builder);
 
-        Result<? extends Model> res = builder.buildRawModel( new File( getClass().getResource("/poms/factory/simple.xml" ).getFile() ), ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL, false);
-        assertNotNull( res.get() );
+        Result<? extends Model> res = builder.buildRawModel(
+                new File(getClass().getResource("/poms/factory/simple.xml").getFile()),
+                ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL,
+                false);
+        assertNotNull(res.get());
     }
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java
index 8206cee..8f41bd9 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileModelSourceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.io.File;
 import java.io.IOException;
@@ -29,51 +28,43 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assumptions.assumeTrue;
 
-
 /**
  * Test that validate the solution of MNG-6261 issue
  *
  */
-public class FileModelSourceTest
-{
+class FileModelSourceTest {
 
     /**
      * Test of equals method, of class FileModelSource.
      */
     @Test
-    public void testEquals()
-            throws Exception
-    {
-        File tempFile = createTempFile( "pomTest" );
-        FileModelSource instance = new FileModelSource( tempFile );
+    void testEquals() throws Exception {
+        File tempFile = createTempFile("pomTest");
+        FileModelSource instance = new FileModelSource(tempFile);
 
-        assertFalse( instance.equals( null ) );
-        assertFalse( instance.equals( new Object() ) );
-        assertTrue( instance.equals( instance ) );
-        assertTrue( instance.equals( new FileModelSource( tempFile ) ) );
+        assertFalse(instance.equals(null));
+        assertFalse(instance.equals(new Object()));
+        assertTrue(instance.equals(instance));
+        assertTrue(instance.equals(new FileModelSource(tempFile)));
     }
 
     @Test
-    public void testWindowsPaths()
-            throws Exception
-    {
-        assumeTrue( Os.isFamily( "Windows" ) );
+    void testWindowsPaths() throws Exception {
+        assumeTrue(Os.isFamily("Windows"));
 
-        File upperCaseFile = createTempFile( "TESTE" );
+        File upperCaseFile = createTempFile("TESTE");
         String absolutePath = upperCaseFile.getAbsolutePath();
-        File lowerCaseFile = new File( absolutePath.toLowerCase() );
+        File lowerCaseFile = new File(absolutePath.toLowerCase());
 
-        FileModelSource upperCaseFileSource = new FileModelSource( upperCaseFile );
-        FileModelSource lowerCaseFileSource = new FileModelSource( lowerCaseFile );
+        FileModelSource upperCaseFileSource = new FileModelSource(upperCaseFile);
+        FileModelSource lowerCaseFileSource = new FileModelSource(lowerCaseFile);
 
-        assertTrue( upperCaseFileSource.equals( lowerCaseFileSource ) );
+        assertTrue(upperCaseFileSource.equals(lowerCaseFileSource));
     }
 
-    private File createTempFile( String name ) throws IOException
-    {
-        File tempFile = File.createTempFile( name, ".xml" );
+    private File createTempFile(String name) throws IOException {
+        File tempFile = File.createTempFile(name, ".xml");
         tempFile.deleteOnExit();
         return tempFile;
     }
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java
index 286664c..920e814 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/FileToRawModelMergerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
@@ -26,56 +25,45 @@
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-import org.apache.maven.model.merge.ModelMerger;
+import org.apache.maven.model.v4.MavenMerger;
 import org.junit.jupiter.api.Test;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.hasItems;
 
-public class FileToRawModelMergerTest
-{
+class FileToRawModelMergerTest {
 
     /**
      * Ensures that all list-merge methods are overridden
      */
     @Test
-    public void testOverriddenMergeMethods()
-    {
-        List<String> methodNames =
-            Stream.of( ModelMerger.class.getDeclaredMethods() )
-                .filter( m -> m.getName().startsWith( "merge" ) )
-                .filter( m ->
-                    {
-                        String baseName = m.getName().substring( 5 /* merge */ );
-                        String entity = baseName.substring( baseName.indexOf( '_' ) + 1 );
-                        try
-                        {
-                            Type returnType = m.getParameterTypes()[0].getMethod( "get" + entity ).getGenericReturnType();
-                            if ( returnType instanceof ParameterizedType )
-                            {
-                                return !( (ParameterizedType) returnType ).getActualTypeArguments()[0].equals( String.class );
-                            }
-                            else
-                            {
-                                return false;
-                            }
-                        }
-                        catch ( ReflectiveOperationException | SecurityException e )
-                        {
+    void testOverriddenMergeMethods() {
+        List<String> methodNames = Stream.of(MavenMerger.class.getDeclaredMethods())
+                .filter(m -> m.getName().startsWith("merge"))
+                .filter(m -> {
+                    String baseName = m.getName().substring(5 /* merge */);
+                    String entity = baseName.substring(baseName.indexOf('_') + 1);
+                    try {
+                        Type returnType = m.getParameterTypes()[0]
+                                .getMethod("get" + entity)
+                                .getGenericReturnType();
+                        if (returnType instanceof ParameterizedType) {
+                            return !((ParameterizedType) returnType).getActualTypeArguments()[0].equals(String.class);
+                        } else {
                             return false;
                         }
-                    } )
-                .map( Method::getName )
-                .collect( Collectors.toList() );
+                    } catch (ReflectiveOperationException | SecurityException e) {
+                        return false;
+                    }
+                })
+                .map(Method::getName)
+                .collect(Collectors.toList());
 
-        List<String> overriddenMethods =
-            Stream.of( FileToRawModelMerger.class.getDeclaredMethods() )
-                .map( Method::getName )
-                .filter( m -> m.startsWith( "merge" ) )
-                .collect( Collectors.toList() );
+        List<String> overriddenMethods = Stream.of(FileToRawModelMerger.class.getDeclaredMethods())
+                .map(Method::getName)
+                .filter(m -> m.startsWith("merge"))
+                .collect(Collectors.toList());
 
-        assertThat( overriddenMethods, hasItems( methodNames.toArray( new String[0] ) ) );
+        assertThat(overriddenMethods, hasItems(methodNames.toArray(new String[0])));
     }
-
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/ModelBuildingExceptionTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/ModelBuildingExceptionTest.java
new file mode 100644
index 0000000..387056d
--- /dev/null
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/ModelBuildingExceptionTest.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.building;
+
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class ModelBuildingExceptionTest {
+
+    @Test
+    void testMessage() {
+        DefaultModelProblem pb1 =
+                new DefaultModelProblem("message1", ModelProblem.Severity.ERROR, null, "source", 0, 0, "modelId", null);
+        DefaultModelProblem pb2 =
+                new DefaultModelProblem("message2", ModelProblem.Severity.ERROR, null, "source", 0, 0, "modelId", null);
+        String msg = ModelBuildingException.toMessage("modelId", Arrays.asList(pb1, pb2));
+        assertEquals(
+                "2 problems were encountered while building the effective model for modelId" + System.lineSeparator()
+                        + "    - [ERROR] message1" + System.lineSeparator()
+                        + "    - [ERROR] message2",
+                msg);
+    }
+}
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java b/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java
index b311d77..9271005 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/building/SimpleProblemCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.building;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,11 +26,8 @@
 /**
  * A simple model problem collector for testing the model building components.
  *
- * @author Benjamin Bentmann
  */
-public class SimpleProblemCollector
-    implements ModelProblemCollector
-{
+public class SimpleProblemCollector implements ModelProblemCollector {
     private Model model;
 
     private List<String> warnings = new ArrayList<>();
@@ -40,49 +36,45 @@
 
     private List<String> fatals = new ArrayList<>();
 
-    public SimpleProblemCollector()
-    {
-    }
+    public SimpleProblemCollector() {}
 
-    public SimpleProblemCollector( Model model )
-    {
+    public SimpleProblemCollector(Model model) {
         this.model = model;
     }
 
-    public Model getModel()
-    {
+    public Model getModel() {
         return model;
     }
 
-    public List<String> getWarnings()
-    {
+    public List<String> getWarnings() {
         return warnings;
     }
 
-    public List<String> getErrors()
-    {
+    public List<String> getErrors() {
         return errors;
     }
 
-    public List<String> getFatals()
-    {
+    public List<String> getFatals() {
         return fatals;
     }
 
-    public void add( ModelProblemCollectorRequest req )
-    {
-        switch ( req.getSeverity() )
-        {
+    public void add(ModelProblemCollectorRequest req) {
+        switch (req.getSeverity()) {
             case FATAL:
-                fatals.add( req.getMessage() );
+                if (!fatals.contains(req.getMessage())) {
+                    fatals.add(req.getMessage());
+                }
                 break;
             case ERROR:
-                errors.add( req.getMessage() );
+                if (!errors.contains(req.getMessage())) {
+                    errors.add(req.getMessage());
+                }
                 break;
             case WARNING:
-                warnings.add( req.getMessage() );
+                if (!warnings.contains(req.getMessage())) {
+                    warnings.add(req.getMessage());
+                }
                 break;
         }
-
     }
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
index b573ad1..5f9dbde 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/DefaultInheritanceAssemblerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.inheritance;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,20 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.inheritance;
 
 import java.io.File;
 import java.io.IOException;
-import java.nio.file.Path;
 
-import org.apache.maven.model.Model;
-import org.apache.maven.model.building.AbstractModelSourceTransformer;
+import org.apache.maven.api.model.Model;
 import org.apache.maven.model.building.SimpleProblemCollector;
-import org.apache.maven.model.building.TransformerContext;
-import org.apache.maven.model.building.TransformerException;
 import org.apache.maven.model.io.DefaultModelReader;
 import org.apache.maven.model.io.DefaultModelWriter;
 import org.apache.maven.model.io.ModelWriter;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.xmlunit.matchers.CompareMatcher;
@@ -41,10 +35,8 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author Hervé Boutemy
  */
-public class DefaultInheritanceAssemblerTest
-{
+class DefaultInheritanceAssemblerTest {
     private DefaultModelReader reader;
 
     private ModelWriter writer;
@@ -52,38 +44,23 @@
     private InheritanceAssembler assembler;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        reader = new DefaultModelReader( new AbstractModelSourceTransformer()
-        {
-            @Override
-            public XmlPullParser transform( XmlPullParser parser, Path pomFile, TransformerContext context )
-                    throws IOException, TransformerException
-            {
-                return null;
-            }
-        } );
+    void setUp() throws Exception {
+        reader = new DefaultModelReader(null);
         writer = new DefaultModelWriter();
         assembler = new DefaultInheritanceAssembler();
     }
 
-    private File getPom( String name )
-    {
-        return new File( "src/test/resources/poms/inheritance/" + name + ".xml" );
+    private File getPom(String name) {
+        return new File("src/test/resources/poms/inheritance/" + name + ".xml");
     }
 
-    private Model getModel( String name )
-        throws IOException
-    {
-        return reader.read( getPom( name ), null );
+    private Model getModel(String name) throws IOException {
+        return reader.read(getPom(name), null).getDelegate();
     }
 
     @Test
-    public void testPluginConfiguration()
-        throws Exception
-    {
-        testInheritance( "plugin-configuration" );
+    void testPluginConfiguration() throws Exception {
+        testInheritance("plugin-configuration");
     }
 
     /**
@@ -92,10 +69,8 @@
      * @throws IOException Model read problem
      */
     @Test
-    public void testUrls()
-        throws Exception
-    {
-        testInheritance( "urls" );
+    void testUrls() throws Exception {
+        testInheritance("urls");
     }
 
     /**
@@ -103,10 +78,8 @@
      * @throws IOException Model read problem
      */
     @Test
-    public void testFlatUrls()
-        throws IOException
-    {
-        testInheritance( "flat-urls" );
+    void testFlatUrls() throws IOException {
+        testInheritance("flat-urls");
     }
 
     /**
@@ -114,10 +87,8 @@
      * @throws Exception
      */
     @Test
-    public void testNoAppendUrls()
-        throws Exception
-    {
-        testInheritance( "no-append-urls" );
+    void testNoAppendUrls() throws Exception {
+        testInheritance("no-append-urls");
     }
 
     /**
@@ -125,10 +96,8 @@
      * @throws Exception
      */
     @Test
-    public void testNoAppendUrls2()
-        throws Exception
-    {
-        testInheritance( "no-append-urls2" );
+    void testNoAppendUrls2() throws Exception {
+        testInheritance("no-append-urls2");
     }
 
     /**
@@ -136,10 +105,8 @@
      * @throws Exception
      */
     @Test
-    public void testNoAppendUrls3()
-        throws Exception
-    {
-        testInheritance( "no-append-urls3" );
+    void testNoAppendUrls3() throws Exception {
+        testInheritance("no-append-urls3");
     }
 
     /**
@@ -149,106 +116,98 @@
      * @throws IOException Model read problem
      */
     @Test
-    public void testFlatTrickyUrls()
-        throws IOException
-    {
+    void testFlatTrickyUrls() throws IOException {
         // parent references child with artifactId (which is not directory name)
         // then relative path calculation will fail during build from disk but success when calculated from repo
-        try
-        {
+        try {
             // build from disk expected to fail
-            testInheritance( "tricky-flat-artifactId-urls", false );
-            //fail( "should have failed since module reference == artifactId != directory name" );
-        }
-        catch ( AssertionError afe )
-        {
+            testInheritance("tricky-flat-artifactId-urls", false);
+            // fail( "should have failed since module reference == artifactId != directory name" );
+        } catch (AssertionError afe) {
             // expected failure: wrong relative path calculation
-            assertTrue( afe.getMessage().contains(
-                                "Expected text value 'http://www.apache.org/path/to/parent/child-artifact-id/' but was " +
-                                        "'http://www.apache.org/path/to/parent/../child-artifact-id/'" ),
-                        afe.getMessage() );
+            assertTrue(
+                    afe.getMessage()
+                            .contains(
+                                    "Expected text value 'http://www.apache.org/path/to/parent/child-artifact-id/' but was "
+                                            + "'http://www.apache.org/path/to/parent/../child-artifact-id/'"),
+                    afe.getMessage());
         }
         // but ok from repo: local disk is ignored
-        testInheritance( "tricky-flat-artifactId-urls", true );
+        testInheritance("tricky-flat-artifactId-urls", true);
 
         // parent references child with directory name (which is not artifact id)
         // then relative path calculation will success during build from disk but fail when calculated from repo
-        testInheritance( "tricky-flat-directory-urls", false );
+        testInheritance("tricky-flat-directory-urls", false);
 
         AssertionError afe = assertThrows(
                 AssertionError.class,
-                () -> testInheritance( "tricky-flat-directory-urls", true ),
-                "should have failed since module reference == directory name != artifactId" );
+                () -> testInheritance("tricky-flat-directory-urls", true),
+                "should have failed since module reference == directory name != artifactId");
         // expected failure
-        assertTrue( afe.getMessage().contains(
-                                "Expected text value 'http://www.apache.org/path/to/parent/../child-artifact-id/' but was " +
-                                        "'http://www.apache.org/path/to/parent/child-artifact-id/'" ),
-                    afe.getMessage() );
+        assertTrue(
+                afe.getMessage()
+                        .contains(
+                                "Expected text value 'http://www.apache.org/path/to/parent/../child-artifact-id/' but was "
+                                        + "'http://www.apache.org/path/to/parent/child-artifact-id/'"),
+                afe.getMessage());
     }
 
     @Test
-    public void testWithEmptyUrl()
-        throws IOException
-    {
-            testInheritance( "empty-urls", false );
+    void testWithEmptyUrl() throws IOException {
+        testInheritance("empty-urls", false);
     }
 
-    public void testInheritance( String baseName )
-        throws IOException
-    {
-        testInheritance( baseName, false );
-        testInheritance( baseName, true );
+    public void testInheritance(String baseName) throws IOException {
+        testInheritance(baseName, false);
+        testInheritance(baseName, true);
     }
 
-    public void testInheritance( String baseName, boolean fromRepo )
-        throws IOException
-    {
-        Model parent = getModel( baseName + "-parent" );
+    public void testInheritance(String baseName, boolean fromRepo) throws IOException {
+        Model parent = getModel(baseName + "-parent");
 
-        Model child = getModel( baseName + "-child" );
+        Model child = getModel(baseName + "-child");
 
-        if ( fromRepo )
-        {
+        if (fromRepo) {
             // when model is read from repo, a stream is used, then pomFile == null
             // (has consequences in inheritance algorithm since getProjectDirectory() returns null)
-            parent.setPomFile( null );
-            child.setPomFile( null );
+            parent = Model.newBuilder(parent, true).pomFile(null).build();
+            child = Model.newBuilder(child, true).pomFile(null).build();
         }
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
 
-        assembler.assembleModelInheritance( child, parent, null, problems );
+        Model assembled = assembler.assembleModelInheritance(child, parent, null, problems);
 
         // write baseName + "-actual"
-        File actual = new File( "target/test-classes/poms/inheritance/" + baseName
-            + ( fromRepo ? "-build" : "-repo" ) + "-actual.xml" );
-        writer.write( actual, null, child );
+        File actual = new File(
+                "target/test-classes/poms/inheritance/" + baseName + (fromRepo ? "-build" : "-repo") + "-actual.xml");
+        writer.write(actual, null, assembled);
 
         // check with getPom( baseName + "-expected" )
-        File expected = getPom( baseName + "-expected" );
+        File expected = getPom(baseName + "-expected");
 
-        assertThat( actual, CompareMatcher.isIdenticalTo( expected ).ignoreComments().ignoreWhitespace() );
+        assertThat(
+                actual, CompareMatcher.isIdenticalTo(expected).ignoreComments().ignoreWhitespace());
     }
 
     @Test
-    public void testModulePathNotArtifactId()
-        throws IOException
-    {
-        Model parent = getModel( "module-path-not-artifactId-parent" );
+    void testModulePathNotArtifactId() throws IOException {
+        Model parent = getModel("module-path-not-artifactId-parent");
 
-        Model child = getModel( "module-path-not-artifactId-child" );
+        Model child = getModel("module-path-not-artifactId-child");
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
 
-        assembler.assembleModelInheritance( child, parent, null, problems );
+        Model model = assembler.assembleModelInheritance(child, parent, null, problems);
 
-        File actual = new File( "target/test-classes/poms/inheritance/module-path-not-artifactId-actual.xml" );
+        File actual = new File("target/test-classes/poms/inheritance/module-path-not-artifactId-actual.xml");
 
-        writer.write( actual, null, child );
+        writer.write(actual, null, model);
 
         // check with getPom( "module-path-not-artifactId-effective" )
-        File expected = getPom( "module-path-not-artifactId-expected" );
+        File expected = getPom("module-path-not-artifactId-expected");
 
-        assertThat( actual, CompareMatcher.isIdenticalTo(expected).ignoreComments().ignoreWhitespace() );
+        assertThat(
+                actual, CompareMatcher.isIdenticalTo(expected).ignoreComments().ignoreWhitespace());
     }
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/MergerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/MergerTest.java
new file mode 100644
index 0000000..b3d3f85
--- /dev/null
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/inheritance/MergerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.inheritance;
+
+import java.io.InputStream;
+import java.io.StringReader;
+
+import org.apache.maven.api.model.InputLocation;
+import org.apache.maven.api.model.InputSource;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.model.v4.MavenMerger;
+import org.apache.maven.model.v4.MavenStaxReader;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class MergerTest {
+
+    @Test
+    void testMergerPreserveLocations() throws Exception {
+        try (InputStream is = getClass().getResourceAsStream("/poms/factory/complex.xml")) {
+
+            InputSource inputSource = new InputSource(null, "classpath:/poms/factory/complex.xml");
+            Model model = new MavenStaxReader().read(is, true, inputSource);
+            InputLocation propertiesLocation = model.getLocation("properties");
+            assertNotNull(propertiesLocation);
+            assertEquals(13, propertiesLocation.getLineNumber());
+            assertEquals(5, propertiesLocation.getColumnNumber());
+            InputLocation filterPropLocation = propertiesLocation.getLocation("my.filter.value");
+            assertNotNull(filterPropLocation);
+            assertEquals(14, filterPropLocation.getLineNumber());
+            assertEquals(31, filterPropLocation.getColumnNumber());
+
+            Model model2 = Model.newBuilder(model).build();
+            propertiesLocation = model2.getLocation("properties");
+            assertNotNull(propertiesLocation);
+            assertEquals(13, propertiesLocation.getLineNumber());
+            assertEquals(5, propertiesLocation.getColumnNumber());
+            filterPropLocation = propertiesLocation.getLocation("my.filter.value");
+            assertNotNull(filterPropLocation);
+            assertEquals(14, filterPropLocation.getLineNumber());
+            assertEquals(31, filterPropLocation.getColumnNumber());
+            assertNotNull(model.getLocation("groupId"));
+
+            Model mergeInput = new MavenStaxReader()
+                    .read(
+                            new StringReader("<project>\n"
+                                    + "  <properties>\n"
+                                    + "    <my.prop>my-value</my.prop>\n"
+                                    + "  </properties>\n"
+                                    + "</project>"),
+                            true,
+                            new InputSource(null, "merge-input"));
+            propertiesLocation = mergeInput.getLocation("properties");
+            assertNotNull(propertiesLocation);
+            assertEquals(2, propertiesLocation.getLineNumber());
+            assertEquals(3, propertiesLocation.getColumnNumber());
+            filterPropLocation = propertiesLocation.getLocation("my.prop");
+            assertNotNull(filterPropLocation);
+            assertEquals(3, filterPropLocation.getLineNumber());
+            assertEquals(22, filterPropLocation.getColumnNumber());
+
+            Model result = new MavenMerger().merge(model, mergeInput, true, null);
+            propertiesLocation = result.getLocation("properties");
+            assertNotNull(propertiesLocation);
+            assertEquals(-1, propertiesLocation.getLineNumber());
+            assertEquals(-1, propertiesLocation.getColumnNumber());
+            filterPropLocation = propertiesLocation.getLocation("my.filter.value");
+            assertNotNull(filterPropLocation);
+            assertEquals(14, filterPropLocation.getLineNumber());
+            assertEquals(31, filterPropLocation.getColumnNumber());
+            filterPropLocation = propertiesLocation.getLocation("my.prop");
+            assertNotNull(filterPropLocation);
+            assertEquals(3, filterPropLocation.getLineNumber());
+            assertEquals(22, filterPropLocation.getColumnNumber());
+            assertNotNull(result.getLocation("groupId"));
+
+            result = new DefaultInheritanceAssembler.InheritanceModelMerger().merge(model, mergeInput, true, null);
+            propertiesLocation = result.getLocation("properties");
+            assertNotNull(propertiesLocation);
+            assertEquals(-1, propertiesLocation.getLineNumber());
+            assertEquals(-1, propertiesLocation.getColumnNumber());
+            filterPropLocation = propertiesLocation.getLocation("my.filter.value");
+            assertNotNull(filterPropLocation);
+            assertEquals(14, filterPropLocation.getLineNumber());
+            assertEquals(31, filterPropLocation.getColumnNumber());
+            filterPropLocation = propertiesLocation.getLocation("my.prop");
+            assertNotNull(filterPropLocation);
+            assertEquals(3, filterPropLocation.getLineNumber());
+            assertEquals(22, filterPropLocation.getColumnNumber());
+            assertNotNull(result.getLocation("groupId"));
+        }
+    }
+}
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java
index ca9d28e..6d28832 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/AbstractModelInterpolatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,516 +16,542 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
 
 import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.text.SimpleDateFormat;
+import java.util.Arrays;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Properties;
 import java.util.TimeZone;
 
-import org.apache.maven.model.Build;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Organization;
-import org.apache.maven.model.Repository;
-import org.apache.maven.model.Resource;
-import org.apache.maven.model.Scm;
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Organization;
+import org.apache.maven.api.model.Repository;
+import org.apache.maven.api.model.Resource;
+import org.apache.maven.api.model.Scm;
 import org.apache.maven.model.building.DefaultModelBuildingRequest;
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.SimpleProblemCollector;
+import org.apache.maven.model.root.RootLocator;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author jdcasey
  */
-public abstract class AbstractModelInterpolatorTest
-{
+public abstract class AbstractModelInterpolatorTest {
     private Properties context;
 
     @BeforeEach
-    public void setUp()
-    {
+    public void setUp() {
         context = new Properties();
-        context.put( "basedir", "myBasedir" );
-        context.put( "project.baseUri", "myBaseUri" );
+        context.put("basedir", "myBasedir");
+        context.put("project.baseUri", "myBaseUri");
     }
 
-
-    protected void assertProblemFree( SimpleProblemCollector collector )
-    {
-        assertEquals( 0, collector.getErrors().size(), "Expected no errors" );
-        assertEquals( 0, collector.getWarnings().size(), "Expected no warnings" );
-        assertEquals( 0, collector.getFatals().size(), "Expected no fatals" );
+    protected void assertProblemFree(SimpleProblemCollector collector) {
+        assertEquals(0, collector.getErrors().size(), "Expected no errors");
+        assertEquals(0, collector.getWarnings().size(), "Expected no warnings");
+        assertEquals(0, collector.getFatals().size(), "Expected no fatals");
     }
 
-    protected void assertCollectorState( int numFatals, int numErrors, int numWarnings, SimpleProblemCollector collector )
-    {
-        assertEquals( numErrors, collector.getErrors().size(), "Errors" );
-        assertEquals( numWarnings, collector.getWarnings().size(), "Warnings" );
-        assertEquals( numFatals, collector.getFatals().size(), "Fatals" );
+    protected void assertCollectorState(
+            int numFatals, int numErrors, int numWarnings, SimpleProblemCollector collector) {
+        assertEquals(numErrors, collector.getErrors().size(), "Errors");
+        assertEquals(numWarnings, collector.getWarnings().size(), "Warnings");
+        assertEquals(numFatals, collector.getFatals().size(), "Fatals");
     }
 
-    private ModelBuildingRequest createModelBuildingRequest( Properties p )
-    {
+    private ModelBuildingRequest createModelBuildingRequest(Properties p) {
         ModelBuildingRequest config = new DefaultModelBuildingRequest();
-        if ( p != null )
-        {
-            config.setSystemProperties( p );
+        if (p != null) {
+            config.setSystemProperties(p);
         }
         return config;
     }
 
     @Test
-    public void testDefaultBuildTimestampFormatShouldFormatTimeIn24HourFormat()
-    {
+    public void testDefaultBuildTimestampFormatShouldFormatTimeIn24HourFormat() {
         Calendar cal = Calendar.getInstance();
-        cal.setTimeZone( MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE );
-        cal.set( Calendar.HOUR, 12 );
-        cal.set( Calendar.AM_PM, Calendar.AM );
+        cal.setTimeZone(MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE);
+        cal.set(Calendar.HOUR, 12);
+        cal.set(Calendar.AM_PM, Calendar.AM);
 
         // just to make sure all the bases are covered...
-        cal.set( Calendar.HOUR_OF_DAY, 0 );
-        cal.set( Calendar.MINUTE, 16 );
-        cal.set( Calendar.SECOND, 0 );
-        cal.set( Calendar.YEAR, 1976 );
-        cal.set( Calendar.MONTH, Calendar.NOVEMBER );
-        cal.set( Calendar.DATE, 11 );
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 16);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.YEAR, 1976);
+        cal.set(Calendar.MONTH, Calendar.NOVEMBER);
+        cal.set(Calendar.DATE, 11);
 
         Date firstTestDate = cal.getTime();
 
-        cal.set( Calendar.HOUR, 11 );
-        cal.set( Calendar.AM_PM, Calendar.PM );
+        cal.set(Calendar.HOUR, 11);
+        cal.set(Calendar.AM_PM, Calendar.PM);
 
         // just to make sure all the bases are covered...
-        cal.set( Calendar.HOUR_OF_DAY, 23 );
+        cal.set(Calendar.HOUR_OF_DAY, 23);
 
         Date secondTestDate = cal.getTime();
 
-        SimpleDateFormat format = new SimpleDateFormat( MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT );
-        format.setTimeZone( MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE );
-        assertEquals( "1976-11-11T00:16:00Z", format.format( firstTestDate ) );
-        assertEquals( "1976-11-11T23:16:00Z", format.format( secondTestDate ) );
+        SimpleDateFormat format = new SimpleDateFormat(MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT);
+        format.setTimeZone(MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE);
+        assertEquals("1976-11-11T00:16:00Z", format.format(firstTestDate));
+        assertEquals("1976-11-11T23:16:00Z", format.format(secondTestDate));
     }
 
     @Test
-    public void testDefaultBuildTimestampFormatWithLocalTimeZoneMidnightRollover()
-    {
+    public void testDefaultBuildTimestampFormatWithLocalTimeZoneMidnightRollover() {
         Calendar cal = Calendar.getInstance();
-        cal.setTimeZone( TimeZone.getTimeZone( "Europe/Berlin" ) );
+        cal.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
 
-        cal.set( Calendar.HOUR_OF_DAY, 1 );
-        cal.set( Calendar.MINUTE, 16 );
-        cal.set( Calendar.SECOND, 0 );
-        cal.set( Calendar.YEAR, 2014 );
-        cal.set( Calendar.MONTH, Calendar.JUNE );
-        cal.set( Calendar.DATE, 16 );
+        cal.set(Calendar.HOUR_OF_DAY, 1);
+        cal.set(Calendar.MINUTE, 16);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.YEAR, 2014);
+        cal.set(Calendar.MONTH, Calendar.JUNE);
+        cal.set(Calendar.DATE, 16);
 
         Date firstTestDate = cal.getTime();
 
-        cal.set( Calendar.MONTH, Calendar.NOVEMBER );
+        cal.set(Calendar.MONTH, Calendar.NOVEMBER);
 
         Date secondTestDate = cal.getTime();
 
-        SimpleDateFormat format = new SimpleDateFormat( MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT );
-        format.setTimeZone( MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE );
-        assertEquals( "2014-06-15T23:16:00Z", format.format( firstTestDate ) );
-        assertEquals( "2014-11-16T00:16:00Z", format.format( secondTestDate ) );
+        SimpleDateFormat format = new SimpleDateFormat(MavenBuildTimestamp.DEFAULT_BUILD_TIMESTAMP_FORMAT);
+        format.setTimeZone(MavenBuildTimestamp.DEFAULT_BUILD_TIME_ZONE);
+        assertEquals("2014-06-15T23:16:00Z", format.format(firstTestDate));
+        assertEquals("2014-11-16T00:16:00Z", format.format(secondTestDate));
     }
 
     @Test
-    public void testShouldNotThrowExceptionOnReferenceToNonExistentValue() throws Exception
-    {
-        Model model = new Model();
-
-        Scm scm = new Scm();
-        scm.setConnection( "${test}/somepath" );
-
-        model.setScm( scm );
+    public void testShouldNotThrowExceptionOnReferenceToNonExistentValue() throws Exception {
+        Scm scm = Scm.newBuilder().connection("${test}/somepath").build();
+        Model model = Model.newBuilder().scm(scm).build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
 
-        assertProblemFree( collector );
-        assertEquals( "${test}/somepath", out.getScm().getConnection() );
+        assertProblemFree(collector);
+        assertEquals("${test}/somepath", out.getScm().getConnection());
     }
 
     @Test
-    public void testShouldThrowExceptionOnRecursiveScmConnectionReference() throws Exception
-    {
-        Model model = new Model();
-
-        Scm scm = new Scm();
-        scm.setConnection( "${project.scm.connection}/somepath" );
-
-        model.setScm( scm );
+    public void testShouldThrowExceptionOnRecursiveScmConnectionReference() throws Exception {
+        Scm scm = Scm.newBuilder()
+                .connection("${project.scm.connection}/somepath")
+                .build();
+        Model model = Model.newBuilder().scm(scm).build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
-        assertCollectorState( 0, 1, 0, collector );
+        interpolator.interpolateModel(model, null, createModelBuildingRequest(context), collector);
+        assertCollectorState(0, 1, 0, collector);
     }
 
     @Test
-    public void testShouldNotThrowExceptionOnReferenceToValueContainingNakedExpression() throws Exception
-    {
-        Model model = new Model();
-
-        Scm scm = new Scm();
-        scm.setConnection( "${test}/somepath" );
-
-        model.setScm( scm );
-
-        model.addProperty( "test", "test" );
+    public void testShouldNotThrowExceptionOnReferenceToValueContainingNakedExpression() throws Exception {
+        Scm scm = Scm.newBuilder().connection("${test}/somepath").build();
+        Map<String, String> props = new HashMap<>();
+        props.put("test", "test");
+        Model model = Model.newBuilder().scm(scm).properties(props).build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
 
-        assertProblemFree( collector );
+        assertProblemFree(collector);
 
-        assertEquals( "test/somepath", out.getScm().getConnection() );
+        assertEquals("test/somepath", out.getScm().getConnection());
     }
 
     @Test
-    public void shouldInterpolateOrganizationNameCorrectly() throws Exception
-    {
+    public void shouldInterpolateOrganizationNameCorrectly() throws Exception {
         String orgName = "MyCo";
 
-        Model model = new Model();
-        model.setName( "${project.organization.name} Tools" );
-
-        Organization org = new Organization();
-        org.setName( orgName );
-
-        model.setOrganization( org );
+        Model model = Model.newBuilder()
+                .name("${project.organization.name} Tools")
+                .organization(Organization.newBuilder().name(orgName).build())
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                new SimpleProblemCollector() );
+        Model out = interpolator.interpolateModel(
+                model, new File("."), createModelBuildingRequest(context), new SimpleProblemCollector());
 
-        assertEquals( orgName + " Tools", out.getName() );
+        assertEquals(orgName + " Tools", out.getName());
     }
 
     @Test
-    public void shouldInterpolateDependencyVersionToSetSameAsProjectVersion() throws Exception
-    {
-        Model model = new Model();
-        model.setVersion( "3.8.1" );
-
-        Dependency dep = new Dependency();
-        dep.setVersion( "${project.version}" );
-
-        model.addDependency( dep );
+    public void shouldInterpolateDependencyVersionToSetSameAsProjectVersion() throws Exception {
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .dependencies(Collections.singletonList(
+                        Dependency.newBuilder().version("${project.version}").build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
-        assertCollectorState( 0, 0, 0, collector );
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
+        assertCollectorState(0, 0, 0, collector);
 
-        assertEquals( "3.8.1", ( out.getDependencies().get( 0 ) ).getVersion() );
+        assertEquals("3.8.1", (out.getDependencies().get(0)).getVersion());
     }
 
     @Test
-    public void testShouldNotInterpolateDependencyVersionWithInvalidReference() throws Exception
-    {
-        Model model = new Model();
-        model.setVersion( "3.8.1" );
-
-        Dependency dep = new Dependency();
-        dep.setVersion( "${something}" );
-
-        model.addDependency( dep );
+    public void testShouldNotInterpolateDependencyVersionWithInvalidReference() throws Exception {
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .dependencies(Collections.singletonList(
+                        Dependency.newBuilder().version("${something}").build()))
+                .build();
 
         /*
-         // This is the desired behaviour, however there are too many crappy poms in the repo and an issue with the
-         // timing of executing the interpolation
+        // This is the desired behaviour, however there are too many crappy poms in the repo and an issue with the
+        // timing of executing the interpolation
 
-         try
-         {
-         new RegexBasedModelInterpolator().interpolate( model, context );
-         fail( "Should have failed to interpolate with invalid reference" );
-         }
-         catch ( ModelInterpolationException expected )
-         {
-         assertTrue( true );
-         }
-         */
+        try
+        {
+        new RegexBasedModelInterpolator().interpolate( model, context );
+        fail( "Should have failed to interpolate with invalid reference" );
+        }
+        catch ( ModelInterpolationException expected )
+        {
+        assertTrue( true );
+        }
+        */
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
-        assertProblemFree( collector );
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
 
-        assertEquals( "${something}", ( out.getDependencies().get( 0 ) ).getVersion() );
+        assertEquals("${something}", (out.getDependencies().get(0)).getVersion());
     }
 
     @Test
-    public void testTwoReferences() throws Exception
-    {
-        Model model = new Model();
-        model.setVersion( "3.8.1" );
-        model.setArtifactId( "foo" );
-
-        Dependency dep = new Dependency();
-        dep.setVersion( "${project.artifactId}-${project.version}" );
-
-        model.addDependency( dep );
+    public void testTwoReferences() throws Exception {
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .artifactId("foo")
+                .dependencies(Collections.singletonList(Dependency.newBuilder()
+                        .version("${project.artifactId}-${project.version}")
+                        .build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
-        assertCollectorState( 0, 0, 0, collector );
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
+        assertCollectorState(0, 0, 0, collector);
 
-        assertEquals( "foo-3.8.1", ( out.getDependencies().get( 0 ) ).getVersion() );
+        assertEquals("foo-3.8.1", (out.getDependencies().get(0)).getVersion());
     }
 
     @Test
-    public void testBasedir() throws Exception
-    {
-        Model model = new Model();
-        model.setVersion( "3.8.1" );
-        model.setArtifactId( "foo" );
-
-        Repository repository = new Repository();
-
-        repository.setUrl( "file://localhost/${basedir}/temp-repo" );
-
-        model.addRepository( repository );
+    public void testBasedir() throws Exception {
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .artifactId("foo")
+                .repositories(Collections.singletonList(Repository.newBuilder()
+                        .url("file://localhost/${basedir}/temp-repo")
+                        .build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
-        assertProblemFree( collector );
+        Model out = interpolator.interpolateModel(model, null, createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
 
-        assertEquals( "file://localhost/myBasedir/temp-repo", ( out.getRepositories().get( 0 ) ).getUrl() );
+        assertEquals(
+                "file://localhost/myBasedir/temp-repo", (out.getRepositories().get(0)).getUrl());
     }
 
     @Test
-    public void testBaseUri() throws Exception
-    {
-        Model model = new Model();
-        model.setVersion( "3.8.1" );
-        model.setArtifactId( "foo" );
-
-        Repository repository = new Repository();
-
-        repository.setUrl( "${project.baseUri}/temp-repo" );
-
-        model.addRepository( repository );
+    public void testBaseUri() throws Exception {
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .artifactId("foo")
+                .repositories(Collections.singletonList(Repository.newBuilder()
+                        .url("${project.baseUri}/temp-repo")
+                        .build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
-        assertProblemFree( collector );
+        Model out = interpolator.interpolateModel(model, null, createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
 
-        assertEquals( "myBaseUri/temp-repo", ( out.getRepositories().get( 0 ) ).getUrl() );
+        assertEquals("myBaseUri/temp-repo", (out.getRepositories().get(0)).getUrl());
     }
 
     @Test
-    public void testEnvars() throws Exception
-    {
-        Properties context = new Properties();
+    void testRootDirectory() throws Exception {
+        Path rootDirectory = Paths.get("myRootDirectory");
 
-        context.put( "env.HOME", "/path/to/home" );
-
-        Model model = new Model();
-
-        Properties modelProperties = new Properties();
-
-        modelProperties.setProperty( "outputDirectory", "${env.HOME}" );
-
-        model.setProperties( modelProperties );
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .artifactId("foo")
+                .repositories(Collections.singletonList(Repository.newBuilder()
+                        .url("file:${project.rootDirectory}/temp-repo")
+                        .build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
-        assertProblemFree( collector );
+        Model out = interpolator.interpolateModel(
+                model, rootDirectory.toFile(), createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
 
-        assertEquals( "/path/to/home", out.getProperties().getProperty( "outputDirectory" ) );
+        assertEquals("file:myRootDirectory/temp-repo", (out.getRepositories().get(0)).getUrl());
     }
 
     @Test
-    public void envarExpressionThatEvaluatesToNullReturnsTheLiteralString() throws Exception
-    {
-        Model model = new Model();
+    void testRootDirectoryWithUri() throws Exception {
+        Path rootDirectory = Paths.get("myRootDirectory");
 
-        Properties modelProperties = new Properties();
-
-        modelProperties.setProperty( "outputDirectory", "${env.DOES_NOT_EXIST}" );
-
-        model.setProperties( modelProperties );
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .artifactId("foo")
+                .repositories(Collections.singletonList(Repository.newBuilder()
+                        .url("${project.rootDirectory.uri}/temp-repo")
+                        .build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
-        assertProblemFree( collector );
+        Model out = interpolator.interpolateModel(
+                model, rootDirectory.toFile(), createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
 
-        assertEquals( out.getProperties().getProperty( "outputDirectory" ), "${env.DOES_NOT_EXIST}" );
+        assertEquals(
+                rootDirectory.resolve("temp-repo").toUri().toString(),
+                (out.getRepositories().get(0)).getUrl());
     }
 
     @Test
-    public void expressionThatEvaluatesToNullReturnsTheLiteralString() throws Exception
-    {
-        Model model = new Model();
-
-        Properties modelProperties = new Properties();
-
-        modelProperties.setProperty( "outputDirectory", "${DOES_NOT_EXIST}" );
-
-        model.setProperties( modelProperties );
+    void testRootDirectoryWithNull() throws Exception {
+        Model model = Model.newBuilder()
+                .version("3.8.1")
+                .artifactId("foo")
+                .repositories(Collections.singletonList(Repository.newBuilder()
+                        .url("file:///${project.rootDirectory}/temp-repo")
+                        .build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, new File( "." ), createModelBuildingRequest( context ),
-                collector );
-        assertProblemFree( collector );
+        IllegalStateException e = assertThrows(
+                IllegalStateException.class,
+                () -> interpolator.interpolateModel(model, null, createModelBuildingRequest(context), collector));
 
-        assertEquals( out.getProperties().getProperty( "outputDirectory" ), "${DOES_NOT_EXIST}" );
+        assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
     }
 
     @Test
-    public void shouldInterpolateSourceDirectoryReferencedFromResourceDirectoryCorrectly() throws Exception
-    {
-        Model model = new Model();
+    public void testEnvars() throws Exception {
+        context.put("env.HOME", "/path/to/home");
 
-        Build build = new Build();
-        build.setSourceDirectory( "correct" );
+        Map<String, String> modelProperties = new HashMap<>();
+        modelProperties.put("outputDirectory", "${env.HOME}");
 
-        Resource res = new Resource();
-        res.setDirectory( "${project.build.sourceDirectory}" );
-
-        build.addResource( res );
-
-        model.setBuild( build );
+        Model model = Model.newBuilder().properties(modelProperties).build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ), collector );
-        assertCollectorState( 0, 0, 0, collector );
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
 
+        assertEquals("/path/to/home", out.getProperties().get("outputDirectory"));
+    }
+
+    @Test
+    public void envarExpressionThatEvaluatesToNullReturnsTheLiteralString() throws Exception {
+
+        Map<String, String> modelProperties = new HashMap<>();
+        modelProperties.put("outputDirectory", "${env.DOES_NOT_EXIST}");
+
+        Model model = Model.newBuilder().properties(modelProperties).build();
+
+        ModelInterpolator interpolator = createInterpolator();
+
+        final SimpleProblemCollector collector = new SimpleProblemCollector();
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
+
+        assertEquals(out.getProperties().get("outputDirectory"), "${env.DOES_NOT_EXIST}");
+    }
+
+    @Test
+    public void expressionThatEvaluatesToNullReturnsTheLiteralString() throws Exception {
+        Map<String, String> modelProperties = new HashMap<>();
+        modelProperties.put("outputDirectory", "${DOES_NOT_EXIST}");
+
+        Model model = Model.newBuilder().properties(modelProperties).build();
+
+        ModelInterpolator interpolator = createInterpolator();
+
+        final SimpleProblemCollector collector = new SimpleProblemCollector();
+        Model out = interpolator.interpolateModel(model, new File("."), createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
+
+        assertEquals(out.getProperties().get("outputDirectory"), "${DOES_NOT_EXIST}");
+    }
+
+    @Test
+    public void shouldInterpolateSourceDirectoryReferencedFromResourceDirectoryCorrectly() throws Exception {
+        Model model = Model.newBuilder()
+                .build(Build.newBuilder()
+                        .sourceDirectory("correct")
+                        .resources(Arrays.asList(Resource.newBuilder()
+                                .directory("${project.build.sourceDirectory}")
+                                .build()))
+                        .build())
+                .build();
+
+        ModelInterpolator interpolator = createInterpolator();
+
+        final SimpleProblemCollector collector = new SimpleProblemCollector();
+        Model out = interpolator.interpolateModel(model, null, createModelBuildingRequest(context), collector);
+        assertCollectorState(0, 0, 0, collector);
 
         List<Resource> outResources = out.getBuild().getResources();
         Iterator<Resource> resIt = outResources.iterator();
 
-        assertEquals( build.getSourceDirectory(), resIt.next().getDirectory() );
+        assertEquals(model.getBuild().getSourceDirectory(), resIt.next().getDirectory());
     }
 
     @Test
-    public void shouldInterpolateUnprefixedBasedirExpression() throws Exception
-    {
-        File basedir = new File( "/test/path" );
-        Model model = new Model();
-        Dependency dep = new Dependency();
-        dep.setSystemPath( "${basedir}/artifact.jar" );
-
-        model.addDependency( dep );
+    public void shouldInterpolateUnprefixedBasedirExpression() throws Exception {
+        File basedir = new File("/test/path");
+        Model model = Model.newBuilder()
+                .dependencies(Collections.singletonList(Dependency.newBuilder()
+                        .systemPath("${basedir}/artifact.jar")
+                        .build()))
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
 
         final SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model result = interpolator.interpolateModel( model, basedir, createModelBuildingRequest( context ),
-                collector );
-        assertProblemFree( collector );
-
+        Model result = interpolator.interpolateModel(model, basedir, createModelBuildingRequest(context), collector);
+        assertProblemFree(collector);
 
         List<Dependency> rDeps = result.getDependencies();
-        assertNotNull( rDeps );
-        assertEquals( 1, rDeps.size() );
-        assertEquals( new File( basedir, "artifact.jar" ).getAbsolutePath(),
-                new File( rDeps.get( 0 ).getSystemPath() ).getAbsolutePath() );
+        assertNotNull(rDeps);
+        assertEquals(1, rDeps.size());
+        assertEquals(
+                new File(basedir, "artifact.jar").getAbsolutePath(),
+                new File(rDeps.get(0).getSystemPath()).getAbsolutePath());
     }
 
     @Test
-    public void testRecursiveExpressionCycleNPE() throws Exception
-    {
-        Properties props = new Properties();
-        props.setProperty( "aa", "${bb}" );
-        props.setProperty( "bb", "${aa}" );
+    public void testRecursiveExpressionCycleNPE() throws Exception {
+        Map<String, String> props = new HashMap<>();
+        props.put("aa", "${bb}");
+        props.put("bb", "${aa}");
         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
 
-        Model model = new Model();
-        model.setProperties( props );
+        Model model = Model.newBuilder().properties(props).build();
 
         SimpleProblemCollector collector = new SimpleProblemCollector();
         ModelInterpolator interpolator = createInterpolator();
-        interpolator.interpolateModel( model, null, request, collector );
+        interpolator.interpolateModel(model, null, request, collector);
 
-        assertCollectorState( 0, 2, 0, collector );
-        assertTrue( collector.getErrors().get( 0 ).contains( "Detected the following recursive expression cycle" ) );
+        assertCollectorState(0, 2, 0, collector);
+        assertTrue(collector.getErrors().get(0).contains("Detected the following recursive expression cycle"));
     }
 
     @Test
-    public void testRecursiveExpressionCycleBaseDir() throws Exception
-    {
-        Properties props = new Properties();
-        props.setProperty( "basedir", "${basedir}" );
+    public void testRecursiveExpressionCycleBaseDir() throws Exception {
+        Map<String, String> props = new HashMap<>();
+        props.put("basedir", "${basedir}");
         DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
 
-        Model model = new Model();
-        model.setProperties( props );
+        Model model = Model.newBuilder().properties(props).build();
 
         SimpleProblemCollector collector = new SimpleProblemCollector();
         ModelInterpolator interpolator = createInterpolator();
-        interpolator.interpolateModel( model, null, request, collector );
+        interpolator.interpolateModel(model, null, request, collector);
 
-        assertCollectorState( 0, 1, 0, collector );
+        assertCollectorState(0, 1, 0, collector);
         assertEquals(
                 "Resolving expression: '${basedir}': Detected the following recursive expression cycle in 'basedir': [basedir]",
-                collector.getErrors().get( 0 ) );
+                collector.getErrors().get(0));
     }
 
     @Test
-    public void shouldIgnorePropertiesWithPomPrefix() throws Exception
-    {
+    public void shouldIgnorePropertiesWithPomPrefix() throws Exception {
         final String orgName = "MyCo";
-        final String expectedName = "${pom.organization.name} Tools";
+        final String uninterpolatedName = "${pom.organization.name} Tools";
+        final String interpolatedName = uninterpolatedName;
 
-        Model model = new Model();
-        model.setName( expectedName );
-
-        Organization org = new Organization();
-        org.setName( orgName );
-
-        model.setOrganization( org );
+        Model model = Model.newBuilder()
+                .name(uninterpolatedName)
+                .organization(Organization.newBuilder().name(orgName).build())
+                .build();
 
         ModelInterpolator interpolator = createInterpolator();
         SimpleProblemCollector collector = new SimpleProblemCollector();
-        Model out = interpolator.interpolateModel( model, null, createModelBuildingRequest( context ),
-                collector );
+        Model out = interpolator.interpolateModel(
+                model,
+                null,
+                createModelBuildingRequest(context).setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_4_0),
+                collector);
 
-        assertCollectorState( 0, 0, 0, collector );
-        assertEquals( out.getName(), expectedName );
+        assertCollectorState(0, 0, 0, collector);
+        assertEquals(interpolatedName, out.getName());
+    }
+
+    @Test
+    public void shouldWarnPropertiesWithPomPrefix() throws Exception {
+        final String orgName = "MyCo";
+        final String uninterpolatedName = "${pom.organization.name} Tools";
+        final String interpolatedName = "MyCo Tools";
+
+        Model model = Model.newBuilder()
+                .name(uninterpolatedName)
+                .organization(Organization.newBuilder().name(orgName).build())
+                .build();
+
+        ModelInterpolator interpolator = createInterpolator();
+        SimpleProblemCollector collector = new SimpleProblemCollector();
+        Model out = interpolator.interpolateModel(
+                model,
+                null,
+                createModelBuildingRequest(context).setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_3_1),
+                collector);
+
+        assertCollectorState(0, 0, 1, collector);
+        assertEquals(interpolatedName, out.getName());
     }
 
     protected abstract ModelInterpolator createInterpolator() throws Exception;
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/MavenBuildTimestampTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/MavenBuildTimestampTest.java
index 73ea399..b72c1e1 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/MavenBuildTimestampTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/MavenBuildTimestampTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,23 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
 
 import java.util.Date;
-import java.util.Properties;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class MavenBuildTimestampTest
-{
+class MavenBuildTimestampTest {
     @Test
-    public void testMavenBuildTimestampUsesUTC()
-    {
-        Properties interpolationProperties = new Properties();
-        interpolationProperties.setProperty( "maven.build.timestamp.format", "yyyyMMdd'T'HHmm'Z'" );
-        MavenBuildTimestamp timestamp = new MavenBuildTimestamp( new Date(), interpolationProperties );
+    void testMavenBuildTimestampUsesUTC() {
+        Map<String, String> interpolationProperties = new HashMap<>();
+        interpolationProperties.put("maven.build.timestamp.format", "yyyyMMdd'T'HHmm'Z'");
+        MavenBuildTimestamp timestamp = new MavenBuildTimestamp(new Date(), interpolationProperties);
         String formattedTimestamp = timestamp.formattedTimestamp();
-        assertTrue( formattedTimestamp.endsWith( "Z" ), "We expect the UTC marker at the end of the timestamp." );
+        assertTrue(formattedTimestamp.endsWith("Z"), "We expect the UTC marker at the end of the timestamp.");
     }
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java
deleted file mode 100644
index cc2f297..0000000
--- a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringSearchModelInterpolatorTest.java
+++ /dev/null
@@ -1,618 +0,0 @@
-package org.apache.maven.model.interpolation;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-import java.lang.reflect.Field;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.Callable;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Future;
-import java.util.concurrent.FutureTask;
-
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.InputSource;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.building.DefaultModelBuildingRequest;
-import org.apache.maven.model.building.ModelBuildingRequest;
-import org.apache.maven.model.building.SimpleProblemCollector;
-import org.junit.jupiter.api.Test;
-
-import static org.hamcrest.CoreMatchers.anyOf;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-/**
- * StringSearchModelInterpolatorTest - not in use
- *
- * @author jdcasey
- * @author Benjamin Bentmann
- * @deprecated replaced by StringVisitorModelInterpolator (MNG-6697)
- */
-public class StringSearchModelInterpolatorTest
-    extends AbstractModelInterpolatorTest
-{
-    protected ModelInterpolator createInterpolator()
-    {
-        return new StringSearchModelInterpolator( null, null, new DefaultModelVersionProcessor() );
-    }
-
-    @Test
-    public void testInterpolateStringArray()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        String[] values = { "${key}", "${key2}" };
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest(p);
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( values, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "value", values[0] );
-        assertEquals( "value2", values[1] );
-    }
-
-    private ModelBuildingRequest createModelBuildingRequest( Properties p )
-    {
-        ModelBuildingRequest config = new DefaultModelBuildingRequest();
-        config.setSystemProperties( p );
-        return config;
-    }
-
-    @Test
-    public void testInterpolateObjectWithStringArrayField()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        String[] values = { "${key}", "${key2}" };
-
-        ObjectWithStringArrayField obj = new ObjectWithStringArrayField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "value", obj.values[0] );
-        assertEquals( "value2", obj.values[1] );
-    }
-
-    @Test
-    public void testInterpolateObjectWithStringListField()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        List<String> values = new ArrayList<>();
-        values.add( "${key}" );
-        values.add( "${key2}" );
-
-        ObjectWithListField obj = new ObjectWithListField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "value", obj.values.get( 0 ) );
-        assertEquals( "value2", obj.values.get( 1 ) );
-    }
-
-    @Test
-    public void testInterpolateObjectWithStringListFieldAndOneLiteralValue()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        List<String> values = new ArrayList<>();
-        values.add( "key" );
-        values.add( "${key2}" );
-
-        ObjectWithListField obj = new ObjectWithListField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "key", obj.values.get( 0 ) );
-        assertEquals( "value2", obj.values.get( 1 ) );
-    }
-
-    @Test
-    public void testInterpolateObjectWithUnmodifiableStringListField()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        List<String> values = Collections.unmodifiableList( Collections.singletonList( "${key}" ) );
-
-        ObjectWithListField obj = new ObjectWithListField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "${key}", obj.values.get( 0 ) );
-    }
-
-    @Test
-    public void testInterpolateObjectWithStringArrayListField()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-        p.setProperty( "key3", "value3" );
-        p.setProperty( "key4", "value4" );
-
-        List<String[]> values = new ArrayList<>();
-        values.add( new String[] { "${key}", "${key2}" } );
-        values.add( new String[] { "${key3}", "${key4}" } );
-
-        ObjectWithListField obj = new ObjectWithListField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "value", ( (String[]) obj.values.get( 0 ) )[0] );
-        assertEquals( "value2", ( (String[]) obj.values.get( 0 ) )[1] );
-        assertEquals( "value3", ( (String[]) obj.values.get( 1 ) )[0] );
-        assertEquals( "value4", ( (String[]) obj.values.get( 1 ) )[1] );
-    }
-
-    @Test
-    public void testInterpolateObjectWithStringToStringMapField()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        Map<String, String> values = new HashMap<>();
-        values.put( "key", "${key}" );
-        values.put( "key2", "${key2}" );
-
-        ObjectWithMapField obj = new ObjectWithMapField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "value", obj.values.get( "key" ) );
-        assertEquals( "value2", obj.values.get( "key2" ) );
-    }
-
-    @Test
-    public void testInterpolateObjectWithStringToStringMapFieldAndOneLiteralValue()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        Map<String, String> values = new HashMap<>();
-        values.put( "key", "val" );
-        values.put( "key2", "${key2}" );
-
-        ObjectWithMapField obj = new ObjectWithMapField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "val", obj.values.get( "key" ) );
-        assertEquals( "value2", obj.values.get( "key2" ) );
-    }
-
-    @Test
-    public void testInterpolateObjectWithUnmodifiableStringToStringMapField()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-
-        Map<String, String> values = Collections.unmodifiableMap( Collections.singletonMap( "key", "${key}" ) );
-
-        ObjectWithMapField obj = new ObjectWithMapField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "${key}", obj.values.get( "key" ) );
-    }
-
-    @Test
-    public void testInterpolateObjectWithStringToStringArrayMapField()
-    {
-        Model model = new Model();
-
-        Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-        p.setProperty( "key3", "value3" );
-        p.setProperty( "key4", "value4" );
-
-        Map<String, String[]> values = new HashMap<>();
-        values.put( "key", new String[] { "${key}", "${key2}" } );
-        values.put( "key2", new String[] { "${key3}", "${key4}" } );
-
-        ObjectWithMapField obj = new ObjectWithMapField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        final SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertEquals( "value", ( (String[]) obj.values.get( "key" ) )[0] );
-        assertEquals( "value2", ( (String[]) obj.values.get( "key" ) )[1] );
-        assertEquals( "value3", ( (String[]) obj.values.get( "key2" ) )[0] );
-        assertEquals( "value4", ( (String[]) obj.values.get( "key2" ) )[1] );
-    }
-
-    @Test
-    public void testInterpolateObjectWithPomFile()
-            throws Exception
-    {
-        Model model = new Model();
-        model.setPomFile( new File( System.getProperty( "user.dir" ), "pom.xml" ) );
-        File baseDir = model.getProjectDirectory();
-
-        Properties p = new Properties();
-
-        Map<String, String> values = new HashMap<>();
-        values.put( "key", "${project.basedir}" + File.separator + "target" );
-
-        ObjectWithMapField obj = new ObjectWithMapField( values );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        assertThat( baseDir.getAbsolutePath(), is( System.getProperty( "user.dir" ) ) );
-        assertThat( obj.values.size(), is( 1 ) );
-        assertThat( (String) obj.values.get( "key" ), is( anyOf(
-                is( System.getProperty( "user.dir" ) + File.separator + "target" ),
-                // TODO why MVN adds dot /./ in paths???
-                is( System.getProperty( "user.dir" ) + File.separator + '.' + File.separator + "target" )
-        ) ) );
-    }
-
-    @Test
-    public void testNotInterpolateObjectWithFile()
-            throws Exception
-    {
-        Model model = new Model();
-
-        File baseDir = new File( System.getProperty( "user.dir" ) );
-
-        Properties p = new Properties();
-
-        ObjectWithNotInterpolatedFile obj = new ObjectWithNotInterpolatedFile( baseDir );
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        Map<Class<?>, ?> cache = getCachedEntries();
-
-        Object objCacheItem = cache.get( Object.class );
-        Object fileCacheItem = cache.get( File.class );
-
-        assertNotNull( objCacheItem );
-        assertNotNull( fileCacheItem );
-
-        assertThat( readFieldsArray( objCacheItem ).length, is( 0 ) );
-        assertThat( readFieldsArray( fileCacheItem ).length, is( 0 ) );
-    }
-
-    private static Object[] readFieldsArray( Object o ) throws NoSuchFieldException, IllegalAccessException
-    {
-        assertNotNull( o );
-        Field field = o.getClass().getDeclaredField( "fields" );
-        field.setAccessible( true );
-        return (Object[]) field.get( o );
-    }
-
-    private static Map<Class<?>, ?> getCachedEntries() throws NoSuchFieldException, IllegalAccessException
-    {
-        Field field = StringSearchModelInterpolator.class.getDeclaredField( "CACHED_ENTRIES" );
-        field.setAccessible( true );
-        //noinspection unchecked
-        return (Map<Class<?>, ?>) field.get( null );
-    }
-
-    @Test
-    public void testNotInterpolateFile()
-            throws Exception
-    {
-        Model model = new Model();
-
-        File baseDir = new File( System.getProperty( "user.dir" ) );
-
-        Properties p = new Properties();
-
-        StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        ModelBuildingRequest config = createModelBuildingRequest( p );
-
-        SimpleProblemCollector collector = new SimpleProblemCollector();
-        interpolator.interpolateObject( baseDir, model, new File( "." ), config, collector );
-        assertProblemFree( collector );
-
-        Map<Class<?>, ?> cache = getCachedEntries();
-
-        Object fileCacheItem = cache.get( File.class );
-
-        assertNotNull( fileCacheItem );
-
-        assertThat( readFieldsArray( fileCacheItem ).length, is( 0 ) );
-    }
-
-
-    @Test
-    public void testConcurrentInterpolation()
-        throws Exception
-    {
-        final Model model = new Model();
-
-        final Properties p = new Properties();
-        p.setProperty( "key", "value" );
-        p.setProperty( "key2", "value2" );
-        p.setProperty( "key3", "value3" );
-        p.setProperty( "key4", "value4" );
-        p.setProperty( "key5", "value5" );
-
-        final StringSearchModelInterpolator interpolator = (StringSearchModelInterpolator) createInterpolator();
-
-        int numItems = 100;
-        final CountDownLatch countDownLatch = new CountDownLatch(1);
-
-        List<Future<SimpleProblemCollector>>  futures = new ArrayList<>();
-        for ( int i = 0; i < numItems; i++ )
-        {
-            Callable<SimpleProblemCollector> future = () ->
-            {
-                final ObjectWithMixedProtection obj = getValueList();
-                final ModelBuildingRequest config = createModelBuildingRequest( p );
-
-                countDownLatch.await();
-                final SimpleProblemCollector collector = new SimpleProblemCollector();
-                interpolator.interpolateObject( obj, model, new File( "." ), config, collector );
-                return collector;
-            };
-            FutureTask<SimpleProblemCollector> task = new FutureTask<>( future );
-            futures.add( task );
-            new Thread( task ).start();
-        }
-        countDownLatch.countDown(); // Start all the threads
-        for ( Future<SimpleProblemCollector> result : futures )
-        {
-            SimpleProblemCollector problemCollector = result.get(); // ArrayIndexOutOfBoundsException are typical indication of threading issues
-            assertProblemFree( problemCollector );
-        }
-    }
-
-    private ObjectWithMixedProtection getValueList()
-    {
-        List<String[]> values = new ArrayList<>();
-
-        values.add( new String[] { "${key}", "${key2}" } );
-        values.add( new String[] { "${key3}", "${key4}" } );
-        List<String> values2 = new ArrayList<>();
-        values.add( new String[] { "${key}", "${key2}" } );
-        values.add( new String[] { "${key3}", "${key4}" } );
-        List<String> values3 = new ArrayList<>();
-        values.add( new String[] { "${key}", "${key2}" } );
-        values.add( new String[] { "${key3}", "${key4}" } );
-
-        return new ObjectWithMixedProtection( values, values2, values3, "${key5}" );
-    }
-
-    private static final class ObjectWithStringArrayField
-    {
-        private final String[] values;
-
-        public ObjectWithStringArrayField( String[] values )
-        {
-            this.values = values;
-        }
-    }
-
-    private static final class ObjectWithListField
-    {
-        private final List<?> values;
-
-        public ObjectWithListField( List<?> values )
-        {
-            this.values = values;
-        }
-    }
-
-    private static final class ObjectWithMapField
-    {
-        private final Map<?, ?> values;
-
-        public ObjectWithMapField( Map<?, ?> values )
-        {
-            this.values = values;
-        }
-    }
-
-    private static final class ObjectWithNotInterpolatedFile
-    {
-        private final File f;
-
-        ObjectWithNotInterpolatedFile( File f )
-        {
-            this.f = f;
-        }
-    }
-
-    @SuppressWarnings( "unused" )
-    private static final class ObjectWithMixedProtection
-    {
-        private List<?> values1;
-        protected List<?> values2;
-        List<?> values3;
-        private String fooBar;
-
-        private ObjectWithMixedProtection( List<?> values1, List<?> values2, List<?> values3 )
-        {
-            this.values1 = values1;
-            this.values2 = values2;
-            this.values3 = values3;
-        }
-
-        private ObjectWithMixedProtection( List<?> values1, List<?> values2, List<?> values3, String fooBar )
-        {
-            this.values1 = values1;
-            this.values2 = values2;
-            this.values3 = values3;
-            this.fooBar = fooBar;
-        }
-
-        public String getFooBar()
-        {
-            return fooBar;
-        }
-    }
-
-    @Test
-    public void testFinalFieldsExcludedFromInterpolation()
-    {
-        Properties props = new Properties();
-        props.setProperty( "expression", "value" );
-        DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
-        request.setUserProperties( props );
-
-        SimpleProblemCollector problems = new SimpleProblemCollector();
-        StringSearchModelInterpolator interpolator =
-            new StringSearchModelInterpolator( null, null, new DefaultModelVersionProcessor() );
-        interpolator.interpolateObject( new ClassWithFinalField(), new Model(), null, request, problems );
-
-        assertProblemFree( problems );
-    }
-
-    static class ClassWithFinalField
-    {
-        public static final String CONSTANT = "${expression}";
-    }
-
-    @Test
-    public void locationTrackerShouldBeExcludedFromInterpolation()
-    {
-        Properties props = new Properties();
-        props.setProperty( "expression", "value" );
-        DefaultModelBuildingRequest request = new DefaultModelBuildingRequest();
-        request.setUserProperties( props );
-
-        InputSource source = new InputSource();
-        source.setLocation( "${expression}" );
-        source.setModelId( "${expression}" );
-        Model model = new Model();
-        model.setLocation( "", new InputLocation( 1, 1, source ) );
-
-        SimpleProblemCollector problems = new SimpleProblemCollector();
-        StringSearchModelInterpolator interpolator =
-            new StringSearchModelInterpolator( null, null, new DefaultModelVersionProcessor() );
-        interpolator.interpolateObject( model, model, null, request, problems );
-
-        assertProblemFree( problems );
-        assertEquals( "${expression}", source.getLocation() );
-        assertEquals( "${expression}", source.getModelId() );
-    }
-
-}
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolatorTest.java
index 8fa92ce..02ea9ba 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/StringVisitorModelInterpolatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.interpolation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.interpolation;
 
-public class StringVisitorModelInterpolatorTest extends AbstractModelInterpolatorTest
-{
-    protected ModelInterpolator createInterpolator()
-    {
-        return new StringVisitorModelInterpolator( null, null, new DefaultModelVersionProcessor() );
+public class StringVisitorModelInterpolatorTest extends AbstractModelInterpolatorTest {
+    protected ModelInterpolator createInterpolator() {
+        return new StringVisitorModelInterpolator(null, null, bd -> true);
     }
-}
\ No newline at end of file
+}
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/reflection/ReflectionValueExtractorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/reflection/ReflectionValueExtractorTest.java
new file mode 100644
index 0000000..1c960c8
--- /dev/null
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/interpolation/reflection/ReflectionValueExtractorTest.java
@@ -0,0 +1,574 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.interpolation.reflection;
+
+/*
+ * Copyright The Codehaus Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * ReflectionValueExtractorTest class.
+ */
+public class ReflectionValueExtractorTest {
+    private Project project;
+
+    /**
+     * <p>setUp.</p>
+     */
+    @BeforeEach
+    void setUp() {
+        Dependency dependency1 = new Dependency();
+        dependency1.setArtifactId("dep1");
+        Dependency dependency2 = new Dependency();
+        dependency2.setArtifactId("dep2");
+
+        project = new Project();
+        project.setModelVersion("4.0.0");
+        project.setGroupId("org.apache.maven");
+        project.setArtifactId("maven-core");
+        project.setName("Maven");
+        project.setVersion("2.0-SNAPSHOT");
+        project.setScm(new Scm());
+        project.getScm().setConnection("scm-connection");
+        project.addDependency(dependency1);
+        project.addDependency(dependency2);
+        project.setBuild(new Build());
+
+        // Build up an artifactMap
+        project.addArtifact(new Artifact("g0", "a0", "v0", "e0", "c0"));
+        project.addArtifact(new Artifact("g1", "a1", "v1", "e1", "c1"));
+        project.addArtifact(new Artifact("g2", "a2", "v2", "e2", "c2"));
+    }
+
+    /**
+     * <p>testValueExtraction.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    void testValueExtraction() throws Exception {
+        // ----------------------------------------------------------------------
+        // Top level values
+        // ----------------------------------------------------------------------
+
+        assertEquals("4.0.0", ReflectionValueExtractor.evaluate("project.modelVersion", project));
+
+        assertEquals("org.apache.maven", ReflectionValueExtractor.evaluate("project.groupId", project));
+
+        assertEquals("maven-core", ReflectionValueExtractor.evaluate("project.artifactId", project));
+
+        assertEquals("Maven", ReflectionValueExtractor.evaluate("project.name", project));
+
+        assertEquals("2.0-SNAPSHOT", ReflectionValueExtractor.evaluate("project.version", project));
+
+        // ----------------------------------------------------------------------
+        // SCM
+        // ----------------------------------------------------------------------
+
+        assertEquals("scm-connection", ReflectionValueExtractor.evaluate("project.scm.connection", project));
+
+        // ----------------------------------------------------------------------
+        // Dependencies
+        // ----------------------------------------------------------------------
+
+        List<?> dependencies = (List) ReflectionValueExtractor.evaluate("project.dependencies", project);
+
+        assertNotNull(dependencies);
+
+        assertEquals(2, dependencies.size());
+
+        // ----------------------------------------------------------------------
+        // Dependencies - using index notation
+        // ----------------------------------------------------------------------
+
+        // List
+        Dependency dependency = (Dependency) ReflectionValueExtractor.evaluate("project.dependencies[0]", project);
+
+        assertNotNull(dependency);
+
+        assertEquals("dep1", dependency.getArtifactId());
+
+        String artifactId = (String) ReflectionValueExtractor.evaluate("project.dependencies[1].artifactId", project);
+
+        assertEquals("dep2", artifactId);
+
+        // Array
+
+        dependency = (Dependency) ReflectionValueExtractor.evaluate("project.dependenciesAsArray[0]", project);
+
+        assertNotNull(dependency);
+
+        assertEquals("dep1", dependency.getArtifactId());
+
+        artifactId = (String) ReflectionValueExtractor.evaluate("project.dependenciesAsArray[1].artifactId", project);
+
+        assertEquals("dep2", artifactId);
+
+        // Map
+
+        dependency = (Dependency) ReflectionValueExtractor.evaluate("project.dependenciesAsMap(dep1)", project);
+
+        assertNotNull(dependency);
+
+        assertEquals("dep1", dependency.getArtifactId());
+
+        artifactId = (String) ReflectionValueExtractor.evaluate("project.dependenciesAsMap(dep2).artifactId", project);
+
+        assertEquals("dep2", artifactId);
+
+        // ----------------------------------------------------------------------
+        // Build
+        // ----------------------------------------------------------------------
+
+        Build build = (Build) ReflectionValueExtractor.evaluate("project.build", project);
+
+        assertNotNull(build);
+    }
+
+    /**
+     * <p>testValueExtractorWithAInvalidExpression.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testValueExtractorWithAInvalidExpression() throws Exception {
+        assertNull(ReflectionValueExtractor.evaluate("project.foo", project));
+        assertNull(ReflectionValueExtractor.evaluate("project.dependencies[10]", project));
+        assertNull(ReflectionValueExtractor.evaluate("project.dependencies[0].foo", project));
+    }
+
+    /**
+     * <p>testMappedDottedKey.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testMappedDottedKey() throws Exception {
+        Map<String, String> map = new HashMap<String, String>();
+        map.put("a.b", "a.b-value");
+
+        assertEquals("a.b-value", ReflectionValueExtractor.evaluate("h.value(a.b)", new ValueHolder(map)));
+    }
+
+    /**
+     * <p>testIndexedMapped.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testIndexedMapped() throws Exception {
+        Map<Object, Object> map = new HashMap<Object, Object>();
+        map.put("a", "a-value");
+        List<Object> list = new ArrayList<Object>();
+        list.add(map);
+
+        assertEquals("a-value", ReflectionValueExtractor.evaluate("h.value[0](a)", new ValueHolder(list)));
+    }
+
+    /**
+     * <p>testMappedIndexed.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testMappedIndexed() throws Exception {
+        List<Object> list = new ArrayList<Object>();
+        list.add("a-value");
+        Map<Object, Object> map = new HashMap<Object, Object>();
+        map.put("a", list);
+        assertEquals("a-value", ReflectionValueExtractor.evaluate("h.value(a)[0]", new ValueHolder(map)));
+    }
+
+    /**
+     * <p>testMappedMissingDot.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testMappedMissingDot() throws Exception {
+        Map<Object, Object> map = new HashMap<Object, Object>();
+        map.put("a", new ValueHolder("a-value"));
+        assertNull(ReflectionValueExtractor.evaluate("h.value(a)value", new ValueHolder(map)));
+    }
+
+    /**
+     * <p>testIndexedMissingDot.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testIndexedMissingDot() throws Exception {
+        List<Object> list = new ArrayList<Object>();
+        list.add(new ValueHolder("a-value"));
+        assertNull(ReflectionValueExtractor.evaluate("h.value[0]value", new ValueHolder(list)));
+    }
+
+    /**
+     * <p>testDotDot.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testDotDot() throws Exception {
+        assertNull(ReflectionValueExtractor.evaluate("h..value", new ValueHolder("value")));
+    }
+
+    /**
+     * <p>testBadIndexedSyntax.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testBadIndexedSyntax() throws Exception {
+        List<Object> list = new ArrayList<Object>();
+        list.add("a-value");
+        Object value = new ValueHolder(list);
+
+        assertNull(ReflectionValueExtractor.evaluate("h.value[", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value[]", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value[a]", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value[0", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value[0)", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value[-1]", value));
+    }
+
+    /**
+     * <p>testBadMappedSyntax.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testBadMappedSyntax() throws Exception {
+        Map<Object, Object> map = new HashMap<Object, Object>();
+        map.put("a", "a-value");
+        Object value = new ValueHolder(map);
+
+        assertNull(ReflectionValueExtractor.evaluate("h.value(", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value()", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value(a", value));
+        assertNull(ReflectionValueExtractor.evaluate("h.value(a]", value));
+    }
+
+    /**
+     * <p>testIllegalIndexedType.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testIllegalIndexedType() throws Exception {
+        try {
+            ReflectionValueExtractor.evaluate("h.value[1]", new ValueHolder("string"));
+        } catch (Exception e) {
+            // TODO assert exception message
+        }
+    }
+
+    /**
+     * <p>testIllegalMappedType.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testIllegalMappedType() throws Exception {
+        try {
+            ReflectionValueExtractor.evaluate("h.value(key)", new ValueHolder("string"));
+        } catch (Exception e) {
+            // TODO assert exception message
+        }
+    }
+
+    /**
+     * <p>testTrimRootToken.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testTrimRootToken() throws Exception {
+        assertNull(ReflectionValueExtractor.evaluate("project", project, true));
+    }
+
+    /**
+     * <p>testArtifactMap.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testArtifactMap() throws Exception {
+        assertEquals(
+                "g0",
+                ((Artifact) ReflectionValueExtractor.evaluate("project.artifactMap(g0:a0:c0)", project)).getGroupId());
+        assertEquals(
+                "a1",
+                ((Artifact) ReflectionValueExtractor.evaluate("project.artifactMap(g1:a1:c1)", project))
+                        .getArtifactId());
+        assertEquals(
+                "c2",
+                ((Artifact) ReflectionValueExtractor.evaluate("project.artifactMap(g2:a2:c2)", project))
+                        .getClassifier());
+    }
+
+    public static class Artifact {
+        private String groupId;
+
+        private String artifactId;
+
+        private String version;
+
+        private String extension;
+
+        private String classifier;
+
+        public Artifact(String groupId, String artifactId, String version, String extension, String classifier) {
+            this.groupId = groupId;
+            this.artifactId = artifactId;
+            this.version = version;
+            this.extension = extension;
+            this.classifier = classifier;
+        }
+
+        public String getGroupId() {
+            return groupId;
+        }
+
+        public void setGroupId(String groupId) {
+            this.groupId = groupId;
+        }
+
+        public String getArtifactId() {
+            return artifactId;
+        }
+
+        public void setArtifactId(String artifactId) {
+            this.artifactId = artifactId;
+        }
+
+        public String getVersion() {
+            return version;
+        }
+
+        public void setVersion(String version) {
+            this.version = version;
+        }
+
+        public String getExtension() {
+            return extension;
+        }
+
+        public void setExtension(String extension) {
+            this.extension = extension;
+        }
+
+        public String getClassifier() {
+            return classifier;
+        }
+
+        public void setClassifier(String classifier) {
+            this.classifier = classifier;
+        }
+    }
+
+    public static class Project {
+        private String modelVersion;
+
+        private String groupId;
+
+        private Scm scm;
+
+        private List<Dependency> dependencies = new ArrayList<>();
+
+        private Build build;
+
+        private String artifactId;
+
+        private String name;
+
+        private String version;
+
+        private Map<String, Artifact> artifactMap = new HashMap<>();
+        private String description;
+
+        public void setModelVersion(String modelVersion) {
+            this.modelVersion = modelVersion;
+        }
+
+        public void setGroupId(String groupId) {
+            this.groupId = groupId;
+        }
+
+        public void setScm(Scm scm) {
+            this.scm = scm;
+        }
+
+        public void addDependency(Dependency dependency) {
+            this.dependencies.add(dependency);
+        }
+
+        public void setBuild(Build build) {
+            this.build = build;
+        }
+
+        public void setArtifactId(String artifactId) {
+            this.artifactId = artifactId;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public void setVersion(String version) {
+            this.version = version;
+        }
+
+        public Scm getScm() {
+            return scm;
+        }
+
+        public String getModelVersion() {
+            return modelVersion;
+        }
+
+        public String getGroupId() {
+            return groupId;
+        }
+
+        public List<Dependency> getDependencies() {
+            return dependencies;
+        }
+
+        public Build getBuild() {
+            return build;
+        }
+
+        public String getArtifactId() {
+            return artifactId;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public String getVersion() {
+            return version;
+        }
+
+        public Dependency[] getDependenciesAsArray() {
+            return getDependencies().toArray(new Dependency[0]);
+        }
+
+        public Map<String, Dependency> getDependenciesAsMap() {
+            Map<String, Dependency> ret = new HashMap<>();
+            for (Dependency dep : getDependencies()) {
+                ret.put(dep.getArtifactId(), dep);
+            }
+            return ret;
+        }
+
+        // ${project.artifactMap(g:a:v)}
+        public void addArtifact(Artifact a) {
+            artifactMap.put(a.getGroupId() + ":" + a.getArtifactId() + ":" + a.getClassifier(), a);
+        }
+
+        public Map<String, Artifact> getArtifactMap() {
+            return artifactMap;
+        }
+
+        public void setDescription(String description) {
+            this.description = description;
+        }
+
+        public String getDescription() {
+            return description;
+        }
+    }
+
+    public static class Build {}
+
+    public static class Dependency {
+        private String artifactId;
+
+        public String getArtifactId() {
+            return artifactId;
+        }
+
+        public void setArtifactId(String id) {
+            artifactId = id;
+        }
+    }
+
+    public static class Scm {
+        private String connection;
+
+        public void setConnection(String connection) {
+            this.connection = connection;
+        }
+
+        public String getConnection() {
+            return connection;
+        }
+    }
+
+    public static class ValueHolder {
+        private final Object value;
+
+        public ValueHolder(Object value) {
+            this.value = value;
+        }
+
+        public Object getValue() {
+            return value;
+        }
+    }
+
+    /**
+     * <p>testRootPropertyRegression.</p>
+     *
+     * @throws Exception if any.
+     */
+    @Test
+    public void testRootPropertyRegression() throws Exception {
+        Project project = new Project();
+        project.setDescription("c:\\\\org\\apache\\test");
+        Object evalued = ReflectionValueExtractor.evaluate("description", project);
+        assertNotNull(evalued);
+    }
+}
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/merge/MavenModelMergerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/merge/MavenModelMergerTest.java
index 636f3fb..8e0b2be 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/merge/MavenModelMergerTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/merge/MavenModelMergerTest.java
@@ -1,6 +1,3 @@
-package org.apache.maven.model.merge;
-
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -10,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -19,83 +16,86 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.merge;
 
 import java.util.Collections;
 
-import org.apache.maven.model.Model;
-import org.apache.maven.model.Prerequisites;
-import org.apache.maven.model.Profile;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Prerequisites;
+import org.apache.maven.api.model.Profile;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 
-public class MavenModelMergerTest
-{
+class MavenModelMergerTest {
     private MavenModelMerger modelMerger = new MavenModelMerger();
 
     // modelVersion is neither inherited nor injected
     @Test
-    public void testMergeModel_ModelVersion()
-    {
-        Model parent = new Model();
-        parent.setModelVersion( "4.0.0" );
-        Model model = new Model();
-        modelMerger.mergeModel_ModelVersion( model, parent, false, null );
-        assertNull( model.getModelVersion() );
+    void testMergeModel_ModelVersion() {
+        Model parent = Model.newBuilder().modelVersion("4.0.0").build();
+        Model model = Model.newInstance();
+        Model.Builder builder = Model.newBuilder(model);
+        modelMerger.mergeModel_ModelVersion(builder, model, parent, false, null);
+        assertNull(builder.build().getModelVersion());
 
-        model.setModelVersion( "5.0.0" );
-        modelMerger.mergeModel_ModelVersion( model, parent, false, null );
-        assertEquals( "5.0.0", model.getModelVersion() );
+        model = Model.newBuilder().modelVersion("5.0.0").build();
+        builder = Model.newBuilder(model);
+        modelMerger.mergeModel_ModelVersion(builder, model, parent, false, null);
+        assertEquals("5.0.0", builder.build().getModelVersion());
     }
 
     // ArtifactId is neither inherited nor injected
     @Test
-    public void testMergeModel_ArtifactId()
-    {
-        Model parent = new Model();
-        parent.setArtifactId( "PARENT" );
-        Model model = new Model();
-        modelMerger.mergeModel_ArtifactId( model, parent, false, null );
-        assertNull( model.getArtifactId() );
+    void testMergeModel_ArtifactId() {
+        Model parent = Model.newBuilder().artifactId("PARENT").build();
+        Model model = Model.newInstance();
+        Model.Builder builder = Model.newBuilder(model);
+        modelMerger.mergeModel_ArtifactId(builder, model, parent, false, null);
+        assertNull(model.getArtifactId());
 
-        model.setArtifactId( "MODEL" );
-        modelMerger.mergeModel_ArtifactId( model, parent, false, null );
-        assertEquals( "MODEL", model.getArtifactId() );
+        model = Model.newBuilder().artifactId("MODEL").build();
+        builder = Model.newBuilder(model);
+        modelMerger.mergeModel_ArtifactId(builder, model, parent, false, null);
+        assertEquals("MODEL", builder.build().getArtifactId());
     }
 
     // Prerequisites are neither inherited nor injected
     @Test
-    public void testMergeModel_Prerequisites()
-    {
-        Model parent = new Model();
-        parent.setPrerequisites( new Prerequisites() );
-        Model model = new Model();
-        modelMerger.mergeModel_Prerequisites( model, parent, false, null );
-        assertNull( model.getPrerequisites() );
+    void testMergeModel_Prerequisites() {
+        Model parent =
+                Model.newBuilder().prerequisites(Prerequisites.newInstance()).build();
+        Model model = Model.newInstance();
+        Model.Builder builder = Model.newBuilder(model);
+        modelMerger.mergeModel_Prerequisites(builder, model, parent, false, null);
+        assertNull(builder.build().getPrerequisites());
 
-        Prerequisites modelPrerequisites = new Prerequisites();
-        modelPrerequisites.setMaven( "3.0" );
-        model.setPrerequisites( modelPrerequisites );
-        modelMerger.mergeModel_Prerequisites( model, parent, false, null );
-        assertEquals( modelPrerequisites, model.getPrerequisites() );
+        Prerequisites modelPrerequisites =
+                Prerequisites.newBuilder().maven("3.0").build();
+        model = Model.newBuilder().prerequisites(modelPrerequisites).build();
+        builder = Model.newBuilder(model);
+        modelMerger.mergeModel_Prerequisites(builder, model, parent, false, null);
+        assertEquals(modelPrerequisites, builder.build().getPrerequisites());
     }
 
     // Profiles are neither inherited nor injected
     @Test
-    public void testMergeModel_Profiles()
-    {
-        Model parent = new Model();
-        parent.setProfiles( Collections.singletonList( new Profile() ) );;
-        Model model = new Model();
-        modelMerger.mergeModel_Profiles( model, parent, false, null );
-        assertEquals( 0, model.getProfiles().size() );
+    void testMergeModel_Profiles() {
+        Model parent = Model.newBuilder()
+                .profiles(Collections.singletonList(Profile.newInstance()))
+                .build();
+        Model model = Model.newInstance();
+        Model.Builder builder = Model.newBuilder(model);
+        modelMerger.mergeModel_Profiles(builder, model, parent, false, null);
+        assertEquals(0, builder.build().getProfiles().size());
 
-        Profile modelProfile = new Profile();
-        modelProfile.setId( "MODEL" );
-        model.setProfiles( Collections.singletonList( modelProfile ) );
-        modelMerger.mergeModel_Prerequisites( model, parent, false, null );
-        assertEquals( Collections.singletonList( modelProfile ), model.getProfiles() );
+        Profile modelProfile = Profile.newBuilder().id("MODEL").build();
+        model = Model.newBuilder()
+                .profiles(Collections.singletonList(modelProfile))
+                .build();
+        builder = Model.newBuilder(model);
+        modelMerger.mergeModel_Prerequisites(builder, model, parent, false, null);
+        assertEquals(Collections.singletonList(modelProfile), builder.build().getProfiles());
     }
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/path/DefaultUrlNormalizerTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/path/DefaultUrlNormalizerTest.java
index 010abe0..cffd9c3 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/path/DefaultUrlNormalizerTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/path/DefaultUrlNormalizerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.path;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.path;
 
 import org.junit.jupiter.api.Test;
 
@@ -25,66 +24,57 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 
 /**
- * @author Benjamin Bentmann
  */
-public class DefaultUrlNormalizerTest
-{
+class DefaultUrlNormalizerTest {
 
     private UrlNormalizer normalizer = new DefaultUrlNormalizer();
 
-    private String normalize( String url )
-    {
-        return normalizer.normalize( url );
+    private String normalize(String url) {
+        return normalizer.normalize(url);
     }
 
     @Test
-    public void testNullSafe()
-    {
-        assertNull( normalize( null ) );
+    void testNullSafe() {
+        assertNull(normalize(null));
     }
 
     @Test
-    public void testTrailingSlash()
-    {
-        assertEquals( "", normalize( "" ) );
-        assertEquals( "http://server.org/dir", normalize( "http://server.org/dir" ) );
-        assertEquals( "http://server.org/dir/", normalize( "http://server.org/dir/" ) );
+    void testTrailingSlash() {
+        assertEquals("", normalize(""));
+        assertEquals("http://server.org/dir", normalize("http://server.org/dir"));
+        assertEquals("http://server.org/dir/", normalize("http://server.org/dir/"));
     }
 
     @Test
-    public void testRemovalOfParentRefs()
-    {
-        assertEquals( "http://server.org/child", normalize( "http://server.org/parent/../child" ) );
-        assertEquals( "http://server.org/child", normalize( "http://server.org/grand/parent/../../child" ) );
+    void testRemovalOfParentRefs() {
+        assertEquals("http://server.org/child", normalize("http://server.org/parent/../child"));
+        assertEquals("http://server.org/child", normalize("http://server.org/grand/parent/../../child"));
 
-        assertEquals( "http://server.org//child", normalize( "http://server.org/parent/..//child" ) );
-        assertEquals( "http://server.org/child", normalize( "http://server.org/parent//../child" ) );
+        assertEquals("http://server.org//child", normalize("http://server.org/parent/..//child"));
+        assertEquals("http://server.org/child", normalize("http://server.org/parent//../child"));
     }
 
     @Test
-    public void testPreservationOfDoubleSlashes()
-    {
-        assertEquals( "scm:hg:ssh://localhost//home/user", normalize( "scm:hg:ssh://localhost//home/user" ) );
-        assertEquals( "file:////UNC/server", normalize( "file:////UNC/server" ) );
-        assertEquals( "[fetch=]http://server.org/[push=]ssh://server.org/",
-                      normalize( "[fetch=]http://server.org/[push=]ssh://server.org/" ) );
+    void testPreservationOfDoubleSlashes() {
+        assertEquals("scm:hg:ssh://localhost//home/user", normalize("scm:hg:ssh://localhost//home/user"));
+        assertEquals("file:////UNC/server", normalize("file:////UNC/server"));
+        assertEquals(
+                "[fetch=]http://server.org/[push=]ssh://server.org/",
+                normalize("[fetch=]http://server.org/[push=]ssh://server.org/"));
     }
 
     @Test
-    public void absolutePathTraversalPastRootIsOmitted()
-    {
-        assertEquals( "/", normalize("/../" ) );
+    void absolutePathTraversalPastRootIsOmitted() {
+        assertEquals("/", normalize("/../"));
     }
 
     @Test
-    public void parentDirectoryRemovedFromRelativeUriReference()
-    {
-        assertEquals( "", normalize( "a/../" ) );
+    void parentDirectoryRemovedFromRelativeUriReference() {
+        assertEquals("", normalize("a/../"));
     }
 
     @Test
-    public void leadingParentDirectoryNotRemovedFromRelativeUriReference()
-    {
-        assertEquals( "../", normalize( "../" ) );
+    void leadingParentDirectoryNotRemovedFromRelativeUriReference() {
+        assertEquals("../", normalize("../"));
     }
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/AbstractProfileActivatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/AbstractProfileActivatorTest.java
index 6140fc5..a706a1e 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/AbstractProfileActivatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/AbstractProfileActivatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,10 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile.activation;
 
 import java.util.Properties;
 
-import org.apache.maven.model.Profile;
+import org.apache.maven.api.model.Profile;
 import org.apache.maven.model.building.SimpleProblemCollector;
 import org.apache.maven.model.profile.DefaultProfileActivationContext;
 import org.apache.maven.model.profile.ProfileActivationContext;
@@ -33,10 +32,8 @@
 /**
  * Provides common services to test {@link ProfileActivator} implementations.
  *
- * @author Benjamin Bentmann
  */
-public abstract class AbstractProfileActivatorTest<T extends ProfileActivator>
-{
+public abstract class AbstractProfileActivatorTest<T extends ProfileActivator> {
 
     protected T activator;
 
@@ -44,25 +41,21 @@
     abstract void setUp() throws Exception;
 
     @AfterEach
-    void tearDown() throws Exception
-    {
+    void tearDown() throws Exception {
         activator = null;
     }
 
-    protected ProfileActivationContext newContext( final Properties userProperties, final Properties systemProperties )
-    {
+    protected ProfileActivationContext newContext(final Properties userProperties, final Properties systemProperties) {
         DefaultProfileActivationContext context = new DefaultProfileActivationContext();
-        return context.setUserProperties( userProperties ).setSystemProperties( systemProperties );
+        return context.setUserProperties(userProperties).setSystemProperties(systemProperties);
     }
 
-    protected void assertActivation( boolean active, Profile profile, ProfileActivationContext context )
-    {
+    protected void assertActivation(boolean active, Profile profile, ProfileActivationContext context) {
         SimpleProblemCollector problems = new SimpleProblemCollector();
 
-        assertEquals( active, activator.isActive( profile, context, problems ) );
+        assertEquals(active, activator.isActive(new org.apache.maven.model.Profile(profile), context, problems));
 
-        assertEquals( 0, problems.getErrors().size(), problems.getErrors().toString() );
-        assertEquals( 0, problems.getWarnings().size(), problems.getWarnings().toString() );
+        assertEquals(0, problems.getErrors().size(), problems.getErrors().toString());
+        assertEquals(0, problems.getWarnings().size(), problems.getWarnings().toString());
     }
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.java
index 300fc13..56447be 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/FileProfileActivatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,30 +16,31 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.model.Activation;
-import org.apache.maven.model.ActivationFile;
-import org.apache.maven.model.Profile;
-import org.apache.maven.model.path.DefaultPathTranslator;
-import org.apache.maven.model.path.ProfileActivationFilePathInterpolator;
-import org.apache.maven.model.profile.DefaultProfileActivationContext;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
+package org.apache.maven.model.profile.activation;
 
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Path;
 
+import org.apache.maven.api.model.Activation;
+import org.apache.maven.api.model.ActivationFile;
+import org.apache.maven.api.model.Profile;
+import org.apache.maven.model.path.DefaultPathTranslator;
+import org.apache.maven.model.path.ProfileActivationFilePathInterpolator;
+import org.apache.maven.model.profile.DefaultProfileActivationContext;
+import org.apache.maven.model.root.RootLocator;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 /**
  * Tests {@link FileProfileActivator}.
  *
- * @author Ravil Galeyev
  */
-public class FileProfileActivatorTest extends AbstractProfileActivatorTest<FileProfileActivator>
-{
+class FileProfileActivatorTest extends AbstractProfileActivatorTest<FileProfileActivator> {
 
     @TempDir
     Path tempDir;
@@ -50,76 +49,84 @@
 
     @BeforeEach
     @Override
-    void setUp() throws Exception
-    {
-        activator = new FileProfileActivator( new ProfileActivationFilePathInterpolator( new DefaultPathTranslator() ) );
+    void setUp() throws Exception {
+        activator = new FileProfileActivator(
+                new ProfileActivationFilePathInterpolator(new DefaultPathTranslator(), bd -> true));
 
-        context.setProjectDirectory( new File( tempDir.toString() ) );
+        context.setProjectDirectory(tempDir.toFile());
 
-        File file = new File( tempDir.resolve( "file.txt" ).toString() );
-        if ( !file.createNewFile() )
-        {
-            throw new IOException( "Can't create " + file );
+        File file = new File(tempDir.resolve("file.txt").toString());
+        if (!file.createNewFile()) {
+            throw new IOException("Can't create " + file);
         }
     }
 
     @Test
-    public void testIsActiveNoFile()
-    {
-        assertActivation( false, newExistsProfile( null ), context );
-        assertActivation( false, newExistsProfile( "someFile.txt" ), context );
-        assertActivation( false, newExistsProfile( "${basedir}/someFile.txt" ), context );
+    void testRootDirectoryWithNull() {
+        context.setProjectDirectory(null);
 
-        assertActivation( false, newMissingProfile( null ), context );
-        assertActivation( true, newMissingProfile( "someFile.txt" ), context );
-        assertActivation( true, newMissingProfile( "${basedir}/someFile.txt" ), context );
+        IllegalStateException e = assertThrows(
+                IllegalStateException.class,
+                () -> assertActivation(false, newExistsProfile("${rootDirectory}"), context));
+        assertEquals(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE, e.getMessage());
     }
 
     @Test
-    public void testIsActiveExistsFileExists()
-    {
-        assertActivation( true, newExistsProfile( "file.txt" ), context );
-        assertActivation( true, newExistsProfile( "${basedir}" ), context );
-        assertActivation( true, newExistsProfile( "${basedir}/" + "file.txt" ), context );
-
-        assertActivation( false, newMissingProfile( "file.txt" ), context );
-        assertActivation( false, newMissingProfile( "${basedir}" ), context );
-        assertActivation( false, newMissingProfile( "${basedir}/" + "file.txt" ), context );
+    void testRootDirectory() {
+        assertActivation(false, newExistsProfile("${rootDirectory}/someFile.txt"), context);
+        assertActivation(true, newMissingProfile("${rootDirectory}/someFile.txt"), context);
+        assertActivation(true, newExistsProfile("${rootDirectory}"), context);
+        assertActivation(true, newExistsProfile("${rootDirectory}/" + "file.txt"), context);
+        assertActivation(false, newMissingProfile("${rootDirectory}"), context);
+        assertActivation(false, newMissingProfile("${rootDirectory}/" + "file.txt"), context);
     }
 
     @Test
-    public void testIsActiveExistsLeavesFileUnchanged()
-    {
-        Profile profile = newExistsProfile( "file.txt" );
-        assertEquals( "file.txt", profile.getActivation().getFile().getExists() );
+    void testIsActiveNoFile() {
+        assertActivation(false, newExistsProfile(null), context);
+        assertActivation(false, newExistsProfile("someFile.txt"), context);
+        assertActivation(false, newExistsProfile("${basedir}/someFile.txt"), context);
 
-        assertActivation( true, profile, context );
-
-        assertEquals( "file.txt", profile.getActivation().getFile().getExists() );
+        assertActivation(false, newMissingProfile(null), context);
+        assertActivation(true, newMissingProfile("someFile.txt"), context);
+        assertActivation(true, newMissingProfile("${basedir}/someFile.txt"), context);
     }
 
-    private Profile newExistsProfile( String filePath )
-    {
-        ActivationFile activationFile = new ActivationFile();
-        activationFile.setExists( filePath );
-        return newProfile( activationFile );
+    @Test
+    void testIsActiveExistsFileExists() {
+        assertActivation(true, newExistsProfile("file.txt"), context);
+        assertActivation(true, newExistsProfile("${basedir}"), context);
+        assertActivation(true, newExistsProfile("${basedir}/" + "file.txt"), context);
+
+        assertActivation(false, newMissingProfile("file.txt"), context);
+        assertActivation(false, newMissingProfile("${basedir}"), context);
+        assertActivation(false, newMissingProfile("${basedir}/" + "file.txt"), context);
     }
 
-    private Profile newMissingProfile( String filePath )
-    {
-        ActivationFile activationFile = new ActivationFile();
-        activationFile.setMissing( filePath );
-        return newProfile( activationFile );
+    @Test
+    void testIsActiveExistsLeavesFileUnchanged() {
+        Profile profile = newExistsProfile("file.txt");
+        assertEquals("file.txt", profile.getActivation().getFile().getExists());
+
+        assertActivation(true, profile, context);
+
+        assertEquals("file.txt", profile.getActivation().getFile().getExists());
     }
 
-    private Profile newProfile( ActivationFile activationFile )
-    {
-        Activation activation = new Activation();
-        activation.setFile( activationFile );
+    private Profile newExistsProfile(String filePath) {
+        ActivationFile activationFile =
+                ActivationFile.newBuilder().exists(filePath).build();
+        return newProfile(activationFile);
+    }
 
-        Profile profile = new Profile();
-        profile.setActivation( activation );
+    private Profile newMissingProfile(String filePath) {
+        ActivationFile activationFile =
+                ActivationFile.newBuilder().missing(filePath).build();
+        return newProfile(activationFile);
+    }
 
-        return profile;
+    private Profile newProfile(ActivationFile activationFile) {
+        Activation activation = Activation.newBuilder().file(activationFile).build();
+        return Profile.newBuilder().activation(activation).build();
     }
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivatorTest.java
index ce57bf0..74d6f19 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/JdkVersionProfileActivatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,179 +16,157 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile.activation;
 
 import java.util.Properties;
 
-import org.apache.maven.model.Activation;
-import org.apache.maven.model.Profile;
+import org.apache.maven.api.model.Activation;
+import org.apache.maven.api.model.Profile;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 /**
  * Tests {@link JdkVersionProfileActivator}.
  *
- * @author Benjamin Bentmann
  */
-public class JdkVersionProfileActivatorTest
-    extends AbstractProfileActivatorTest<JdkVersionProfileActivator>
-{
+class JdkVersionProfileActivatorTest extends AbstractProfileActivatorTest<JdkVersionProfileActivator> {
 
     @Override
     @BeforeEach
-    void setUp() throws Exception
-    {
+    void setUp() throws Exception {
         activator = new JdkVersionProfileActivator();
     }
 
-    private Profile newProfile(String jdkVersion )
-    {
-        Activation a = new Activation();
-        a.setJdk( jdkVersion );
+    private Profile newProfile(String jdkVersion) {
+        Activation a = Activation.newBuilder().jdk(jdkVersion).build();
 
-        Profile p = new Profile();
-        p.setActivation( a );
+        Profile p = Profile.newBuilder().activation(a).build();
 
         return p;
     }
 
-    private Properties newProperties( String javaVersion )
-    {
+    private Properties newProperties(String javaVersion) {
         Properties props = new Properties();
-        props.setProperty( "java.version", javaVersion );
+        props.setProperty("java.version", javaVersion);
         return props;
     }
 
     @Test
-    public void testNullSafe()
-        throws Exception
-    {
-        Profile p = new Profile();
+    void testNullSafe() throws Exception {
+        Profile p = Profile.newInstance();
 
-        assertActivation( false, p, newContext( null, null ) );
+        assertActivation(false, p, newContext(null, null));
 
-        p.setActivation( new Activation() );
+        p = p.withActivation(Activation.newInstance());
 
-        assertActivation( false, p, newContext( null, null ) );
+        assertActivation(false, p, newContext(null, null));
     }
 
     @Test
-    public void testPrefix()
-        throws Exception
-    {
-        Profile profile = newProfile( "1.4" );
+    void testPrefix() throws Exception {
+        Profile profile = newProfile("1.4");
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.4" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.4.2" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.4.2_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.4.2_09-b03" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.4")));
+        assertActivation(true, profile, newContext(null, newProperties("1.4.2")));
+        assertActivation(true, profile, newContext(null, newProperties("1.4.2_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.4.2_09-b03")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.3" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.3")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.5" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.5")));
     }
 
     @Test
-    public void testPrefixNegated()
-        throws Exception
-    {
-        Profile profile = newProfile( "!1.4" );
+    void testPrefixNegated() throws Exception {
+        Profile profile = newProfile("!1.4");
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.4" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2_09" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2_09-b03" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.4")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2_09")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2_09-b03")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.3" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.3")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.5" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.5")));
     }
 
     @Test
-    public void testVersionRangeInclusiveBounds()
-        throws Exception
-    {
-        Profile profile = newProfile( "[1.5,1.6]" );
+    void testVersionRangeInclusiveBounds() throws Exception {
+        Profile profile = newProfile("[1.5,1.6]");
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.4" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2_09" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2_09-b03" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.4")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2_09")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2_09-b03")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.5" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09-b03" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.1" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.5")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09-b03")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.1")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.6" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.6.0" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.6.0_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.6.0_09-b03" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.6")));
+        assertActivation(true, profile, newContext(null, newProperties("1.6.0")));
+        assertActivation(true, profile, newContext(null, newProperties("1.6.0_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.6.0_09-b03")));
     }
 
     @Test
-    public void testVersionRangeExclusiveBounds()
-        throws Exception
-    {
-        Profile profile = newProfile( "(1.3,1.6)" );
+    void testVersionRangeExclusiveBounds() throws Exception {
+        Profile profile = newProfile("(1.3,1.6)");
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.3" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.3.0" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.3.0_09" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.3.0_09-b03" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.3")));
+        assertActivation(false, profile, newContext(null, newProperties("1.3.0")));
+        assertActivation(false, profile, newContext(null, newProperties("1.3.0_09")));
+        assertActivation(false, profile, newContext(null, newProperties("1.3.0_09-b03")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.3.1" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.3.1_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.3.1_09-b03" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.3.1")));
+        assertActivation(true, profile, newContext(null, newProperties("1.3.1_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.3.1_09-b03")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.5" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09-b03" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.1" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.5")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09-b03")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.1")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.6" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.6")));
     }
 
     @Test
-    public void testVersionRangeInclusiveLowerBound()
-        throws Exception
-    {
-        Profile profile = newProfile( "[1.5,)" );
+    void testVersionRangeInclusiveLowerBound() throws Exception {
+        Profile profile = newProfile("[1.5,)");
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.4" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2_09" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.4.2_09-b03" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.4")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2_09")));
+        assertActivation(false, profile, newContext(null, newProperties("1.4.2_09-b03")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.5" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09-b03" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.1" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.5")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09-b03")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.1")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.6" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.6.0" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.6.0_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.6.0_09-b03" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.6")));
+        assertActivation(true, profile, newContext(null, newProperties("1.6.0")));
+        assertActivation(true, profile, newContext(null, newProperties("1.6.0_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.6.0_09-b03")));
     }
 
     @Test
-    public void testVersionRangeExclusiveUpperBound()
-        throws Exception
-    {
-        Profile profile = newProfile( "(,1.6)" );
+    void testVersionRangeExclusiveUpperBound() throws Exception {
+        Profile profile = newProfile("(,1.6)");
 
-        assertActivation( true, profile, newContext( null, newProperties( "1.5" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.0_09-b03" ) ) );
-        assertActivation( true, profile, newContext( null, newProperties( "1.5.1" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("1.5")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.0_09-b03")));
+        assertActivation(true, profile, newContext(null, newProperties("1.5.1")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "1.6" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.6.0" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.6.0_09" ) ) );
-        assertActivation( false, profile, newContext( null, newProperties( "1.6.0_09-b03" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("1.6")));
+        assertActivation(false, profile, newContext(null, newProperties("1.6.0")));
+        assertActivation(false, profile, newContext(null, newProperties("1.6.0_09")));
+        assertActivation(false, profile, newContext(null, newProperties("1.6.0_09-b03")));
     }
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/PropertyProfileActivatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/PropertyProfileActivatorTest.java
index 72a6775..12ac885 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/PropertyProfileActivatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/profile/activation/PropertyProfileActivatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.profile.activation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,182 +16,153 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.profile.activation;
 
 import java.util.Properties;
 
-import org.apache.maven.model.Activation;
-import org.apache.maven.model.ActivationProperty;
-import org.apache.maven.model.Profile;
+import org.apache.maven.api.model.Activation;
+import org.apache.maven.api.model.ActivationProperty;
+import org.apache.maven.api.model.Profile;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 /**
  * Tests {@link PropertyProfileActivator}.
  *
- * @author Benjamin Bentmann
  */
-public class PropertyProfileActivatorTest
-    extends AbstractProfileActivatorTest<PropertyProfileActivator>
-{
+class PropertyProfileActivatorTest extends AbstractProfileActivatorTest<PropertyProfileActivator> {
 
     @BeforeEach
     @Override
-    void setUp() throws Exception
-    {
+    void setUp() throws Exception {
         activator = new PropertyProfileActivator();
     }
 
-    private Profile newProfile(String key, String value )
-    {
-        ActivationProperty ap = new ActivationProperty();
-        ap.setName( key );
-        ap.setValue( value );
+    private Profile newProfile(String key, String value) {
+        ActivationProperty ap =
+                ActivationProperty.newBuilder().name(key).value(value).build();
 
-        Activation a = new Activation();
-        a.setProperty( ap );
+        Activation a = Activation.newBuilder().property(ap).build();
 
-        Profile p = new Profile();
-        p.setActivation( a );
+        Profile p = Profile.newBuilder().activation(a).build();
 
         return p;
     }
 
-    private Properties newProperties( String key, String value )
-    {
+    private Properties newProperties(String key, String value) {
         Properties props = new Properties();
-        props.setProperty( key, value );
+        props.setProperty(key, value);
         return props;
     }
 
     @Test
-    public void testNullSafe()
-        throws Exception
-    {
-        Profile p = new Profile();
+    void testNullSafe() throws Exception {
+        Profile p = Profile.newInstance();
 
-        assertActivation( false, p, newContext( null, null ) );
+        assertActivation(false, p, newContext(null, null));
 
-        p.setActivation( new Activation() );
+        p = p.withActivation(Activation.newInstance());
 
-        assertActivation( false, p, newContext( null, null ) );
+        assertActivation(false, p, newContext(null, null));
     }
 
     @Test
-    public void testWithNameOnly_UserProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "prop", null );
+    void testWithNameOnly_UserProperty() throws Exception {
+        Profile profile = newProfile("prop", null);
 
-        assertActivation( true, profile, newContext( newProperties( "prop", "value" ), null ) );
+        assertActivation(true, profile, newContext(newProperties("prop", "value"), null));
 
-        assertActivation( false, profile, newContext( newProperties( "prop", "" ), null ) );
+        assertActivation(false, profile, newContext(newProperties("prop", ""), null));
 
-        assertActivation( false, profile, newContext( newProperties( "other", "value" ), null ) );
+        assertActivation(false, profile, newContext(newProperties("other", "value"), null));
     }
 
     @Test
-    public void testWithNameOnly_SystemProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "prop", null );
+    void testWithNameOnly_SystemProperty() throws Exception {
+        Profile profile = newProfile("prop", null);
 
-        assertActivation( true, profile, newContext( null, newProperties( "prop", "value" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("prop", "value")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "prop", "" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("prop", "")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "other", "value" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("other", "value")));
     }
 
     @Test
-    public void testWithNegatedNameOnly_UserProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "!prop", null );
+    void testWithNegatedNameOnly_UserProperty() throws Exception {
+        Profile profile = newProfile("!prop", null);
 
-        assertActivation( false, profile, newContext( newProperties( "prop", "value" ), null ) );
+        assertActivation(false, profile, newContext(newProperties("prop", "value"), null));
 
-        assertActivation( true, profile, newContext( newProperties( "prop", "" ), null ) );
+        assertActivation(true, profile, newContext(newProperties("prop", ""), null));
 
-        assertActivation( true, profile, newContext( newProperties( "other", "value" ), null ) );
+        assertActivation(true, profile, newContext(newProperties("other", "value"), null));
     }
 
     @Test
-    public void testWithNegatedNameOnly_SystemProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "!prop", null );
+    void testWithNegatedNameOnly_SystemProperty() throws Exception {
+        Profile profile = newProfile("!prop", null);
 
-        assertActivation( false, profile, newContext( null, newProperties( "prop", "value" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("prop", "value")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "prop", "" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("prop", "")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "other", "value" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("other", "value")));
     }
 
     @Test
-    public void testWithValue_UserProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "prop", "value" );
+    void testWithValue_UserProperty() throws Exception {
+        Profile profile = newProfile("prop", "value");
 
-        assertActivation( true, profile, newContext( newProperties( "prop", "value" ), null ) );
+        assertActivation(true, profile, newContext(newProperties("prop", "value"), null));
 
-        assertActivation( false, profile, newContext( newProperties( "prop", "other" ), null ) );
+        assertActivation(false, profile, newContext(newProperties("prop", "other"), null));
 
-        assertActivation( false, profile, newContext( newProperties( "prop", "" ), null ) );
+        assertActivation(false, profile, newContext(newProperties("prop", ""), null));
     }
 
     @Test
-    public void testWithValue_SystemProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "prop", "value" );
+    void testWithValue_SystemProperty() throws Exception {
+        Profile profile = newProfile("prop", "value");
 
-        assertActivation( true, profile, newContext( null, newProperties( "prop", "value" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("prop", "value")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "prop", "other" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("prop", "other")));
 
-        assertActivation( false, profile, newContext( null, newProperties( "other", "" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("other", "")));
     }
 
     @Test
-    public void testWithNegatedValue_UserProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "prop", "!value" );
+    void testWithNegatedValue_UserProperty() throws Exception {
+        Profile profile = newProfile("prop", "!value");
 
-        assertActivation( false, profile, newContext( newProperties( "prop", "value" ), null ) );
+        assertActivation(false, profile, newContext(newProperties("prop", "value"), null));
 
-        assertActivation( true, profile, newContext( newProperties( "prop", "other" ), null ) );
+        assertActivation(true, profile, newContext(newProperties("prop", "other"), null));
 
-        assertActivation( true, profile, newContext( newProperties( "prop", "" ), null ) );
+        assertActivation(true, profile, newContext(newProperties("prop", ""), null));
     }
 
     @Test
-    public void testWithNegatedValue_SystemProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "prop", "!value" );
+    void testWithNegatedValue_SystemProperty() throws Exception {
+        Profile profile = newProfile("prop", "!value");
 
-        assertActivation( false, profile, newContext( null, newProperties( "prop", "value" ) ) );
+        assertActivation(false, profile, newContext(null, newProperties("prop", "value")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "prop", "other" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("prop", "other")));
 
-        assertActivation( true, profile, newContext( null, newProperties( "other", "" ) ) );
+        assertActivation(true, profile, newContext(null, newProperties("other", "")));
     }
 
     @Test
-    public void testWithValue_UserPropertyDominantOverSystemProperty()
-        throws Exception
-    {
-        Profile profile = newProfile( "prop", "value" );
+    void testWithValue_UserPropertyDominantOverSystemProperty() throws Exception {
+        Profile profile = newProfile("prop", "value");
 
-        Properties props1 = newProperties( "prop", "value" );
-        Properties props2 = newProperties( "prop", "other" );
+        Properties props1 = newProperties("prop", "value");
+        Properties props2 = newProperties("prop", "other");
 
-        assertActivation( true, profile, newContext( props1, props2 ) );
+        assertActivation(true, profile, newContext(props1, props2));
 
-        assertActivation( false, profile, newContext( props2, props1 ) );
+        assertActivation(false, profile, newContext(props2, props1));
     }
-
 }
diff --git a/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java b/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java
index 57dae7c..946002f 100644
--- a/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java
+++ b/maven-model-builder/src/test/java/org/apache/maven/model/validation/DefaultModelValidatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model.validation;
 
 import java.io.InputStream;
 import java.util.List;
@@ -27,7 +26,7 @@
 import org.apache.maven.model.building.ModelBuildingRequest;
 import org.apache.maven.model.building.SimpleProblemCollector;
 import org.apache.maven.model.interpolation.DefaultModelVersionProcessor;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.model.v4.MavenStaxReader;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
@@ -37,860 +36,807 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
  */
-public class DefaultModelValidatorTest
-{
+class DefaultModelValidatorTest {
 
     private ModelValidator validator;
 
-    private Model read( String pom )
-        throws Exception
-    {
+    private Model read(String pom) throws Exception {
         String resource = "/poms/validation/" + pom;
-        InputStream is = getClass().getResourceAsStream( resource );
-        assertNotNull( is, "missing resource: " + resource );
-        return new MavenXpp3Reader().read( is );
+        try (InputStream is = getClass().getResourceAsStream(resource)) {
+            assertNotNull(is, "missing resource: " + resource);
+            return new Model(new MavenStaxReader().read(is));
+        }
     }
 
-    private SimpleProblemCollector validate( String pom )
-        throws Exception
-    {
-        return validateEffective( pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
+    private SimpleProblemCollector validate(String pom) throws Exception {
+        return validateEffective(pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
     }
 
-    private SimpleProblemCollector validateRaw( String pom )
-        throws Exception
-    {
-        return validateRaw( pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
+    private SimpleProblemCollector validateRaw(String pom) throws Exception {
+        return validateRaw(pom, ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
     }
 
-    private SimpleProblemCollector validateEffective( String pom, int level )
-        throws Exception
-    {
-        ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( level );
+    private SimpleProblemCollector validateEffective(String pom, int level) throws Exception {
+        ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel(level);
 
-        Model model =  read( pom );
+        Model model = read(pom);
 
-        SimpleProblemCollector problems = new SimpleProblemCollector( model );
+        SimpleProblemCollector problems = new SimpleProblemCollector(model);
 
-        validator.validateEffectiveModel( model, request, problems );
+        validator.validateEffectiveModel(model, request, problems);
 
         return problems;
     }
 
-    private SimpleProblemCollector validateRaw( String pom, int level )
-        throws Exception
-    {
-        ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel( level );
+    private SimpleProblemCollector validateRaw(String pom, int level) throws Exception {
+        ModelBuildingRequest request = new DefaultModelBuildingRequest().setValidationLevel(level);
 
-        Model model = read( pom );
+        Model model = read(pom);
 
-        SimpleProblemCollector problems = new SimpleProblemCollector( model );
+        SimpleProblemCollector problems = new SimpleProblemCollector(model);
 
-        validator.validateFileModel( model, request, problems );
+        validator.validateFileModel(model, request, problems);
 
-        validator.validateRawModel( model, request, problems );
+        validator.validateRawModel(model, request, problems);
 
         return problems;
     }
 
-    private void assertContains( String msg, String substring )
-    {
-        assertTrue( msg.contains( substring ), "\"" + substring + "\" was not found in: " + msg );
+    private void assertContains(String msg, String substring) {
+        assertTrue(msg.contains(substring), "\"" + substring + "\" was not found in: " + msg);
     }
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        validator = new DefaultModelValidator( new DefaultModelVersionProcessor() );
+    void setUp() throws Exception {
+        validator = new DefaultModelValidator(new DefaultModelVersionProcessor());
     }
 
     @AfterEach
-    public void tearDown()
-        throws Exception
-    {
+    void tearDown() throws Exception {
         this.validator = null;
     }
 
-    private void assertViolations( SimpleProblemCollector result, int fatals, int errors, int warnings )
-    {
-        assertEquals( fatals, result.getFatals().size(), String.valueOf( result.getFatals() ) );
-        assertEquals( errors, result.getErrors().size(), String.valueOf( result.getErrors() ) );
-        assertEquals( warnings, result.getWarnings().size(), String.valueOf( result.getWarnings() ) );
+    private void assertViolations(SimpleProblemCollector result, int fatals, int errors, int warnings) {
+        assertEquals(fatals, result.getFatals().size(), String.valueOf(result.getFatals()));
+        assertEquals(errors, result.getErrors().size(), String.valueOf(result.getErrors()));
+        assertEquals(warnings, result.getWarnings().size(), String.valueOf(result.getWarnings()));
     }
 
     @Test
-    public void testMissingModelVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-modelVersion-pom.xml" );
+    void testMissingModelVersion() throws Exception {
+        SimpleProblemCollector result = validate("missing-modelVersion-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertEquals( "'modelVersion' is missing.", result.getErrors().get( 0 ) );
+        assertEquals("'modelVersion' is missing.", result.getErrors().get(0));
     }
 
     @Test
-    public void testBadModelVersion()
-        throws Exception
-    {
+    void testBadModelVersion() throws Exception {
         SimpleProblemCollector result =
-            validateRaw( "bad-modelVersion.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
+                validateRaw("bad-modelVersion.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
 
-        assertViolations( result, 1, 0, 0 );
+        assertViolations(result, 1, 0, 0);
 
-        assertTrue( result.getFatals().get( 0 ).contains( "modelVersion" ) );
+        assertTrue(result.getFatals().get(0).contains("modelVersion"));
     }
 
     @Test
-    public void testMissingArtifactId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-artifactId-pom.xml" );
+    void testModelVersionMessage() throws Exception {
+        SimpleProblemCollector result =
+                validateRaw("modelVersion-4_0.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertEquals( "'artifactId' is missing.", result.getErrors().get( 0 ) );
+        assertTrue(result.getErrors().get(0).contains("'modelVersion' must be one of"));
     }
 
     @Test
-    public void testMissingGroupId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-groupId-pom.xml" );
+    void testMissingArtifactId() throws Exception {
+        SimpleProblemCollector result = validate("missing-artifactId-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertEquals( "'groupId' is missing.", result.getErrors().get( 0 ) );
+        assertEquals("'artifactId' is missing.", result.getErrors().get(0));
     }
 
     @Test
-    public void testInvalidCoordinateIds()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "invalid-coordinate-ids-pom.xml" );
+    void testMissingGroupId() throws Exception {
+        SimpleProblemCollector result = validate("missing-groupId-pom.xml");
 
-        assertViolations( result, 0, 2, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertEquals( "'groupId' with value 'o/a/m' does not match a valid coordinate id pattern.",
-                      result.getErrors().get( 0 ) );
-
-        assertEquals( "'artifactId' with value 'm$-do$' does not match a valid coordinate id pattern.",
-                      result.getErrors().get( 1 ) );
+        assertEquals("'groupId' is missing.", result.getErrors().get(0));
     }
 
     @Test
-    public void testMissingType()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-type-pom.xml" );
+    void testInvalidCoordinateIds() throws Exception {
+        SimpleProblemCollector result = validate("invalid-coordinate-ids-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 2, 0);
 
-        assertEquals( "'packaging' is missing.", result.getErrors().get( 0 ) );
+        assertEquals(
+                "'groupId' with value 'o/a/m' does not match a valid coordinate id pattern.",
+                result.getErrors().get(0));
+
+        assertEquals(
+                "'artifactId' with value 'm$-do$' does not match a valid coordinate id pattern.",
+                result.getErrors().get(1));
     }
 
     @Test
-    public void testMissingVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-version-pom.xml" );
+    void testMissingType() throws Exception {
+        SimpleProblemCollector result = validate("missing-type-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertEquals( "'version' is missing.", result.getErrors().get( 0 ) );
+        assertEquals("'packaging' is missing.", result.getErrors().get(0));
     }
 
     @Test
-    public void testInvalidAggregatorPackaging()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "invalid-aggregator-packaging-pom.xml" );
+    void testMissingVersion() throws Exception {
+        SimpleProblemCollector result = validate("missing-version-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "Aggregator projects require 'pom' as packaging." ) );
+        assertEquals("'version' is missing.", result.getErrors().get(0));
     }
 
     @Test
-    public void testMissingDependencyArtifactId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-dependency-artifactId-pom.xml" );
+    void testInvalidAggregatorPackaging() throws Exception {
+        SimpleProblemCollector result = validate("invalid-aggregator-packaging-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "'dependencies.dependency.artifactId' for groupId:null:jar is missing" ) );
+        assertTrue(result.getErrors().get(0).contains("Aggregator projects require 'pom' as packaging."));
     }
 
     @Test
-    public void testMissingDependencyGroupId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-dependency-groupId-pom.xml" );
+    void testMissingDependencyArtifactId() throws Exception {
+        SimpleProblemCollector result = validate("missing-dependency-artifactId-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "'dependencies.dependency.groupId' for null:artifactId:jar is missing" ) );
+        assertTrue(result.getErrors()
+                .get(0)
+                .contains("'dependencies.dependency.artifactId' for groupId:null:jar is missing"));
     }
 
     @Test
-    public void testMissingDependencyVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-dependency-version-pom.xml" );
+    void testMissingDependencyGroupId() throws Exception {
+        SimpleProblemCollector result = validate("missing-dependency-groupId-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "'dependencies.dependency.version' for groupId:artifactId:jar is missing" ) );
+        assertTrue(result.getErrors()
+                .get(0)
+                .contains("'dependencies.dependency.groupId' for null:artifactId:jar is missing"));
     }
 
     @Test
-    public void testMissingDependencyManagementArtifactId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-dependency-mgmt-artifactId-pom.xml" );
+    void testMissingDependencyVersion() throws Exception {
+        SimpleProblemCollector result = validate("missing-dependency-version-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "'dependencyManagement.dependencies.dependency.artifactId' for groupId:null:jar is missing" ) );
+        assertTrue(result.getErrors()
+                .get(0)
+                .contains("'dependencies.dependency.version' for groupId:artifactId:jar is missing"));
     }
 
     @Test
-    public void testMissingDependencyManagementGroupId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-dependency-mgmt-groupId-pom.xml" );
+    void testMissingDependencyManagementArtifactId() throws Exception {
+        SimpleProblemCollector result = validate("missing-dependency-mgmt-artifactId-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "'dependencyManagement.dependencies.dependency.groupId' for null:artifactId:jar is missing" ) );
+        assertTrue(result.getErrors()
+                .get(0)
+                .contains("'dependencyManagement.dependencies.dependency.artifactId' for groupId:null:jar is missing"));
     }
 
     @Test
-    public void testMissingAll()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-1-pom.xml" );
+    void testMissingDependencyManagementGroupId() throws Exception {
+        SimpleProblemCollector result = validate("missing-dependency-mgmt-groupId-pom.xml");
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 1, 0);
+
+        assertTrue(result.getErrors()
+                .get(0)
+                .contains("'dependencyManagement.dependencies.dependency.groupId' for null:artifactId:jar is missing"));
+    }
+
+    @Test
+    void testMissingAll() throws Exception {
+        SimpleProblemCollector result = validate("missing-1-pom.xml");
+
+        assertViolations(result, 0, 4, 0);
 
         List<String> messages = result.getErrors();
 
-        assertTrue( messages.contains( "'modelVersion' is missing." ) );
-        assertTrue( messages.contains( "'groupId' is missing." ) );
-        assertTrue( messages.contains( "'artifactId' is missing." ) );
-        assertTrue( messages.contains( "'version' is missing." ) );
+        assertTrue(messages.contains("'modelVersion' is missing."));
+        assertTrue(messages.contains("'groupId' is missing."));
+        assertTrue(messages.contains("'artifactId' is missing."));
+        assertTrue(messages.contains("'version' is missing."));
         // type is inherited from the super pom
     }
 
     @Test
-    public void testMissingPluginArtifactId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-plugin-artifactId-pom.xml" );
+    void testMissingPluginArtifactId() throws Exception {
+        SimpleProblemCollector result = validate("missing-plugin-artifactId-pom.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertEquals( "'build.plugins.plugin.artifactId' is missing.", result.getErrors().get( 0 ) );
+        assertEquals(
+                "'build.plugins.plugin.artifactId' is missing.",
+                result.getErrors().get(0));
     }
 
     @Test
-    public void testEmptyPluginVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "empty-plugin-version.xml" );
+    void testEmptyPluginVersion() throws Exception {
+        SimpleProblemCollector result = validate("empty-plugin-version.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertEquals( "'build.plugins.plugin.version' for org.apache.maven.plugins:maven-it-plugin"
-            + " must be a valid version but is ''.", result.getErrors().get( 0 ) );
+        assertEquals(
+                "'build.plugins.plugin.version' for org.apache.maven.plugins:maven-it-plugin"
+                        + " must be a valid version but is ''.",
+                result.getErrors().get(0));
     }
 
     @Test
-    public void testMissingRepositoryId()
-        throws Exception
-    {
+    void testMissingRepositoryId() throws Exception {
         SimpleProblemCollector result =
-            validateRaw( "missing-repository-id-pom.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT );
+                validateRaw("missing-repository-id-pom.xml", ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 4, 0);
 
-        assertEquals( "'repositories.repository.id' is missing.", result.getErrors().get( 0 ) );
+        assertEquals(
+                "'repositories.repository.id' is missing.", result.getErrors().get(0));
 
-        assertEquals( "'repositories.repository.[null].url' is missing.", result.getErrors().get( 1 ) );
+        assertEquals(
+                "'repositories.repository.[null].url' is missing.",
+                result.getErrors().get(1));
 
-        assertEquals( "'pluginRepositories.pluginRepository.id' is missing.", result.getErrors().get( 2 ) );
+        assertEquals(
+                "'pluginRepositories.pluginRepository.id' is missing.",
+                result.getErrors().get(2));
 
-        assertEquals( "'pluginRepositories.pluginRepository.[null].url' is missing.", result.getErrors().get( 3 ) );
+        assertEquals(
+                "'pluginRepositories.pluginRepository.[null].url' is missing.",
+                result.getErrors().get(3));
     }
 
     @Test
-    public void testMissingResourceDirectory()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-resource-directory-pom.xml" );
+    void testMissingResourceDirectory() throws Exception {
+        SimpleProblemCollector result = validate("missing-resource-directory-pom.xml");
 
-        assertViolations( result, 0, 2, 0 );
+        assertViolations(result, 0, 2, 0);
 
-        assertEquals( "'build.resources.resource.directory' is missing.", result.getErrors().get( 0 ) );
+        assertEquals(
+                "'build.resources.resource.directory' is missing.",
+                result.getErrors().get(0));
 
-        assertEquals( "'build.testResources.testResource.directory' is missing.", result.getErrors().get( 1 ) );
+        assertEquals(
+                "'build.testResources.testResource.directory' is missing.",
+                result.getErrors().get(1));
     }
 
     @Test
-    public void testBadPluginDependencyScope()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-plugin-dependency-scope.xml" );
+    void testBadPluginDependencyScope() throws Exception {
+        SimpleProblemCollector result = validate("bad-plugin-dependency-scope.xml");
 
-        assertViolations( result, 0, 3, 0 );
+        assertViolations(result, 0, 3, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "test:d" ) );
+        assertTrue(result.getErrors().get(0).contains("test:d"));
 
-        assertTrue( result.getErrors().get( 1 ).contains( "test:e" ) );
+        assertTrue(result.getErrors().get(1).contains("test:e"));
 
-        assertTrue( result.getErrors().get( 2 ).contains( "test:f" ) );
+        assertTrue(result.getErrors().get(2).contains("test:f"));
     }
 
     @Test
-    public void testBadDependencyScope()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-dependency-scope.xml" );
+    void testBadDependencyScope() throws Exception {
+        SimpleProblemCollector result = validate("bad-dependency-scope.xml");
 
-        assertViolations( result, 0, 0, 2 );
+        assertViolations(result, 0, 0, 2);
 
-        assertTrue( result.getWarnings().get( 0 ).contains( "test:f" ) );
+        assertTrue(result.getWarnings().get(0).contains("test:f"));
 
-        assertTrue( result.getWarnings().get( 1 ).contains( "test:g" ) );
+        assertTrue(result.getWarnings().get(1).contains("test:g"));
     }
 
     @Test
-    public void testBadDependencyManagementScope()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-dependency-management-scope.xml" );
+    void testBadDependencyManagementScope() throws Exception {
+        SimpleProblemCollector result = validate("bad-dependency-management-scope.xml");
 
-        assertViolations( result, 0, 0, 1 );
+        assertViolations(result, 0, 0, 1);
 
-        assertContains( result.getWarnings().get( 0 ), "test:g" );
+        assertContains(result.getWarnings().get(0), "test:g");
     }
 
     @Test
-    public void testBadDependencyVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-dependency-version.xml" );
+    void testBadDependencyVersion() throws Exception {
+        SimpleProblemCollector result = validate("bad-dependency-version.xml");
 
-        assertViolations( result, 0, 2, 0 );
+        assertViolations(result, 0, 2, 0);
 
-        assertContains( result.getErrors().get( 0 ),
-                        "'dependencies.dependency.version' for test:b:jar must be a valid version" );
-        assertContains( result.getErrors().get( 1 ),
-                        "'dependencies.dependency.version' for test:c:jar must not contain any of these characters" );
+        assertContains(
+                result.getErrors().get(0), "'dependencies.dependency.version' for test:b:jar must be a valid version");
+        assertContains(
+                result.getErrors().get(1),
+                "'dependencies.dependency.version' for test:c:jar must not contain any of these characters");
     }
 
     @Test
-    public void testDuplicateModule()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "duplicate-module.xml" );
+    void testDuplicateModule() throws Exception {
+        SimpleProblemCollector result = validateRaw("duplicate-module.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "child" ) );
+        assertTrue(result.getErrors().get(0).contains("child"));
     }
 
     @Test
-    public void testInvalidProfileId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "invalid-profile-ids.xml" );
+    void testInvalidProfileId() throws Exception {
+        SimpleProblemCollector result = validateRaw("invalid-profile-ids.xml");
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 4, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "+invalid-id" ) );
-        assertTrue( result.getErrors().get( 1 ).contains( "-invalid-id" ) );
-        assertTrue( result.getErrors().get( 2 ).contains( "!invalid-id" ) );
-        assertTrue( result.getErrors().get( 3 ).contains( "?invalid-id" ) );
+        assertTrue(result.getErrors().get(0).contains("+invalid-id"));
+        assertTrue(result.getErrors().get(1).contains("-invalid-id"));
+        assertTrue(result.getErrors().get(2).contains("!invalid-id"));
+        assertTrue(result.getErrors().get(3).contains("?invalid-id"));
     }
 
-    public void testDuplicateProfileId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "duplicate-profile-id.xml" );
+    public void testDuplicateProfileId() throws Exception {
+        SimpleProblemCollector result = validateRaw("duplicate-profile-id.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "non-unique-id" ) );
+        assertTrue(result.getErrors().get(0).contains("non-unique-id"));
     }
 
     @Test
-    public void testBadPluginVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-plugin-version.xml" );
+    void testBadPluginVersion() throws Exception {
+        SimpleProblemCollector result = validate("bad-plugin-version.xml");
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 4, 0);
 
-        assertContains( result.getErrors().get( 0 ),
-                        "'build.plugins.plugin.version' for test:mip must be a valid version" );
-        assertContains( result.getErrors().get( 1 ),
-                        "'build.plugins.plugin.version' for test:rmv must be a valid version" );
-        assertContains( result.getErrors().get( 2 ),
-                        "'build.plugins.plugin.version' for test:lmv must be a valid version" );
-        assertContains( result.getErrors().get( 3 ),
-                        "'build.plugins.plugin.version' for test:ifsc must not contain any of these characters" );
+        assertContains(
+                result.getErrors().get(0), "'build.plugins.plugin.version' for test:mip must be a valid version");
+        assertContains(
+                result.getErrors().get(1), "'build.plugins.plugin.version' for test:rmv must be a valid version");
+        assertContains(
+                result.getErrors().get(2), "'build.plugins.plugin.version' for test:lmv must be a valid version");
+        assertContains(
+                result.getErrors().get(3),
+                "'build.plugins.plugin.version' for test:ifsc must not contain any of these characters");
     }
 
     @Test
-    public void testDistributionManagementStatus()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "distribution-management-status.xml" );
+    void testDistributionManagementStatus() throws Exception {
+        SimpleProblemCollector result = validate("distribution-management-status.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "distributionManagement.status" ) );
+        assertTrue(result.getErrors().get(0).contains("distributionManagement.status"));
     }
 
     @Test
-    public void testIncompleteParent()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "incomplete-parent.xml" );
+    void testIncompleteParent() throws Exception {
+        SimpleProblemCollector result = validateRaw("incomplete-parent.xml");
 
-        assertViolations( result, 3, 0, 0 );
-        assertTrue( result.getFatals().get( 0 ).contains( "parent.groupId" ) );
-        assertTrue( result.getFatals().get( 1 ).contains( "parent.artifactId" ) );
-        assertTrue( result.getFatals().get( 2 ).contains( "parent.version" ) );
+        assertViolations(result, 3, 0, 0);
+        assertTrue(result.getFatals().get(0).contains("parent.groupId"));
+        assertTrue(result.getFatals().get(1).contains("parent.artifactId"));
+        assertTrue(result.getFatals().get(2).contains("parent.version"));
     }
 
     @Test
-    public void testHardCodedSystemPath()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "hard-coded-system-path.xml" );
+    void testHardCodedSystemPath() throws Exception {
+        SimpleProblemCollector result = validateRaw("hard-coded-system-path.xml");
 
-        assertViolations( result, 0, 0, 3 );
+        assertViolations(result, 0, 0, 3);
 
-        assertContains( result.getWarnings().get( 0 ),
-                        "'dependencies.dependency.scope' for test:a:jar declares usage of deprecated 'system' scope" );
-        assertContains( result.getWarnings().get( 1 ),
-                        "'dependencies.dependency.systemPath' for test:a:jar should use a variable instead of a hard-coded path" );
-        assertContains( result.getWarnings().get( 2 ),
-                        "'dependencies.dependency.scope' for test:b:jar declares usage of deprecated 'system' scope" );
-
+        assertContains(
+                result.getWarnings().get(0),
+                "'dependencies.dependency.scope' for test:a:jar declares usage of deprecated 'system' scope");
+        assertContains(
+                result.getWarnings().get(1),
+                "'dependencies.dependency.systemPath' for test:a:jar should use a variable instead of a hard-coded path");
+        assertContains(
+                result.getWarnings().get(2),
+                "'dependencies.dependency.scope' for test:b:jar declares usage of deprecated 'system' scope");
     }
 
     @Test
-    public void testEmptyModule()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "empty-module.xml" );
+    void testEmptyModule() throws Exception {
+        SimpleProblemCollector result = validate("empty-module.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "'modules.module[0]' has been specified without a path" ) );
+        assertTrue(result.getErrors().get(0).contains("'modules.module[0]' has been specified without a path"));
     }
 
     @Test
-    public void testDuplicatePlugin()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "duplicate-plugin.xml" );
+    void testDuplicatePlugin() throws Exception {
+        SimpleProblemCollector result = validateRaw("duplicate-plugin.xml");
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 4, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "duplicate declaration of plugin test:duplicate" ) );
-        assertTrue( result.getErrors().get( 1 ).contains( "duplicate declaration of plugin test:managed-duplicate" ) );
-        assertTrue( result.getErrors().get( 2 ).contains( "duplicate declaration of plugin profile:duplicate" ) );
-        assertTrue( result.getErrors().get( 3 ).contains( "duplicate declaration of plugin profile:managed-duplicate" ) );
+        assertTrue(result.getErrors().get(0).contains("duplicate declaration of plugin test:duplicate"));
+        assertTrue(result.getErrors().get(1).contains("duplicate declaration of plugin test:managed-duplicate"));
+        assertTrue(result.getErrors().get(2).contains("duplicate declaration of plugin profile:duplicate"));
+        assertTrue(result.getErrors().get(3).contains("duplicate declaration of plugin profile:managed-duplicate"));
     }
 
     @Test
-    public void testDuplicatePluginExecution()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "duplicate-plugin-execution.xml" );
+    void testDuplicatePluginExecution() throws Exception {
+        SimpleProblemCollector result = validateRaw("duplicate-plugin-execution.xml");
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 4, 0);
 
-        assertContains( result.getErrors().get( 0 ), "duplicate execution with id a" );
-        assertContains( result.getErrors().get( 1 ), "duplicate execution with id default" );
-        assertContains( result.getErrors().get( 2 ), "duplicate execution with id c" );
-        assertContains( result.getErrors().get( 3 ), "duplicate execution with id b" );
+        assertContains(result.getErrors().get(0), "duplicate execution with id a");
+        assertContains(result.getErrors().get(1), "duplicate execution with id default");
+        assertContains(result.getErrors().get(2), "duplicate execution with id c");
+        assertContains(result.getErrors().get(3), "duplicate execution with id b");
     }
 
     @Test
-    public void testReservedRepositoryId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "reserved-repository-id.xml" );
+    void testReservedRepositoryId() throws Exception {
+        SimpleProblemCollector result = validate("reserved-repository-id.xml");
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 4, 0);
 
-        assertContains( result.getErrors().get( 0 ), "'repositories.repository.id'" + " must not be 'local'" );
-        assertContains( result.getErrors().get( 1 ), "'pluginRepositories.pluginRepository.id' must not be 'local'" );
-        assertContains( result.getErrors().get( 2 ), "'distributionManagement.repository.id' must not be 'local'" );
-        assertContains( result.getErrors().get( 3 ),
-                        "'distributionManagement.snapshotRepository.id' must not be 'local'" );
+        assertContains(result.getErrors().get(0), "'repositories.repository.id'" + " must not be 'local'");
+        assertContains(result.getErrors().get(1), "'pluginRepositories.pluginRepository.id' must not be 'local'");
+        assertContains(result.getErrors().get(2), "'distributionManagement.repository.id' must not be 'local'");
+        assertContains(result.getErrors().get(3), "'distributionManagement.snapshotRepository.id' must not be 'local'");
     }
 
     @Test
-    public void testMissingPluginDependencyGroupId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-plugin-dependency-groupId.xml" );
+    void testMissingPluginDependencyGroupId() throws Exception {
+        SimpleProblemCollector result = validate("missing-plugin-dependency-groupId.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( ":a:" ) );
+        assertTrue(result.getErrors().get(0).contains(":a:"));
     }
 
     @Test
-    public void testMissingPluginDependencyArtifactId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-plugin-dependency-artifactId.xml" );
+    void testMissingPluginDependencyArtifactId() throws Exception {
+        SimpleProblemCollector result = validate("missing-plugin-dependency-artifactId.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "test:" ) );
+        assertTrue(result.getErrors().get(0).contains("test:"));
     }
 
     @Test
-    public void testMissingPluginDependencyVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-plugin-dependency-version.xml" );
+    void testMissingPluginDependencyVersion() throws Exception {
+        SimpleProblemCollector result = validate("missing-plugin-dependency-version.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "test:a" ) );
+        assertTrue(result.getErrors().get(0).contains("test:a"));
     }
 
     @Test
-    public void testBadPluginDependencyVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-plugin-dependency-version.xml" );
+    void testBadPluginDependencyVersion() throws Exception {
+        SimpleProblemCollector result = validate("bad-plugin-dependency-version.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertTrue( result.getErrors().get( 0 ).contains( "test:b" ) );
+        assertTrue(result.getErrors().get(0).contains("test:b"));
     }
 
     @Test
-    public void testBadVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-version.xml" );
+    void testBadVersion() throws Exception {
+        SimpleProblemCollector result = validate("bad-version.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertContains( result.getErrors().get( 0 ), "'version' must not contain any of these characters" );
+        assertContains(result.getErrors().get(0), "'version' must not contain any of these characters");
     }
 
     @Test
-    public void testBadSnapshotVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-snapshot-version.xml" );
+    void testBadSnapshotVersion() throws Exception {
+        SimpleProblemCollector result = validate("bad-snapshot-version.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertContains( result.getErrors().get( 0 ), "'version' uses an unsupported snapshot version format" );
+        assertContains(result.getErrors().get(0), "'version' uses an unsupported snapshot version format");
     }
 
     @Test
-    public void testBadRepositoryId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "bad-repository-id.xml" );
+    void testBadRepositoryId() throws Exception {
+        SimpleProblemCollector result = validate("bad-repository-id.xml");
 
-        assertViolations( result, 0, 4, 0 );
+        assertViolations(result, 0, 4, 0);
 
-        assertContains( result.getErrors().get( 0 ),
-                        "'repositories.repository.id' must not contain any of these characters" );
-        assertContains( result.getErrors().get( 1 ),
-                        "'pluginRepositories.pluginRepository.id' must not contain any of these characters" );
-        assertContains( result.getErrors().get( 2 ),
-                        "'distributionManagement.repository.id' must not contain any of these characters" );
-        assertContains( result.getErrors().get( 3 ),
-                        "'distributionManagement.snapshotRepository.id' must not contain any of these characters" );
+        assertContains(
+                result.getErrors().get(0), "'repositories.repository.id' must not contain any of these characters");
+        assertContains(
+                result.getErrors().get(1),
+                "'pluginRepositories.pluginRepository.id' must not contain any of these characters");
+        assertContains(
+                result.getErrors().get(2),
+                "'distributionManagement.repository.id' must not contain any of these characters");
+        assertContains(
+                result.getErrors().get(3),
+                "'distributionManagement.snapshotRepository.id' must not contain any of these characters");
     }
 
     @Test
-    public void testBadDependencyExclusionId()
-        throws Exception
-    {
+    void testBadDependencyExclusionId() throws Exception {
         SimpleProblemCollector result =
-            validateEffective( "bad-dependency-exclusion-id.xml", ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0 );
+                validateEffective("bad-dependency-exclusion-id.xml", ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0);
 
-        assertViolations( result, 0, 0, 2 );
+        assertViolations(result, 0, 0, 2);
 
-        assertContains( result.getWarnings().get( 0 ),
-                        "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar" );
-        assertContains( result.getWarnings().get( 1 ),
-                        "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar" );
+        assertContains(
+                result.getWarnings().get(0), "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar");
+        assertContains(
+                result.getWarnings().get(1),
+                "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar");
 
         // MNG-3832: Aether (part of M3+) supports wildcard expressions for exclusions
 
-        SimpleProblemCollector result_30 = validate( "bad-dependency-exclusion-id.xml" );
+        SimpleProblemCollector result_30 = validate("bad-dependency-exclusion-id.xml");
 
-        assertViolations( result_30, 0, 0, 0 );
-
+        assertViolations(result_30, 0, 0, 0);
     }
 
     @Test
-    public void testMissingDependencyExclusionId()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-dependency-exclusion-id.xml" );
+    void testMissingDependencyExclusionId() throws Exception {
+        SimpleProblemCollector result = validate("missing-dependency-exclusion-id.xml");
 
-        assertViolations( result, 0, 0, 2 );
+        assertViolations(result, 0, 0, 2);
 
-        assertContains( result.getWarnings().get( 0 ),
-                        "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar is missing" );
-        assertContains( result.getWarnings().get( 1 ),
-                        "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar is missing" );
+        assertContains(
+                result.getWarnings().get(0),
+                "'dependencies.dependency.exclusions.exclusion.groupId' for gid:aid:jar is missing");
+        assertContains(
+                result.getWarnings().get(1),
+                "'dependencies.dependency.exclusions.exclusion.artifactId' for gid:aid:jar is missing");
     }
 
     @Test
-    public void testBadImportScopeType()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "bad-import-scope-type.xml" );
+    void testBadImportScopeType() throws Exception {
+        SimpleProblemCollector result = validateRaw("bad-import-scope-type.xml");
 
-        assertViolations( result, 0, 0, 1 );
+        assertViolations(result, 0, 0, 1);
 
-        assertContains( result.getWarnings().get( 0 ),
-                        "'dependencyManagement.dependencies.dependency.type' for test:a:jar must be 'pom'" );
+        assertContains(
+                result.getWarnings().get(0),
+                "'dependencyManagement.dependencies.dependency.type' for test:a:jar must be 'pom'");
     }
 
     @Test
-    public void testBadImportScopeClassifier()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "bad-import-scope-classifier.xml" );
+    void testBadImportScopeClassifier() throws Exception {
+        SimpleProblemCollector result = validateRaw("bad-import-scope-classifier.xml");
 
-        assertViolations( result, 0, 1, 0 );
+        assertViolations(result, 0, 1, 0);
 
-        assertContains( result.getErrors().get( 0 ),
-                        "'dependencyManagement.dependencies.dependency.classifier' for test:a:pom:cls must be empty" );
+        assertContains(
+                result.getErrors().get(0),
+                "'dependencyManagement.dependencies.dependency.classifier' for test:a:pom:cls must be empty");
     }
 
     @Test
-    public void testSystemPathRefersToProjectBasedir()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "basedir-system-path.xml" );
+    void testSystemPathRefersToProjectBasedir() throws Exception {
+        SimpleProblemCollector result = validateRaw("basedir-system-path.xml");
 
-        assertViolations( result, 0, 0, 4 );
+        assertViolations(result, 0, 0, 4);
 
-        assertContains( result.getWarnings().get( 0 ),
-                        "'dependencies.dependency.scope' for test:a:jar declares usage of deprecated 'system' scope" );
-        assertContains( result.getWarnings().get( 1 ),
-                        "'dependencies.dependency.systemPath' for test:a:jar should not point at files within the project directory" );
-        assertContains( result.getWarnings().get( 2 ),
-                        "'dependencies.dependency.scope' for test:b:jar declares usage of deprecated 'system' scope" );
-        assertContains( result.getWarnings().get( 3 ),
-                        "'dependencies.dependency.systemPath' for test:b:jar should not point at files within the project directory" );
+        assertContains(
+                result.getWarnings().get(0),
+                "'dependencies.dependency.scope' for test:a:jar declares usage of deprecated 'system' scope");
+        assertContains(
+                result.getWarnings().get(1),
+                "'dependencies.dependency.systemPath' for test:a:jar should not point at files within the project directory");
+        assertContains(
+                result.getWarnings().get(2),
+                "'dependencies.dependency.scope' for test:b:jar declares usage of deprecated 'system' scope");
+        assertContains(
+                result.getWarnings().get(3),
+                "'dependencies.dependency.systemPath' for test:b:jar should not point at files within the project directory");
     }
 
     @Test
-    public void testInvalidVersionInPluginManagement()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/missing-plugin-version-pluginManagement.xml" );
+    void testInvalidVersionInPluginManagement() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/missing-plugin-version-pluginManagement.xml");
 
-        assertViolations( result, 1, 0, 0 );
+        assertViolations(result, 1, 0, 0);
 
-        assertEquals( "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' version of a plugin must be defined. ",
-                      result.getFatals().get( 0 ) );
-
+        assertEquals(
+                "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' version of a plugin must be defined. ",
+                result.getFatals().get(0));
     }
 
     @Test
-    public void testInvalidGroupIdInPluginManagement()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/missing-groupId-pluginManagement.xml" );
+    void testInvalidGroupIdInPluginManagement() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/missing-groupId-pluginManagement.xml");
 
-        assertViolations( result, 1, 0, 0 );
+        assertViolations(result, 1, 0, 0);
 
-        assertEquals( "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' groupId of a plugin must be defined. ",
-                      result.getFatals().get( 0 ) );
-
+        assertEquals(
+                "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' groupId of a plugin must be defined. ",
+                result.getFatals().get(0));
     }
 
     @Test
-    public void testInvalidArtifactIdInPluginManagement()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/missing-artifactId-pluginManagement.xml" );
+    void testInvalidArtifactIdInPluginManagement() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/missing-artifactId-pluginManagement.xml");
 
-        assertViolations( result, 1, 0, 0 );
+        assertViolations(result, 1, 0, 0);
 
-        assertEquals( "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' artifactId of a plugin must be defined. ",
-                      result.getFatals().get( 0 ) );
-
+        assertEquals(
+                "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' artifactId of a plugin must be defined. ",
+                result.getFatals().get(0));
     }
 
     @Test
-    public void testInvalidGroupAndArtifactIdInPluginManagement()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/missing-ga-pluginManagement.xml" );
+    void testInvalidGroupAndArtifactIdInPluginManagement() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/missing-ga-pluginManagement.xml");
 
-        assertViolations( result, 2, 0, 0 );
+        assertViolations(result, 2, 0, 0);
 
-        assertEquals( "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' groupId of a plugin must be defined. ",
-                      result.getFatals().get( 0 ) );
+        assertEquals(
+                "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' groupId of a plugin must be defined. ",
+                result.getFatals().get(0));
 
-        assertEquals( "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' artifactId of a plugin must be defined. ",
-                      result.getFatals().get( 1 ) );
-
+        assertEquals(
+                "'build.pluginManagement.plugins.plugin.(groupId:artifactId)' artifactId of a plugin must be defined. ",
+                result.getFatals().get(1));
     }
 
     @Test
-    public void testMissingReportPluginVersion()
-        throws Exception
-    {
-        SimpleProblemCollector result = validate( "missing-report-version-pom.xml" );
+    void testMissingReportPluginVersion() throws Exception {
+        SimpleProblemCollector result = validate("missing-report-version-pom.xml");
 
-        assertViolations( result, 0, 0, 0 );
+        assertViolations(result, 0, 0, 0);
     }
 
     @Test
-    public void testDeprecatedDependencyMetaversionsLatestAndRelease()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "deprecated-dependency-metaversions-latest-and-release.xml" );
+    void testDeprecatedDependencyMetaversionsLatestAndRelease() throws Exception {
+        SimpleProblemCollector result = validateRaw("deprecated-dependency-metaversions-latest-and-release.xml");
 
-        assertViolations( result, 0, 0, 2 );
+        assertViolations(result, 0, 0, 2);
 
-        assertContains( result.getWarnings().get( 0 ),
-                        "'dependencies.dependency.version' for test:a:jar is either LATEST or RELEASE (both of them are being deprecated)" );
-        assertContains( result.getWarnings().get( 1 ),
-                        "'dependencies.dependency.version' for test:b:jar is either LATEST or RELEASE (both of them are being deprecated)" );
+        assertContains(
+                result.getWarnings().get(0),
+                "'dependencies.dependency.version' for test:a:jar is either LATEST or RELEASE (both of them are being deprecated)");
+        assertContains(
+                result.getWarnings().get(1),
+                "'dependencies.dependency.version' for test:b:jar is either LATEST or RELEASE (both of them are being deprecated)");
     }
 
     @Test
-    public void testSelfReferencingDependencyInRawModel()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/self-referencing.xml" );
+    void testSelfReferencingDependencyInRawModel() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/self-referencing.xml");
 
-        assertViolations( result, 1, 0, 0 );
+        assertViolations(result, 1, 0, 0);
 
-        assertEquals( "'dependencies.dependency[com.example.group:testinvalidpom:0.0.1-SNAPSHOT]' for com.example.group:testinvalidpom:0.0.1-SNAPSHOT is referencing itself.",
-                      result.getFatals().get( 0 ) );
-
+        assertEquals(
+                "'dependencies.dependency[com.example.group:testinvalidpom:0.0.1-SNAPSHOT]' for com.example.group:testinvalidpom:0.0.1-SNAPSHOT is referencing itself.",
+                result.getFatals().get(0));
     }
 
     @Test
-    public void testSelfReferencingDependencyWithClassifierInRawModel() throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/self-referencing-classifier.xml" );
+    void testSelfReferencingDependencyWithClassifierInRawModel() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/self-referencing-classifier.xml");
 
-        assertViolations( result, 0, 0, 0 );
+        assertViolations(result, 0, 0, 0);
     }
 
     @Test
-    public void testCiFriendlySha1()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/ok-ci-friendly-sha1.xml" );
-        assertViolations( result, 0, 0, 0 );
+    void testCiFriendlySha1() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-sha1.xml");
+        assertViolations(result, 0, 0, 0);
     }
 
     @Test
-    public void testCiFriendlyRevision()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/ok-ci-friendly-revision.xml" );
-        assertViolations( result, 0, 0, 0 );
+    void testCiFriendlyRevision() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-revision.xml");
+        assertViolations(result, 0, 0, 0);
     }
 
     @Test
-    public void testCiFriendlyChangeList()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/ok-ci-friendly-changelist.xml" );
-        assertViolations( result, 0, 0, 0 );
+    void testCiFriendlyChangeList() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-changelist.xml");
+        assertViolations(result, 0, 0, 0);
     }
 
     @Test
-    public void testCiFriendlyAllExpressions()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/ok-ci-friendly-all-expressions.xml" );
-        assertViolations( result, 0, 0, 0 );
+    void testCiFriendlyAllExpressions() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/ok-ci-friendly-all-expressions.xml");
+        assertViolations(result, 0, 0, 0);
     }
 
     @Test
-    public void testCiFriendlyBad()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/bad-ci-friendly.xml" );
-        assertViolations( result, 0, 0, 1 );
-        assertEquals( "'version' contains an expression but should be a constant.", result.getWarnings().get( 0 ) );
+    void testCiFriendlyBad() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/bad-ci-friendly.xml");
+        assertViolations(result, 0, 0, 1);
+        assertEquals(
+                "'version' contains an expression but should be a constant.",
+                result.getWarnings().get(0));
     }
 
     @Test
-    public void testCiFriendlyBadSha1Plus()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/bad-ci-friendly-sha1plus.xml" );
-        assertViolations( result, 0, 0, 1 );
-        assertEquals( "'version' contains an expression but should be a constant.", result.getWarnings().get( 0 ) );
+    void testCiFriendlyBadSha1Plus() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/bad-ci-friendly-sha1plus.xml");
+        assertViolations(result, 0, 0, 1);
+        assertEquals(
+                "'version' contains an expression but should be a constant.",
+                result.getWarnings().get(0));
     }
 
     @Test
-    public void testCiFriendlyBadSha1Plus2()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/bad-ci-friendly-sha1plus2.xml" );
-        assertViolations( result, 0, 0, 1 );
-        assertEquals( "'version' contains an expression but should be a constant.", result.getWarnings().get( 0 ) );
+    void testCiFriendlyBadSha1Plus2() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/bad-ci-friendly-sha1plus2.xml");
+        assertViolations(result, 0, 0, 1);
+        assertEquals(
+                "'version' contains an expression but should be a constant.",
+                result.getWarnings().get(0));
     }
 
     @Test
-    public void testParentVersionLATEST()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/bad-parent-version-latest.xml" );
-        assertViolations( result, 0, 0, 1 );
-        assertEquals( "'parent.version' is either LATEST or RELEASE (both of them are being deprecated)", result.getWarnings().get( 0 ) );
+    void testParentVersionLATEST() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/bad-parent-version-latest.xml");
+        assertViolations(result, 0, 0, 1);
+        assertEquals(
+                "'parent.version' is either LATEST or RELEASE (both of them are being deprecated)",
+                result.getWarnings().get(0));
     }
 
     @Test
-    public void testParentVersionRELEASE()
-        throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/bad-parent-version-release.xml" );
-        assertViolations( result, 0, 0, 1 );
-        assertEquals( "'parent.version' is either LATEST or RELEASE (both of them are being deprecated)", result.getWarnings().get( 0 ) );
+    void testParentVersionRELEASE() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/bad-parent-version-release.xml");
+        assertViolations(result, 0, 0, 1);
+        assertEquals(
+                "'parent.version' is either LATEST or RELEASE (both of them are being deprecated)",
+                result.getWarnings().get(0));
     }
 
     @Test
-    public void repositoryWithExpression() throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/repository-with-expression.xml" );
-        assertViolations( result, 0, 1, 0 );
-        assertEquals( "'repositories.repository.[repo].url' contains an expression but should be a constant.", result.getErrors().get( 0 ) );
+    void repositoryWithExpression() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/repository-with-expression.xml");
+        assertViolations(result, 0, 1, 0);
+        assertEquals(
+                "'repositories.repository.[repo].url' contains an expression but should be a constant.",
+                result.getErrors().get(0));
     }
 
     @Test
-    public void repositoryWithBasedirExpression() throws Exception
-    {
-        SimpleProblemCollector result = validateRaw( "raw-model/repository-with-basedir-expression.xml" );
-        assertViolations( result, 0, 0, 0 );
+    void repositoryWithBasedirExpression() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/repository-with-basedir-expression.xml");
+        assertViolations(result, 0, 0, 0);
     }
 
+    @Test
+    void profileActivationWithAllowedExpression() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/profile-activation-file-with-allowed-expressions.xml");
+        assertViolations(result, 0, 0, 0);
+    }
+
+    @Test
+    void profileActivationWithProjectExpression() throws Exception {
+        SimpleProblemCollector result = validateRaw("raw-model/profile-activation-file-with-project-expressions.xml");
+        assertViolations(result, 0, 0, 2);
+
+        assertEquals(
+                "'profiles.profile[exists-project-version].activation.file.exists' "
+                        + "Failed to interpolate file location ${project.version}/test.txt: "
+                        + "${project.version} expressions are not supported during profile activation.",
+                result.getWarnings().get(0));
+
+        assertEquals(
+                "'profiles.profile[missing-project-version].activation.file.missing' "
+                        + "Failed to interpolate file location ${project.version}/test.txt: "
+                        + "${project.version} expressions are not supported during profile activation.",
+                result.getWarnings().get(1));
+    }
 }
diff --git a/maven-model-builder/src/test/resources/poms/validation/modelVersion-4_0.xml b/maven-model-builder/src/test/resources/poms/validation/modelVersion-4_0.xml
new file mode 100644
index 0000000..544331b
--- /dev/null
+++ b/maven-model-builder/src/test/resources/poms/validation/modelVersion-4_0.xml
@@ -0,0 +1,25 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project>
+  <modelVersion>4.0</modelVersion>
+  <groupId>foo</groupId>
+  <artifactId>bar</artifactId>
+  <version>0.1</version>
+</project>
diff --git a/maven-model-builder/src/test/resources/poms/validation/raw-model/profile-activation-file-with-allowed-expressions.xml b/maven-model-builder/src/test/resources/poms/validation/raw-model/profile-activation-file-with-allowed-expressions.xml
new file mode 100644
index 0000000..a4beb62
--- /dev/null
+++ b/maven-model-builder/src/test/resources/poms/validation/raw-model/profile-activation-file-with-allowed-expressions.xml
@@ -0,0 +1,64 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>
+  <artifactId>aid</artifactId>
+  <groupId>gid</groupId>
+  <version>0.1</version>
+  <packaging>pom</packaging>
+
+  <profiles>
+    <profile>
+      <id>exists-basedir</id>
+      <activation>
+        <file>
+          <exists>${basedir}/test.txt</exists>
+        </file>
+      </activation>
+    </profile>
+    <profile>
+      <id>missing-basedir</id>
+      <activation>
+        <file>
+          <missing>${basedir}/test.txt</missing>
+        </file>
+      </activation>
+    </profile>
+
+    <profile>
+      <id>exists-project-basedir</id>
+      <activation>
+        <file>
+          <exists>${project.basedir}/test.txt</exists>
+        </file>
+      </activation>
+    </profile>
+    <profile>
+      <id>missing-project-basedir</id>
+      <activation>
+        <file>
+          <missing>${project.basedir}/test.txt</missing>
+        </file>
+      </activation>
+    </profile>
+
+  </profiles>
+</project>
diff --git a/maven-model-builder/src/test/resources/poms/validation/raw-model/profile-activation-file-with-project-expressions.xml b/maven-model-builder/src/test/resources/poms/validation/raw-model/profile-activation-file-with-project-expressions.xml
new file mode 100644
index 0000000..65953c3
--- /dev/null
+++ b/maven-model-builder/src/test/resources/poms/validation/raw-model/profile-activation-file-with-project-expressions.xml
@@ -0,0 +1,48 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>
+  <artifactId>aid</artifactId>
+  <groupId>gid</groupId>
+  <version>0.1</version>
+  <packaging>pom</packaging>
+
+  <profiles>
+
+    <profile>
+      <id>exists-project-version</id>
+      <activation>
+        <file>
+          <exists>${project.version}/test.txt</exists>
+        </file>
+      </activation>
+    </profile>
+    <profile>
+      <id>missing-project-version</id>
+      <activation>
+        <file>
+          <missing>${project.version}/test.txt</missing>
+        </file>
+      </activation>
+    </profile>
+
+  </profiles>
+</project>
diff --git a/maven-model-transform/pom.xml b/maven-model-transform/pom.xml
deleted file mode 100644
index 5024085..0000000
--- a/maven-model-transform/pom.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<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>org.apache.maven</groupId>
-    <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
-  </parent>
-  <artifactId>maven-model-transform</artifactId>
-  <name>Maven Model XML Transform</name>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-params</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.xmlunit</groupId>
-      <artifactId>xmlunit-assertj</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-
-  </dependencies>
-</project>
\ No newline at end of file
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
deleted file mode 100644
index dba9026..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.java
+++ /dev/null
@@ -1,109 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.nio.file.Path;
-import java.util.Optional;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * Base implementation for providing the BuildToRawPomXML.
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class BuildToRawPomXMLFilterFactory
-{
-    private final boolean consume;
-
-    public BuildToRawPomXMLFilterFactory()
-    {
-        this( false );
-    }
-
-    public BuildToRawPomXMLFilterFactory( boolean consume )
-    {
-        this.consume = consume;
-    }
-
-    /**
-     *
-     * @param projectFile will be used by ConsumerPomXMLFilter to get the right filter
-     */
-    public final XmlPullParser get( XmlPullParser orgParser, Path projectFile )
-
-    {
-        // Ensure that xs:any elements aren't touched by next filters
-        XmlPullParser parser = orgParser instanceof FastForwardFilter
-                ? orgParser : new FastForwardFilter( orgParser );
-
-        if ( getDependencyKeyToVersionMapper() != null )
-        {
-            parser = new ReactorDependencyXMLFilter( parser, getDependencyKeyToVersionMapper() );
-        }
-
-        if ( getRelativePathMapper() != null )
-        {
-            parser = new ParentXMLFilter( parser, getRelativePathMapper(), projectFile.getParent() );
-        }
-
-        CiFriendlyXMLFilter ciFriendlyFilter = new CiFriendlyXMLFilter( parser, consume );
-        getChangelist().ifPresent( ciFriendlyFilter::setChangelist  );
-        getRevision().ifPresent( ciFriendlyFilter::setRevision );
-        getSha1().ifPresent( ciFriendlyFilter::setSha1 );
-        parser = ciFriendlyFilter;
-
-        return parser;
-    }
-
-    /**
-     * @return the mapper or {@code null} if relativePaths don't need to be mapped
-     */
-    protected Function<Path, Optional<RelativeProject>> getRelativePathMapper()
-    {
-        return null;
-    }
-
-    protected BiFunction<String, String, String> getDependencyKeyToVersionMapper()
-    {
-        return null;
-    }
-
-    // getters for the 3 magic properties of CIFriendly versions ( https://maven.apache.org/maven-ci-friendly.html )
-
-    protected Optional<String> getChangelist()
-    {
-        return Optional.empty();
-    }
-
-    protected Optional<String> getRevision()
-    {
-        return Optional.empty();
-    }
-
-    protected Optional<String> getSha1()
-    {
-        return Optional.empty();
-    }
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/CiFriendlyXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/CiFriendlyXMLFilter.java
deleted file mode 100644
index f981a8f..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/CiFriendlyXMLFilter.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-import java.util.function.Function;
-
-import org.apache.maven.model.transform.pull.NodeBufferingParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * Resolves all ci-friendly properties occurrences between version-tags
- *
- * @author Robert Scholte
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-class CiFriendlyXMLFilter
-    extends NodeBufferingParser
-{
-    private final boolean replace;
-
-    private Function<String, String> replaceChain = Function.identity();
-
-    CiFriendlyXMLFilter( XmlPullParser xmlPullParser, boolean replace )
-    {
-        super( xmlPullParser, "version" );
-        this.replace = replace;
-    }
-
-    public CiFriendlyXMLFilter setChangelist( String changelist )
-    {
-        replaceChain = replaceChain.andThen( t -> t.replace( "${changelist}", changelist ) );
-        return this;
-    }
-
-    public CiFriendlyXMLFilter setRevision( String revision )
-    {
-        replaceChain = replaceChain.andThen( t -> t.replace( "${revision}", revision ) );
-        return this;
-    }
-
-    public CiFriendlyXMLFilter setSha1( String sha1 )
-    {
-        replaceChain = replaceChain.andThen( t -> t.replace( "${sha1}", sha1 ) );
-        return this;
-    }
-
-    /**
-     * @return {@code true} is any of the ci properties is set, otherwise {@code false}
-     */
-    public boolean isSet()
-    {
-        return !replaceChain.equals( Function.identity() );
-    }
-
-    @Override
-    protected void process( List<Event> buffer )
-    {
-        for ( Event event : buffer )
-        {
-            if ( event.event == TEXT && replace && event.text.contains( "${" ) )
-            {
-                event.text = replaceChain.apply( event.text );
-            }
-            pushEvent( event );
-        }
-    }
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
deleted file mode 100644
index c6647ba..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/FastForwardFilter.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.util.ArrayDeque;
-import java.util.Deque;
-
-import org.apache.maven.model.transform.pull.BufferingParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * This filter will bypass all following filters and write directly to the output.
- * Should be used in case of a DOM that should not be effected by other filters,
- * even though the elements match.
- *
- * @author Robert Scholte
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-class FastForwardFilter extends BufferingParser
-{
-    /**
-     * DOM elements of pom
-     *
-     * <ul>
-     *  <li>execution.configuration</li>
-     *  <li>plugin.configuration</li>
-     *  <li>plugin.goals</li>
-     *  <li>profile.reports</li>
-     *  <li>project.reports</li>
-     *  <li>reportSet.configuration</li>
-     * <ul>
-     */
-    private final Deque<String> state = new ArrayDeque<>();
-
-    private int domDepth = 0;
-
-    FastForwardFilter( XmlPullParser xmlPullParser )
-    {
-        super( xmlPullParser );
-    }
-
-    @Override
-    public int next() throws XmlPullParserException, IOException
-    {
-        int event = super.next();
-        filter();
-        return event;
-    }
-
-    @Override
-    public int nextToken() throws XmlPullParserException, IOException
-    {
-        int event = super.nextToken();
-        filter();
-        return event;
-    }
-
-    protected void filter() throws XmlPullParserException, IOException
-    {
-        if ( xmlPullParser.getEventType() == START_TAG )
-        {
-            String localName = xmlPullParser.getName();
-            if ( domDepth > 0 )
-            {
-                domDepth++;
-            }
-            else
-            {
-                final String key = state.peekLast() + '/' + localName;
-                switch ( key )
-                {
-                    case "execution/configuration":
-                    case "plugin/configuration":
-                    case "plugin/goals":
-                    case "profile/reports":
-                    case "project/reports":
-                    case "reportSet/configuration":
-                        if ( domDepth == 0 )
-                        {
-                            bypass( true );
-                        }
-                        domDepth++;
-                        break;
-                    default:
-                        break;
-                }
-            }
-            state.add( localName );
-        }
-        else if ( xmlPullParser.getEventType() == END_TAG )
-        {
-            if ( domDepth > 0 )
-            {
-                if ( --domDepth == 0 )
-                {
-                    bypass( false );
-                }
-            }
-            state.removeLast();
-        }
-    }
-
-    @Override
-    public void bypass( boolean bypass )
-    {
-        this.bypass = bypass;
-    }
-}
\ No newline at end of file
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModulesXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModulesXMLFilter.java
deleted file mode 100644
index 4d3f94a..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ModulesXMLFilter.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.model.transform.pull.NodeBufferingParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * Remove all modules, this is just buildtime information
- *
- * @author Robert Scholte
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-class ModulesXMLFilter
-    extends NodeBufferingParser
-{
-    ModulesXMLFilter( XmlPullParser xmlPullParser )
-    {
-        super( xmlPullParser, "modules" );
-    }
-
-    protected void process( List<Event> buffer )
-    {
-        // Do nothing, as we want to delete those nodes completely
-    }
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
deleted file mode 100644
index 37ac28b..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ParentXMLFilter.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.function.Function;
-
-import org.apache.maven.model.transform.pull.NodeBufferingParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * <p>
- * Transforms relativePath to version.
- * We could decide to simply allow {@code <parent/>}, but let's require the GA for now for checking
- * This filter does NOT remove the relativePath (which is done by {@link RelativePathXMLFilter}, it will only
- * optionally include the version based on the path
- * </p>
- *
- * @author Robert Scholte
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-class ParentXMLFilter
-    extends NodeBufferingParser
-{
-
-    private final Function<Path, Optional<RelativeProject>> relativePathMapper;
-
-    private final Path projectPath;
-
-    /**
-     * @param relativePathMapper
-     */
-    ParentXMLFilter( XmlPullParser parser,
-                     Function<Path, Optional<RelativeProject>> relativePathMapper, Path projectPath )
-    {
-        super( parser, "parent" );
-        this.relativePathMapper = relativePathMapper;
-        this.projectPath = projectPath;
-    }
-
-    protected void process( List<Event> buffer )
-    {
-        String tagName = null;
-        String groupId = null;
-        String artifactId = null;
-        String version = null;
-        String relativePath = null;
-        String whitespaceAfterParentStart = "";
-        boolean hasVersion = false;
-        boolean hasRelativePath = false;
-        for ( int i = 0; i < buffer.size(); i++ )
-        {
-            Event event = buffer.get( i );
-            if ( event.event == START_TAG )
-            {
-                tagName = event.name;
-                hasVersion |= "version".equals( tagName );
-                hasRelativePath |= "relativePath".equals( tagName );
-            }
-            else if ( event.event == TEXT )
-            {
-                if ( event.text.matches( "\\s+" ) )
-                {
-                    if ( whitespaceAfterParentStart.isEmpty() )
-                    {
-                        whitespaceAfterParentStart = event.text;
-                    }
-                }
-                else if ( "groupId".equals( tagName ) )
-                {
-                    groupId = nullSafeAppend( groupId, event.text );
-                }
-                else if ( "artifactId".equals( tagName ) )
-                {
-                    artifactId = nullSafeAppend( artifactId, event.text );
-                }
-                else if ( "relativePath".equals( tagName ) )
-                {
-                    relativePath = nullSafeAppend( relativePath, event.text );
-                }
-                else if ( "version".equals( tagName ) )
-                {
-                    version = nullSafeAppend( version, event.text );
-                }
-            }
-            else if ( event.event == END_TAG && "parent".equals( event.name ) )
-            {
-                Optional<RelativeProject> resolvedParent;
-                if ( !hasVersion && ( !hasRelativePath || relativePath != null ) )
-                {
-                    Path relPath = Paths.get( Objects.toString( relativePath, "../pom.xml" ) );
-                    resolvedParent = resolveRelativePath( relPath, groupId, artifactId );
-                }
-                else
-                {
-                    resolvedParent = Optional.empty();
-                }
-                if ( !hasVersion && resolvedParent.isPresent() )
-                {
-                    int pos = buffer.get( i - 1 ).event == TEXT ? i - 1  : i;
-                    Event e = new Event();
-                    e.event = TEXT;
-                    e.text = whitespaceAfterParentStart;
-                    buffer.add( pos++, e );
-                    e = new Event();
-                    e.event = START_TAG;
-                    e.namespace = buffer.get( 0 ).namespace;
-                    e.prefix = buffer.get( 0 ).prefix;
-                    e.name = "version";
-                    buffer.add( pos++, e );
-                    e = new Event();
-                    e.event = TEXT;
-                    e.text = resolvedParent.get().getVersion();
-                    buffer.add( pos++, e );
-                    e = new Event();
-                    e.event = END_TAG;
-                    e.name = "version";
-                    e.namespace = buffer.get( 0 ).namespace;
-                    e.prefix = buffer.get( 0 ).prefix;
-                    buffer.add( pos++, e );
-                }
-                break;
-            }
-        }
-        buffer.forEach( this::pushEvent );
-   }
-
-
-    protected Optional<RelativeProject> resolveRelativePath( Path relativePath, String groupId, String artifactId )
-    {
-        Path pomPath = projectPath.resolve( relativePath );
-        if ( Files.isDirectory( pomPath ) )
-        {
-            pomPath = pomPath.resolve( "pom.xml" );
-        }
-
-        Optional<RelativeProject> mappedProject = relativePathMapper.apply( pomPath.normalize() );
-
-        if ( mappedProject.isPresent() )
-        {
-            RelativeProject project = mappedProject.get();
-
-            if ( Objects.equals( groupId, project.getGroupId() )
-                && Objects.equals( artifactId, project.getArtifactId() ) )
-            {
-                return mappedProject;
-            }
-        }
-        return Optional.empty();
-    }
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
deleted file mode 100644
index ec8bd4b..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.nio.file.Path;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * @author Guillaume Nodet
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class RawToConsumerPomXMLFilterFactory
-{
-    private BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory;
-
-    public RawToConsumerPomXMLFilterFactory( BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory )
-    {
-        this.buildPomXMLFilterFactory = buildPomXMLFilterFactory;
-    }
-
-    public final XmlPullParser get( XmlPullParser orgParser, Path projectPath )
-    {
-        // Ensure that xs:any elements aren't touched by next filters
-        XmlPullParser parser = orgParser instanceof FastForwardFilter
-                ? orgParser : new FastForwardFilter( orgParser );
-
-        parser = buildPomXMLFilterFactory.get( parser, projectPath );
-
-        // Strip modules
-        parser = new ModulesXMLFilter( parser );
-        // Adjust relativePath
-        parser = new RelativePathXMLFilter( parser );
-
-        return parser;
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
deleted file mode 100644
index 7f9dd3b..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/ReactorDependencyXMLFilter.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-import java.util.function.BiFunction;
-
-import org.apache.maven.model.transform.pull.NodeBufferingParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * Will apply the version if the dependency is part of the reactor
- *
- * @author Robert Scholte
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-public class ReactorDependencyXMLFilter extends NodeBufferingParser
-{
-    private final BiFunction<String, String, String> reactorVersionMapper;
-
-    public ReactorDependencyXMLFilter( XmlPullParser xmlPullParser,
-                                       BiFunction<String, String, String> reactorVersionMapper )
-    {
-        super( xmlPullParser, "dependency" );
-        this.reactorVersionMapper = reactorVersionMapper;
-    }
-
-    protected void process( List<Event> buffer )
-    {
-        // whiteSpace after <dependency>, to be used to position <version>
-        String dependencyWhitespace = "";
-        boolean hasVersion = false;
-        String groupId = null;
-        String artifactId = null;
-        String tagName = null;
-        for ( int i = 0; i < buffer.size(); i++ )
-        {
-            Event event = buffer.get( i );
-            if ( event.event == START_TAG )
-            {
-                tagName = event.name;
-                hasVersion |= "version".equals( tagName );
-            }
-            else if ( event.event == TEXT )
-            {
-                if ( event.text.matches( "\\s+" ) )
-                {
-                    if ( dependencyWhitespace.isEmpty() )
-                    {
-                        dependencyWhitespace = event.text;
-                    }
-                }
-                else if ( "groupId".equals( tagName ) )
-                {
-                    groupId = nullSafeAppend( groupId, event.text );
-                }
-                else if ( "artifactId".equals( tagName ) )
-                {
-                    artifactId = nullSafeAppend( artifactId, event.text );
-                }
-            }
-            else if ( event.event == END_TAG && "dependency".equals( event.name ) )
-            {
-                String version = reactorVersionMapper.apply( groupId, artifactId  );
-                if ( !hasVersion && version != null )
-                {
-                    int pos = buffer.get( i - 1 ).event == TEXT ? i - 1  : i;
-                    Event e = new Event();
-                    e.event = TEXT;
-                    e.text = dependencyWhitespace;
-                    buffer.add( pos++, e );
-                    e = new Event();
-                    e.event = START_TAG;
-                    e.namespace = buffer.get( 0 ).namespace;
-                    e.prefix = buffer.get( 0 ).prefix;
-                    e.name = "version";
-                    buffer.add( pos++, e );
-                    e = new Event();
-                    e.event = TEXT;
-                    e.text = version;
-                    buffer.add( pos++, e );
-                    e = new Event();
-                    e.event = END_TAG;
-                    e.name = "version";
-                    e.namespace = buffer.get( 0 ).namespace;
-                    e.prefix = buffer.get( 0 ).prefix;
-                    buffer.add( pos++, e );
-                }
-                break;
-            }
-        }
-        buffer.forEach( this::pushEvent );
-    }
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
deleted file mode 100644
index 3064a29..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativePathXMLFilter.java
+++ /dev/null
@@ -1,75 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.List;
-
-import org.apache.maven.model.transform.pull.NodeBufferingParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-
-/**
- * Remove relativePath element, has no value for consumer pom
- *
- * @author Robert Scholte
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-public class RelativePathXMLFilter extends NodeBufferingParser
-{
-
-    public RelativePathXMLFilter( XmlPullParser xmlPullParser )
-    {
-        super( xmlPullParser, "parent" );
-    }
-
-    protected void process( List<Event> buffer )
-    {
-        boolean skip = false;
-        Event prev = null;
-        for ( Event event : buffer )
-        {
-            if ( event.event == START_TAG && "relativePath".equals( event.name ) )
-            {
-                skip = true;
-                if ( prev != null && prev.event == TEXT && prev.text.matches( "\\s+" ) )
-                {
-                    prev = null;
-                }
-                event = null;
-            }
-            else if ( event.event == END_TAG && "relativePath".equals( event.name ) )
-            {
-                skip = false;
-                event = null;
-            }
-            else if ( skip )
-            {
-                event = null;
-            }
-            if ( prev != null )
-            {
-                pushEvent( prev );
-            }
-            prev = event;
-        }
-        pushEvent( prev );
-    }
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativeProject.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativeProject.java
deleted file mode 100644
index 81af137..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/RelativeProject.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/**
- *
- * @author Robert Scholte
- * @since 4.0.0
- */
-public class RelativeProject
-{
-    private final String groupId;
-
-    private final String artifactId;
-
-    private final String version;
-
-    public RelativeProject( String groupId, String artifactId, String version )
-    {
-        this.groupId = groupId;
-        this.artifactId = artifactId;
-        this.version = version;
-    }
-
-    public String getGroupId()
-    {
-        return groupId;
-    }
-
-    public String getArtifactId()
-    {
-        return artifactId;
-    }
-
-    public String getVersion()
-    {
-        return version;
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/BufferingParser.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/BufferingParser.java
deleted file mode 100644
index e366268..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/BufferingParser.java
+++ /dev/null
@@ -1,561 +0,0 @@
-package org.apache.maven.model.transform.pull;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Reader;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.Objects;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * An xml pull parser filter base implementation.
- *
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-public class BufferingParser implements XmlPullParser
-{
-
-    protected XmlPullParser xmlPullParser;
-    protected Deque<Event> events;
-    protected Event current;
-    protected boolean bypass;
-
-    @SuppressWarnings( "checkstyle:VisibilityModifier" )
-    public static class Event
-    {
-        public int event;
-        public String name;
-        public String prefix;
-        public String namespace;
-        public boolean empty;
-        public String text;
-        public Attribute[] attributes;
-        public Namespace[] namespaces;
-    }
-
-    @SuppressWarnings( "checkstyle:VisibilityModifier" )
-    public static class Namespace
-    {
-        public String prefix;
-        public String uri;
-    }
-
-    @SuppressWarnings( "checkstyle:VisibilityModifier" )
-    public static class Attribute
-    {
-        public String name;
-        public String prefix;
-        public String namespace;
-        public String type;
-        public String value;
-        public boolean isDefault;
-    }
-
-
-    public BufferingParser( XmlPullParser xmlPullParser )
-    {
-        this.xmlPullParser = xmlPullParser;
-    }
-
-    @Override
-    public void setFeature( String name, boolean state ) throws XmlPullParserException
-    {
-        xmlPullParser.setFeature( name, state );
-    }
-
-    @Override
-    public boolean getFeature( String name )
-    {
-        return xmlPullParser.getFeature( name );
-    }
-
-    @Override
-    public void setProperty( String name, Object value ) throws XmlPullParserException
-    {
-        xmlPullParser.setProperty( name, value );
-    }
-
-    @Override
-    public Object getProperty( String name )
-    {
-        return xmlPullParser.getProperty( name );
-    }
-
-    @Override
-    public void setInput( Reader in ) throws XmlPullParserException
-    {
-        xmlPullParser.setInput( in );
-    }
-
-    @Override
-    public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException
-    {
-        xmlPullParser.setInput( inputStream, inputEncoding );
-    }
-
-    @Override
-    public String getInputEncoding()
-    {
-        return xmlPullParser.getInputEncoding();
-    }
-
-    @Override
-    public void defineEntityReplacementText( String entityName, String replacementText ) throws XmlPullParserException
-    {
-        xmlPullParser.defineEntityReplacementText( entityName, replacementText );
-    }
-
-    @Override
-    public int getNamespaceCount( int depth ) throws XmlPullParserException
-    {
-//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
-        return xmlPullParser.getNamespaceCount( depth );
-    }
-
-    @Override
-    public String getNamespacePrefix( int pos ) throws XmlPullParserException
-    {
-//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
-        return xmlPullParser.getNamespacePrefix( pos );
-    }
-
-    @Override
-    public String getNamespaceUri( int pos ) throws XmlPullParserException
-    {
-//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
-        return xmlPullParser.getNamespaceUri( pos );
-    }
-
-    @Override
-    public String getNamespace( String prefix )
-    {
-//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
-        return xmlPullParser.getNamespace( prefix );
-    }
-
-    @Override
-    public int getDepth()
-    {
-//  TODO:      if (current != null) throw new IllegalStateException("Not supported during events replay");
-        return xmlPullParser.getDepth();
-    }
-
-    @Override
-    public String getPositionDescription()
-    {
-        if ( current != null )
-        {
-            throw new IllegalStateException( "Not supported during events replay" );
-        }
-        return xmlPullParser.getPositionDescription();
-    }
-
-    @Override
-    public int getLineNumber()
-    {
-        if ( current != null )
-        {
-            throw new IllegalStateException( "Not supported during events replay" );
-        }
-        return xmlPullParser.getLineNumber();
-    }
-
-    @Override
-    public int getColumnNumber()
-    {
-        if ( current != null )
-        {
-            throw new IllegalStateException( "Not supported during events replay" );
-        }
-        return xmlPullParser.getColumnNumber();
-    }
-
-    @Override
-    public boolean isWhitespace() throws XmlPullParserException
-    {
-        if ( current != null )
-        {
-            if ( current.event == TEXT || current.event == CDSECT )
-            {
-                return current.text.matches( "[ \r\t\n]+" );
-            }
-            else if ( current.event == IGNORABLE_WHITESPACE )
-            {
-                return true;
-            }
-            else
-            {
-                throw new XmlPullParserException( "no content available to check for whitespaces" );
-            }
-        }
-        return xmlPullParser.isWhitespace();
-    }
-
-    @Override
-    public String getText()
-    {
-        return current != null ? current.text : xmlPullParser.getText();
-    }
-
-    @Override
-    public char[] getTextCharacters( int[] holderForStartAndLength )
-    {
-        if ( current != null )
-        {
-            throw new IllegalStateException( "Not supported during events replay" );
-        }
-        return xmlPullParser.getTextCharacters( holderForStartAndLength );
-    }
-
-    @Override
-    public String getNamespace()
-    {
-        return current != null ? current.namespace : xmlPullParser.getNamespace();
-    }
-
-    @Override
-    public String getName()
-    {
-        return current != null ? current.name : xmlPullParser.getName();
-    }
-
-    @Override
-    public String getPrefix()
-    {
-        return current != null ? current.prefix : xmlPullParser.getPrefix();
-    }
-
-    @Override
-    public boolean isEmptyElementTag() throws XmlPullParserException
-    {
-        return current != null ? current.empty : xmlPullParser.isEmptyElementTag();
-    }
-
-    @Override
-    public int getAttributeCount()
-    {
-        if ( current != null )
-        {
-            return current.attributes != null ? current.attributes.length : 0;
-        }
-        else
-        {
-            return xmlPullParser.getAttributeCount();
-        }
-    }
-
-    @Override
-    public String getAttributeNamespace( int index )
-    {
-        if ( current != null )
-        {
-            return current.attributes[index].namespace;
-        }
-        else
-        {
-            return xmlPullParser.getAttributeNamespace( index );
-        }
-    }
-
-    @Override
-    public String getAttributeName( int index )
-    {
-        if ( current != null )
-        {
-            return current.attributes[index].name;
-        }
-        else
-        {
-            return xmlPullParser.getAttributeName( index );
-        }
-    }
-
-    @Override
-    public String getAttributePrefix( int index )
-    {
-        if ( current != null )
-        {
-            return current.attributes[index].prefix;
-        }
-        else
-        {
-            return xmlPullParser.getAttributePrefix( index );
-        }
-    }
-
-    @Override
-    public String getAttributeType( int index )
-    {
-        if ( current != null )
-        {
-            return current.attributes[index].type;
-        }
-        else
-        {
-            return xmlPullParser.getAttributeType( index );
-        }
-    }
-
-    @Override
-    public boolean isAttributeDefault( int index )
-    {
-        if ( current != null )
-        {
-            return current.attributes[index].isDefault;
-        }
-        else
-        {
-            return xmlPullParser.isAttributeDefault( index );
-        }
-    }
-
-    @Override
-    public String getAttributeValue( int index )
-    {
-        if ( current != null )
-        {
-            return current.attributes[index].value;
-        }
-        else
-        {
-            return xmlPullParser.getAttributeValue( index );
-        }
-    }
-
-    @Override
-    public String getAttributeValue( String namespace, String name )
-    {
-        if ( current != null )
-        {
-            if ( current.attributes != null )
-            {
-                for ( Attribute attr : current.attributes )
-                {
-                    if ( Objects.equals( namespace, attr.namespace )
-                            && Objects.equals( name, attr.name ) )
-                    {
-                        return attr.value;
-                    }
-                }
-            }
-            return null;
-        }
-        else
-        {
-            return xmlPullParser.getAttributeValue( namespace, name );
-        }
-    }
-
-    @Override
-    public void require( int type, String namespace, String name ) throws XmlPullParserException, IOException
-    {
-        if ( current != null )
-        {
-            throw new IllegalStateException( "Not supported during events replay" );
-        }
-        xmlPullParser.require( type, namespace, name );
-    }
-
-    @Override
-    public int getEventType() throws XmlPullParserException
-    {
-        return current != null ? current.event : xmlPullParser.getEventType();
-    }
-
-    @Override
-    public int next() throws XmlPullParserException, IOException
-    {
-        while ( true )
-        {
-            if ( events != null && !events.isEmpty() )
-            {
-                current = events.removeFirst();
-                return current.event;
-            }
-            else
-            {
-                current = null;
-            }
-            if ( getEventType() == END_DOCUMENT )
-            {
-                throw new XmlPullParserException( "already reached end of XML input", this, null );
-            }
-            int currentEvent = xmlPullParser.next();
-            if ( bypass() || accept() )
-            {
-                return currentEvent;
-            }
-        }
-    }
-
-    @Override
-    public int nextToken() throws XmlPullParserException, IOException
-    {
-        while ( true )
-        {
-            if ( events != null && !events.isEmpty() )
-            {
-                current = events.removeFirst();
-                return current.event;
-            }
-            else
-            {
-                current = null;
-            }
-            if ( getEventType() == END_DOCUMENT )
-            {
-                throw new XmlPullParserException( "already reached end of XML input", this, null );
-            }
-            int currentEvent = xmlPullParser.nextToken();
-            if ( bypass() || accept() )
-            {
-                return currentEvent;
-            }
-        }
-    }
-
-    @Override
-    public int nextTag() throws XmlPullParserException, IOException
-    {
-        int eventType = next();
-        if ( eventType == TEXT && isWhitespace() )
-        { // skip whitespace
-            eventType = next();
-        }
-        if ( eventType != START_TAG && eventType != END_TAG )
-        {
-            throw new XmlPullParserException( "expected START_TAG or END_TAG not "
-                    + TYPES[getEventType()], this, null );
-        }
-        return eventType;
-    }
-
-    @Override
-    public String nextText() throws XmlPullParserException, IOException
-    {
-        int eventType = getEventType();
-        if ( eventType != START_TAG )
-        {
-            throw new XmlPullParserException( "parser must be on START_TAG to read next text", this, null );
-        }
-        eventType = next();
-        if ( eventType == TEXT )
-        {
-            final String result = getText();
-            eventType = next();
-            if ( eventType != END_TAG )
-            {
-                throw new XmlPullParserException( "TEXT must be immediately followed by END_TAG and not "
-                        + TYPES[getEventType()], this, null );
-            }
-            return result;
-        }
-        else if ( eventType == END_TAG )
-        {
-            return "";
-        }
-        else
-        {
-            throw new XmlPullParserException( "parser must be on START_TAG or TEXT to read text", this, null );
-        }
-    }
-
-    protected Event bufferEvent() throws XmlPullParserException
-    {
-        Event event = new Event();
-        XmlPullParser pp = xmlPullParser;
-        event.event = xmlPullParser.getEventType();
-        switch ( event.event )
-        {
-            case START_DOCUMENT:
-            case END_DOCUMENT:
-                break;
-            case START_TAG:
-                event.name = pp.getName();
-                event.namespace = pp.getNamespace();
-                event.prefix = pp.getPrefix();
-                event.empty = pp.isEmptyElementTag();
-                event.text = pp.getText();
-                break;
-            case END_TAG:
-                event.name = pp.getName();
-                event.namespace = pp.getNamespace();
-                event.prefix = pp.getPrefix();
-                event.text = pp.getText();
-                break;
-            case TEXT:
-            case COMMENT:
-            case IGNORABLE_WHITESPACE:
-                event.text = pp.getText();
-                break;
-            default:
-                break;
-        }
-        return event;
-    }
-
-    protected void pushEvent( Event event )
-    {
-        if ( events == null )
-        {
-            events = new ArrayDeque<>();
-        }
-        events.add( event );
-    }
-
-    protected boolean accept() throws XmlPullParserException, IOException
-    {
-        return true;
-    }
-
-    public void bypass( boolean bypass )
-    {
-        if ( bypass && events != null && !events.isEmpty() )
-        {
-            throw new IllegalStateException( "Can not disable filter while processing" );
-        }
-        this.bypass = bypass;
-    }
-
-    public boolean bypass()
-    {
-        return bypass
-                || ( xmlPullParser instanceof BufferingParser
-                        && ( (BufferingParser) xmlPullParser ).bypass() );
-    }
-
-    protected static String nullSafeAppend( String originalValue, String charSegment )
-    {
-        if ( originalValue == null )
-        {
-            return charSegment;
-        }
-        else
-        {
-            return originalValue + charSegment;
-        }
-    }
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/NodeBufferingParser.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/NodeBufferingParser.java
deleted file mode 100644
index 7ea1e3e..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/NodeBufferingParser.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.apache.maven.model.transform.pull;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-/**
- * Buffer events while parsing a given element to allow some post-processing.
- *
- * @author Guillaume Nodet
- * @since 4.0.0
- */
-public abstract class NodeBufferingParser extends BufferingParser
-{
-
-    private final List<Event> buffer = new ArrayList<>();
-
-    private final String nodeName;
-
-    private boolean buffering;
-
-    public NodeBufferingParser( XmlPullParser xmlPullParser, String nodeName )
-    {
-        super( xmlPullParser );
-        this.nodeName = Objects.requireNonNull( nodeName );
-    }
-
-    @Override
-    protected boolean accept() throws XmlPullParserException, IOException
-    {
-        if ( nodeName.equals( xmlPullParser.getName() ) )
-        {
-            if ( xmlPullParser.getEventType() == START_TAG && !buffering )
-            {
-                buffer.add( bufferEvent() );
-                buffering = true;
-                return false;
-            }
-            if ( xmlPullParser.getEventType() == END_TAG && buffering )
-            {
-                buffer.add( bufferEvent() );
-                process( buffer );
-                buffering = false;
-                buffer.clear();
-                return false;
-            }
-        }
-        else if ( buffering )
-        {
-            buffer.add( bufferEvent() );
-            return false;
-        }
-        return true;
-    }
-
-    protected abstract void process( List<Event> buffer );
-
-}
diff --git a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java b/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java
deleted file mode 100644
index f2243c8..0000000
--- a/maven-model-transform/src/main/java/org/apache/maven/model/transform/pull/XmlUtils.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package org.apache.maven.model.transform.pull;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-
-import org.codehaus.plexus.util.xml.XmlStreamReader;
-import org.codehaus.plexus.util.xml.pull.MXSerializer;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-import org.codehaus.plexus.util.xml.pull.XmlSerializer;
-
-public class XmlUtils
-{
-
-    public static ByteArrayInputStream writeDocument( XmlStreamReader reader, XmlPullParser parser )
-            throws IOException, XmlPullParserException
-    {
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        Writer writer = newWriter( reader, baos );
-        writeDocument( parser, writer );
-        return new ByteArrayInputStream( baos.toByteArray() );
-    }
-
-    public static void writeDocument( XmlPullParser parser, Writer writer )
-            throws IOException, XmlPullParserException
-    {
-        XmlSerializer serializer = new MXSerializer();
-        serializer.setOutput( writer );
-
-        while ( parser.nextToken() != XmlPullParser.END_DOCUMENT )
-        {
-            switch ( parser.getEventType() )
-            {
-                case XmlPullParser.START_DOCUMENT:
-                    serializer.startDocument( parser.getInputEncoding(), true );
-                    break;
-                case XmlPullParser.END_DOCUMENT:
-                    serializer.endDocument();
-                case XmlPullParser.START_TAG:
-                    int nsStart = parser.getNamespaceCount( parser.getDepth() - 1 );
-                    int nsEnd = parser.getNamespaceCount( parser.getDepth() );
-                    for ( int i = nsStart; i < nsEnd; i++ )
-                    {
-                        String prefix = parser.getNamespacePrefix( i );
-                        String ns = parser.getNamespaceUri( i );
-                        serializer.setPrefix( prefix, ns );
-                    }
-                    serializer.startTag( parser.getNamespace(), parser.getName() );
-                    for ( int i = 0; i < parser.getAttributeCount(); i++ )
-                    {
-                        serializer.attribute( parser.getAttributeNamespace( i ),
-                                              parser.getAttributeName( i ),
-                                              parser.getAttributeValue( i ) );
-                    }
-                    break;
-                case XmlPullParser.END_TAG:
-                    serializer.endTag( parser.getNamespace(), parser.getName() );
-                    break;
-                case XmlPullParser.TEXT:
-                    serializer.text( normalize( parser.getText() ) );
-                    break;
-                case XmlPullParser.CDSECT:
-                    serializer.cdsect( parser.getText() );
-                    break;
-                case XmlPullParser.ENTITY_REF:
-                    serializer.entityRef( parser.getName() );
-                    break;
-                case XmlPullParser.IGNORABLE_WHITESPACE:
-                    serializer.ignorableWhitespace( normalize( parser.getText() ) );
-                    break;
-                case XmlPullParser.PROCESSING_INSTRUCTION:
-                    serializer.processingInstruction( parser.getText() );
-                    break;
-                case XmlPullParser.COMMENT:
-                    serializer.comment( normalize( parser.getText() ) );
-                    break;
-                case XmlPullParser.DOCDECL:
-                    serializer.docdecl( normalize( parser.getText() ) );
-                    break;
-                default:
-                    break;
-            }
-        }
-
-        serializer.endDocument();
-    }
-
-    private static OutputStreamWriter newWriter( XmlStreamReader reader, ByteArrayOutputStream baos )
-            throws UnsupportedEncodingException
-    {
-        if ( reader.getEncoding() != null )
-        {
-            return new OutputStreamWriter( baos, reader.getEncoding() );
-        }
-        else
-        {
-            return new OutputStreamWriter( baos );
-        }
-    }
-
-    private static String normalize( String input )
-    {
-        if ( input.indexOf( '\n' ) >= 0 && !"\n".equals( System.lineSeparator() ) )
-        {
-            return input.replace( "\n", System.lineSeparator() );
-        }
-        return input;
-    }
-}
diff --git a/maven-model-transform/src/site/apt/index.apt b/maven-model-transform/src/site/apt/index.apt
deleted file mode 100644
index fa329c6..0000000
--- a/maven-model-transform/src/site/apt/index.apt
+++ /dev/null
@@ -1,73 +0,0 @@
-~~ Licensed to the Apache Software Foundation (ASF) under one
-~~ or more contributor license agreements.  See the NOTICE file
-~~ distributed with this work for additional information
-~~ regarding copyright ownership.  The ASF licenses this file
-~~ to you under the Apache License, Version 2.0 (the
-~~ "License"); you may not use this file except in compliance
-~~ with the License.  You may obtain a copy of the License at
-~~
-~~ http://www.apache.org/licenses/LICENSE-2.0
-~~
-~~ Unless required by applicable law or agreed to in writing,
-~~ software distributed under the License is distributed on an
-~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-~~ KIND, either express or implied.  See the License for the
-~~ specific language governing permissions and limitations
-~~ under the License.
-
- -----
- Introduction
- -----
- Hervé Boutemy
- -----
- 2021-04-04
- -----
-
-Maven Model XML Transformer
-
- Maven Model XML Transformer provides build/consumer <<<pom.xml>>> transformers.
-
- In order to keep formatting, comments and every detail when transforming a build <<<pom.xml>>> to a consumer <<<pom.xml>>>, transformation happens directly on the stream of SAX events.
-
- There are 3 states of a <<<pom.xml>>> content:
-
- [[1]] the <<build>> <<<pom.xml>>>, as it is stored on disk during development and in source control, which can be simplified to ease source code maintenance,
-
- [[2]] the <<raw>> content (usually not saved to a file), which is enriched from initial build content, to match Maven Model validation rules,
-
- [[3]] the <<consumer>> <<<pom.xml>>>, as it is saved to local repository or remote repository, to be used as dependencies descriptor when consumed by a project.
-
- []
-
- Transformation is implemented as two filters:
-
- * <<build to raw>> in <<<BuildToRawPomXMLFilter>>> ({{{./apidocs/org/apache/maven/model/transform/BuildPomToRawXMLFilter.html}javadoc}}),
-   with its <<<BuildToRawPomXMLFilterFactory>>> ({{{./xref/org/apache/maven/model/transform/BuildToRawPomXMLFilterFactory.html}source}}) assembling transformation steps,
-
-   * in a multi-module build, <<<parent>>>'s <<<version>>> is automatically added,
-
-   * in a multi-module build, dependencies <<<version>>> is automatically added for reactor modules,
-
-   * CI-friendly <<<$\{sha1}>>>, <<<$\{revision}>>> and <<<$\{changelist}>>> are properties are replaced with their value,
-
-   []
-
- * <<raw to consumer>> in <<<RawToConsumerPomXMLFilter>>>  ({{{./apidocs/org/apache/maven/model/transform/RawToConsumerPomXMLFilter.html}javadoc}}),
-   with its <<<RawToConsumerPomXMLFilterFactory>>> ({{{./xref/org/apache/maven/model/transform/RawToConsumerPomXMLFilterFactory.html}source}}) assembling transformation steps.
-
-   * <<<modules>>> is stripped because it only has a meaning at build time on disk, but not once mapped to repository format,
-
-   * <<<parent>>>'s <<<relativePath>>> is stripped because it only has a meaning at build time on disk, but not once mapped to repository format.
-
-   []
-
- []
-
- For Maven 4, every state of Maven Model remains with the same <<<maven-4.0.0.xsd>>> schema, but it the future Maven 5+:
-
- * build model should evolve to add new features configuration in new <v5> model fields, or remove some old unused fields,
-
- * consumer model should at least continue to produce a <<<maven-4.0.0.xsd>>>-compliant <<<pom.xml>>> for compatibility with the vast and diverse dependency consumers ecosystem,
-   but may also produce in parallel new consumption formats (yet to be defined).
-
- []
diff --git a/maven-model-transform/src/site/site.xml b/maven-model-transform/src/site/site.xml
deleted file mode 100644
index e475330..0000000
--- a/maven-model-transform/src/site/site.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
-
-  <edit>${project.scm.url}</edit>
-
-  <body>
-    <menu name="Overview">
-      <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
-      <item name="Source Xref" href="xref/index.html"/>
-      <!--item name="FAQ" href="faq.html"/-->
-    </menu>
-
-    <menu ref="parent"/>
-    <menu ref="reports"/>
-  </body>
-</project>
\ No newline at end of file
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/AbstractXMLFilterTests.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/AbstractXMLFilterTests.java
deleted file mode 100644
index a18f81a..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/AbstractXMLFilterTests.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-
-import org.apache.maven.model.transform.pull.XmlUtils;
-import org.codehaus.plexus.util.xml.pull.MXParser;
-import org.codehaus.plexus.util.xml.pull.MXSerializer;
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-
-public abstract class AbstractXMLFilterTests
-{
-    protected XmlPullParser getFilter(XmlPullParser parser)
-    {
-        throw new UnsupportedOperationException( "Override one of the getFilter() methods" );
-    }
-
-    protected String transform( String input )
-        throws XmlPullParserException, IOException
-    {
-        return transform( new StringReader( input ) );
-    }
-
-    protected String transform( Reader input )
-            throws XmlPullParserException, IOException {
-
-        MXParser parser = new MXParser();
-        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
-        parser.setInput(input);
-        XmlPullParser filter = getFilter( parser );
-
-        StringWriter writer = new StringWriter();
-        XmlUtils.writeDocument( filter, writer );
-        return writer.toString();
-    }
-
-}
\ No newline at end of file
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/CiFriendlyXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/CiFriendlyXMLFilterTest.java
deleted file mode 100644
index bfbbc11..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/CiFriendlyXMLFilterTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class CiFriendlyXMLFilterTest extends AbstractXMLFilterTests
-{
-    @Override
-    protected CiFriendlyXMLFilter getFilter(XmlPullParser parser) {
-
-        CiFriendlyXMLFilter filter = new CiFriendlyXMLFilter( parser, true );
-        filter.setChangelist( "CHANGELIST" );
-        return filter;
-    }
-
-    @Test
-    public void changelist() throws Exception
-    {
-        String input = "<project>"
-            + "  <groupId>GROUPID</groupId>"
-            + "  <artifactId>ARTIFACTID</artifactId>"
-            +   "<version>${changelist}</version>"
-            + "</project>";
-        String expected = "<project>"
-                        + "  <groupId>GROUPID</groupId>"
-                        + "  <artifactId>ARTIFACTID</artifactId>"
-                        +   "<version>CHANGELIST</version>"
-                        + "</project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
deleted file mode 100644
index ee77d12..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ConsumerPomXMLFilterTest.java
+++ /dev/null
@@ -1,248 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Optional;
-import java.util.function.BiFunction;
-import java.util.function.Function;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.junit.jupiter.api.Test;
-
-public class ConsumerPomXMLFilterTest extends AbstractXMLFilterTests
-{
-    @Override
-    protected XmlPullParser getFilter( XmlPullParser orgParser )
-    {
-        final BuildToRawPomXMLFilterFactory buildPomXMLFilterFactory = new BuildToRawPomXMLFilterFactory( true )
-        {
-            @Override
-            protected Function<Path, Optional<RelativeProject>> getRelativePathMapper()
-            {
-                return null;
-            }
-
-            @Override
-            protected BiFunction<String, String, String> getDependencyKeyToVersionMapper()
-            {
-                return null;
-            }
-
-            @Override
-            protected Optional<String> getSha1()
-            {
-                return Optional.empty();
-            }
-
-            @Override
-            protected Optional<String> getRevision()
-            {
-                return Optional.empty();
-            }
-
-            @Override
-            protected Optional<String> getChangelist()
-            {
-                return Optional.of( "CL" );
-            }
-
-        };
-
-        XmlPullParser parser = new RawToConsumerPomXMLFilterFactory( buildPomXMLFilterFactory )
-                        .get( orgParser, Paths.get( "pom.xml" ) );
-        return parser;
-    }
-
-    @Test
-    public void aggregatorWithParent()
-        throws Exception
-    {
-        String input = "<project>\n"
-                     + "  <parent>\n"
-                     + "    <groupId>GROUPID</groupId>\n"
-                     + "    <artifactId>PARENT</artifactId>\n"
-                     + "    <version>VERSION</version>\n"
-                     + "    <relativePath>../pom.xml</relativePath>\n"
-                     + "  </parent>\n"
-                     + "  <artifactId>PROJECT</artifactId>\n"
-                     + "  <modules>\n"
-                     + "    <module>ab</module>\n"
-                     + "    <module>../cd</module>\n"
-                     + "  </modules>\n"
-                     + "</project>";
-        String expected = "<project>\n"
-                        + "  <parent>\n"
-                        + "    <groupId>GROUPID</groupId>\n"
-                        + "    <artifactId>PARENT</artifactId>\n"
-                        + "    <version>VERSION</version>\n"
-                        + "  </parent>\n"
-                        + "  <artifactId>PROJECT</artifactId>\n"
-                        + "</project>";
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).ignoreWhitespace().areIdentical();
-    }
-
-    @Test
-    public void aggregatorWithCliFriendlyVersion()
-        throws Exception
-    {
-        String input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
-            "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
-            "       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
-            "       xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0\n" +
-            "                           http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
-            "  <modelVersion>4.0.0</modelVersion>\n" +
-            "  <groupId>org.sonatype.mavenbook.multispring</groupId>\n" +
-            "  <artifactId>parent</artifactId>\n" +
-            "  <version>0.9-${changelist}-SNAPSHOT</version>\n" +
-            "  <packaging>pom</packaging>\n" +
-            "  <name>Multi-Spring Chapter Parent Project</name>\n" +
-            "  <modules>\n" +
-            "    <module>simple-parent</module>\n" +
-            "  </modules>\n" +
-            "  \n" +
-            "  <pluginRepositories>\n" +
-            "    <pluginRepository>\n" +
-            "      <id>apache.snapshots</id>\n" +
-            "      <url>http://repository.apache.org/snapshots/</url>\n" +
-            "    </pluginRepository>\n" +
-            "  </pluginRepositories>\n" +
-            "</project>";
-        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
-            "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
-            "       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
-            "       xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0\n" +
-            "                           http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
-            "  <modelVersion>4.0.0</modelVersion>\n" +
-            "  <groupId>org.sonatype.mavenbook.multispring</groupId>\n" +
-            "  <artifactId>parent</artifactId>\n" +
-            "  <version>0.9-CL-SNAPSHOT</version>\n" +
-            "  <packaging>pom</packaging>\n" +
-            "  <name>Multi-Spring Chapter Parent Project</name>\n" +
-            "  \n" +
-            "  <pluginRepositories>\n" +
-            "    <pluginRepository>\n" +
-            "      <id>apache.snapshots</id>\n" +
-            "      <url>http://repository.apache.org/snapshots/</url>\n" +
-            "    </pluginRepository>\n" +
-            "  </pluginRepositories>\n" +
-            "</project>";
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).ignoreWhitespace().areIdentical();
-    }
-
-    @Test
-    public void licenseHeader()
-        throws Exception
-    {
-        String input = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
-            "\n" +
-            "<!--\n" +
-            "Licensed to the Apache Software Foundation (ASF) under one\n" +
-            "or more contributor license agreements.  See the NOTICE file\n" +
-            "distributed with this work for additional information\n" +
-            "regarding copyright ownership.  The ASF licenses this file\n" +
-            "to you under the Apache License, Version 2.0 (the\n" +
-            "\"License\"); you may not use this file except in compliance\n" +
-            "with the License.  You may obtain a copy of the License at\n" +
-            "\n" +
-            "    http://www.apache.org/licenses/LICENSE-2.0\n" +
-            "\n" +
-            "Unless required by applicable law or agreed to in writing,\n" +
-            "software distributed under the License is distributed on an\n" +
-            "\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n" +
-            "KIND, either express or implied.  See the License for the\n" +
-            "specific language governing permissions and limitations\n" +
-            "under the License.\n" +
-            "-->\n" +
-            "\n" +
-            "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
-            "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
-            "  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n" +
-            "  <modelVersion>4.0.0</modelVersion>\n" +
-            "  <parent>\n" +
-            "    <groupId>org.apache.maven</groupId>\n" +
-            "    <artifactId>maven</artifactId>\n" +
-            "    <version>4.0.0-SNAPSHOT</version>\n" +
-            "  </parent>\n" +
-            "  <artifactId>maven-xml</artifactId>\n" +
-            "  <name>Maven XML</name>\n" +
-            "  \n" +
-            "  <properties>\n" +
-            "    <maven.compiler.source>1.8</maven.compiler.source>\n" +
-            "    <maven.compiler.target>1.8</maven.compiler.target>\n" +
-            "  </properties>\n" +
-            "\n" +
-            "  <build>\n" +
-            "    <plugins>\n" +
-            "      <plugin>\n" +
-            "        <groupId>org.codehaus.mojo</groupId>\n" +
-            "        <artifactId>animal-sniffer-maven-plugin</artifactId>\n" +
-            "        <configuration>\n" +
-            "          <signature>\n" +
-            "            <groupId>org.codehaus.mojo.signature</groupId>\n" +
-            "            <artifactId>java18</artifactId>\n" +
-            "            <version>1.0</version>\n" +
-            "          </signature>\n" +
-            "        </configuration>\n" +
-            "      </plugin>\n" +
-            "    </plugins>\n" +
-            "  </build>\n" +
-            "  \n" +
-            "  <dependencies>\n" +
-            "    <dependency>\n" +
-            "      <groupId>javax.inject</groupId>\n" +
-            "      <artifactId>javax.inject</artifactId>\n" +
-            "      <optional>true</optional>\n" +
-            "    </dependency>\n" +
-            "    <dependency>\n" +
-            "      <groupId>org.xmlunit</groupId>\n" +
-            "      <artifactId>xmlunit-assertj</artifactId>\n" +
-            "      <scope>test</scope>\n" +
-            "    </dependency>\n" +
-            "  </dependencies>\n" +
-            "</project>";
-        String expected = input;
-
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-
-    @Test
-    public void lexicalHandler()
-        throws Exception
-    {
-        String input = "<project><!--before--><modules>"
-                        + "<!--pre-in-->"
-                        + "<module><!--in-->ab</module>"
-                        + "<module>../cd</module>"
-                        + "<!--post-in-->"
-                        + "</modules>"
-                        + "<!--after--></project>";
-        String expected = "<project><!--before--><!--after--></project>";
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
deleted file mode 100644
index 0080788..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ModulesXMLFilterTest.java
+++ /dev/null
@@ -1,107 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.junit.jupiter.api.Test;
-
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
-public class ModulesXMLFilterTest
-    extends AbstractXMLFilterTests
-{
-
-    @Override
-    protected ModulesXMLFilter getFilter( XmlPullParser parser )
-    {
-        return new ModulesXMLFilter( parser );
-    }
-
-    @Test
-    public void emptyModules()
-        throws Exception
-    {
-        String input = "<project><modules/></project>";
-        String expected = "<project/>";
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-
-    @Test
-    public void setOfModules()
-        throws Exception
-    {
-        String input = "<project><modules>"
-                + "<module>ab</module>"
-                + "<module>../cd</module>"
-                + "</modules></project>";
-        String expected = "<project/>";
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-
-    @Test
-    public void noModules()
-        throws Exception
-    {
-        String input = "<project><name>NAME</name></project>";
-        String expected = input;
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-
-    @Test
-    public void comment()
-        throws Exception
-    {
-
-        String input = "<project><!--before--><modules>"
-                        + "<!--pre-in-->"
-                        + "<module><!--in-->ab</module>"
-                        + "<module>../cd</module>"
-                        + "<!--post-in-->"
-                        + "</modules>"
-                        + "<!--after--></project>";
-        String expected = "<project><!--before--><!--after--></project>";
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-
-    @Test
-    public void setOfModulesLF()
-        throws Exception
-    {
-        String input = "<project>\n"
-            + "\n"
-            + "  <modules>\n"
-            + "    <module>ab</module>\n"
-            + "    <module>../cd</module>\n"
-            + "  </modules>\n"
-            + "\n"
-            + "</project>\n";
-        String expected = "<project>\n"
-            + "\n"
-            + "  \n"
-            + "\n"
-            + "</project>\n";
-        String actual = transform( input );
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ParentXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ParentXMLFilterTest.java
deleted file mode 100644
index 8571493..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ParentXMLFilterTest.java
+++ /dev/null
@@ -1,340 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Optional;
-import java.util.function.Function;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-public class ParentXMLFilterTest
-    extends AbstractXMLFilterTests
-{
-    private Function<XmlPullParser, XmlPullParser> filterCreator;
-
-    @BeforeEach
-    void reset() {
-        filterCreator = null;
-    }
-
-    @Override
-    protected XmlPullParser getFilter( XmlPullParser parser )
-    {
-        Function<XmlPullParser, XmlPullParser> filterCreator =
-            (this.filterCreator != null ? this.filterCreator : this::createFilter);
-        return filterCreator.apply(parser);
-    }
-
-    protected XmlPullParser createFilter( XmlPullParser parser ) {
-        return createFilter( parser,
-                x -> Optional.of(new RelativeProject("GROUPID", "ARTIFACTID", "1.0.0")),
-                Paths.get( "pom.xml").toAbsolutePath() );
-    }
-
-    protected XmlPullParser createFilter( XmlPullParser parser, Function<Path, Optional<RelativeProject>> pathMapper, Path projectPath ) {
-        return new ParentXMLFilter( new FastForwardFilter( parser ), pathMapper, projectPath );
-    }
-
-    @Test
-    public void testWithFastForward()
-        throws Exception
-    {
-        String input = "<project>"
-                        + "<build>"
-                            + "<plugins>"
-                                + "<plugin>"
-                                    + "<configuration>"
-                                        + "<parent>"
-                                            + "<groupId>GROUPID</groupId>"
-                                            + "<artifactId>ARTIFACTID</artifactId>"
-                                        + "</parent>"
-                                    + "</configuration>"
-                                + "</plugin>"
-                            + "</plugins>"
-                        + "</build>"
-                    + "</project>";
-        String expected = input;
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testWithFastForwardAfterByPass()
-            throws Exception
-    {
-        String input = "<project>"
-                        + "<build>"
-                            + "<plugins>"
-                                + "<plugin>"
-                                    + "<configuration>"
-                                        + "<parent>"
-                                            + "<groupId>GROUPID</groupId>"
-                                            + "<artifactId>ARTIFACTID</artifactId>"
-                                        + "</parent>"
-                                    + "</configuration>"
-                                + "</plugin>"
-                            + "</plugins>"
-                        + "</build>"
-                        + "<parent>"
-                            + "<groupId>GROUPID</groupId>"
-                            + "<artifactId>ARTIFACTID</artifactId>"
-                        + "</parent>"
-                    + "</project>";
-        String expected = "<project>"
-                            + "<build>"
-                                + "<plugins>"
-                                    + "<plugin>"
-                                        + "<configuration>"
-                                            + "<parent>"
-                                                + "<groupId>GROUPID</groupId>"
-                                                + "<artifactId>ARTIFACTID</artifactId>"
-                                            + "</parent>"
-                                        + "</configuration>"
-                                    + "</plugin>"
-                                + "</plugins>"
-                            + "</build>"
-                            + "<parent>"
-                                + "<groupId>GROUPID</groupId>"
-                                + "<artifactId>ARTIFACTID</artifactId>"
-                                + "<version>1.0.0</version>"
-                            + "</parent>"
-                        + "</project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testMinimum()
-        throws Exception
-    {
-        String input = "<project><parent /></project>";
-        String expected = input;
-        String actual = transform( input );
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testNoRelativePath()
-        throws Exception
-    {
-        String input = "<project><parent>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "<version>VERSION</version>"
-            + "</parent></project>";
-        String expected = input;
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testDefaultRelativePath()
-        throws Exception
-    {
-        String input = "<project>\n"
-            + "  <parent>\n"
-            + "    <groupId>GROUPID</groupId>\n"
-            + "    <artifactId>ARTIFACTID</artifactId>\n"
-            + "  </parent>\n"
-            + "</project>";
-        String expected = "<project>" + System.lineSeparator()
-                        + "  <parent>" + System.lineSeparator()
-                        + "    <groupId>GROUPID</groupId>" + System.lineSeparator()
-                        + "    <artifactId>ARTIFACTID</artifactId>" + System.lineSeparator()
-                        + "    <version>1.0.0</version>" + System.lineSeparator()
-                        + "  </parent>" + System.lineSeparator()
-                        + "</project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    /**
-     * An empty relative path means it must be downloaded from a repository.
-     * That implies that the version cannot be solved (if missing, Maven should complain)
-     *
-     * @throws Exception
-     */
-    @Test
-    public void testEmptyRelativePathNoVersion()
-        throws Exception
-    {
-        String input = "<project><parent>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "<relativePath></relativePath>"
-            + "</parent></project>";
-        String expected = "<project><parent>"
-                        + "<groupId>GROUPID</groupId>"
-                        + "<artifactId>ARTIFACTID</artifactId>"
-                        + "<relativePath />" // SAX optimization, however "" != null ...
-                        + "</parent></project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testNoVersion()
-        throws Exception
-    {
-        String input = "<project><parent>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "<relativePath>RELATIVEPATH</relativePath>"
-            + "</parent></project>";
-        String expected = "<project><parent>"
-                        + "<groupId>GROUPID</groupId>"
-                        + "<artifactId>ARTIFACTID</artifactId>"
-                        + "<relativePath>RELATIVEPATH</relativePath>"
-                        + "<version>1.0.0</version>"
-                        + "</parent></project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testInvalidRelativePath()
-        throws Exception
-    {
-        filterCreator = parser -> createFilter(parser, x -> Optional.ofNullable( null ), Paths.get( "pom.xml").toAbsolutePath() );
-
-        String input = "<project><parent>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "<relativePath>RELATIVEPATH</relativePath>"
-            + "</parent></project>";
-        String expected = input;
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testRelativePathAndVersion()
-        throws Exception
-    {
-        String input = "<project><parent>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "<relativePath>RELATIVEPATH</relativePath>"
-            + "<version>1.0.0</version>"
-            + "</parent></project>";
-        String expected = "<project><parent>"
-                        + "<groupId>GROUPID</groupId>"
-                        + "<artifactId>ARTIFACTID</artifactId>"
-                        + "<relativePath>RELATIVEPATH</relativePath>"
-                        + "<version>1.0.0</version>"
-                        + "</parent></project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testWithWeirdNamespace()
-        throws Exception
-    {
-        String input = "<relativePath:project xmlns:relativePath=\"relativePath\">"
-            + "<relativePath:parent>"
-            + "<relativePath:groupId>GROUPID</relativePath:groupId>"
-            + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>"
-            + "<relativePath:relativePath>RELATIVEPATH</relativePath:relativePath>"
-            + "</relativePath:parent></relativePath:project>";
-        String expected = "<relativePath:project xmlns:relativePath=\"relativePath\">"
-                        + "<relativePath:parent>"
-                        + "<relativePath:groupId>GROUPID</relativePath:groupId>"
-                        + "<relativePath:artifactId>ARTIFACTID</relativePath:artifactId>"
-                        + "<relativePath:relativePath>RELATIVEPATH</relativePath:relativePath>"
-                        + "<relativePath:version>1.0.0</relativePath:version>"
-                        + "</relativePath:parent>"
-                        + "</relativePath:project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void comment()
-        throws Exception
-    {
-        String input = "<project><!--before--><parent>"
-                    + "<groupId>GROUPID</groupId>"
-                    + "<artifactId>ARTIFACTID</artifactId>"
-                    + "<!--version here-->"
-                    + "</parent>"
-                    + "</project>";
-        String expected = "<project><!--before--><parent>"
-                        + "<groupId>GROUPID</groupId>"
-                        + "<artifactId>ARTIFACTID</artifactId>"
-                        + "<!--version here-->"
-                        + "<version>1.0.0</version>"
-                        + "</parent>"
-                        + "</project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-
-    @Test
-    public void testIndent()
-        throws Exception
-    {
-        String input = "<project>\n"
-            + "  <parent>\n"
-            + "    <groupId>GROUPID</groupId>\n"
-            + "    <artifactId>ARTIFACTID</artifactId>\n"
-            + "    <!--version here-->\n"
-            + "  </parent>\n"
-            + "</project>";
-        String expected = "<project>" + System.lineSeparator()
-            + "  <parent>" + System.lineSeparator()
-            + "    <groupId>GROUPID</groupId>" + System.lineSeparator()
-            + "    <artifactId>ARTIFACTID</artifactId>" + System.lineSeparator()
-            + "    <!--version here-->" + System.lineSeparator()
-            + "    <version>1.0.0</version>" + System.lineSeparator()
-            + "  </parent>" + System.lineSeparator()
-            + "</project>";
-
-        String actual = transform( input );
-
-        assertEquals( expected, actual );
-    }
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ReactorDependencyXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/ReactorDependencyXMLFilterTest.java
deleted file mode 100644
index 0304ea6..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/ReactorDependencyXMLFilterTest.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.function.BiFunction;
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
-public class ReactorDependencyXMLFilterTest
-    extends AbstractXMLFilterTests
-{
-    private BiFunction<String, String, String> reactorVersionMapper;
-
-    @BeforeEach
-    protected void reset() {
-        reactorVersionMapper = null;
-    }
-
-    @Override
-    protected ReactorDependencyXMLFilter getFilter(XmlPullParser parser)
-    {
-        return new ReactorDependencyXMLFilter( parser,
-                reactorVersionMapper != null ? reactorVersionMapper : (g, a) -> "1.0.0" );
-    }
-
-    @Test
-    public void testDefaultDependency()
-        throws Exception
-    {
-        String input = "<dependency>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "<version>VERSION</version>"
-            + "</dependency>";
-        String expected = input;
-
-        String actual = transform( input );
-
-        assertThat( actual ).isEqualTo( expected );
-    }
-
-    @Test
-    public void testManagedDependency()
-        throws Exception
-    {
-        reactorVersionMapper = (g, a) -> null;
-
-        String input = "<dependency>"
-            + "<groupId>GROUPID</groupId>"
-            + "<artifactId>ARTIFACTID</artifactId>"
-            + "</dependency>";
-        String expected = input;
-
-        String actual = transform( input );
-
-        assertThat( actual ).isEqualTo( expected );
-    }
-
-    @Test
-    public void testReactorDependency()
-        throws Exception
-    {
-        String input = "<dependency>"
-                        + "<groupId>GROUPID</groupId>"
-                        + "<artifactId>ARTIFACTID</artifactId>"
-                        + "</dependency>";
-        String expected = "<dependency>"
-                        + "<groupId>GROUPID</groupId>"
-                        + "<artifactId>ARTIFACTID</artifactId>"
-                        + "<version>1.0.0</version>"
-                        + "</dependency>";
-
-        String actual = transform( input );
-
-        assertThat( actual ).isEqualTo( expected );
-    }
-
-    @Test
-    public void testReactorDependencyLF()
-        throws Exception
-    {
-        String input = "<dependency>\n"
-                        + "  <groupId>GROUPID</groupId>\n"
-                        + "  <artifactId>ARTIFACTID</artifactId>\n"
-                        + "  <!-- include version here --> "
-                        + "</dependency>";
-        String expected = "<dependency>\n"
-                        + "  <groupId>GROUPID</groupId>\n"
-                        + "  <artifactId>ARTIFACTID</artifactId>\n"
-                        + "  <!-- include version here -->\n"
-                        + "  <version>1.0.0</version>\n"
-                        + "</dependency>";
-
-        String actual = transform( input );
-
-        assertThat( actual ).and( expected ).ignoreWhitespace().areIdentical();
-    }
-
-    @Test
-    public void multipleDependencies()
-        throws Exception
-    {
-        String input = "<project>\n" +
-            "  <modelVersion>4.0.0</modelVersion>\n" +
-            "    <groupId>tests.project</groupId>\n" +
-            "    <artifactId>duplicate-plugin-defs-merged</artifactId>\n" +
-            "    <version>1</version>\n" +
-            "    <build>\n" +
-            "      <plugins>\n" +
-            "        <plugin>\n" +
-            "          <artifactId>maven-compiler-plugin</artifactId>\n" +
-            "          <dependencies>\n" +
-            "            <dependency>\n" +
-            "              <groupId>group</groupId>\n" +
-            "              <artifactId>first</artifactId>\n" +
-            "              <version>1</version>\n" +
-            "            </dependency>\n" +
-            "          </dependencies>\n" +
-            "        </plugin>\n" +
-            "        <plugin>\n" +
-            "          <artifactId>maven-compiler-plugin</artifactId>\n" +
-            "          <dependencies>\n" +
-            "            <dependency>\n" +
-            "              <groupId>group</groupId>\n" +
-            "              <artifactId>second</artifactId>\n" +
-            "              <version>1</version>\n" +
-            "            </dependency>\n" +
-            "          </dependencies>\n" +
-            "        </plugin>\n" +
-            "      </plugins>\n" +
-            "    </build>\n" +
-            "</project>";
-        String expected = input;
-
-        String actual = transform( input );
-
-        assertThat( actual ).and( expected ).areIdentical();
-    }
-}
diff --git a/maven-model-transform/src/test/java/org/apache/maven/model/transform/RelativePathXMLFilterTest.java b/maven-model-transform/src/test/java/org/apache/maven/model/transform/RelativePathXMLFilterTest.java
deleted file mode 100644
index bfe3582..0000000
--- a/maven-model-transform/src/test/java/org/apache/maven/model/transform/RelativePathXMLFilterTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package org.apache.maven.model.transform;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.codehaus.plexus.util.xml.pull.XmlPullParser;
-import org.junit.jupiter.api.Test;
-
-import static org.xmlunit.assertj.XmlAssert.assertThat;
-
-public class RelativePathXMLFilterTest
-    extends AbstractXMLFilterTests
-{
-    @Override
-    protected RelativePathXMLFilter getFilter(XmlPullParser parser)
-    {
-        return new RelativePathXMLFilter(parser);
-    }
-
-    @Test
-    public void testRelativePath()
-        throws Exception
-    {
-        String input = "<project>\n"
-                        + "  <parent>\n"
-                        + "    <groupId>GROUPID</groupId>\n"
-                        + "    <artifactId>PARENT</artifactId>\n"
-                        + "    <version>VERSION</version>\n"
-                        + "    <relativePath>../pom.xml</relativePath>\n"
-                        + "  </parent>\n"
-                        + "  <artifactId>PROJECT</artifactId>\n"
-                        + "</project>";
-           String expected = "<project>\n"
-                           + "  <parent>\n"
-                           + "    <groupId>GROUPID</groupId>\n"
-                           + "    <artifactId>PARENT</artifactId>\n"
-                           + "    <version>VERSION</version>\n"
-                           + "  </parent>\n"
-                           + "  <artifactId>PROJECT</artifactId>\n"
-                           + "</project>";
-           String actual = transform( input );
-           assertThat( actual ).and( expected ).areIdentical();
-    }
-
-    @Test
-    public void testRelativePathNS()
-        throws Exception
-    {
-        String input = "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
-            "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
-            "  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
-                        + "  <parent>\n"
-                        + "    <groupId>GROUPID</groupId>\n"
-                        + "    <artifactId>PARENT</artifactId>\n"
-                        + "    <version>VERSION</version>\n"
-                        + "    <relativePath>../pom.xml</relativePath>\n"
-                        + "  </parent>\n"
-                        + "  <artifactId>PROJECT</artifactId>\n"
-                        + "</project>";
-           String expected = "<project xmlns=\"http://maven.apache.org/POM/4.0.0\"\n" +
-               "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
-               "  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
-                           + "  <parent>\n"
-                           + "    <groupId>GROUPID</groupId>\n"
-                           + "    <artifactId>PARENT</artifactId>\n"
-                           + "    <version>VERSION</version>\n"
-                           + "  </parent>\n"
-                           + "  <artifactId>PROJECT</artifactId>\n"
-                           + "</project>";
-           String actual = transform( input );
-           assertThat( actual ).and( expected ).areIdentical();
-    }
-
-    @Test
-    public void testRelativePathPasNS()
-        throws Exception
-    {
-        String input = "<p:project xmlns:p=\"http://maven.apache.org/POM/4.0.0\"\n" +
-            "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
-            "  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
-                        + "  <p:parent>\n"
-                        + "    <p:groupId>GROUPID</p:groupId>\n"
-                        + "    <p:artifactId>PARENT</p:artifactId>\n"
-                        + "    <p:version>VERSION</p:version>\n"
-                        + "    <p:relativePath>../pom.xml</p:relativePath>\n"
-                        + "  </p:parent>\n"
-                        + "  <p:artifactId>PROJECT</p:artifactId>\n"
-                        + "</p:project>";
-           String expected = "<p:project xmlns:p=\"http://maven.apache.org/POM/4.0.0\"\n" +
-               "  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
-               "  xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n"
-                           + "  <p:parent>\n"
-                           + "    <p:groupId>GROUPID</p:groupId>\n"
-                           + "    <p:artifactId>PARENT</p:artifactId>\n"
-                           + "    <p:version>VERSION</p:version>\n"
-                           + "  </p:parent>\n"
-                           + "  <p:artifactId>PROJECT</p:artifactId>\n"
-                           + "</p:project>";
-           String actual = transform( input );
-           assertThat( actual ).and( expected ).areIdentical();
-    }
-
-}
diff --git a/maven-model/pom.xml b/maven-model/pom.xml
index 10f1d2b..3450386 100644
--- a/maven-model/pom.xml
+++ b/maven-model/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-model</artifactId>
@@ -35,8 +33,34 @@
 
   <dependencies>
     <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-model</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-xml-impl</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
       <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
+      <artifactId>plexus-xml</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.openjdk.jmh</groupId>
+      <artifactId>jmh-core</artifactId>
+      <version>1.36</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.openjdk.jmh</groupId>
+      <artifactId>jmh-generator-annprocess</artifactId>
+      <version>1.36</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.woodstox</groupId>
+      <artifactId>woodstox-core</artifactId>
     </dependency>
   </dependencies>
 
@@ -46,24 +70,112 @@
         <groupId>org.codehaus.modello</groupId>
         <artifactId>modello-maven-plugin</artifactId>
         <configuration>
-          <version>4.0.0</version>
+          <basedir>${project.basedir}/../api/maven-api-model</basedir>
+          <velocityBasedir>${project.basedir}/../src/mdo</velocityBasedir>
+          <version>4.1.0</version>
           <models>
             <model>src/main/mdo/maven.mdo</model>
           </models>
+          <params>
+            <param>forcedIOModelVersion=4.0.0</param>
+            <param>packageModelV3=org.apache.maven.model</param>
+            <param>packageModelV4=org.apache.maven.api.model</param>
+            <param>packageToolV4=org.apache.maven.model.v4</param>
+            <param>isMavenModel=true</param>
+            <param>minimalVersion=4.0.0</param>
+          </params>
         </configuration>
         <executions>
           <execution>
-            <id>modello</id>
+            <id>modello-site-docs</id>
             <goals>
-              <goal>java</goal>
-              <goal>xpp3-reader</goal>
-              <goal>xpp3-extended-reader</goal>
-              <goal>xpp3-writer</goal>
-              <goal>xpp3-extended-writer</goal>
+              <goal>xdoc</goal>
             </goals>
+            <phase>pre-site</phase>
+          </execution>
+          <execution>
+            <id>modello-schema</id>
+            <goals>
+              <goal>xsd</goal>
+            </goals>
+            <phase>generate-resources</phase>
+          </execution>
+          <execution>
+            <id>model-v3</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <version>4.0.99</version>
+              <templates>
+                <template>model-v3.vm</template>
+              </templates>
+            </configuration>
+          </execution>
+          <execution>
+            <id>model-v4</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <version>4.1.0</version>
+              <templates>
+                <template>merger.vm</template>
+                <template>transformer.vm</template>
+                <template>reader-stax.vm</template>
+                <template>writer-stax.vm</template>
+                <template>model-version.vm</template>
+              </templates>
+            </configuration>
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/package-info.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <parameter>
+            <excludes>
+              <exclude>org.apache.maven.model.*#setOtherLocation(java.lang.Object,org.apache.maven.model.InputLocation):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.ConfigurationContainer#isInheritanceApplied():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.ConfigurationContainer#setInherited(boolean):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.ConfigurationContainer#unsetInheritanceApplied():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Contributor#addProperty(java.lang.String,java.lang.String):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Dependency#clearManagementKey():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.ModelBase#addProperty(java.lang.String,java.lang.String):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.ModelBase#getReports():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.ModelBase#setReports(java.lang.Object):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Notifier#addConfiguration(java.lang.String,java.lang.String):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Plugin#getGoals():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Plugin#setGoals(java.lang.Object):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Reporting#flushReportPluginMap():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Reporting#getReportPluginsAsMap():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Resource#initMergeId():METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Scm#setChildScmConnectionInheritAppendPath(boolean):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Scm#setChildScmDeveloperConnectionInheritAppendPath(boolean):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Scm#setChildScmUrlInheritAppendPath(boolean):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.Site#setChildSiteUrlInheritAppendPath(boolean):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.io.xpp3.MavenXpp3Reader#contentTransformer</exclude>
+              <exclude>org.apache.maven.model.io.xpp3.MavenXpp3ReaderEx#contentTransformer</exclude>
+              <exclude>org.apache.maven.model.io.xpp3.MavenXpp3WriterEx#stringFormatter</exclude>
+              <exclude>org.apache.maven.model.io.xpp3.MavenXpp3WriterEx#toString(org.apache.maven.model.InputLocation):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.io.xpp3.MavenXpp3WriterEx#writeXpp3DomToSerializer(org.codehaus.plexus.util.xml.Xpp3Dom,org.codehaus.plexus.util.xml.pull.XmlSerializer):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.model.merge.ModelMerger</exclude>
+            </excludes>
+          </parameter>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
diff --git a/maven-model/src/main/java/org/apache/maven/model/BaseObject.java b/maven-model/src/main/java/org/apache/maven/model/BaseObject.java
new file mode 100644
index 0000000..355453d
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/BaseObject.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model;
+
+import java.io.Serializable;
+
+public abstract class BaseObject implements Serializable, Cloneable, InputLocationTracker {
+    protected transient ChildrenTracking childrenTracking;
+
+    protected Object delegate;
+
+    public BaseObject() {}
+
+    public BaseObject(Object delegate, BaseObject parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent != null ? parent::replace : null;
+    }
+
+    public BaseObject(Object delegate, ChildrenTracking parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent;
+    }
+
+    public Object getDelegate() {
+        return delegate;
+    }
+
+    public void update(Object newDelegate) {
+        if (delegate != newDelegate) {
+            if (childrenTracking != null) {
+                childrenTracking.replace(delegate, newDelegate);
+            }
+            delegate = newDelegate;
+        }
+    }
+
+    protected boolean replace(Object oldDelegate, Object newDelegate) {
+        return false;
+    }
+
+    @FunctionalInterface
+    protected interface ChildrenTracking {
+        boolean replace(Object oldDelegate, Object newDelegate);
+    }
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/InputLocation.java b/maven-model/src/main/java/org/apache/maven/model/InputLocation.java
new file mode 100644
index 0000000..1b48e04
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/InputLocation.java
@@ -0,0 +1,358 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model;
+
+import java.util.stream.Collectors;
+
+/**
+ * Class InputLocation.
+ *
+ * @version $Revision$ $Date$
+ */
+@SuppressWarnings("all")
+public final class InputLocation implements java.io.Serializable, Cloneable, InputLocationTracker {
+
+    // --------------------------/
+    // - Class/Member Variables -/
+    // --------------------------/
+
+    /**
+     * The one-based line number. The value will be non-positive if
+     * unknown.
+     */
+    private int lineNumber = -1;
+
+    /**
+     * The one-based column number. The value will be non-positive
+     * if unknown.
+     */
+    private int columnNumber = -1;
+
+    /**
+     * Field source.
+     */
+    private InputSource source;
+
+    /**
+     * Field locations.
+     */
+    private java.util.Map<Object, InputLocation> locations;
+
+    /**
+     * Field location.
+     */
+    private InputLocation location;
+
+    // ----------------/
+    // - Constructors -/
+    // ----------------/
+
+    public InputLocation(org.apache.maven.api.model.InputLocation location) {
+        this.lineNumber = location.getLineNumber();
+        this.columnNumber = location.getColumnNumber();
+        this.source = location.getSource() != null ? new InputSource(location.getSource()) : null;
+        this.locations = location.getLocations().isEmpty()
+                ? null
+                : location.getLocations().entrySet().stream()
+                        .collect(Collectors.toMap(
+                                e -> e.getKey(),
+                                e -> e.getValue() == location ? this : new InputLocation(e.getValue())));
+    }
+
+    public InputLocation(int lineNumber, int columnNumber) {
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+    } // -- org.apache.maven.model.InputLocation(int, int)
+
+    public InputLocation(int lineNumber, int columnNumber, InputSource source) {
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+        this.source = source;
+    } // -- org.apache.maven.model.InputLocation(int, int, InputSource)
+
+    // -----------/
+    // - Methods -/
+    // -----------/
+
+    /**
+     * Method clone.
+     *
+     * @return InputLocation
+     */
+    public InputLocation clone() {
+        try {
+            InputLocation copy = (InputLocation) super.clone();
+
+            if (copy.locations != null) {
+                copy.locations = new java.util.LinkedHashMap(copy.locations);
+            }
+
+            return copy;
+        } catch (Exception ex) {
+            throw (RuntimeException)
+                    new UnsupportedOperationException(getClass().getName() + " does not support clone()").initCause(ex);
+        }
+    } // -- InputLocation clone()
+
+    /**
+     * Get the one-based column number. The value will be
+     * non-positive if unknown.
+     *
+     * @return int
+     */
+    public int getColumnNumber() {
+        return this.columnNumber;
+    } // -- int getColumnNumber()
+
+    /**
+     * Get the one-based line number. The value will be
+     * non-positive if unknown.
+     *
+     * @return int
+     */
+    public int getLineNumber() {
+        return this.lineNumber;
+    } // -- int getLineNumber()
+
+    /**
+     *
+     *
+     * @param key
+     * @return InputLocation
+     */
+    public InputLocation getLocation(Object key) {
+        if (key instanceof String) {
+            switch ((String) key) {
+                case "": {
+                    return this.location;
+                }
+                default: {
+                    return getOtherLocation(key);
+                }
+            }
+        } else {
+            return getOtherLocation(key);
+        }
+    } // -- InputLocation getLocation( Object )
+
+    /**
+     *
+     *
+     * @return Map
+     */
+    public java.util.Map<Object, InputLocation> getLocations() {
+        return locations;
+    } // -- java.util.Map<Object, InputLocation> getLocations()
+
+    /**
+     *
+     *
+     * @param key
+     * @param location
+     */
+    public void setLocation(Object key, InputLocation location) {
+        if (key instanceof String) {
+            switch ((String) key) {
+                case "": {
+                    this.location = location;
+                    return;
+                }
+                default: {
+                    setOtherLocation(key, location);
+                    return;
+                }
+            }
+        } else {
+            setOtherLocation(key, location);
+        }
+    } // -- void setLocation( Object, InputLocation )
+
+    /**
+     *
+     *
+     * @param key
+     * @param location
+     */
+    public void setOtherLocation(Object key, InputLocation location) {
+        if (location != null) {
+            if (this.locations == null) {
+                this.locations = new java.util.LinkedHashMap<>();
+            }
+            this.locations.put(key, location);
+        }
+    } // -- void setOtherLocation( Object, InputLocation )
+
+    /**
+     *
+     *
+     * @param key
+     * @return InputLocation
+     */
+    private InputLocation getOtherLocation(Object key) {
+        return (locations != null) ? locations.get(key) : null;
+    } // -- InputLocation getOtherLocation( Object )
+
+    /**
+     * Get the source field.
+     *
+     * @return InputSource
+     */
+    public InputSource getSource() {
+        return this.source;
+    } // -- InputSource getSource()
+
+    /**
+     * Method merge.
+     *
+     * @param target
+     * @param sourceDominant
+     * @param source
+     * @return InputLocation
+     */
+    public static InputLocation merge(InputLocation target, InputLocation source, boolean sourceDominant) {
+        if (source == null) {
+            return target;
+        } else if (target == null) {
+            return source;
+        }
+
+        InputLocation result = new InputLocation(target.getLineNumber(), target.getColumnNumber(), target.getSource());
+
+        java.util.Map<Object, InputLocation> locations;
+        java.util.Map<Object, InputLocation> sourceLocations = source.getLocations();
+        java.util.Map<Object, InputLocation> targetLocations = target.getLocations();
+        if (sourceLocations == null) {
+            locations = targetLocations;
+        } else if (targetLocations == null) {
+            locations = sourceLocations;
+        } else {
+            locations = new java.util.LinkedHashMap();
+            locations.putAll(sourceDominant ? targetLocations : sourceLocations);
+            locations.putAll(sourceDominant ? sourceLocations : targetLocations);
+        }
+        result.setLocations(locations);
+
+        return result;
+    } // -- InputLocation merge( InputLocation, InputLocation, boolean )
+
+    /**
+     * Method merge.
+     *
+     * @param target
+     * @param indices
+     * @param source
+     * @return InputLocation
+     */
+    public static InputLocation merge(
+            InputLocation target, InputLocation source, java.util.Collection<Integer> indices) {
+        if (source == null) {
+            return target;
+        } else if (target == null) {
+            return source;
+        }
+
+        InputLocation result = new InputLocation(target.getLineNumber(), target.getColumnNumber(), target.getSource());
+
+        java.util.Map<Object, InputLocation> locations;
+        java.util.Map<Object, InputLocation> sourceLocations = source.getLocations();
+        java.util.Map<Object, InputLocation> targetLocations = target.getLocations();
+        if (sourceLocations == null) {
+            locations = targetLocations;
+        } else if (targetLocations == null) {
+            locations = sourceLocations;
+        } else {
+            locations = new java.util.LinkedHashMap<>();
+            for (java.util.Iterator<Integer> it = indices.iterator(); it.hasNext(); ) {
+                InputLocation location;
+                Integer index = it.next();
+                if (index.intValue() < 0) {
+                    location = sourceLocations.get(Integer.valueOf(~index.intValue()));
+                } else {
+                    location = targetLocations.get(index);
+                }
+                locations.put(Integer.valueOf(locations.size()), location);
+            }
+        }
+        result.setLocations(locations);
+
+        return result;
+    } // -- InputLocation merge( InputLocation, InputLocation, java.util.Collection )
+
+    /**
+     *
+     *
+     * @param locations
+     */
+    public void setLocations(java.util.Map<Object, InputLocation> locations) {
+        this.locations = locations;
+    } // -- void setLocations( java.util.Map )
+
+    public org.apache.maven.api.model.InputLocation toApiLocation() {
+        if (locations != null && locations.values().contains(this)) {
+            if (locations.size() == 1 && locations.values().iterator().next() == this) {
+                return new org.apache.maven.api.model.InputLocation(
+                        lineNumber,
+                        columnNumber,
+                        source != null ? source.toApiSource() : null,
+                        locations.keySet().iterator().next());
+            } else {
+                return new org.apache.maven.api.model.InputLocation(
+                        lineNumber, columnNumber, source != null ? source.toApiSource() : null);
+            }
+        } else {
+            return new org.apache.maven.api.model.InputLocation(
+                    lineNumber,
+                    columnNumber,
+                    source != null ? source.toApiSource() : null,
+                    locations != null
+                            ? locations.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue()
+                                    .toApiLocation()))
+                            : null);
+        }
+    }
+
+    // -----------------/
+    // - Inner Classes -/
+    // -----------------/
+
+    /**
+     * Class StringFormatter.
+     *
+     * @version $Revision$ $Date$
+     */
+    public abstract static class StringFormatter {
+
+        // -----------/
+        // - Methods -/
+        // -----------/
+
+        /**
+         * Method toString.
+         *
+         * @param location
+         * @return String
+         */
+        public abstract String toString(InputLocation location);
+    }
+
+    @Override
+    public String toString() {
+        return getLineNumber() + " : " + getColumnNumber() + ", " + getSource();
+    }
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/InputLocationTracker.java b/maven-model/src/main/java/org/apache/maven/model/InputLocationTracker.java
new file mode 100644
index 0000000..ebc4666
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/InputLocationTracker.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model;
+
+/**
+ * Interface InputLocationTracker.
+ *
+ * @version $Revision$ $Date$
+ */
+@SuppressWarnings("all")
+public interface InputLocationTracker {
+
+    // -----------/
+    // - Methods -/
+    // -----------/
+
+    /**
+     * Gets the location of the specified field in the input
+     * source.
+     *
+     * @param field The key of the field, must not be
+     * <code>null</code>.
+     * @return The location of the field in the input source or
+     * <code>null</code> if unknown.
+     */
+    public InputLocation getLocation(Object field);
+    /**
+     * Sets the location of the specified field.
+     *
+     * @param field The key of the field, must not be
+     * <code>null</code>.
+     * @param location The location of the field, may be
+     * <code>null</code>.
+     */
+    public void setLocation(Object field, InputLocation location);
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/InputSource.java b/maven-model/src/main/java/org/apache/maven/model/InputSource.java
new file mode 100644
index 0000000..10674ec
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/InputSource.java
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model;
+
+/**
+ * Class InputSource.
+ *
+ * @version $Revision$ $Date$
+ */
+@SuppressWarnings("all")
+public class InputSource implements java.io.Serializable, Cloneable {
+
+    // --------------------------/
+    // - Class/Member Variables -/
+    // --------------------------/
+
+    /**
+     *
+     *
+     *             The identifier of the POM in the format {@code
+     * <groupId>:<artifactId>:<version>}.
+     *
+     *
+     */
+    private String modelId;
+
+    /**
+     *
+     *
+     *             The path/URL of the POM or {@code null} if
+     * unknown.
+     *
+     *
+     */
+    private String location;
+
+    // ----------------/
+    // - Constructors -/
+    // ----------------/
+
+    public InputSource() {}
+
+    public InputSource(org.apache.maven.api.model.InputSource source) {
+        this.modelId = source.getModelId();
+        this.location = source.getLocation();
+    }
+
+    // -----------/
+    // - Methods -/
+    // -----------/
+
+    /**
+     * Method clone.
+     *
+     * @return InputSource
+     */
+    public InputSource clone() {
+        try {
+            InputSource copy = (InputSource) super.clone();
+
+            return copy;
+        } catch (Exception ex) {
+            throw (RuntimeException)
+                    new UnsupportedOperationException(getClass().getName() + " does not support clone()").initCause(ex);
+        }
+    } // -- InputSource clone()
+
+    /**
+     * Get the path/URL of the POM or {@code null} if unknown.
+     *
+     * @return String
+     */
+    public String getLocation() {
+        return this.location;
+    } // -- String getLocation()
+
+    /**
+     * Get the identifier of the POM in the format {@code
+     * <groupId>:<artifactId>:<version>}.
+     *
+     * @return String
+     */
+    public String getModelId() {
+        return this.modelId;
+    } // -- String getModelId()
+
+    /**
+     * Set the path/URL of the POM or {@code null} if unknown.
+     *
+     * @param location
+     */
+    public void setLocation(String location) {
+        this.location = location;
+    } // -- void setLocation( String )
+
+    /**
+     * Set the identifier of the POM in the format {@code
+     * <groupId>:<artifactId>:<version>}.
+     *
+     * @param modelId
+     */
+    public void setModelId(String modelId) {
+        this.modelId = modelId;
+    } // -- void setModelId( String )
+
+    @Override
+    public String toString() {
+        return getModelId() + " " + getLocation();
+    }
+
+    public org.apache.maven.api.model.InputSource toApiSource() {
+        return new org.apache.maven.api.model.InputSource(modelId, location);
+    }
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3Reader.java b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3Reader.java
new file mode 100644
index 0000000..9d47e7d
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3Reader.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.io.xpp3;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.maven.model.InputSource;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.v4.MavenStaxReader;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * @deprecated Use MavenStaxReader instead
+ */
+@Deprecated
+public class MavenXpp3Reader {
+    private MavenStaxReader delegate;
+
+    public MavenXpp3Reader() {
+        this(null, false);
+    }
+
+    public MavenXpp3Reader(ContentTransformer contentTransformer) {
+        this(contentTransformer, false);
+    }
+
+    protected MavenXpp3Reader(ContentTransformer contentTransformer, boolean addLocationInformation) {
+        delegate =
+                contentTransformer != null ? new MavenStaxReader(contentTransformer::transform) : new MavenStaxReader();
+        delegate.setAddLocationInformation(addLocationInformation);
+    }
+
+    /**
+     * Returns the state of the "add default entities" flag.
+     *
+     * @return boolean
+     */
+    public boolean getAddDefaultEntities() {
+        return delegate.getAddDefaultEntities();
+    } // -- boolean getAddDefaultEntities()
+
+    /**
+     * Sets the state of the "add default entities" flag.
+     *
+     * @param addDefaultEntities a addDefaultEntities object.
+     */
+    public void setAddDefaultEntities(boolean addDefaultEntities) {
+        delegate.setAddLocationInformation(addDefaultEntities);
+    } // -- void setAddDefaultEntities( boolean )
+
+    protected Model read(Reader reader, boolean strict, InputSource source) throws IOException, XmlPullParserException {
+        try {
+            org.apache.maven.api.model.Model model =
+                    delegate.read(reader, strict, source != null ? source.toApiSource() : null);
+            return new Model(model);
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     *
+     * @param reader a reader object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Model
+     */
+    public Model read(Reader reader, boolean strict) throws IOException, XmlPullParserException {
+        return read(reader, strict, null);
+    } // -- Model read( Reader, boolean )
+
+    /**
+     *
+     * @param reader a reader object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Model
+     */
+    public Model read(Reader reader) throws IOException, XmlPullParserException {
+        return read(reader, true);
+    } // -- Model read( Reader )
+
+    protected Model read(InputStream is, boolean strict, InputSource source)
+            throws IOException, XmlPullParserException {
+        try {
+            org.apache.maven.api.model.Model model =
+                    delegate.read(is, strict, source != null ? source.toApiSource() : null);
+            return new Model(model);
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Model
+     */
+    public Model read(InputStream in, boolean strict) throws IOException, XmlPullParserException {
+        return read(in, strict, null);
+    } // -- Model read( InputStream, boolean )
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Model
+     */
+    public Model read(InputStream in) throws IOException, XmlPullParserException {
+        return read(in, true);
+    } // -- Model read( InputStream )
+
+    public interface ContentTransformer {
+        /**
+         * Interpolate the value read from the xpp3 document
+         * @param source The source value
+         * @param fieldName A description of the field being interpolated. The implementation may use this to
+         *                           log stuff.
+         * @return The interpolated value.
+         */
+        String transform(String source, String fieldName);
+    }
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx.java b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx.java
new file mode 100644
index 0000000..4ba7005
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3ReaderEx.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.io.xpp3;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.maven.model.InputSource;
+import org.apache.maven.model.Model;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * @deprecated Use MavenStaxReader instead
+ */
+@Deprecated
+public class MavenXpp3ReaderEx extends MavenXpp3Reader {
+
+    public MavenXpp3ReaderEx() {
+        this(null);
+    }
+
+    public MavenXpp3ReaderEx(ContentTransformer contentTransformer) {
+        super(contentTransformer != null ? contentTransformer::transform : null, true);
+    }
+
+    @Override
+    public Model read(Reader reader, boolean strict, InputSource source) throws IOException, XmlPullParserException {
+        return super.read(reader, strict, source);
+    }
+
+    @Override
+    public Model read(Reader reader, boolean strict) throws IOException, XmlPullParserException {
+        return super.read(reader, strict);
+    }
+
+    @Override
+    public Model read(Reader reader) throws IOException, XmlPullParserException {
+        return super.read(reader);
+    }
+
+    @Override
+    public Model read(InputStream in, boolean strict, InputSource source) throws IOException, XmlPullParserException {
+        return super.read(in, strict, source);
+    }
+
+    @Override
+    public Model read(InputStream in, boolean strict) throws IOException, XmlPullParserException {
+        return super.read(in, strict);
+    }
+
+    @Override
+    public Model read(InputStream in) throws IOException, XmlPullParserException {
+        return super.read(in);
+    }
+
+    public interface ContentTransformer {
+        /**
+         * Interpolate the value read from the xpp3 document
+         *
+         * @param source    the source value
+         * @param fieldName a description of the field being interpolated. The implementation may use this to
+         *                  log stuff
+         * @return the interpolated value
+         */
+        String transform(String source, String fieldName);
+    }
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3Writer.java b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3Writer.java
new file mode 100644
index 0000000..7c241e6
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3Writer.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.io.xpp3;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.Model;
+import org.apache.maven.model.v4.MavenStaxWriter;
+
+/**
+ * @deprecated Use MavenStaxWriter instead
+ */
+@Deprecated
+public class MavenXpp3Writer {
+    // --------------------------/
+    // - Class/Member Variables -/
+    // --------------------------/
+
+    private final MavenStaxWriter delegate = new MavenStaxWriter();
+
+    // -----------/
+    // - Methods -/
+    // -----------/
+
+    public MavenXpp3Writer() {
+        this(false);
+    }
+
+    protected MavenXpp3Writer(boolean addLocationInformation) {
+        delegate.setAddLocationInformation(addLocationInformation);
+    }
+
+    /**
+     * Method setFileComment.
+     *
+     * @param fileComment a fileComment object.
+     */
+    public void setFileComment(String fileComment) {
+        delegate.setFileComment(fileComment);
+    } // -- void setFileComment( String )
+
+    /**
+     * Method setStringFormatter.
+     *
+     * @param stringFormatter
+     */
+    public void setStringFormatter(InputLocation.StringFormatter stringFormatter) {
+        delegate.setStringFormatter(
+                stringFormatter != null
+                        ? new org.apache.maven.api.model.InputLocation.StringFormatter() {
+                            @Override
+                            public String toString(org.apache.maven.api.model.InputLocation location) {
+                                return stringFormatter.toString(new InputLocation(location));
+                            }
+                        }
+                        : null);
+    } // -- void setStringFormatter( InputLocation.StringFormatter )
+
+    /**
+     * Method write.
+     *
+     * @param writer a writer object.
+     * @param model a model object.
+     * @throws IOException java.io.IOException if any.
+     */
+    public void write(Writer writer, Model model) throws IOException {
+        try {
+            delegate.write(writer, model.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    } // -- void write( Writer, Model )
+
+    /**
+     * Method write.
+     *
+     * @param stream a stream object.
+     * @param model a model object.
+     * @throws IOException java.io.IOException if any.
+     */
+    public void write(OutputStream stream, Model model) throws IOException {
+        try {
+            delegate.write(stream, model.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    } // -- void write( OutputStream, Model )
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3WriterEx.java b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3WriterEx.java
new file mode 100644
index 0000000..09fbbae
--- /dev/null
+++ b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/MavenXpp3WriterEx.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.io.xpp3;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.maven.model.InputLocation;
+import org.apache.maven.model.Model;
+
+/**
+ * @deprecated Use MavenStaxWriter instead
+ */
+@Deprecated
+public class MavenXpp3WriterEx extends MavenXpp3Writer {
+
+    // -----------/
+    // - Methods -/
+    // -----------/
+
+    public MavenXpp3WriterEx() {
+        super(true);
+    }
+
+    /**
+     * Method setFileComment.
+     *
+     * @param fileComment a fileComment object.
+     */
+    public void setFileComment(String fileComment) {
+        super.setFileComment(fileComment);
+    } // -- void setFileComment( String )
+
+    /**
+     * Method setStringFormatter.
+     *
+     * @param stringFormatter
+     */
+    public void setStringFormatter(InputLocation.StringFormatter stringFormatter) {
+        super.setStringFormatter(stringFormatter);
+    } // -- void setStringFormatter( InputLocation.StringFormatter )
+
+    /**
+     * Method write.
+     *
+     * @param writer a writer object.
+     * @param model a model object.
+     * @throws IOException java.io.IOException if any.
+     */
+    public void write(Writer writer, Model model) throws IOException {
+        super.write(writer, model);
+    } // -- void write( Writer, Model )
+
+    /**
+     * Method write.
+     *
+     * @param stream a stream object.
+     * @param model a model object.
+     * @throws IOException java.io.IOException if any.
+     */
+    public void write(OutputStream stream, Model model) throws IOException {
+        super.write(stream, model);
+    } // -- void write( OutputStream, Model )
+}
diff --git a/maven-model/src/main/java/org/apache/maven/model/io/xpp3/package-info.java b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/package-info.java
index 299193d..68205b8 100644
--- a/maven-model/src/main/java/org/apache/maven/model/io/xpp3/package-info.java
+++ b/maven-model/src/main/java/org/apache/maven/model/io/xpp3/package-info.java
@@ -9,22 +9,3 @@
  * DOM content representation (see <code>&lt;configuration&gt;</code> elements).
  */
 package org.apache.maven.model.io.xpp3;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
\ No newline at end of file
diff --git a/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger.java b/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger.java
deleted file mode 100644
index 2ac6fbf..0000000
--- a/maven-model/src/main/java/org/apache/maven/model/merge/ModelMerger.java
+++ /dev/null
@@ -1,2802 +0,0 @@
-package org.apache.maven.model.merge;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.ObjectStreamException;
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Properties;
-import java.util.function.BinaryOperator;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-import org.apache.maven.model.Activation;
-import org.apache.maven.model.Build;
-import org.apache.maven.model.BuildBase;
-import org.apache.maven.model.CiManagement;
-import org.apache.maven.model.ConfigurationContainer;
-import org.apache.maven.model.Contributor;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.DependencyManagement;
-import org.apache.maven.model.DeploymentRepository;
-import org.apache.maven.model.Developer;
-import org.apache.maven.model.DistributionManagement;
-import org.apache.maven.model.Exclusion;
-import org.apache.maven.model.Extension;
-import org.apache.maven.model.FileSet;
-import org.apache.maven.model.InputLocation;
-import org.apache.maven.model.IssueManagement;
-import org.apache.maven.model.License;
-import org.apache.maven.model.MailingList;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.ModelBase;
-import org.apache.maven.model.Notifier;
-import org.apache.maven.model.Organization;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.PatternSet;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.model.PluginConfiguration;
-import org.apache.maven.model.PluginContainer;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.PluginManagement;
-import org.apache.maven.model.Prerequisites;
-import org.apache.maven.model.Profile;
-import org.apache.maven.model.Relocation;
-import org.apache.maven.model.ReportPlugin;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Reporting;
-import org.apache.maven.model.Repository;
-import org.apache.maven.model.RepositoryBase;
-import org.apache.maven.model.RepositoryPolicy;
-import org.apache.maven.model.Resource;
-import org.apache.maven.model.Scm;
-import org.apache.maven.model.Site;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
-
-/**
- * This is a hand-crafted prototype of the default model merger that should eventually be generated by Modello by a new
- * Java plugin. Code structure to merge source (read-only) object into the target object is:<ul>
- * <li><code>merge<i>Classname</i>( <i>Classname</i> target, <i>Classname</i> source, boolean sourceDominant,
- * Map&lt;Object, Object&gt; context )</code> for each model class</li>
- * <li><code>merge<i>Classname</i>_<i>FieldName</i>( <i>Classname</i> target, <i>Classname</i> source, boolean
- * sourceDominant, Map&lt;Object, Object&gt; context )</code> for each field of each model class</li>
- * <li><code>Object get<i>Classname</i>Key( <i>Classname</i> <i>classname</i> )</code>
- * for each class that is used in a list</li>
- * </ul>
- * Code is written like it could be generated, with default behaviour to be overridden when necessary.
- * This is particularly the case for <code>Object get<i>Classname</i>Key( <i>Classname</i> <i>classname</i> )</code>
- * method, which by default return the object itself and is expected to be overridden to calculate better suited key
- * value.
- *
- * @author Benjamin Bentmann
- */
-@SuppressWarnings( { "checkstyle:methodname" } )
-public class ModelMerger
-{
-
-    /**
-     * Merges the specified source object into the given target object.
-     *
-     * @param target The target object whose existing contents should be merged with the source, must not be
-     *            <code>null</code>.
-     * @param source The (read-only) source object that should be merged into the target object, may be
-     *            <code>null</code>.
-     * @param sourceDominant A flag indicating whether either the target object or the source object provides the
-     *            dominant data.
-     * @param hints A set of key-value pairs that customized merger implementations can use to carry domain-specific
-     *            information along, may be <code>null</code>.
-     */
-    public void merge( Model target, Model source, boolean sourceDominant, Map<?, ?> hints )
-    {
-        Objects.requireNonNull( target, "target cannot be null" );
-
-        if ( source == null )
-        {
-            return;
-        }
-
-        Map<Object, Object> context = new HashMap<>();
-        if ( hints != null )
-        {
-            context.putAll( hints );
-        }
-
-        mergeModel( target, source, sourceDominant, context );
-    }
-
-    protected void mergeModel( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeModelBase( target, source, sourceDominant, context );
-
-        mergeModel_ChildProjectUrlInheritAppendPath( target, source, sourceDominant, context );
-        mergeModel_ModelVersion( target, source, sourceDominant, context );
-        mergeModel_Parent( target, source, sourceDominant, context );
-        mergeModel_GroupId( target, source, sourceDominant, context );
-        mergeModel_ArtifactId( target, source, sourceDominant, context );
-        mergeModel_Version( target, source, sourceDominant, context );
-        mergeModel_Packaging( target, source, sourceDominant, context );
-        mergeModel_Name( target, source, sourceDominant, context );
-        mergeModel_Description( target, source, sourceDominant, context );
-        mergeModel_Url( target, source, sourceDominant, context );
-        mergeModel_InceptionYear( target, source, sourceDominant, context );
-        mergeModel_Organization( target, source, sourceDominant, context );
-        mergeModel_Licenses( target, source, sourceDominant, context );
-        mergeModel_MailingLists( target, source, sourceDominant, context );
-        mergeModel_Developers( target, source, sourceDominant, context );
-        mergeModel_Contributors( target, source, sourceDominant, context );
-        mergeModel_IssueManagement( target, source, sourceDominant, context );
-        mergeModel_Scm( target, source, sourceDominant, context );
-        mergeModel_CiManagement( target, source, sourceDominant, context );
-        mergeModel_Prerequisites( target, source, sourceDominant, context );
-        mergeModel_Build( target, source, sourceDominant, context );
-        mergeModel_Profiles( target, source, sourceDominant, context );
-    }
-
-    protected void mergeModel_ModelVersion( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getModelVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getModelVersion() == null )
-            {
-                target.setModelVersion( src );
-                target.setLocation( "modelVersion", source.getLocation( "modelVersion" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_Parent( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        Parent src = source.getParent();
-        if ( src != null )
-        {
-            Parent tgt = target.getParent();
-            if ( tgt == null )
-            {
-                tgt = new Parent();
-                tgt.setRelativePath( null );
-                target.setParent( tgt );
-            }
-            mergeParent( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModel_GroupId( Model target, Model source, boolean sourceDominant,
-                                       Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_ArtifactId( Model target, Model source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_ChildProjectUrlInheritAppendPath( Model target, Model source, boolean sourceDominant,
-                                                                Map<Object, Object> context )
-    {
-        String src = source.getChildProjectUrlInheritAppendPath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getChildProjectUrlInheritAppendPath() == null )
-            {
-                target.setChildProjectUrlInheritAppendPath( src );
-                target.setLocation( "child.project.url.inherit.append.path",
-                                    source.getLocation( "child.project.url.inherit.append.path" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_Version( Model target, Model source, boolean sourceDominant,
-                                       Map<Object, Object> context )
-    {
-        String src = source.getVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getVersion() == null )
-            {
-                target.setVersion( src );
-                target.setLocation( "version", source.getLocation( "version" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_Packaging( Model target, Model source, boolean sourceDominant,
-                                         Map<Object, Object> context )
-    {
-        String src = source.getPackaging();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getPackaging() == null )
-            {
-                target.setPackaging( src );
-                target.setLocation( "packaging", source.getLocation( "packaging" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_Name( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getName() == null )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_Description( Model target, Model source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getDescription();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getDescription() == null )
-            {
-                target.setDescription( src );
-                target.setLocation( "description", source.getLocation( "description" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_Url( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_InceptionYear( Model target, Model source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getInceptionYear();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getInceptionYear() == null )
-            {
-                target.setInceptionYear( src );
-                target.setLocation( "inceptionYear", source.getLocation( "inceptionYear" ) );
-            }
-        }
-    }
-
-    protected void mergeModel_Organization( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        Organization src = source.getOrganization();
-        if ( src != null )
-        {
-            Organization tgt = target.getOrganization();
-            if ( tgt == null )
-            {
-                tgt = new Organization();
-                target.setOrganization( tgt );
-            }
-            mergeOrganization( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModel_Licenses( Model target, Model source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        target.setLicenses( merge( target.getLicenses(), source.getLicenses(),
-                                    sourceDominant, getLicenseKey() ) );
-    }
-
-    protected void mergeModel_MailingLists( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        target.setMailingLists( merge( target.getMailingLists(), source.getMailingLists(),
-                                       sourceDominant, getMailingListKey() ) );
-    }
-
-    protected void mergeModel_Developers( Model target, Model source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        target.setDevelopers( merge( target.getDevelopers(), source.getDevelopers(),
-                sourceDominant, getDeveloperKey() ) );
-    }
-
-    protected void mergeModel_Contributors( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        target.setContributors( merge( target.getContributors(), source.getContributors(),
-                sourceDominant, getContributorKey() ) );
-    }
-
-    protected void mergeModel_IssueManagement( Model target, Model source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        IssueManagement src = source.getIssueManagement();
-        if ( src != null )
-        {
-            IssueManagement tgt = target.getIssueManagement();
-            if ( tgt == null )
-            {
-                tgt = new IssueManagement();
-                target.setIssueManagement( tgt );
-            }
-            mergeIssueManagement( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModel_Scm( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        Scm src = source.getScm();
-        if ( src != null )
-        {
-            Scm tgt = target.getScm();
-            if ( tgt == null )
-            {
-                tgt = new Scm();
-                tgt.setTag( null );
-                target.setScm( tgt );
-            }
-            mergeScm( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModel_CiManagement( Model target, Model source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        CiManagement src = source.getCiManagement();
-        if ( src != null )
-        {
-            CiManagement tgt = target.getCiManagement();
-            if ( tgt == null )
-            {
-                tgt = new CiManagement();
-                target.setCiManagement( tgt );
-            }
-            mergeCiManagement( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModel_Prerequisites( Model target, Model source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        Prerequisites src = source.getPrerequisites();
-        if ( src != null )
-        {
-            Prerequisites tgt = target.getPrerequisites();
-            if ( tgt == null )
-            {
-                tgt = new Prerequisites();
-                tgt.setMaven( null );
-                target.setPrerequisites( tgt );
-            }
-            mergePrerequisites( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModel_Build( Model target, Model source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        Build src = source.getBuild();
-        if ( src != null )
-        {
-            Build tgt = target.getBuild();
-            if ( tgt == null )
-            {
-                tgt = new Build();
-                target.setBuild( tgt );
-            }
-            mergeBuild( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModel_Profiles( Model target, Model source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        target.setProfiles( merge( target.getProfiles(), source.getProfiles(),
-                sourceDominant, getProfileKey() ) );
-    }
-
-    protected void mergeModelBase( ModelBase target, ModelBase source, boolean sourceDominant,
-                                   Map<Object, Object> context )
-    {
-        mergeModelBase_DistributionManagement( target, source, sourceDominant, context );
-        mergeModelBase_Modules( target, source, sourceDominant, context );
-        mergeModelBase_Repositories( target, source, sourceDominant, context );
-        mergeModelBase_PluginRepositories( target, source, sourceDominant, context );
-        mergeModelBase_Dependencies( target, source, sourceDominant, context );
-        mergeModelBase_Reporting( target, source, sourceDominant, context );
-        mergeModelBase_DependencyManagement( target, source, sourceDominant, context );
-        mergeModelBase_Properties( target, source, sourceDominant, context );
-    }
-
-    protected void mergeModelBase_Modules( ModelBase target, ModelBase source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        target.setModules( merge( target.getModules(), source.getModules(), sourceDominant, e -> e ) );
-    }
-
-    protected void mergeModelBase_Dependencies( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        target.setDependencies( merge( target.getDependencies(), source.getDependencies(),
-                sourceDominant, getDependencyKey() ) );
-    }
-
-    protected void mergeModelBase_Repositories( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        target.setRepositories( merge( target.getRepositories(), source.getRepositories(),
-                sourceDominant, getRepositoryKey() ) );
-    }
-
-    protected void mergeModelBase_PluginRepositories( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                      Map<Object, Object> context )
-    {
-        target.setPluginRepositories( merge( target.getPluginRepositories(), source.getPluginRepositories(),
-                sourceDominant, getRepositoryKey() ) );
-    }
-
-    protected void mergeModelBase_DistributionManagement( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                          Map<Object, Object> context )
-    {
-        DistributionManagement src = source.getDistributionManagement();
-        if ( src != null )
-        {
-            DistributionManagement tgt = target.getDistributionManagement();
-            if ( tgt == null )
-            {
-                tgt = new DistributionManagement();
-                target.setDistributionManagement( tgt );
-            }
-            mergeDistributionManagement( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModelBase_Reporting( ModelBase target, ModelBase source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        Reporting src = source.getReporting();
-        if ( src != null )
-        {
-            Reporting tgt = target.getReporting();
-            if ( tgt == null )
-            {
-                tgt = new Reporting();
-                target.setReporting( tgt );
-            }
-            mergeReporting( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModelBase_DependencyManagement( ModelBase target, ModelBase source, boolean sourceDominant,
-                                                        Map<Object, Object> context )
-    {
-        DependencyManagement src = source.getDependencyManagement();
-        if ( src != null )
-        {
-            DependencyManagement tgt = target.getDependencyManagement();
-            if ( tgt == null )
-            {
-                tgt = new DependencyManagement();
-                target.setDependencyManagement( tgt );
-            }
-            mergeDependencyManagement( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeModelBase_Properties( ModelBase target, ModelBase source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        Properties merged = new Properties();
-        if ( sourceDominant )
-        {
-            merged.putAll( target.getProperties() );
-            merged.putAll( source.getProperties() );
-        }
-        else
-        {
-            merged.putAll( source.getProperties() );
-            merged.putAll( target.getProperties() );
-        }
-        target.setProperties( merged );
-        target.setLocation( "properties", InputLocation.merge( target.getLocation( "properties" ),
-                                                               source.getLocation( "properties" ), sourceDominant ) );
-    }
-
-    protected void mergeDistributionManagement( DistributionManagement target, DistributionManagement source,
-                                                boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeDistributionManagement_Repository( target, source, sourceDominant, context );
-        mergeDistributionManagement_SnapshotRepository( target, source, sourceDominant, context );
-        mergeDistributionManagement_Site( target, source, sourceDominant, context );
-        mergeDistributionManagement_Status( target, source, sourceDominant, context );
-        mergeDistributionManagement_DownloadUrl( target, source, sourceDominant, context );
-    }
-
-    protected void mergeDistributionManagement_Repository( DistributionManagement target,
-                                                           DistributionManagement source, boolean sourceDominant,
-                                                           Map<Object, Object> context )
-    {
-        DeploymentRepository src = source.getRepository();
-        if ( src != null )
-        {
-            DeploymentRepository tgt = target.getRepository();
-            if ( tgt == null )
-            {
-                tgt = new DeploymentRepository();
-                target.setRepository( tgt );
-            }
-            mergeDeploymentRepository( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeDistributionManagement_SnapshotRepository( DistributionManagement target,
-                                                                   DistributionManagement source,
-                                                                   boolean sourceDominant,
-                                                                   Map<Object, Object> context )
-    {
-        DeploymentRepository src = source.getSnapshotRepository();
-        if ( src != null )
-        {
-            DeploymentRepository tgt = target.getSnapshotRepository();
-            if ( tgt == null )
-            {
-                tgt = new DeploymentRepository();
-                target.setSnapshotRepository( tgt );
-            }
-            mergeDeploymentRepository( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeDistributionManagement_Site( DistributionManagement target, DistributionManagement source,
-                                                     boolean sourceDominant, Map<Object, Object> context )
-    {
-        Site src = source.getSite();
-        if ( src != null )
-        {
-            Site tgt = target.getSite();
-            if ( tgt == null )
-            {
-                tgt = new Site();
-                target.setSite( tgt );
-            }
-            mergeSite( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeDistributionManagement_Status( DistributionManagement target, DistributionManagement source,
-                                                       boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getStatus();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getStatus() == null )
-            {
-                target.setStatus( src );
-                target.setLocation( "status", source.getLocation( "status" ) );
-            }
-        }
-    }
-
-    protected void mergeDistributionManagement_DownloadUrl( DistributionManagement target,
-                                                            DistributionManagement source, boolean sourceDominant,
-                                                            Map<Object, Object> context )
-    {
-        String src = source.getDownloadUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getDownloadUrl() == null )
-            {
-                target.setDownloadUrl( src );
-                target.setLocation( "downloadUrl", source.getLocation( "downloadUrl" ) );
-            }
-        }
-    }
-
-    protected void mergeRelocation( Relocation target, Relocation source, boolean sourceDominant,
-                                    Map<Object, Object> context )
-    {
-        mergeRelocation_GroupId( target, source, sourceDominant, context );
-        mergeRelocation_ArtifactId( target, source, sourceDominant, context );
-        mergeRelocation_Version( target, source, sourceDominant, context );
-        mergeRelocation_Message( target, source, sourceDominant, context );
-    }
-
-    protected void mergeRelocation_GroupId( Relocation target, Relocation source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergeRelocation_ArtifactId( Relocation target, Relocation source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergeRelocation_Version( Relocation target, Relocation source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getVersion() == null )
-            {
-                target.setVersion( src );
-                target.setLocation( "version", source.getLocation( "version" ) );
-            }
-        }
-    }
-
-    protected void mergeRelocation_Message( Relocation target, Relocation source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getMessage();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getMessage() == null )
-            {
-                target.setMessage( src );
-                target.setLocation( "message", source.getLocation( "message" ) );
-            }
-        }
-    }
-
-    protected void mergeDeploymentRepository( DeploymentRepository target, DeploymentRepository source,
-                                              boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeRepository( target, source, sourceDominant, context );
-        mergeDeploymentRepository_UniqueVersion( target, source, sourceDominant, context );
-    }
-
-    protected void mergeDeploymentRepository_UniqueVersion( DeploymentRepository target, DeploymentRepository source,
-                                                            boolean sourceDominant, Map<Object, Object> context )
-    {
-        if ( sourceDominant )
-        {
-            target.setUniqueVersion( source.isUniqueVersion() );
-            target.setLocation( "uniqueVersion", source.getLocation( "uniqueVersion" ) );
-        }
-    }
-
-    protected void mergeSite( Site target, Site source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeSite_ChildSiteUrlInheritAppendPath( target, source, sourceDominant, context );
-        mergeSite_Id( target, source, sourceDominant, context );
-        mergeSite_Name( target, source, sourceDominant, context );
-        mergeSite_Url( target, source, sourceDominant, context );
-    }
-
-    protected void mergeSite_ChildSiteUrlInheritAppendPath( Site target, Site source, boolean sourceDominant,
-                                                            Map<Object, Object> context )
-    {
-        String src = source.getChildSiteUrlInheritAppendPath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getChildSiteUrlInheritAppendPath() == null )
-            {
-                target.setChildSiteUrlInheritAppendPath( src );
-                target.setLocation( "child.site.url.inherit.append.path",
-                                    source.getLocation( "child.site.url.inherit.append.path" ) );
-            }
-        }
-    }
-
-    protected void mergeSite_Id( Site target, Site source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getId() == null )
-            {
-                target.setId( src );
-                target.setLocation( "id", source.getLocation( "id" ) );
-            }
-        }
-    }
-
-    protected void mergeSite_Name( Site target, Site source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getName() == null )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
-            }
-        }
-    }
-
-    protected void mergeSite_Url( Site target, Site source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeRepository( Repository target, Repository source, boolean sourceDominant,
-                                    Map<Object, Object> context )
-    {
-        mergeRepositoryBase( target, source, sourceDominant, context );
-        mergeRepository_Releases( target, source, sourceDominant, context );
-        mergeRepository_Snapshots( target, source, sourceDominant, context );
-    }
-
-    protected void mergeRepository_Releases( Repository target, Repository source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        RepositoryPolicy src = source.getReleases();
-        if ( src != null )
-        {
-            RepositoryPolicy tgt = target.getReleases();
-            if ( tgt == null )
-            {
-                tgt = new RepositoryPolicy();
-                target.setReleases( tgt );
-            }
-            mergeRepositoryPolicy( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeRepository_Snapshots( Repository target, Repository source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        RepositoryPolicy src = source.getSnapshots();
-        if ( src != null )
-        {
-            RepositoryPolicy tgt = target.getSnapshots();
-            if ( tgt == null )
-            {
-                tgt = new RepositoryPolicy();
-                target.setSnapshots( tgt );
-            }
-            mergeRepositoryPolicy( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergeRepositoryBase( RepositoryBase target, RepositoryBase source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        mergeRepositoryBase_Id( target, source, sourceDominant, context );
-        mergeRepositoryBase_Name( target, source, sourceDominant, context );
-        mergeRepositoryBase_Url( target, source, sourceDominant, context );
-        mergeRepositoryBase_Layout( target, source, sourceDominant, context );
-    }
-
-    protected void mergeRepositoryBase_Id( RepositoryBase target, RepositoryBase source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getId() == null )
-            {
-                target.setId( src );
-                target.setLocation( "id", source.getLocation( "id" ) );
-            }
-        }
-    }
-
-    protected void mergeRepositoryBase_Url( RepositoryBase target, RepositoryBase source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeRepositoryBase_Name( RepositoryBase target, RepositoryBase source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getName() == null )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
-            }
-        }
-    }
-
-    protected void mergeRepositoryBase_Layout( RepositoryBase target, RepositoryBase source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getLayout();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getLayout() == null )
-            {
-                target.setLayout( src );
-                target.setLocation( "layout", source.getLocation( "layout" ) );
-            }
-        }
-    }
-
-    protected void mergeRepositoryPolicy( RepositoryPolicy target, RepositoryPolicy source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        mergeRepositoryPolicy_Enabled( target, source, sourceDominant, context );
-        mergeRepositoryPolicy_UpdatePolicy( target, source, sourceDominant, context );
-        mergeRepositoryPolicy_ChecksumPolicy( target, source, sourceDominant, context );
-    }
-
-    protected void mergeRepositoryPolicy_Enabled( RepositoryPolicy target, RepositoryPolicy source,
-                                                  boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getEnabled();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getEnabled() == null )
-            {
-                target.setEnabled( src );
-                target.setLocation( "enabled", source.getLocation( "enabled" ) );
-            }
-        }
-    }
-
-    protected void mergeRepositoryPolicy_UpdatePolicy( RepositoryPolicy target, RepositoryPolicy source,
-                                                       boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getUpdatePolicy();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUpdatePolicy() == null )
-            {
-                target.setUpdatePolicy( src );
-                target.setLocation( "updatePolicy", source.getLocation( "updatePolicy" ) );
-            }
-        }
-    }
-
-    protected void mergeRepositoryPolicy_ChecksumPolicy( RepositoryPolicy target, RepositoryPolicy source,
-                                                         boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getChecksumPolicy();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getChecksumPolicy() == null )
-            {
-                target.setChecksumPolicy( src );
-                target.setLocation( "checksumPolicy", source.getLocation( "checksumPolicy" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency( Dependency target, Dependency source, boolean sourceDominant,
-                                    Map<Object, Object> context )
-    {
-        mergeDependency_GroupId( target, source, sourceDominant, context );
-        mergeDependency_ArtifactId( target, source, sourceDominant, context );
-        mergeDependency_Version( target, source, sourceDominant, context );
-        mergeDependency_Type( target, source, sourceDominant, context );
-        mergeDependency_Classifier( target, source, sourceDominant, context );
-        mergeDependency_Scope( target, source, sourceDominant, context );
-        mergeDependency_SystemPath( target, source, sourceDominant, context );
-        mergeDependency_Optional( target, source, sourceDominant, context );
-        mergeDependency_Exclusions( target, source, sourceDominant, context );
-    }
-
-    protected void mergeDependency_GroupId( Dependency target, Dependency source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_ArtifactId( Dependency target, Dependency source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_Version( Dependency target, Dependency source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getVersion() == null )
-            {
-                target.setVersion( src );
-                target.setLocation( "version", source.getLocation( "version" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_Type( Dependency target, Dependency source, boolean sourceDominant,
-                                         Map<Object, Object> context )
-    {
-        String src = source.getType();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getType() == null )
-            {
-                target.setType( src );
-                target.setLocation( "type", source.getLocation( "type" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_Classifier( Dependency target, Dependency source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getClassifier();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getClassifier() == null )
-            {
-                target.setClassifier( src );
-                target.setLocation( "classifier", source.getLocation( "classifier" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_Scope( Dependency target, Dependency source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getScope();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getScope() == null )
-            {
-                target.setScope( src );
-                target.setLocation( "scope", source.getLocation( "scope" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_SystemPath( Dependency target, Dependency source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getSystemPath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getSystemPath() == null )
-            {
-                target.setSystemPath( src );
-                target.setLocation( "systemPath", source.getLocation( "systemPath" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_Optional( Dependency target, Dependency source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getOptional();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getOptional() == null )
-            {
-                target.setOptional( src );
-                target.setLocation( "optional", source.getLocation( "optional" ) );
-            }
-        }
-    }
-
-    protected void mergeDependency_Exclusions( Dependency target, Dependency source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        target.setExclusions( merge( target.getExclusions(), source.getExclusions(),
-                sourceDominant, getExclusionKey() ) );
-    }
-
-    protected void mergeExclusion( Exclusion target, Exclusion source, boolean sourceDominant,
-                                   Map<Object, Object> context )
-    {
-        mergeExclusion_GroupId( target, source, sourceDominant, context );
-        mergeExclusion_ArtifactId( target, source, sourceDominant, context );
-    }
-
-    protected void mergeExclusion_GroupId( Exclusion target, Exclusion source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergeExclusion_ArtifactId( Exclusion target, Exclusion source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergeReporting( Reporting target, Reporting source, boolean sourceDominant,
-                                   Map<Object, Object> context )
-    {
-        mergeReporting_OutputDirectory( target, source, sourceDominant, context );
-        mergeReporting_ExcludeDefaults( target, source, sourceDominant, context );
-        mergeReporting_Plugins( target, source, sourceDominant, context );
-    }
-
-    protected void mergeReporting_OutputDirectory( Reporting target, Reporting source, boolean sourceDominant,
-                                                   Map<Object, Object> context )
-    {
-        String src = source.getOutputDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getOutputDirectory() == null )
-            {
-                target.setOutputDirectory( src );
-                target.setLocation( "outputDirectory", source.getLocation( "outputDirectory" ) );
-            }
-        }
-    }
-
-    protected void mergeReporting_ExcludeDefaults( Reporting target, Reporting source, boolean sourceDominant,
-                                                   Map<Object, Object> context )
-    {
-        String src = source.getExcludeDefaults();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getExcludeDefaults() == null )
-            {
-                target.setExcludeDefaults( src );
-                target.setLocation( "excludeDefaults", source.getLocation( "excludeDefaults" ) );
-            }
-        }
-    }
-
-    protected void mergeReporting_Plugins( Reporting target, Reporting source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        target.setPlugins( merge( target.getPlugins(), source.getPlugins(),
-                sourceDominant, getReportPluginKey() ) );
-    }
-
-    protected void mergeReportPlugin( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                      Map<Object, Object> context )
-    {
-        mergeConfigurationContainer( target, source, sourceDominant, context );
-        mergeReportPlugin_GroupId( target, source, sourceDominant, context );
-        mergeReportPlugin_ArtifactId( target, source, sourceDominant, context );
-        mergeReportPlugin_Version( target, source, sourceDominant, context );
-        mergeReportPlugin_ReportSets( target, source, sourceDominant, context );
-    }
-
-    protected void mergeReportPlugin_GroupId( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergeReportPlugin_ArtifactId( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergeReportPlugin_Version( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        String src = source.getVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getVersion() == null )
-            {
-                target.setVersion( src );
-                target.setLocation( "version", source.getLocation( "version" ) );
-            }
-        }
-    }
-
-    protected void mergeReportPlugin_ReportSets( ReportPlugin target, ReportPlugin source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
-        target.setReportSets( merge( target.getReportSets(), source.getReportSets(),
-                sourceDominant, getReportSetKey() ) );
-    }
-
-    protected void mergeReportSet( ReportSet target, ReportSet source, boolean sourceDominant,
-                                   Map<Object, Object> context )
-    {
-        mergeConfigurationContainer( target, source, sourceDominant, context );
-        mergeReportSet_Id( target, source, sourceDominant, context );
-        mergeReportSet_Reports( target, source, sourceDominant, context );
-    }
-
-    protected void mergeReportSet_Id( ReportSet target, ReportSet source, boolean sourceDominant,
-                                      Map<Object, Object> context )
-    {
-        String src = source.getId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getId() == null )
-            {
-                target.setId( src );
-                target.setLocation( "id", source.getLocation( "id" ) );
-            }
-        }
-    }
-
-    protected void mergeReportSet_Reports( ReportSet target, ReportSet source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        target.setReports( merge( target.getReports(), source.getReports(), sourceDominant, e -> e ) );
-    }
-
-    protected void mergeDependencyManagement( DependencyManagement target, DependencyManagement source,
-                                              boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeDependencyManagement_Dependencies( target, source, sourceDominant, context );
-    }
-
-    protected void mergeDependencyManagement_Dependencies( DependencyManagement target, DependencyManagement source,
-                                                           boolean sourceDominant, Map<Object, Object> context )
-    {
-        target.setDependencies( merge( target.getDependencies(), source.getDependencies(),
-                                       sourceDominant, getDependencyKey() ) );
-    }
-
-    protected void mergeParent( Parent target, Parent source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeParent_GroupId( target, source, sourceDominant, context );
-        mergeParent_ArtifactId( target, source, sourceDominant, context );
-        mergeParent_Version( target, source, sourceDominant, context );
-        mergeParent_RelativePath( target, source, sourceDominant, context );
-    }
-
-    protected void mergeParent_GroupId( Parent target, Parent source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergeParent_ArtifactId( Parent target, Parent source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergeParent_Version( Parent target, Parent source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        String src = source.getVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getVersion() == null )
-            {
-                target.setVersion( src );
-                target.setLocation( "version", source.getLocation( "version" ) );
-            }
-        }
-    }
-
-    protected void mergeParent_RelativePath( Parent target, Parent source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getRelativePath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getRelativePath() == null )
-            {
-                target.setRelativePath( src );
-                target.setLocation( "relativePath", source.getLocation( "relativePath" ) );
-            }
-        }
-    }
-
-    protected void mergeOrganization( Organization target, Organization source, boolean sourceDominant,
-                                      Map<Object, Object> context )
-    {
-        mergeOrganization_Name( target, source, sourceDominant, context );
-        mergeOrganization_Url( target, source, sourceDominant, context );
-    }
-
-    protected void mergeOrganization_Name( Organization target, Organization source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getName() == null )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
-            }
-        }
-    }
-
-    protected void mergeOrganization_Url( Organization target, Organization source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeLicense( License target, License source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeLicense_Name( target, source, sourceDominant, context );
-        mergeLicense_Url( target, source, sourceDominant, context );
-        mergeLicense_Distribution( target, source, sourceDominant, context );
-        mergeLicense_Comments( target, source, sourceDominant, context );
-    }
-
-    protected void mergeLicense_Name( License target, License source, boolean sourceDominant,
-                                      Map<Object, Object> context )
-    {
-        String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getName() == null )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
-            }
-        }
-    }
-
-    protected void mergeLicense_Url( License target, License source, boolean sourceDominant,
-                                     Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeLicense_Distribution( License target, License source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        String src = source.getDistribution();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getDistribution() == null )
-            {
-                target.setDistribution( src );
-                target.setLocation( "distribution", source.getLocation( "distribution" ) );
-            }
-        }
-    }
-
-    protected void mergeLicense_Comments( License target, License source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getComments();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getComments() == null )
-            {
-                target.setComments( src );
-                target.setLocation( "comments", source.getLocation( "comments" ) );
-            }
-        }
-    }
-
-    protected void mergeMailingList( MailingList target, MailingList source, boolean sourceDominant,
-                                     Map<Object, Object> context )
-    {
-        mergeMailingList_Name( target, source, sourceDominant, context );
-        mergeMailingList_Subscribe( target, source, sourceDominant, context );
-        mergeMailingList_Unsubscribe( target, source, sourceDominant, context );
-        mergeMailingList_Post( target, source, sourceDominant, context );
-        mergeMailingList_OtherArchives( target, source, sourceDominant, context );
-    }
-
-    protected void mergeMailingList_Name( MailingList target, MailingList source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getName() == null )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
-            }
-        }
-    }
-
-    protected void mergeMailingList_Subscribe( MailingList target, MailingList source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getSubscribe();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getSubscribe() == null )
-            {
-                target.setSubscribe( src );
-                target.setLocation( "subscribe", source.getLocation( "subscribe" ) );
-            }
-        }
-    }
-
-    protected void mergeMailingList_Unsubscribe( MailingList target, MailingList source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
-        String src = source.getUnsubscribe();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUnsubscribe() == null )
-            {
-                target.setUnsubscribe( src );
-                target.setLocation( "unsubscribe", source.getLocation( "unsubscribe" ) );
-            }
-        }
-    }
-
-    protected void mergeMailingList_Post( MailingList target, MailingList source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getPost();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getPost() == null )
-            {
-                target.setPost( src );
-                target.setLocation( "post", source.getLocation( "post" ) );
-            }
-        }
-    }
-
-    protected void mergeMailingList_Archive( MailingList target, MailingList source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getArchive();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArchive() == null )
-            {
-                target.setArchive( src );
-                target.setLocation( "archive", source.getLocation( "archive" ) );
-            }
-        }
-    }
-
-    protected void mergeMailingList_OtherArchives( MailingList target, MailingList source, boolean sourceDominant,
-                                                   Map<Object, Object> context )
-    {
-        target.setOtherArchives( merge( target.getOtherArchives(),
-                                        source.getOtherArchives(),
-                                        sourceDominant,
-                                        e -> e ) );
-    }
-
-    protected void mergeDeveloper( Developer target, Developer source, boolean sourceDominant,
-                                   Map<Object, Object> context )
-    {
-        mergeContributor( target, source, sourceDominant, context );
-        mergeDeveloper_Id( target, source, sourceDominant, context );
-    }
-
-    protected void mergeDeveloper_Id( Developer target, Developer source, boolean sourceDominant,
-                                      Map<Object, Object> context )
-    {
-        String src = source.getId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getId() == null )
-            {
-                target.setId( src );
-                target.setLocation( "id", source.getLocation( "id" ) );
-            }
-        }
-    }
-
-    protected void mergeContributor( Contributor target, Contributor source, boolean sourceDominant,
-                                     Map<Object, Object> context )
-    {
-        mergeContributor_Name( target, source, sourceDominant, context );
-        mergeContributor_Email( target, source, sourceDominant, context );
-        mergeContributor_Url( target, source, sourceDominant, context );
-        mergeContributor_Organization( target, source, sourceDominant, context );
-        mergeContributor_OrganizationUrl( target, source, sourceDominant, context );
-        mergeContributor_Timezone( target, source, sourceDominant, context );
-        mergeContributor_Roles( target, source, sourceDominant, context );
-        mergeContributor_Properties( target, source, sourceDominant, context );
-    }
-
-    protected void mergeContributor_Name( Contributor target, Contributor source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getName() == null )
-            {
-                target.setName( src );
-                target.setLocation( "name", source.getLocation( "name" ) );
-            }
-        }
-    }
-
-    protected void mergeContributor_Email( Contributor target, Contributor source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getEmail();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getEmail() == null )
-            {
-                target.setEmail( src );
-                target.setLocation( "email", source.getLocation( "email" ) );
-            }
-        }
-    }
-
-    protected void mergeContributor_Url( Contributor target, Contributor source, boolean sourceDominant,
-                                         Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeContributor_Organization( Contributor target, Contributor source, boolean sourceDominant,
-                                                  Map<Object, Object> context )
-    {
-        String src = source.getOrganization();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getOrganization() == null )
-            {
-                target.setOrganization( src );
-                target.setLocation( "organization", source.getLocation( "organization" ) );
-            }
-        }
-    }
-
-    protected void mergeContributor_OrganizationUrl( Contributor target, Contributor source, boolean sourceDominant,
-                                                     Map<Object, Object> context )
-    {
-        String src = source.getOrganizationUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getOrganizationUrl() == null )
-            {
-                target.setOrganizationUrl( src );
-                target.setLocation( "organizationUrl", source.getLocation( "organizationUrl" ) );
-            }
-        }
-    }
-
-    protected void mergeContributor_Timezone( Contributor target, Contributor source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        String src = source.getTimezone();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getTimezone() == null )
-            {
-                target.setTimezone( src );
-                target.setLocation( "timezone", source.getLocation( "timezone" ) );
-            }
-        }
-    }
-
-    protected void mergeContributor_Roles( Contributor target, Contributor source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        target.setRoles( merge( target.getRoles(), source.getRoles(), sourceDominant, e -> e ) );
-    }
-
-    protected void mergeContributor_Properties( Contributor target, Contributor source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        Properties merged = new Properties();
-        if ( sourceDominant )
-        {
-            merged.putAll( target.getProperties() );
-            merged.putAll( source.getProperties() );
-        }
-        else
-        {
-            merged.putAll( source.getProperties() );
-            merged.putAll( target.getProperties() );
-        }
-        target.setProperties( merged );
-        target.setLocation( "properties", InputLocation.merge( target.getLocation( "properties" ),
-                                                               source.getLocation( "properties" ), sourceDominant ) );
-    }
-
-    protected void mergeIssueManagement( IssueManagement target, IssueManagement source, boolean sourceDominant,
-                                         Map<Object, Object> context )
-    {
-        mergeIssueManagement_Url( target, source, sourceDominant, context );
-        mergeIssueManagement_System( target, source, sourceDominant, context );
-    }
-
-    protected void mergeIssueManagement_System( IssueManagement target, IssueManagement source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        String src = source.getSystem();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getSystem() == null )
-            {
-                target.setSystem( src );
-                target.setLocation( "system", source.getLocation( "system" ) );
-            }
-        }
-    }
-
-    protected void mergeIssueManagement_Url( IssueManagement target, IssueManagement source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeScm( Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeScm_ChildScmConnectionInheritAppendPath( target, source, sourceDominant, context );
-        mergeScm_ChildScmDeveloperConnectionInheritAppendPath( target, source, sourceDominant, context );
-        mergeScm_ChildScmUrlInheritAppendPath( target, source, sourceDominant, context );
-        mergeScm_Url( target, source, sourceDominant, context );
-        mergeScm_Connection( target, source, sourceDominant, context );
-        mergeScm_DeveloperConnection( target, source, sourceDominant, context );
-        mergeScm_Tag( target, source, sourceDominant, context );
-    }
-
-    protected void mergeScm_ChildScmConnectionInheritAppendPath( Scm target, Scm source, boolean sourceDominant,
-                                                                 Map<Object, Object> context )
-    {
-        String src = source.getChildScmConnectionInheritAppendPath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getChildScmConnectionInheritAppendPath() == null )
-            {
-                target.setChildScmConnectionInheritAppendPath( src );
-                target.setLocation( "child.scm.connection.inherit.append.path",
-                                    source.getLocation( "child.scm.connection.inherit.append.path" ) );
-            }
-        }
-    }
-
-    protected void mergeScm_ChildScmDeveloperConnectionInheritAppendPath( Scm target, Scm source,
-                                                                          boolean sourceDominant,
-                                                                          Map<Object, Object> context )
-    {
-        String src = source.getChildScmDeveloperConnectionInheritAppendPath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getChildScmDeveloperConnectionInheritAppendPath() == null )
-            {
-                target.setChildScmDeveloperConnectionInheritAppendPath( src );
-                target.setLocation( "child.scm.developerConnection.inherit.append.path",
-                                    source.getLocation( "child.scm.developerConnection.inherit.append.path" ) );
-            }
-        }
-    }
-
-    protected void mergeScm_ChildScmUrlInheritAppendPath( Scm target, Scm source, boolean sourceDominant,
-                                                          Map<Object, Object> context )
-    {
-        String src = source.getChildScmUrlInheritAppendPath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getChildScmUrlInheritAppendPath() == null )
-            {
-                target.setChildScmUrlInheritAppendPath( src );
-                target.setLocation( "child.scm.url.inherit.append.path",
-                                    source.getLocation( "child.scm.url.inherit.append.path" ) );
-            }
-        }
-    }
-
-    protected void mergeScm_Url( Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeScm_Connection( Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getConnection();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getConnection() == null )
-            {
-                target.setConnection( src );
-                target.setLocation( "connection", source.getLocation( "connection" ) );
-            }
-        }
-    }
-
-    protected void mergeScm_DeveloperConnection( Scm target, Scm source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
-        String src = source.getDeveloperConnection();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getDeveloperConnection() == null )
-            {
-                target.setDeveloperConnection( src );
-                target.setLocation( "developerConnection", source.getLocation( "developerConnection" ) );
-            }
-        }
-    }
-
-    protected void mergeScm_Tag( Scm target, Scm source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getTag();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getTag() == null )
-            {
-                target.setTag( src );
-                target.setLocation( "tag", source.getLocation( "tag" ) );
-            }
-        }
-    }
-
-    protected void mergeCiManagement( CiManagement target, CiManagement source, boolean sourceDominant,
-                                      Map<Object, Object> context )
-    {
-        mergeCiManagement_System( target, source, sourceDominant, context );
-        mergeCiManagement_Url( target, source, sourceDominant, context );
-        mergeCiManagement_Notifiers( target, source, sourceDominant, context );
-    }
-
-    protected void mergeCiManagement_System( CiManagement target, CiManagement source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getSystem();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getSystem() == null )
-            {
-                target.setSystem( src );
-                target.setLocation( "system", source.getLocation( "system" ) );
-            }
-        }
-    }
-
-    protected void mergeCiManagement_Url( CiManagement target, CiManagement source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getUrl();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getUrl() == null )
-            {
-                target.setUrl( src );
-                target.setLocation( "url", source.getLocation( "url" ) );
-            }
-        }
-    }
-
-    protected void mergeCiManagement_Notifiers( CiManagement target, CiManagement source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        target.setNotifiers( merge( target.getNotifiers(), source.getNotifiers(),
-                                    sourceDominant, getNotifierKey() ) );
-    }
-
-    protected void mergeNotifier( Notifier target, Notifier source, boolean sourceDominant,
-                                  Map<Object, Object> context )
-    {
-        mergeNotifier_Type( target, source, sourceDominant, context );
-        mergeNotifier_Address( target, source, sourceDominant, context );
-        mergeNotifier_Configuration( target, source, sourceDominant, context );
-        mergeNotifier_SendOnError( target, source, sourceDominant, context );
-        mergeNotifier_SendOnFailure( target, source, sourceDominant, context );
-        mergeNotifier_SendOnSuccess( target, source, sourceDominant, context );
-        mergeNotifier_SendOnWarning( target, source, sourceDominant, context );
-    }
-
-    protected void mergeNotifier_Type( Notifier target, Notifier source, boolean sourceDominant,
-                                       Map<Object, Object> context )
-    {
-        String src = source.getType();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getType() == null )
-            {
-                target.setType( src );
-            }
-        }
-    }
-
-    protected void mergeNotifier_Address( Notifier target, Notifier source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getAddress();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getAddress() == null )
-            {
-                target.setAddress( src );
-            }
-        }
-    }
-
-    protected void mergeNotifier_Configuration( Notifier target, Notifier source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        Properties merged = new Properties();
-        if ( sourceDominant )
-        {
-            merged.putAll( target.getConfiguration() );
-            merged.putAll( source.getConfiguration() );
-        }
-        else
-        {
-            merged.putAll( source.getConfiguration() );
-            merged.putAll( target.getConfiguration() );
-        }
-        target.setConfiguration( merged );
-    }
-
-    protected void mergeNotifier_SendOnError( Notifier target, Notifier source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        if ( sourceDominant )
-        {
-            target.setSendOnError( source.isSendOnError() );
-        }
-    }
-
-    protected void mergeNotifier_SendOnFailure( Notifier target, Notifier source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        if ( sourceDominant )
-        {
-            target.setSendOnFailure( source.isSendOnFailure() );
-        }
-    }
-
-    protected void mergeNotifier_SendOnSuccess( Notifier target, Notifier source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        if ( sourceDominant )
-        {
-            target.setSendOnSuccess( source.isSendOnSuccess() );
-        }
-    }
-
-    protected void mergeNotifier_SendOnWarning( Notifier target, Notifier source, boolean sourceDominant,
-                                                Map<Object, Object> context )
-    {
-        if ( sourceDominant )
-        {
-            target.setSendOnWarning( source.isSendOnWarning() );
-        }
-    }
-
-    protected void mergePrerequisites( Prerequisites target, Prerequisites source, boolean sourceDominant,
-                                       Map<Object, Object> context )
-    {
-        mergePrerequisites_Maven( target, source, sourceDominant, context );
-    }
-
-    protected void mergePrerequisites_Maven( Prerequisites target, Prerequisites source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getMaven();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getMaven() == null )
-            {
-                target.setMaven( src );
-                target.setLocation( "maven", source.getLocation( "maven" ) );
-            }
-        }
-    }
-
-    protected void mergeBuild( Build target, Build source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeBuildBase( target, source, sourceDominant, context );
-        mergeBuild_SourceDirectory( target, source, sourceDominant, context );
-        mergeBuild_ScriptSourceDirectory( target, source, sourceDominant, context );
-        mergeBuild_TestSourceDirectory( target, source, sourceDominant, context );
-        mergeBuild_OutputDirectory( target, source, sourceDominant, context );
-        mergeBuild_TestOutputDirectory( target, source, sourceDominant, context );
-        mergeBuild_Extensions( target, source, sourceDominant, context );
-    }
-
-    protected void mergeBuild_SourceDirectory( Build target, Build source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getSourceDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getSourceDirectory() == null )
-            {
-                target.setSourceDirectory( src );
-                target.setLocation( "sourceDirectory", source.getLocation( "sourceDirectory" ) );
-            }
-        }
-    }
-
-    protected void mergeBuild_ScriptSourceDirectory( Build target, Build source, boolean sourceDominant,
-                                                     Map<Object, Object> context )
-    {
-        String src = source.getScriptSourceDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getScriptSourceDirectory() == null )
-            {
-                target.setScriptSourceDirectory( src );
-                target.setLocation( "scriptSourceDirectory", source.getLocation( "scriptSourceDirectory" ) );
-            }
-        }
-    }
-
-    protected void mergeBuild_TestSourceDirectory( Build target, Build source, boolean sourceDominant,
-                                                   Map<Object, Object> context )
-    {
-        String src = source.getTestSourceDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getTestSourceDirectory() == null )
-            {
-                target.setTestSourceDirectory( src );
-                target.setLocation( "testSourceDirectory", source.getLocation( "testSourceDirectory" ) );
-            }
-        }
-    }
-
-    protected void mergeBuild_OutputDirectory( Build target, Build source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getOutputDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getOutputDirectory() == null )
-            {
-                target.setOutputDirectory( src );
-                target.setLocation( "outputDirectory", source.getLocation( "outputDirectory" ) );
-            }
-        }
-    }
-
-    protected void mergeBuild_TestOutputDirectory( Build target, Build source, boolean sourceDominant,
-                                                   Map<Object, Object> context )
-    {
-        String src = source.getTestOutputDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getTestOutputDirectory() == null )
-            {
-                target.setTestOutputDirectory( src );
-                target.setLocation( "testOutputDirectory", source.getLocation( "testOutputDirectory" ) );
-            }
-        }
-    }
-
-    protected void mergeBuild_Extensions( Build target, Build source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        target.setExtensions( merge( target.getExtensions(), source.getExtensions(),
-                                     sourceDominant, getExtensionKey() ) );
-    }
-
-    protected void mergeExtension( Extension target, Extension source, boolean sourceDominant,
-                                   Map<Object, Object> context )
-    {
-        mergeExtension_GroupId( target, source, sourceDominant, context );
-        mergeExtension_ArtifactId( target, source, sourceDominant, context );
-        mergeExtension_Version( target, source, sourceDominant, context );
-    }
-
-    protected void mergeExtension_GroupId( Extension target, Extension source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergeExtension_ArtifactId( Extension target, Extension source, boolean sourceDominant,
-                                              Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergeExtension_Version( Extension target, Extension source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getVersion() == null )
-            {
-                target.setVersion( src );
-                target.setLocation( "version", source.getLocation( "version" ) );
-            }
-        }
-    }
-
-    protected void mergeBuildBase( BuildBase target, BuildBase source, boolean sourceDominant,
-                                   Map<Object, Object> context )
-    {
-        mergePluginConfiguration( target, source, sourceDominant, context );
-        mergeBuildBase_DefaultGoal( target, source, sourceDominant, context );
-        mergeBuildBase_FinalName( target, source, sourceDominant, context );
-        mergeBuildBase_Directory( target, source, sourceDominant, context );
-        mergeBuildBase_Resources( target, source, sourceDominant, context );
-        mergeBuildBase_TestResources( target, source, sourceDominant, context );
-        mergeBuildBase_Filters( target, source, sourceDominant, context );
-    }
-
-    protected void mergeBuildBase_DefaultGoal( BuildBase target, BuildBase source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getDefaultGoal();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getDefaultGoal() == null )
-            {
-                target.setDefaultGoal( src );
-                target.setLocation( "defaultGoal", source.getLocation( "defaultGoal" ) );
-            }
-        }
-    }
-
-    protected void mergeBuildBase_Directory( BuildBase target, BuildBase source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getDirectory() == null )
-            {
-                target.setDirectory( src );
-                target.setLocation( "directory", source.getLocation( "directory" ) );
-            }
-        }
-    }
-
-    protected void mergeBuildBase_FinalName( BuildBase target, BuildBase source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getFinalName();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getFinalName() == null )
-            {
-                target.setFinalName( src );
-                target.setLocation( "finalName", source.getLocation( "finalName" ) );
-            }
-        }
-    }
-
-    protected void mergeBuildBase_Filters( BuildBase target, BuildBase source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        target.setFilters( merge( target.getFilters(), source.getFilters(), sourceDominant, e -> e ) );
-    }
-
-    protected void mergeBuildBase_Resources( BuildBase target, BuildBase source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        target.setResources( merge( target.getResources(), source.getResources(),
-                                    sourceDominant, getResourceKey() ) );
-    }
-
-    protected void mergeBuildBase_TestResources( BuildBase target, BuildBase source, boolean sourceDominant,
-                                                 Map<Object, Object> context )
-    {
-        target.setTestResources( merge( target.getTestResources(), source.getTestResources(),
-                                        sourceDominant, getResourceKey() ) );
-    }
-
-    protected void mergePluginConfiguration( PluginConfiguration target, PluginConfiguration source,
-                                             boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergePluginContainer( target, source, sourceDominant, context );
-        mergePluginConfiguration_PluginManagement( target, source, sourceDominant, context );
-    }
-
-    protected void mergePluginConfiguration_PluginManagement( PluginConfiguration target, PluginConfiguration source,
-                                                              boolean sourceDominant, Map<Object, Object> context )
-    {
-        PluginManagement src = source.getPluginManagement();
-        if ( src != null )
-        {
-            PluginManagement tgt = target.getPluginManagement();
-            if ( tgt == null )
-            {
-                tgt = new PluginManagement();
-                target.setPluginManagement( tgt );
-            }
-            mergePluginManagement( tgt, src, sourceDominant, context );
-        }
-    }
-
-    protected void mergePluginContainer( PluginContainer target, PluginContainer source,
-                                         boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergePluginContainer_Plugins( target, source, sourceDominant, context );
-    }
-
-    protected void mergePluginContainer_Plugins( PluginContainer target, PluginContainer source,
-                                                 boolean sourceDominant, Map<Object, Object> context )
-    {
-        target.setPlugins( merge( target.getPlugins(), source.getPlugins(),
-                                  sourceDominant, getPluginKey() ) );
-    }
-
-    protected void mergePluginManagement( PluginManagement target, PluginManagement source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        mergePluginContainer( target, source, sourceDominant, context );
-    }
-
-    protected void mergePlugin( Plugin target, Plugin source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeConfigurationContainer( target, source, sourceDominant, context );
-        mergePlugin_GroupId( target, source, sourceDominant, context );
-        mergePlugin_ArtifactId( target, source, sourceDominant, context );
-        mergePlugin_Version( target, source, sourceDominant, context );
-        mergePlugin_Extensions( target, source, sourceDominant, context );
-        mergePlugin_Dependencies( target, source, sourceDominant, context );
-        mergePlugin_Executions( target, source, sourceDominant, context );
-    }
-
-    protected void mergePlugin_GroupId( Plugin target, Plugin source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        String src = source.getGroupId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getGroupId() == null )
-            {
-                target.setGroupId( src );
-                target.setLocation( "groupId", source.getLocation( "groupId" ) );
-            }
-        }
-    }
-
-    protected void mergePlugin_ArtifactId( Plugin target, Plugin source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getArtifactId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getArtifactId() == null )
-            {
-                target.setArtifactId( src );
-                target.setLocation( "artifactId", source.getLocation( "artifactId" ) );
-            }
-        }
-    }
-
-    protected void mergePlugin_Version( Plugin target, Plugin source, boolean sourceDominant,
-                                        Map<Object, Object> context )
-    {
-        String src = source.getVersion();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getVersion() == null )
-            {
-                target.setVersion( src );
-                target.setLocation( "version", source.getLocation( "version" ) );
-            }
-        }
-    }
-
-    protected void mergePlugin_Extensions( Plugin target, Plugin source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getExtensions();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getExtensions() == null )
-            {
-                target.setExtensions( src );
-                target.setLocation( "extensions", source.getLocation( "extensions" ) );
-            }
-        }
-    }
-
-    protected void mergePlugin_Dependencies( Plugin target, Plugin source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        target.setDependencies( merge( target.getDependencies(), source.getDependencies(),
-                                       sourceDominant, getDependencyKey() ) );
-    }
-
-    protected void mergePlugin_Executions( Plugin target, Plugin source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        target.setExecutions( merge( target.getExecutions(), source.getExecutions(),
-                                     sourceDominant, getPluginExecutionKey() ) );
-    }
-
-    protected void mergeConfigurationContainer( ConfigurationContainer target, ConfigurationContainer source,
-                                                boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeConfigurationContainer_Inherited( target, source, sourceDominant, context );
-        mergeConfigurationContainer_Configuration( target, source, sourceDominant, context );
-    }
-
-    protected void mergeConfigurationContainer_Inherited( ConfigurationContainer target, ConfigurationContainer source,
-                                                          boolean sourceDominant, Map<Object, Object> context )
-    {
-        String src = source.getInherited();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getInherited() == null )
-            {
-                target.setInherited( src );
-                target.setLocation( "inherited", source.getLocation( "inherited" ) );
-            }
-        }
-    }
-
-    protected void mergeConfigurationContainer_Configuration( ConfigurationContainer target,
-                                                              ConfigurationContainer source, boolean sourceDominant,
-                                                              Map<Object, Object> context )
-    {
-        Xpp3Dom src = (Xpp3Dom) source.getConfiguration();
-        if ( src != null )
-        {
-            Xpp3Dom tgt = (Xpp3Dom) target.getConfiguration();
-            if ( sourceDominant || tgt == null )
-            {
-                tgt = Xpp3Dom.mergeXpp3Dom( new Xpp3Dom( src ), tgt );
-            }
-            else
-            {
-                tgt = Xpp3Dom.mergeXpp3Dom( tgt, src );
-            }
-            target.setConfiguration( tgt );
-        }
-    }
-
-    protected void mergePluginExecution( PluginExecution target, PluginExecution source, boolean sourceDominant,
-                                         Map<Object, Object> context )
-    {
-        mergeConfigurationContainer( target, source, sourceDominant, context );
-        mergePluginExecution_Id( target, source, sourceDominant, context );
-        mergePluginExecution_Phase( target, source, sourceDominant, context );
-        mergePluginExecution_Goals( target, source, sourceDominant, context );
-    }
-
-    protected void mergePluginExecution_Id( PluginExecution target, PluginExecution source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getId() == null )
-            {
-                target.setId( src );
-                target.setLocation( "id", source.getLocation( "id" ) );
-            }
-        }
-    }
-
-    protected void mergePluginExecution_Phase( PluginExecution target, PluginExecution source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        String src = source.getPhase();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getPhase() == null )
-            {
-                target.setPhase( src );
-                target.setLocation( "phase", source.getLocation( "phase" ) );
-            }
-        }
-    }
-
-    protected void mergePluginExecution_Goals( PluginExecution target, PluginExecution source, boolean sourceDominant,
-                                               Map<Object, Object> context )
-    {
-        target.setGoals( merge( target.getGoals(), source.getGoals(), sourceDominant, e -> e ) );
-    }
-
-    protected void mergeResource( Resource target, Resource source, boolean sourceDominant,
-                                  Map<Object, Object> context )
-    {
-        mergeFileSet( target, source, sourceDominant, context );
-        mergeResource_TargetPath( target, source, sourceDominant, context );
-        mergeResource_Filtering( target, source, sourceDominant, context );
-        mergeResource_MergeId( target, source, sourceDominant, context );
-    }
-
-    protected void mergeResource_TargetPath( Resource target, Resource source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        String src = source.getTargetPath();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getTargetPath() == null )
-            {
-                target.setTargetPath( src );
-                target.setLocation( "targetPath", source.getLocation( "targetPath" ) );
-            }
-        }
-    }
-
-    protected void mergeResource_Filtering( Resource target, Resource source, boolean sourceDominant,
-                                            Map<Object, Object> context )
-    {
-        String src = source.getFiltering();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getFiltering() == null )
-            {
-                target.setFiltering( src );
-                target.setLocation( "filtering", source.getLocation( "filtering" ) );
-            }
-        }
-    }
-
-    protected void mergeResource_MergeId( Resource target, Resource source, boolean sourceDominant,
-                                          Map<Object, Object> context )
-    {
-        String src = source.getMergeId();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getMergeId() == null )
-            {
-                target.setMergeId( src );
-            }
-        }
-    }
-
-    protected void mergeFileSet( FileSet target, FileSet source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergePatternSet( target, source, sourceDominant, context );
-        mergeFileSet_Directory( target, source, sourceDominant, context );
-    }
-
-    protected void mergeFileSet_Directory( FileSet target, FileSet source, boolean sourceDominant,
-                                           Map<Object, Object> context )
-    {
-        String src = source.getDirectory();
-        if ( src != null )
-        {
-            if ( sourceDominant || target.getDirectory() == null )
-            {
-                target.setDirectory( src );
-                target.setLocation( "directory", source.getLocation( "directory" ) );
-            }
-        }
-    }
-
-    protected void mergePatternSet( PatternSet target, PatternSet source, boolean sourceDominant,
-                                    Map<Object, Object> context )
-    {
-        mergePatternSet_Includes( target, source, sourceDominant, context );
-        mergePatternSet_Excludes( target, source, sourceDominant, context );
-    }
-
-    protected void mergePatternSet_Includes( PatternSet target, PatternSet source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        target.setIncludes( merge( target.getIncludes(), source.getIncludes(), sourceDominant, e -> e ) );
-    }
-
-    protected void mergePatternSet_Excludes( PatternSet target, PatternSet source, boolean sourceDominant,
-                                             Map<Object, Object> context )
-    {
-        target.setExcludes( merge( target.getExcludes(), source.getExcludes(), sourceDominant, e -> e ) );
-    }
-
-    protected void mergeProfile( Profile target, Profile source, boolean sourceDominant, Map<Object, Object> context )
-    {
-        mergeModelBase( target, source, sourceDominant, context );
-        // TODO
-    }
-
-    protected void mergeActivation( Activation target, Activation source, boolean sourceDominant,
-                                    Map<Object, Object> context )
-    {
-        // TODO
-    }
-
-    @Deprecated
-    protected Object getDependencyKey( Dependency dependency )
-    {
-        return dependency;
-    }
-
-    @Deprecated
-    protected Object getPluginKey( Plugin plugin )
-    {
-        return plugin;
-    }
-
-    @Deprecated
-    protected Object getPluginExecutionKey( PluginExecution pluginExecution )
-    {
-        return pluginExecution;
-    }
-
-    @Deprecated
-    protected Object getReportPluginKey( ReportPlugin reportPlugin )
-    {
-        return reportPlugin;
-    }
-
-    @Deprecated
-    protected Object getReportSetKey( ReportSet reportSet )
-    {
-        return reportSet;
-    }
-
-    @Deprecated
-    protected Object getLicenseKey( License license )
-    {
-        return license;
-    }
-
-    @Deprecated
-    protected Object getMailingListKey( MailingList mailingList )
-    {
-        return mailingList;
-    }
-
-    @Deprecated
-    protected Object getDeveloperKey( Developer developer )
-    {
-        return developer;
-    }
-
-    @Deprecated
-    protected Object getContributorKey( Contributor contributor )
-    {
-        return contributor;
-    }
-
-    @Deprecated
-    protected Object getProfileKey( Profile profile )
-    {
-        return profile;
-    }
-
-    @Deprecated
-    protected Object getRepositoryKey( Repository repository )
-    {
-        return getRepositoryBaseKey( repository );
-    }
-
-    @Deprecated
-    protected Object getRepositoryBaseKey( RepositoryBase repositoryBase )
-    {
-        return repositoryBase;
-    }
-
-    @Deprecated
-    protected Object getNotifierKey( Notifier notifier )
-    {
-        return notifier;
-    }
-
-    @Deprecated
-    protected Object getResourceKey( Resource resource )
-    {
-        return resource;
-    }
-
-    @Deprecated
-    protected Object getExtensionKey( Extension extension )
-    {
-        return extension;
-    }
-
-    @Deprecated
-    protected Object getExclusionKey( Exclusion exclusion )
-    {
-        return exclusion;
-    }
-
-    protected KeyComputer<Dependency> getDependencyKey()
-    {
-        return d -> d;
-    }
-
-    protected KeyComputer<Plugin> getPluginKey()
-    {
-        return p -> p;
-    }
-
-    protected KeyComputer<PluginExecution> getPluginExecutionKey()
-    {
-        return e -> e;
-    }
-
-    protected KeyComputer<ReportPlugin> getReportPluginKey()
-    {
-        return p -> p;
-    }
-
-    protected KeyComputer<ReportSet> getReportSetKey()
-    {
-        return s -> s;
-    }
-
-    protected KeyComputer<License> getLicenseKey()
-    {
-        return l -> l;
-    }
-
-    protected KeyComputer<MailingList> getMailingListKey()
-    {
-        return l -> l;
-    }
-
-    protected KeyComputer<Developer> getDeveloperKey()
-    {
-        return d -> d;
-    }
-
-    protected KeyComputer<Contributor> getContributorKey()
-    {
-        return c -> c;
-    }
-
-    protected KeyComputer<Profile> getProfileKey()
-    {
-        return p -> p;
-    }
-
-    protected KeyComputer<Repository> getRepositoryKey()
-    {
-        return r -> r;
-    }
-
-    protected KeyComputer<RepositoryBase> getRepositoryBaseKey()
-    {
-        return r -> r;
-    }
-
-    protected KeyComputer<Notifier> getNotifierKey()
-    {
-        return n -> n;
-    }
-
-    protected KeyComputer<Resource> getResourceKey()
-    {
-        return r -> r;
-    }
-
-    protected KeyComputer<Extension> getExtensionKey()
-    {
-        return e -> e;
-    }
-
-    protected KeyComputer<Exclusion> getExclusionKey()
-    {
-        return e -> e;
-    }
-
-    /**
-     * Use to compute keys for data structures
-     * @param <T> the data structure type
-     */
-    @FunctionalInterface
-    public interface KeyComputer<T> extends Function<T, Object>
-    {
-    }
-
-    /**
-     * Merge two lists
-     */
-    private static <T> List<T> merge( List<T> tgt, List<T> src, boolean sourceDominant, KeyComputer<T> computer )
-    {
-        return merge( tgt, src, computer, ( t, s ) -> sourceDominant ? s : t );
-    }
-
-    private static <T> List<T> merge( List<T> tgt, List<T> src, KeyComputer<T> computer, BinaryOperator<T> remapping )
-    {
-        if ( src.isEmpty() )
-        {
-            return tgt;
-        }
-
-        MergingList<T> list;
-        if ( tgt instanceof MergingList )
-        {
-            list = (MergingList<T>) tgt;
-        }
-        else
-        {
-            list = new MergingList<>( computer, src.size() + tgt.size() );
-            list.mergeAll( tgt, ( t, s ) -> s );
-        }
-
-        list.mergeAll( src, remapping );
-        return list;
-    }
-
-    /**
-     * Merging list
-     * @param <V>
-     */
-    private static class MergingList<V> extends AbstractList<V> implements java.io.Serializable
-    {
-
-        private final KeyComputer<V> keyComputer;
-        private Map<Object, V> map;
-        private List<V> list;
-
-        MergingList( KeyComputer<V> keyComputer, int initialCapacity )
-        {
-            this.map = new LinkedHashMap<>( initialCapacity );
-            this.keyComputer = keyComputer;
-        }
-
-        Object writeReplace() throws ObjectStreamException
-        {
-            return new ArrayList<>( this );
-        }
-
-        @Override
-        public Iterator<V> iterator()
-        {
-            if ( map != null )
-            {
-                return map.values().iterator();
-            }
-            else
-            {
-                return list.iterator();
-            }
-        }
-
-        void mergeAll( Collection<V> vs, BinaryOperator<V> remapping )
-        {
-            if ( map == null )
-            {
-                map = list.stream().collect( Collectors.toMap( keyComputer,
-                                                               Function.identity(),
-                                                               null,
-                                                               LinkedHashMap::new ) );
-
-                list = null;
-            }
-
-            if ( vs instanceof MergingList && ( (MergingList<V>) vs ).map != null )
-            {
-                for ( Map.Entry<Object, V> e : ( (MergingList<V>) vs ).map.entrySet() )
-                {
-                    Object key = e.getKey();
-                    V v = e.getValue();
-                    map.merge( key, v, remapping );
-                }
-            }
-            else
-            {
-                for ( V v : vs )
-                {
-                    Object key = keyComputer.apply( v );
-
-                    map.merge( key, v, remapping );
-                }
-            }
-        }
-
-        @Override
-        public boolean contains( Object o )
-        {
-            if ( map != null )
-            {
-                return map.containsValue( o );
-            }
-            else
-            {
-                return list.contains( o );
-            }
-        }
-
-        private List<V> asList()
-        {
-            if ( list == null )
-            {
-                list = new ArrayList<>( map.values() );
-                map = null;
-            }
-            return list;
-        }
-
-        @Override
-        public void add( int index, V element )
-        {
-            asList().add( index, element );
-        }
-
-        @Override
-        public V remove( int index )
-        {
-            return asList().remove( index );
-        }
-
-        @Override
-        public V get( int index )
-        {
-            return asList().get( index );
-        }
-
-        @Override
-        public int size()
-        {
-            if ( map != null )
-            {
-                return map.size();
-            }
-            else
-            {
-                return list.size();
-            }
-        }
-    }
-}
diff --git a/maven-model/src/main/java/org/apache/maven/model/merge/package-info.java b/maven-model/src/main/java/org/apache/maven/model/merge/package-info.java
index eaa2d17..d7d9113 100644
--- a/maven-model/src/main/java/org/apache/maven/model/merge/package-info.java
+++ b/maven-model/src/main/java/org/apache/maven/model/merge/package-info.java
@@ -3,22 +3,3 @@
  * POM merger.
  */
 package org.apache.maven.model.merge;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
diff --git a/maven-model/src/main/java/org/apache/maven/model/package-info.java b/maven-model/src/main/java/org/apache/maven/model/package-info.java
deleted file mode 100644
index 88d3fa0..0000000
--- a/maven-model/src/main/java/org/apache/maven/model/package-info.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// CHECKSTYLE_OFF: RegexpHeader
-/**
- * Maven POM (Project Object Model) classes, generated from <code>maven.mdo</code> model.
- * The root class is {@link org.apache.maven.model.Model}.
- */
-package org.apache.maven.model;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
\ No newline at end of file
diff --git a/maven-model/src/main/mdo/maven.mdo b/maven-model/src/main/mdo/maven.mdo
deleted file mode 100644
index b669128..0000000
--- a/maven-model/src/main/mdo/maven.mdo
+++ /dev/null
@@ -1,3162 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-
-<!--
-  | Improvements:
-  |
-  | o add specification element to a field, this would be more a technical description of
-  |   what is allowed in the field.
-  |
-  | o validators: there could be several levels of validation. Simple type validation could
-  |   be done with a regex, but we need inter-field validation and rules which could be
-  |   dealt with by something like drools.
-  |
-  | o i18n: would be good to be able to have names/descriptions/specifications
-  |   in as many languages as possible. (see MNG-3626)
-  |
-  | o annotation mechanism so that changes to the model can be accurately tracked.
-  |
-  | o need to clean up all the descriptions, matching anything to the current project-descriptor.xml file and
-  |   improving on that
-  |
-  | o use enums where appropriate (eg dependency scope)
-  |
-  | o a number of elements have a groupId/artifactId and sometimes version. It would be good to have them all extend one
-  |   definition of these types
-  |
--->
-<model xmlns="http://codehaus-plexus.github.io/MODELLO/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/2.0.0 https://codehaus-plexus.github.io/modello/xsd/modello-2.0.0.xsd"
-  xml.namespace="http://maven.apache.org/POM/${version}"
-  xml.schemaLocation="https://maven.apache.org/xsd/maven-${version}.xsd">
-  <id>maven</id>
-  <name>Maven</name>
-  <description>
-    <![CDATA[
-    <p>This is a reference for the Maven project descriptor used in Maven.</p>
-    <p>An XSD is available at:</p>
-    <ul>
-      <li><a href="https://maven.apache.org/xsd/maven-v3_0_0.xsd">https://maven.apache.org/xsd/maven-v3_0_0.xsd</a> for Maven 1.1.</li>
-      <li><a href="https://maven.apache.org/xsd/maven-4.0.0.xsd">https://maven.apache.org/xsd/maven-4.0.0.xsd</a> for Maven 2.0.</li>
-    </ul>
-    ]]>
-  </description>
-  <defaults>
-    <default>
-      <key>package</key>
-      <value>org.apache.maven.model</value>
-    </default>
-  </defaults>
-  <classes>
-    <class rootElement="true" xml.tagName="project" java.clone.hook="cloneHook">
-      <name>Model</name>
-      <superClass>ModelBase</superClass>
-      <description>
-        <![CDATA[
-        The <code>&lt;project&gt;</code> element is the root of the descriptor.
-        The following table lists all of the possible child elements.
-        ]]>
-      </description>
-      <version>3.0.0+</version>
-      <fields>
-
-        <!-- ====================================================================== -->
-        <!-- Model Version                                                          -->
-        <!-- ====================================================================== -->
-
-        <field>
-          <name>modelVersion</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <description>Declares to which version of project descriptor this POM conforms.</description>
-          <type>String</type>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- Parent Model                                                           -->
-        <!-- ====================================================================== -->
-
-        <field xdoc.separator="blank">
-          <name>parent</name>
-          <version>4.0.0+</version>
-          <description>The location of the parent project, if one exists. Values from the parent
-            project will be the default for this project if they are left unspecified. The location
-            is given as a group ID, artifact ID and version.</description>
-          <association>
-            <type>Parent</type>
-          </association>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- groupId/artifactId/Version/Packaging                                   -->
-        <!-- ====================================================================== -->
-
-        <field xdoc.separator="blank">
-          <name>groupId</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description>
-            <![CDATA[
-            A universally unique identifier for a project. It is normal to
-            use a fully-qualified package name to distinguish it from other
-            projects with a similar name (eg. <code>org.apache.maven</code>).
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description>The identifier for this artifact that is unique within the group given by the
-            group ID. An artifact is something that is either produced or used by a project.
-            Examples of artifacts produced by Maven for a project include: JARs, source and binary
-            distributions, and WARs.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>version</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <description>The current version of the artifact produced by this project.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>packaging</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The type of artifact this project produces, for example <code>jar</code>
-              <code>war</code>
-              <code>ear</code>
-              <code>pom</code>.
-            Plugins can create their own packaging, and
-            therefore their own packaging types,
-            so this list does not contain all possible types.
-            ]]>
-          </description>
-          <type>String</type>
-          <defaultValue>jar</defaultValue>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- Elements which describe a project                                      -->
-        <!-- ====================================================================== -->
-
-        <field xdoc.separator="blank">
-          <name>name</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description>The full name of the project.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>description</name>
-          <version>3.0.0+</version>
-          <description>A detailed description of the project, used by Maven whenever it needs to
-            describe the project, such as on the web site. While this element can be specified as
-            CDATA to enable the use of HTML tags within the description, it is discouraged to allow
-            plain text representation. If you need to modify the index page of the generated web
-            site, you are able to specify your own instead of adjusting this text.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The URL to the project's homepage.
-            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
-            project's <code>child.project.url.inherit.append.path="false"</code>
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field xml.attribute="true" xml.tagName="child.project.url.inherit.append.path">
-          <name>childProjectUrlInheritAppendPath</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            When children inherit from project's url, append path or not? Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>
-            <br><b>Default value is</b>: <code>true</code>
-            <br><b>Since</b>: Maven 3.6.1
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>inceptionYear</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description>The year of the project's inception, specified with 4 digits. This value is
-            used when generating copyright notices as well as being informational.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>organization</name>
-          <version>3.0.0+</version>
-          <description>This element describes various attributes of the organization to which the
-            project belongs. These attributes are utilized when documentation is created (for
-            copyright notices and links).</description>
-          <alias>organisation</alias>
-          <association>
-            <type>Organization</type>
-          </association>
-        </field>
-        <field>
-          <name>licenses</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            This element describes all of the licenses for this project.
-            Each license is described by a <code>license</code> element, which
-            is then described by additional elements.
-            Projects should only list the license(s) that applies to the project
-            and not the licenses that apply to dependencies.
-            If multiple licenses are listed, it is assumed that the user can select
-            any of them, not that they must accept all.
-            ]]>
-          </description>
-          <association>
-            <type>License</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>developers</name>
-          <version>3.0.0+</version>
-          <description>Describes the committers of a project.</description>
-          <association>
-            <type>Developer</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>contributors</name>
-          <version>3.0.0+</version>
-          <description>Describes the contributors to a project that are not yet committers.</description>
-          <association>
-            <type>Contributor</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>mailingLists</name>
-          <version>3.0.0+</version>
-          <description>Contains information about a project's mailing lists.</description>
-          <association>
-            <type>MailingList</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- Build prerequisites                                                    -->
-        <!-- ====================================================================== -->
-
-        <field xdoc.separator="blank">
-          <name>prerequisites</name>
-          <version>4.0.0+</version>
-          <description>Describes the prerequisites in the build environment for this project.</description>
-          <association>
-            <type>Prerequisites</type>
-          </association>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- SCM                                                                    -->
-        <!-- ====================================================================== -->
-
-        <field xdoc.separator="blank" xml.insertParentFieldsUpTo="modules">
-          <name>scm</name>
-          <version>4.0.0+</version>
-          <description>Specification for the SCM used by the project, such as CVS, Subversion, etc.</description>
-          <association>
-            <type>Scm</type>
-          </association>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- Issue Tracking                                                         -->
-        <!-- ====================================================================== -->
-
-        <field>
-          <name>issueManagement</name>
-          <version>4.0.0+</version>
-          <description>The project's issue management system information.</description>
-          <association>
-            <type>IssueManagement</type>
-          </association>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- CI Management                                                          -->
-        <!-- ====================================================================== -->
-
-        <field>
-          <name>ciManagement</name>
-          <version>4.0.0+</version>
-          <description>The project's continuous integration information.</description>
-          <association>
-            <type>CiManagement</type>
-          </association>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- Build                                                                  -->
-        <!-- ====================================================================== -->
-
-        <field xdoc.separator="blank" xml.insertParentFieldsUpTo="pluginRepositories">
-          <name>build</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description>Information required to build the project.</description>
-          <association>
-            <type>Build</type>
-          </association>
-        </field>
-
-        <!-- ====================================================================== -->
-        <!-- Profiles                                                               -->
-        <!-- ====================================================================== -->
-
-        <field xdoc.separator="blank" xml.insertParentFieldsUpTo="reporting">
-          <name>profiles</name>
-          <version>4.0.0+</version>
-          <description>A listing of project-local build profiles which will modify the build process
-            when activated.</description>
-          <association>
-            <type>Profile</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    private void cloneHook( Model copy )
-    {
-        copy.pomFile = pomFile;
-    }
-
-    /**
-     * The POM from which this model originated. This is transient runtime state and therefore not managed by Modello.
-     */
-    private java.io.File pomFile;
-
-    /**
-     * Gets the POM file for the corresponding project (if any).
-     *
-     * @return The POM file from which this model originated or {@code null} if this model does not belong to a local
-     *         project (e.g. describes the metadata of some artifact from the repository).
-     */
-    public java.io.File getPomFile()
-    {
-        return pomFile;
-    }
-
-    public void setPomFile( java.io.File pomFile )
-    {
-        this.pomFile = ( pomFile != null ) ? pomFile.getAbsoluteFile() : null;
-    }
-
-    /**
-     * Gets the base directory for the corresponding project (if any).
-     *
-     * @return The base directory for the corresponding project or {@code null} if this model does not belong to a local
-     *         project (e.g. describes the metadata of some artifact from the repository).
-     */
-    public java.io.File getProjectDirectory()
-    {
-        return ( pomFile != null ) ? pomFile.getParentFile() : null;
-    }
-
-    /**
-     * @return the model id as <code>groupId:artifactId:packaging:version</code>
-     */
-    public String getId()
-    {
-        StringBuilder id = new StringBuilder( 64 );
-
-        id.append( ( getGroupId() == null ) ? "[inherited]" : getGroupId() );
-        id.append( ":" );
-        id.append( getArtifactId() );
-        id.append( ":" );
-        id.append( getPackaging() );
-        id.append( ":" );
-        id.append( ( getVersion() == null ) ? "[inherited]" : getVersion() );
-
-        return id.toString();
-    }
-
-    @Override
-    public String toString()
-    {
-        return getId();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-
-    public boolean isChildProjectUrlInheritAppendPath()
-    {
-        return ( childProjectUrlInheritAppendPath != null ) ? Boolean.parseBoolean( childProjectUrlInheritAppendPath ) : true;
-    }
-
-    public void setChildProjectUrlInheritAppendPath( boolean childProjectUrlInheritAppendPath )
-    {
-        this.childProjectUrlInheritAppendPath = String.valueOf( childProjectUrlInheritAppendPath );
-    }
-
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class java.clone="deep">
-      <name>ModelBase</name>
-      <version>3.0.0+</version>
-      <description>
-        <![CDATA[
-        Base class for the <code>Model</code> and the <code>Profile</code> objects.
-        ]]>
-      </description>
-      <fields>
-        <field xdoc.separator="blank">
-          <name>modules</name>
-          <version>4.0.0+</version>
-          <description>The modules (sometimes called subprojects) to build as a part of this
-            project. Each module listed is a relative path to the directory containing the module.
-            To be consistent with the way default urls are calculated from parent, it is recommended
-            to have module names match artifact ids.</description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>distributionManagement</name>
-          <version>4.0.0+</version>
-          <description>Distribution information for a project that enables deployment of the site
-            and artifacts to remote web servers and repositories respectively.</description>
-          <association>
-            <type>DistributionManagement</type>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>properties</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Properties that can be used throughout the POM as a substitution, and
-            are used as filters in resources if enabled.
-            The format is <code>&lt;name&gt;value&lt;/name&gt;</code>.
-            ]]>
-          </description>
-          <type>Properties</type>
-          <association xml.mapStyle="inline">
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>dependencyManagement</name>
-          <version>4.0.0+</version>
-          <required>false</required>
-          <description>Default dependency information for projects that inherit from this one. The
-            dependencies in this section are not immediately resolved. Instead, when a POM derived
-            from this one declares a dependency described by a matching groupId and artifactId, the
-            version and other values from this section are used for that dependency if they were not
-            already specified.</description>
-          <association>
-            <type>DependencyManagement</type>
-          </association>
-        </field>
-        <field>
-          <name>dependencies</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            This element describes all of the dependencies associated with a
-            project.
-            These dependencies are used to construct a classpath for your
-            project during the build process. They are automatically downloaded from the
-            repositories defined in this project.
-            See <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">the
-            dependency mechanism</a> for more information.
-            ]]>
-          </description>
-          <association>
-            <type>Dependency</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>repositories</name>
-          <version>4.0.0+</version>
-          <description>The lists of the remote repositories for discovering dependencies and
-            extensions.</description>
-          <association>
-            <type>Repository</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>pluginRepositories</name>
-          <version>4.0.0+</version>
-          <description>The lists of the remote repositories for discovering plugins for builds and
-            reports.</description>
-          <association>
-            <type>Repository</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>reports</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            <b>Deprecated</b>. Now ignored by Maven.
-            ]]>
-          </description>
-          <type>DOM</type>
-        </field>
-        <field>
-          <name>reporting</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            This element includes the specification of report plugins to use
-            to generate the reports on the Maven-generated site.
-            These reports will be run when a user executes <code>mvn site</code>.
-            All of the reports will be included in the navigation bar for browsing.
-            ]]>
-          </description>
-          <association>
-            <type>Reporting</type>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>PluginContainer</name>
-      <version>3.0.0+</version>
-      <description>Contains the plugins informations for the project.</description>
-      <fields>
-        <field>
-          <name>plugins</name>
-          <version>4.0.0+</version>
-          <description>The list of plugins to use.</description>
-          <association>
-            <type>Plugin</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    java.util.Map<String, Plugin> pluginMap;
-
-    /**
-     * Reset the <code>pluginsMap</code> field to <code>null</code>
-     */
-    public synchronized void flushPluginMap()
-    {
-        this.pluginMap = null;
-    }
-
-    /**
-     * @return a Map of plugins field with <code>Plugins#getKey()</code> as key
-     * @see org.apache.maven.model.Plugin#getKey()
-     */
-    public synchronized java.util.Map<String, Plugin> getPluginsAsMap()
-    {
-        if ( pluginMap == null )
-        {
-            pluginMap = new java.util.LinkedHashMap<String, Plugin>();
-            if ( plugins != null )
-            {
-                for ( java.util.Iterator<Plugin> it = plugins.iterator(); it.hasNext(); )
-                {
-                    Plugin plugin = (Plugin) it.next();
-                    pluginMap.put( plugin.getKey(), plugin );
-                }
-            }
-        }
-
-        return pluginMap;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class>
-      <name>PluginConfiguration</name>
-      <version>3.0.0+</version>
-      <superClass>PluginContainer</superClass>
-      <description>Contains the plugins management informations for the project.</description>
-      <fields>
-        <!-- [ jdcasey:06-Mar-2005 ] Added to handle version management, etc. for
-          | plugins to be used in sub-projects. -->
-        <field>
-          <name>pluginManagement</name>
-          <version>4.0.0+</version>
-          <required>false</required>
-          <description>Default plugin information to be made available for reference by projects
-            derived from this one. This plugin configuration will not be resolved or bound to the
-            lifecycle unless referenced. Any local configuration for a given plugin will override
-            the plugin's entire definition here.</description>
-          <association>
-            <type>PluginManagement</type>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class xdoc.anchorName="profile_build">
-      <name>BuildBase</name>
-      <version>3.0.0+</version>
-      <superClass>PluginConfiguration</superClass>
-      <description>Build configuration in a profile.</description>
-      <fields>
-        <field>
-          <name>defaultGoal</name>
-          <version>3.0.0+</version>
-          <description>The default goal (or phase in Maven 2) to execute when none is specified for
-            the project. Note that in case of a multi-module build, only the default goal of the top-level
-            project is relevant, i.e. the default goals of child modules are ignored. Since Maven 3,
-            multiple goals/phases can be separated by whitespace.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>resources</name>
-          <version>3.0.0+</version>
-          <description><![CDATA[
-            This element describes all of the classpath resources such as properties
-            files associated with a project. These resources are often included in the final
-            package.
-            The default value is <code>src/main/resources</code>.]]>
-          </description>
-          <association>
-            <type>Resource</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>testResources</name>
-          <version>4.0.0+</version>
-          <description><![CDATA[
-            This element describes all of the classpath resources such as properties
-            files associated with a project's unit tests.
-            The default value is <code>src/test/resources</code>.]]>
-          </description>
-          <association>
-            <type>Resource</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>directory</name>
-          <version>4.0.0+</version>
-          <description><![CDATA[
-            The directory where all files generated by the build are placed.
-            The default value is <code>target</code>.]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>finalName</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The filename (excluding the extension, and with no path information) that
-            the produced artifact will be called.
-            The default value is <code>${artifactId}-${version}</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>filters</name>
-          <version>4.0.0+</version>
-          <description>The list of filter properties files that are used when filtering is enabled.</description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class>
-      <name>Build</name>
-      <version>3.0.0+</version>
-      <superClass>BuildBase</superClass>
-      <description>
-        <![CDATA[
-        The <code>&lt;build&gt;</code> element contains informations required to build the project.
-        Default values are defined in Super POM.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>sourceDirectory</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description><![CDATA[
-            This element specifies a directory containing the source of the project. The
-            generated build system will compile the sources from this directory when the project is
-            built. The path given is relative to the project descriptor.
-            The default value is <code>src/main/java</code>.]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>scriptSourceDirectory</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <description><![CDATA[
-            This element specifies a directory containing the script sources of the
-            project. This directory is meant to be different from the sourceDirectory, in that its
-            contents will be copied to the output directory in most cases (since scripts are
-            interpreted rather than compiled).
-            The default value is <code>src/main/scripts</code>.]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>testSourceDirectory</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <description><![CDATA[
-            This element specifies a directory containing the unit test source of the
-            project. The generated build system will compile these directories when the project is
-            being tested. The path given is relative to the project descriptor.
-            The default value is <code>src/test/java</code>.]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>outputDirectory</name>
-          <version>4.0.0+</version>
-          <description><![CDATA[
-            The directory where compiled application classes are placed.
-            The default value is <code>target/classes</code>.]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>testOutputDirectory</name>
-          <version>4.0.0+</version>
-          <description><![CDATA[
-            The directory where compiled test classes are placed.
-            The default value is <code>target/test-classes</code>.]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>extensions</name>
-          <version>4.0.0+</version>
-          <description>A set of build extensions to use from this project.</description>
-          <association>
-            <type>Extension</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>CiManagement</name>
-      <version>4.0.0+</version>
-      <description>
-        <![CDATA[
-        The <code>&lt;CiManagement&gt;</code> element contains informations required to the
-        continuous integration system of the project.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>system</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The name of the continuous integration system, e.g. <code>continuum</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>4.0.0+</version>
-          <description>URL for the continuous integration system used by the project if it has a web
-            interface.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>notifiers</name>
-          <version>4.0.0+</version>
-          <description>Configuration for notifying developers/users when a build is unsuccessful,
-            including user information and notification mode.</description>
-          <association>
-            <multiplicity>*</multiplicity>
-            <type>Notifier</type>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>Notifier</name>
-      <description>Configures one method for notifying users/developers when a build breaks.</description>
-      <version>4.0.0+</version>
-      <fields>
-        <field>
-          <name>type</name>
-          <version>4.0.0+</version>
-          <defaultValue>mail</defaultValue>
-          <type>String</type>
-          <description>The mechanism used to deliver notifications.</description>
-        </field>
-        <field>
-          <name>sendOnError</name>
-          <version>4.0.0+</version>
-          <defaultValue>true</defaultValue>
-          <type>boolean</type>
-          <description>Whether to send notifications on error.</description>
-        </field>
-        <field>
-          <name>sendOnFailure</name>
-          <version>4.0.0+</version>
-          <defaultValue>true</defaultValue>
-          <type>boolean</type>
-          <description>Whether to send notifications on failure.</description>
-        </field>
-        <field>
-          <name>sendOnSuccess</name>
-          <version>4.0.0+</version>
-          <defaultValue>true</defaultValue>
-          <type>boolean</type>
-          <description>Whether to send notifications on success.</description>
-        </field>
-        <field>
-          <name>sendOnWarning</name>
-          <version>4.0.0+</version>
-          <defaultValue>true</defaultValue>
-          <type>boolean</type>
-          <description>Whether to send notifications on warning.</description>
-        </field>
-        <!-- TODO: Remove it after continuum alpha-3 release -->
-        <field>
-          <name>address</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            <b>Deprecated</b>. Where to send the notification to - eg email address.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>configuration</name>
-          <description>Extended configuration specific to this notifier goes here.</description>
-          <type>Properties</type>
-          <association xml.mapStyle="inline">
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>Contributor</name>
-      <description>Description of a person who has contributed to the project, but who does not have
-        commit privileges. Usually, these contributions come in the form of patches submitted.</description>
-      <version>3.0.0+</version>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>3.0.0+</version>
-          <description>The full name of the contributor.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>email</name>
-          <version>3.0.0+</version>
-          <description>The email address of the contributor.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>3.0.0+</version>
-          <description>The URL for the homepage of the contributor.</description>
-          <type>String</type>
-        </field>
-        <!-- TODO: should this just be a single Organization element -->
-        <field>
-          <name>organization</name>
-          <alias>organisation</alias>
-          <version>3.0.0+</version>
-          <description>The organization to which the contributor belongs.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>organizationUrl</name>
-          <alias>organisationUrl</alias>
-          <version>3.0.0+</version>
-          <description>The URL of the organization.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>roles</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The roles the contributor plays in the project. Each role is described by a
-            <code>role</code> element, the body of which is a role name. This can also be used to
-            describe the contribution.
-            ]]>
-          </description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>timezone</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-              The timezone the contributor is in. Typically, this is a number in the range
-              <a href="http://en.wikipedia.org/wiki/UTC%E2%88%9212:00">-12</a> to <a href="http://en.wikipedia.org/wiki/UTC%2B14:00">+14</a>
-              or a valid time zone id like "America/Montreal" (UTC-05:00) or "Europe/Paris" (UTC+01:00).
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>properties</name>
-          <version>3.0.0+</version>
-          <description>Properties about the contributor, such as an instant messenger handle.</description>
-          <type>Properties</type>
-          <association xml.mapStyle="inline">
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>Dependency</name>
-      <version>3.0.0+</version>
-      <description>
-        <![CDATA[
-        The <code>&lt;dependency&gt;</code> element contains information about a dependency
-        of the project.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description>
-            <![CDATA[
-            The project group that produced the dependency, e.g.
-            <code>org.apache.maven</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>3.0.0+</version>
-          <required>true</required>
-          <description>
-            <![CDATA[
-            The unique id for an artifact produced by the project group, e.g.
-            <code>maven-artifact</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>version</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The version of the dependency, e.g. <code>3.2.1</code>. In Maven 2, this can also be
-            specified as a range of versions.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>type</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The type of dependency, that will be mapped to a file extension, an optional classifier, and a few other attributes.
-            Some examples are <code>jar</code>, <code>war</code>, <code>ejb-client</code>
-            and <code>test-jar</code>: see <a href="../maven-core/artifact-handlers.html">default
-            artifact handlers</a> for a list. New types can be defined by extensions, so this is not a complete list.
-            ]]>
-          </description>
-          <type>String</type>
-          <defaultValue>jar</defaultValue>
-        </field>
-        <field>
-          <name>classifier</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The classifier of the dependency. It is appended to
-            the filename after the version. This allows:
-            <ul>
-            <li>referring to attached artifact, for example <code>sources</code> and <code>javadoc</code>:
-            see <a href="../maven-core/artifact-handlers.html">default artifact handlers</a> for a list,</li>
-            <li>distinguishing two artifacts
-            that belong to the same POM but were built differently.
-            For example, <code>jdk14</code> and <code>jdk15</code>.</li>
-            </ul>
-            ]]>
-          </description>
-          <type>String</type>
-          <required>false</required>
-        </field>
-        <field>
-          <name>scope</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The scope of the dependency - <code>compile</code>, <code>runtime</code>,
-            <code>test</code>, <code>system</code>, and <code>provided</code>. Used to
-            calculate the various classpaths used for compilation, testing, and so on.
-            It also assists in determining which artifacts to include in a distribution of
-            this project. For more information, see
-            <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">the
-            dependency mechanism</a>. The default scope is <code>compile</code>.
-            ]]>
-          </description>
-          <type>String</type>
-          <!-- This default has to be enforced at the maven-artifact layer, to allow
-            | injection of defaults from <dependencyManagement/>.
-            | TODO: how can we document it?
-            |-->
-          <!-- defaultValue>compile</defaultValue -->
-        </field>
-        <field>
-          <name>systemPath</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            FOR SYSTEM SCOPE ONLY. Note that use of this property is <b>discouraged</b>
-            and may be replaced in later versions. This specifies the path on the filesystem
-            for this dependency.
-            Requires an absolute path for the value, not relative.
-            Use a property that gives the machine specific absolute path,
-            e.g. <code>${java.home}</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>exclusions</name>
-          <version>4.0.0+</version>
-          <description>Lists a set of artifacts that should be excluded from this dependency's
-            artifact list when it comes to calculating transitive dependencies.</description>
-          <association>
-            <type>Exclusion</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>optional</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Indicates the dependency is optional for use of this library. While the
-            version of the dependency will be taken into account for dependency calculation if the
-            library is used elsewhere, it will not be passed on transitively. Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>. Default value is <code>false</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    public boolean isOptional()
-    {
-        return ( optional != null ) ? Boolean.parseBoolean( optional ) : false;
-    }
-
-    public void setOptional( boolean optional )
-    {
-        this.optional = String.valueOf( optional );
-    }
-
-    /**
-     * @see java.lang.Object#toString()
-     */
-    public String toString()
-    {
-        return "Dependency {groupId=" + groupId + ", artifactId=" + artifactId + ", version=" + version + ", type=" + type + "}";
-    }
-            ]]>
-          </code>
-        </codeSegment>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    private String managementKey;
-
-    /**
-     * @return the management key as <code>groupId:artifactId:type</code>
-     */
-    public String getManagementKey()
-    {
-        if ( managementKey == null )
-        {
-            managementKey = groupId + ":" + artifactId + ":" + type + ( classifier != null ? ":" + classifier : "" );
-        }
-        return managementKey;
-    }
-
-    /**
-     * Clears the management key in case one field has been modified.
-     */
-    public void clearManagementKey()
-    {
-        managementKey = null;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class>
-      <superClass>Contributor</superClass>
-      <name>Developer</name>
-      <description>Information about one of the committers on this project.</description>
-      <version>3.0.0+</version>
-      <fields>
-        <field>
-          <name>id</name>
-          <version>3.0.0+</version>
-          <description>The unique ID of the developer in the SCM.</description>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>Exclusion</name>
-      <version>4.0.0+</version>
-      <description>
-        <![CDATA[
-        The <code>&lt;exclusion&gt;</code> element contains informations required to exclude
-        an artifact to the project.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <version>4.0.0+</version>
-          <description>The group ID of the project to exclude.</description>
-          <type>String</type>
-          <required>true</required>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>4.0.0+</version>
-          <description>The artifact ID of the project to exclude.</description>
-          <type>String</type>
-          <required>true</required>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>IssueManagement</name>
-      <description>Information about the issue tracking (or bug tracking) system used to manage this
-        project.</description>
-      <version>4.0.0+</version>
-      <fields>
-        <field>
-          <name>system</name>
-          <version>4.0.0+</version>
-          <description>The name of the issue management system, e.g. Bugzilla</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>4.0.0+</version>
-          <description>URL for the issue management system used by the project.</description>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>DistributionManagement</name>
-      <version>4.0.0+</version>
-      <description>This elements describes all that pertains to distribution for a project. It is
-        primarily used for deployment of artifacts and the site produced by the build.</description>
-      <fields>
-        <field>
-          <name>repository</name>
-          <version>4.0.0+</version>
-          <description>Information needed to deploy the artifacts generated by the project to a
-            remote repository.</description>
-          <association>
-            <type>DeploymentRepository</type>
-          </association>
-        </field>
-        <field>
-          <name>snapshotRepository</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Where to deploy snapshots of artifacts to. If not given, it defaults to the
-            <code>repository</code> element.
-            ]]>
-          </description>
-          <association>
-            <type>DeploymentRepository</type>
-          </association>
-        </field>
-        <field>
-          <name>site</name>
-          <description>Information needed for deploying the web site of the project.</description>
-          <version>4.0.0+</version>
-          <association>
-            <type>Site</type>
-          </association>
-        </field>
-        <field>
-          <name>downloadUrl</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The URL of the project's download page. If not given users will be
-            referred to the homepage given by <code>url</code>.
-            This is given to assist in locating artifacts that are not in the repository due to
-            licensing restrictions.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>relocation</name>
-          <version>4.0.0+</version>
-          <description>Relocation information of the artifact if it has been moved to a new group ID
-            and/or artifact ID.</description>
-          <association>
-            <type>Relocation</type>
-          </association>
-        </field>
-        <field>
-          <name>status</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Gives the status of this artifact in the remote repository.
-            This must not be set in your local project, as it is updated by
-            tools placing it in the repository. Valid values are: <code>none</code> (default),
-            <code>converted</code> (repository manager converted this from an Maven 1 POM),
-            <code>partner</code>
-            (directly synced from a partner Maven 2 repository), <code>deployed</code> (was deployed from a Maven 2
-            instance), <code>verified</code> (has been hand verified as correct and final).
-            ]]>
-          </description>
-          <required>false</required>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>License</name>
-      <description>Describes the licenses for this project. This is used to generate the license
-        page of the project's web site, as well as being taken into consideration in other reporting
-        and validation. The licenses listed for the project are that of the project itself, and not
-        of dependencies.</description>
-      <version>3.0.0+</version>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>3.0.0+</version>
-          <description>The full legal name of the license.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>3.0.0+</version>
-          <description>The official url for the license text.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>distribution</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The primary method by which this project may be distributed.
-            <dl>
-              <dt>repo</dt>
-              <dd>may be downloaded from the Maven repository</dd>
-              <dt>manual</dt>
-              <dd>user must manually download and install the dependency.</dd>
-            </dl>
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>comments</name>
-          <description>Addendum information pertaining to this license.</description>
-          <version>3.0.0+</version>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>MailingList</name>
-      <version>3.0.0+</version>
-      <description>This element describes all of the mailing lists associated with a project. The
-        auto-generated site references this information.</description>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The name of the mailing list.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>subscribe</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The email address or link that can be used to subscribe to
-            the mailing list.  If this is an email address, a
-            <code>mailto:</code> link will automatically be created
-            when the documentation is created.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>unsubscribe</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The email address or link that can be used to unsubscribe to
-            the mailing list.  If this is an email address, a
-            <code>mailto:</code> link will automatically be created
-            when the documentation is created.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>post</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            The email address or link that can be used to post to
-            the mailing list.  If this is an email address, a
-            <code>mailto:</code> link will automatically be created
-            when the documentation is created.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>archive</name>
-          <version>3.0.0+</version>
-          <description>The link to a URL where you can browse the mailing list archive.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>otherArchives</name>
-          <version>3.0.0+</version>
-          <description>The link to alternate URLs where you can browse the list archive.</description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <comment>We could probably have a specific element for a dev mailing list for things like CI,
-        and maybe even a specific element for the user and scm mailing lists. Then leave the more
-        lose structure for any other type of mailing list.</comment>
-    </class>
-    <class java.clone="deep">
-      <name>Organization</name>
-      <description>Specifies the organization that produces this project.</description>
-      <version>3.0.0+</version>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>3.0.0+</version>
-          <description>The full name of the organization.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>3.0.0+</version>
-          <description>The URL to the organization's home page.</description>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>PatternSet</name>
-      <version>3.0.0+</version>
-      <description>Definition of include or exclude patterns.</description>
-      <fields>
-        <field>
-          <name>includes</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            A list of patterns to include, e.g. <code>**&#47;*.xml</code>.
-            ]]>
-          </description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>excludes</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            A list of patterns to exclude, e.g. <code>**&#47;*.xml</code>
-            ]]>
-          </description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    /**
-     * @see java.lang.Object#toString()
-     */
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 128 );
-
-        sb.append("PatternSet [includes: {");
-        for (java.util.Iterator i = getIncludes().iterator(); i.hasNext(); )
-        {
-            String str = (String) i.next();
-            sb.append(str).append(", ");
-        }
-        if (sb.substring(sb.length() - 2).equals(", ")) sb.delete(sb.length() - 2, sb.length());
-
-        sb.append("}, excludes: {");
-        for (java.util.Iterator i = getExcludes().iterator(); i.hasNext(); )
-        {
-            String str = (String) i.next();
-            sb.append(str).append(", ");
-        }
-        if (sb.substring(sb.length() - 2).equals(", ")) sb.delete(sb.length() - 2, sb.length());
-
-        sb.append("}]");
-        return sb.toString();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class java.clone="deep">
-      <name>Parent</name>
-      <version>4.0.0+</version>
-      <description>
-        <![CDATA[
-        The <code>&lt;parent&gt;</code> element contains information required to locate the parent project from which
-        this project will inherit from.
-        <strong>Note:</strong> The children of this element are not interpolated and must be given as literal values.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <version>4.0.0+</version>
-          <description>The group id of the parent project to inherit from.</description>
-          <required>true</required>
-          <type>String</type>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>4.0.0+</version>
-          <description>The artifact id of the parent project to inherit from.</description>
-          <required>true</required>
-          <type>String</type>
-        </field>
-        <field>
-          <name>version</name>
-          <version>4.0.0+</version>
-          <description>The version of the parent project to inherit.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>relativePath</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The relative path of the parent <code>pom.xml</code> file within the check out.
-            If not specified, it defaults to <code>../pom.xml</code>.
-            Maven looks for the parent POM first in this location on
-            the filesystem, then the local repository, and lastly in the remote repo.
-            <code>relativePath</code> allows you to select a different location,
-            for example when your structure is flat, or deeper without an intermediate parent POM.
-            However, the group ID, artifact ID and version are still required,
-            and must match the file in the location given or it will revert to the repository for the POM.
-            This feature is only for enhancing the development in a local checkout of that project.
-            Set the value to an empty string in case you want to disable the feature and always resolve
-            the parent POM from the repositories.
-            ]]>
-          </description>
-          <type>String</type>
-          <defaultValue>../pom.xml</defaultValue>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    /**
-     * @return the id as <code>groupId:artifactId:version</code>
-     */
-    public String getId()
-    {
-        StringBuilder id = new StringBuilder( 64 );
-
-        id.append( getGroupId() );
-        id.append( ":" );
-        id.append( getArtifactId() );
-        id.append( ":" );
-        id.append( "pom" );
-        id.append( ":" );
-        id.append( getVersion() );
-
-        return id.toString();
-    }
-
-    @Override
-    public String toString()
-    {
-        return getId();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-
-    </class>
-    <class java.clone="deep">
-      <name>Scm</name>
-      <version>4.0.0+</version>
-      <description>
-        <![CDATA[
-        The <code>&lt;scm&gt;</code> element contains informations required to the SCM
-        (Source Control Management) of the project.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>connection</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The source control management system URL
-            that describes the repository and how to connect to the
-            repository. For more information, see the
-            <a href="https://maven.apache.org/scm/scm-url-format.html">URL format</a>
-            and <a href="https://maven.apache.org/scm/scms-overview.html">list of supported SCMs</a>.
-            This connection is read-only.
-            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
-            scm's <code>child.scm.connection.inherit.append.path="false"</code>
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>developerConnection</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Just like <code>connection</code>, but for developers, i.e. this scm connection
-            will not be read only.
-            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
-            scm's <code>child.scm.developerConnection.inherit.append.path="false"</code>
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>tag</name>
-          <version>4.0.0+</version>
-          <description>The tag of current code. By default, it's set to HEAD during development.</description>
-          <type>String</type>
-          <defaultValue>HEAD</defaultValue>
-        </field>
-        <field>
-          <name>url</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The URL to the project's browsable SCM repository, such as ViewVC or Fisheye.
-            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
-            scm's <code>child.scm.url.inherit.append.path="false"</code>
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field xml.attribute="true" xml.tagName="child.scm.connection.inherit.append.path">
-          <name>childScmConnectionInheritAppendPath</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            When children inherit from scm connection, append path or not? Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>
-            <br><b>Default value is</b>: <code>true</code>
-            <br><b>Since</b>: Maven 3.6.1
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field xml.attribute="true" xml.tagName="child.scm.developerConnection.inherit.append.path">
-          <name>childScmDeveloperConnectionInheritAppendPath</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            When children inherit from scm developer connection, append path or not? Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>
-            <br><b>Default value is</b>: <code>true</code>
-            <br><b>Since</b>: Maven 3.6.1
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field xml.attribute="true" xml.tagName="child.scm.url.inherit.append.path">
-          <name>childScmUrlInheritAppendPath</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            When children inherit from scm url, append path or not? Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>
-            <br><b>Default value is</b>: <code>true</code>
-            <br><b>Since</b>: Maven 3.6.1
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-
-    public boolean isChildScmConnectionInheritAppendPath()
-    {
-        return ( childScmConnectionInheritAppendPath != null ) ? Boolean.parseBoolean( childScmConnectionInheritAppendPath ) : true;
-    }
-
-    public void setChildScmConnectionInheritAppendPath( boolean childScmConnectionInheritAppendPath )
-    {
-        this.childScmConnectionInheritAppendPath = String.valueOf( childScmConnectionInheritAppendPath );
-    }
-
-    public boolean isChildScmDeveloperConnectionInheritAppendPath()
-    {
-        return ( childScmDeveloperConnectionInheritAppendPath != null ) ? Boolean.parseBoolean( childScmDeveloperConnectionInheritAppendPath ) : true;
-    }
-
-    public void setChildScmDeveloperConnectionInheritAppendPath( boolean childScmDeveloperConnectionInheritAppendPath )
-    {
-        this.childScmDeveloperConnectionInheritAppendPath = String.valueOf( childScmDeveloperConnectionInheritAppendPath );
-    }
-
-    public boolean isChildScmUrlInheritAppendPath()
-    {
-        return ( childScmUrlInheritAppendPath != null ) ? Boolean.parseBoolean( childScmUrlInheritAppendPath ) : true;
-    }
-
-    public void setChildScmUrlInheritAppendPath( boolean childScmUrlInheritAppendPath )
-    {
-        this.childScmUrlInheritAppendPath = String.valueOf( childScmUrlInheritAppendPath );
-    }
-
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class>
-      <name>FileSet</name>
-      <version>3.0.0+</version>
-      <superClass>PatternSet</superClass>
-      <description>A PatternSet for files.</description>
-      <fields>
-        <field>
-          <name>directory</name>
-          <version>3.0.0+</version>
-          <description>Describe the directory where the resources are stored. The path is relative
-            to the POM.</description>
-          <type>String</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    /**
-     * @see java.lang.Object#toString()
-     */
-    public String toString()
-    {
-        return "FileSet {directory: " + getDirectory() + ", " + super.toString() + "}";
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class>
-      <name>Resource</name>
-      <description>This element describes all of the classpath resources associated with a project
-        or unit tests.</description>
-      <version>3.0.0+</version>
-      <superClass>FileSet</superClass>
-      <fields>
-        <field>
-          <name>targetPath</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            Describe the resource target path. The path is relative to the target/classes
-            directory (i.e. <code>${project.build.outputDirectory}</code>).
-            For example, if you want that resource to appear in a specific package
-            (<code>org.apache.maven.messages</code>), you must specify this
-            element with this value: <code>org/apache/maven/messages</code>.
-            This is not required if you simply put the resources in that directory
-            structure at the source, however.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>filtering</name>
-          <version>3.0.0+</version>
-          <description>
-            <![CDATA[
-            Whether resources are filtered to replace tokens with parameterised values or not.
-            The values are taken from the <code>properties</code> element and from the
-            properties in the files listed in the <code>filters</code> element. Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>. Default value is <code>false</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field xml.transient="true">
-          <name>mergeId</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            FOR INTERNAL USE ONLY. This is a unique identifier assigned to each
-            resource to allow Maven to merge changes to this resource that take
-            place during the execution of a plugin. This field must be managed
-            by the generated parser and formatter classes in order to allow it
-            to survive model interpolation.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    private static int mergeIdCounter = 0;
-
-    public void initMergeId()
-    {
-        if ( getMergeId() == null )
-        {
-            setMergeId( "resource-" + (mergeIdCounter++) );
-        }
-    }
-
-    public boolean isFiltering()
-    {
-        return ( filtering != null ) ? Boolean.parseBoolean( filtering ) : false;
-    }
-
-    public void setFiltering( boolean filtering )
-    {
-        this.filtering = String.valueOf( filtering );
-    }
-
-    /**
-     * @see java.lang.Object#toString()
-     */
-    public String toString()
-    {
-        return "Resource {targetPath: " + getTargetPath() + ", filtering: " + isFiltering() + ", " + super.toString() + "}";
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class java.clone="deep">
-      <name>RepositoryBase</name>
-      <version>4.0.0+</version>
-      <description>A repository contains the information needed for establishing connections with
-        remote repository.</description>
-      <fields>
-        <field>
-          <name>id</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <identifier>true</identifier>
-          <description>
-            <![CDATA[
-            A unique identifier for a repository. This is used to match the repository
-            to configuration in the <code>settings.xml</code> file, for example. Furthermore, the identifier is
-            used during POM inheritance and profile injection to detect repositories that should be merged.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>name</name>
-          <version>4.0.0+</version>
-          <description>Human readable name of the repository.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <description>
-            <![CDATA[
-            The url of the repository, in the form <code>protocol://hostname/path</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>layout</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The type of layout this repository uses for locating and storing artifacts -
-            can be <code>legacy</code> or <code>default</code>.
-            ]]>
-          </description>
-          <type>String</type>
-          <defaultValue>default</defaultValue>
-        </field>
-      </fields>
-    </class>
-
-    <class>
-      <name>Repository</name>
-      <superClass>RepositoryBase</superClass>
-      <version>4.0.0+</version>
-      <description>A repository contains the information needed for establishing connections with
-        remote repository.</description>
-      <fields>
-        <field>
-          <name>releases</name>
-          <version>4.0.0+</version>
-          <description>How to handle downloading of releases from this repository.</description>
-          <association>
-            <type>RepositoryPolicy</type>
-          </association>
-        </field>
-        <field>
-          <name>snapshots</name>
-          <version>4.0.0+</version>
-          <description>How to handle downloading of snapshots from this repository.</description>
-          <association>
-            <type>RepositoryPolicy</type>
-          </association>
-        </field>
-      </fields>
-    </class>
-
-    <class xdoc.anchorName="deployment_repository">
-      <name>DeploymentRepository</name>
-      <superClass>Repository</superClass>
-      <version>4.0.0+</version>
-      <description>Deployment repository contains the information needed for deploying to the remote
-        repository, which adds uniqueVersion property to usual repositories for download.</description>
-      <fields>
-        <field>
-          <name>uniqueVersion</name>
-          <description>Whether to assign snapshots a unique version comprised of the timestamp and
-            build number, or to use the same version each time</description>
-          <type>boolean</type>
-          <defaultValue>true</defaultValue>
-          <version>4.0.0+</version>
-        </field>
-      </fields>
-    </class>
-
-    <class java.clone="deep">
-      <name>RepositoryPolicy</name>
-      <version>4.0.0+</version>
-      <description>Download policy.</description>
-      <fields>
-        <field>
-          <name>enabled</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Whether to use this repository for downloading this type of artifact. Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>. Default value is <code>true</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>updatePolicy</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The frequency for downloading updates - can be
-            <code>always,</code>
-            <code>daily</code>
-            (default),
-            <code>interval:XXX</code>
-            (in minutes) or
-            <code>never</code>
-            (only if it doesn't exist locally).
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>checksumPolicy</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            What to do when verification of an artifact checksum fails. Valid values are
-            <code>ignore</code>,
-            <code>fail</code>
-            (default for Maven 4 and above) or
-            <code>warn</code>
-            (default for Maven 2 and 3)
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-
-    public boolean isEnabled()
-    {
-        return ( enabled != null ) ? Boolean.parseBoolean( enabled ) : true;
-    }
-
-    public void setEnabled( boolean enabled )
-    {
-        this.enabled = String.valueOf( enabled );
-    }
-
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-
-    <!--@todo find better solution for management of site deployments -->
-    <class java.clone="deep">
-      <name>Site</name>
-      <version>4.0.0+</version>
-      <description>Contains the information needed for deploying websites.</description>
-      <fields>
-        <field>
-          <name>id</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            A unique identifier for a deployment location. This is used to match the
-            site to configuration in the <code>settings.xml</code> file, for example.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>name</name>
-          <version>4.0.0+</version>
-          <description>Human readable name of the deployment location.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The url of the location where website is deployed, in the form <code>protocol://hostname/path</code>.
-            <br><b>Default value is</b>: parent value [+ path adjustment] + (artifactId or project.directory property), or just parent value if
-            site's <code>child.site.url.inherit.append.path="false"</code>
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field xml.attribute="true" xml.tagName="child.site.url.inherit.append.path">
-          <name>childSiteUrlInheritAppendPath</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            When children inherit from distribution management site url, append path or not? Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>
-            <br><b>Default value is</b>: <code>true</code>
-            <br><b>Since</b>: Maven 3.6.1
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-
-    public boolean isChildSiteUrlInheritAppendPath()
-    {
-        return ( childSiteUrlInheritAppendPath != null ) ? Boolean.parseBoolean( childSiteUrlInheritAppendPath ) : true;
-    }
-
-    public void setChildSiteUrlInheritAppendPath( boolean childSiteUrlInheritAppendPath )
-    {
-        this.childSiteUrlInheritAppendPath = String.valueOf( childSiteUrlInheritAppendPath );
-    }
-
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-
-    <class java.clone="deep">
-      <name>ConfigurationContainer</name>
-      <version>4.0.0+</version>
-      <description>Contains the configuration information of the container like Plugin.</description>
-      <fields>
-        <field>
-          <name>inherited</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Whether any configuration should be propagated to child POMs. Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>. Default value is <code>true</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <description>
-            <![CDATA[
-            <p>The configuration as DOM object.</p>
-            <p>By default, every element content is trimmed, but starting with Maven 3.1.0, you can add
-            <code>xml:space="preserve"</code> to elements you want to preserve whitespace.</p>
-            <p>You can control how child POMs inherit configuration from parent POMs by adding <code>combine.children</code>
-            or <code>combine.self</code> attributes to the children of the configuration element:</p>
-            <ul>
-            <li><code>combine.children</code>: available values are <code>merge</code> (default) and <code>append</code>,</li>
-            <li><code>combine.self</code>: available values are <code>merge</code> (default) and <code>override</code>.</li>
-            </ul>
-            <p>See <a href="https://maven.apache.org/pom.html#Plugins">POM Reference documentation</a> and
-            <a href="https://codehaus-plexus.github.io/plexus-utils/apidocs/org/codehaus/plexus/util/xml/Xpp3DomUtils.html">Xpp3DomUtils</a>
-            for more information.</p>
-            ]]>
-          </description>
-          <name>configuration</name>
-          <type>DOM</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    public boolean isInherited()
-    {
-        return ( inherited != null ) ? Boolean.parseBoolean( inherited ) : true;
-    }
-
-    public void setInherited( boolean inherited )
-    {
-        this.inherited = String.valueOf( inherited );
-    }
-
-    private boolean inheritanceApplied = true;
-
-    public void unsetInheritanceApplied()
-    {
-        this.inheritanceApplied = false;
-    }
-
-    public boolean isInheritanceApplied()
-    {
-        return inheritanceApplied;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class>
-      <name>Plugin</name>
-      <version>4.0.0+</version>
-      <superClass>ConfigurationContainer</superClass>
-      <description>
-        <![CDATA[
-        The <code>&lt;plugin&gt;</code> element contains informations required for a plugin.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <description>The group ID of the plugin in the repository.</description>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <defaultValue>org.apache.maven.plugins</defaultValue>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <description>The artifact ID of the plugin in the repository.</description>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <required>true</required>
-        </field>
-        <field>
-          <name>version</name>
-          <version>4.0.0+</version>
-          <description>The version (or valid range of versions) of the plugin to be used.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>extensions</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            Whether to load Maven extensions (such as packaging and type handlers) from
-            this plugin. For performance reasons, this should only be enabled when necessary. Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>. Default value is <code>false</code>.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>executions</name>
-          <version>4.0.0+</version>
-          <description>Multiple specifications of a set of goals to execute during the build
-            lifecycle, each having (possibly) a different configuration.</description>
-          <association>
-            <type>PluginExecution</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>dependencies</name>
-          <description>Additional dependencies that this project needs to introduce to the plugin's
-            classloader.</description>
-          <version>4.0.0+</version>
-          <association>
-            <type>Dependency</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>goals</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            <b>Deprecated</b>. Unused by Maven.
-            ]]>
-          </description>
-          <type>DOM</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    public boolean isExtensions()
-    {
-        return ( extensions != null ) ? Boolean.parseBoolean( extensions ) : false;
-    }
-
-    public void setExtensions( boolean extensions )
-    {
-        this.extensions = String.valueOf( extensions );
-    }
-
-    private java.util.Map<String, PluginExecution> executionMap = null;
-
-    /**
-     * Reset the <code>executionMap</code> field to <code>null</code>
-     */
-    public void flushExecutionMap()
-    {
-        this.executionMap = null;
-    }
-
-    /**
-     * @return a Map of executions field with <code>PluginExecution#getId()</code> as key
-     * @see org.apache.maven.model.PluginExecution#getId()
-     */
-    public java.util.Map<String, PluginExecution> getExecutionsAsMap()
-    {
-        if ( executionMap == null )
-        {
-            executionMap = new java.util.LinkedHashMap<String, PluginExecution>();
-            if ( getExecutions() != null )
-            {
-                for ( java.util.Iterator<PluginExecution> i = getExecutions().iterator(); i.hasNext(); )
-                {
-                    PluginExecution exec = (PluginExecution) i.next();
-
-                    if ( executionMap.containsKey( exec.getId() ) )
-                    {
-                        throw new IllegalStateException( "You cannot have two plugin executions with the same (or missing) <id/> elements.\nOffending execution\n\nId: \'" + exec.getId() + "\'\nPlugin:\'" + getKey() + "\'\n\n" );
-                    }
-
-                    executionMap.put( exec.getId(), exec );
-                }
-            }
-        }
-
-        return executionMap;
-    }
-
-    /**
-     * Gets the identifier of the plugin.
-     *
-     * @return The plugin id in the form {@code <groupId>:<artifactId>:<version>}, never {@code null}.
-     */
-    public String getId()
-    {
-        StringBuilder id = new StringBuilder( 128 );
-
-        id.append( ( getGroupId() == null ) ? "[unknown-group-id]" : getGroupId() );
-        id.append( ":" );
-        id.append( ( getArtifactId() == null ) ? "[unknown-artifact-id]" : getArtifactId() );
-        id.append( ":" );
-        id.append( ( getVersion() == null ) ? "[unknown-version]" : getVersion() );
-
-        return id.toString();
-    }
-
-    /**
-     * @return the key of the plugin, ie <code>groupId:artifactId</code>
-     */
-    public String getKey()
-    {
-        return constructKey( groupId, artifactId );
-    }
-
-    /**
-     * @param groupId The group ID of the plugin in the repository
-     * @param artifactId The artifact ID of the reporting plugin in the repository
-     * @return the key of the plugin, ie <code>groupId:artifactId</code>
-     */
-    public static String constructKey( String groupId, String artifactId )
-    {
-        return groupId + ":" + artifactId;
-    }
-
-    /**
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
-    public boolean equals( Object other )
-    {
-        if ( other instanceof Plugin )
-        {
-            Plugin otherPlugin = (Plugin) other;
-
-            return getKey().equals( otherPlugin.getKey() );
-        }
-
-        return false;
-    }
-
-    /**
-     * @see java.lang.Object#hashCode()
-     */
-    public int hashCode()
-    {
-        return getKey().hashCode();
-    }
-
-    /**
-     * @see java.lang.Object#toString()
-     */
-    public String toString()
-    {
-        return "Plugin [" + getKey() + "]";
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class>
-      <name>PluginExecution</name>
-      <version>4.0.0+</version>
-      <superClass>ConfigurationContainer</superClass>
-      <description>
-        <![CDATA[
-        The <code>&lt;execution&gt;</code> element contains informations required for the
-        execution of a plugin.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>id</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <defaultValue>default</defaultValue>
-          <description>The identifier of this execution for labelling the goals during the build,
-            and for matching executions to merge during inheritance and profile injection.</description>
-        </field>
-        <field>
-          <name>phase</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>The build lifecycle phase to bind the goals in this execution to. If omitted,
-            the goals will be bound to the default phase specified by the plugin. </description>
-        </field>
-        <field xml.transient="true">
-          <name>priority</name>
-          <version>4.0.0+</version>
-          <type>int</type>
-          <description>
-            <![CDATA[
-            The priority of this execution compared to other executions which are bound to the same phase.
-            <strong>Warning:</strong> This is an internal utility property that is only public for technical reasons,
-            it is not part of the public API. In particular, this property can be changed or deleted without prior
-            notice.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>goals</name>
-          <version>4.0.0+</version>
-          <description>The goals to execute with the given configuration.</description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    public static final String DEFAULT_EXECUTION_ID = "default";
-
-    @Override
-    public String toString()
-    {
-        return getId();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class java.clone="deep">
-      <name>DependencyManagement</name>
-      <version>4.0.0+</version>
-      <description>Section for management of default dependency information for use in a group of
-        POMs.</description>
-      <fields>
-        <field>
-          <name>dependencies</name>
-          <version>4.0.0+</version>
-          <description>The dependencies specified here are not used until they are referenced in a
-            POM within the group. This allows the specification of a "standard" version for a
-            particular dependency.</description>
-          <association>
-            <type>Dependency</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class>
-      <name>PluginManagement</name>
-      <version>4.0.0+</version>
-      <superClass>PluginContainer</superClass>
-      <description>Section for management of default plugin information for use in a group of POMs.
-      </description>
-    </class>
-    <class java.clone="deep">
-      <name>Reporting</name>
-      <version>4.0.0+</version>
-      <description>Section for management of reports and their configuration.</description>
-      <fields>
-        <field>
-          <name>excludeDefaults</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            If true, then the default reports are not included in the site generation.
-            This includes the reports in the "Project Info" menu. Note: While the type
-            of this field is <code>String</code> for technical reasons, the semantic type is actually
-            <code>Boolean</code>. Default value is <code>false</code>.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>outputDirectory</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            Where to store all of the generated reports. The default is
-            <code>${project.build.directory}/site</code>.
-            ]]>
-          </description>
-          <!-- TODO: why isn't default set here? -->
-        </field>
-        <field>
-          <name>plugins</name>
-          <version>4.0.0+</version>
-          <description>The reporting plugins to use and their configuration.</description>
-          <association>
-            <type>ReportPlugin</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    public boolean isExcludeDefaults()
-    {
-        return ( excludeDefaults != null ) ? Boolean.parseBoolean( excludeDefaults ) : false;
-    }
-
-    public void setExcludeDefaults( boolean excludeDefaults )
-    {
-        this.excludeDefaults = String.valueOf( excludeDefaults );
-    }
-
-    java.util.Map<String, ReportPlugin> reportPluginMap;
-
-    /**
-     * Reset the <code>reportPluginMap</code> field to <code>null</code>
-     */
-    public synchronized void flushReportPluginMap()
-    {
-        this.reportPluginMap = null;
-    }
-
-    /**
-     * @return a Map of plugins field with <code>ReportPlugin#getKey()</code> as key
-     * @see org.apache.maven.model.ReportPlugin#getKey()
-     */
-    public synchronized java.util.Map<String, ReportPlugin> getReportPluginsAsMap()
-    {
-        if ( reportPluginMap == null )
-        {
-            reportPluginMap = new java.util.LinkedHashMap<String, ReportPlugin>();
-            if ( getPlugins() != null )
-            {
-                for ( java.util.Iterator<ReportPlugin> it = getPlugins().iterator(); it.hasNext(); )
-                {
-                    ReportPlugin reportPlugin = (ReportPlugin) it.next();
-                    reportPluginMap.put( reportPlugin.getKey(), reportPlugin );
-                }
-            }
-        }
-
-        return reportPluginMap;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <!-- Profile support -->
-    <class>
-      <name>Profile</name>
-      <superClass>ModelBase</superClass>
-      <version>4.0.0+</version>
-      <description>Modifications to the build process which is activated based on environmental
-        parameters or command line arguments.</description>
-      <fields>
-        <field>
-          <name>id</name>
-          <required>true</required>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <defaultValue>default</defaultValue>
-          <description>The identifier of this build profile. This is used for command line
-            activation, and identifies profiles to be merged.
-          </description>
-        </field>
-        <field>
-          <name>activation</name>
-          <version>4.0.0+</version>
-          <description>The conditional logic which will automatically trigger the inclusion of this
-            profile.</description>
-          <association>
-            <type>Activation</type>
-          </association>
-        </field>
-        <field xml.tagName="build">
-          <name>build</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <description>Information required to build the project.</description>
-          <association>
-            <type>BuildBase</type>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    public static final String SOURCE_POM = "pom";
-
-    public static final String SOURCE_SETTINGS = "settings.xml";
-
-    // We don't want this to be parseable...it's sort of 'hidden'
-    // default source for this profile is in the pom itself.
-    private String source = SOURCE_POM;
-
-    public void setSource( String source )
-    {
-        this.source = source;
-    }
-
-    public String getSource()
-    {
-        return source;
-    }
-
-    /**
-     * @see java.lang.Object#toString()
-     */
-    public String toString()
-    {
-        return "Profile {id: " + getId() + ", source: " + getSource() + "}";
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class java.clone="deep">
-      <name>Activation</name>
-      <version>4.0.0+</version>
-      <description>The conditions within the build runtime environment which will trigger the
-        automatic inclusion of the build profile. Multiple conditions can be defined, which must
-        be all satisfied to activate the profile.
-      </description>
-      <fields>
-        <field>
-          <name>activeByDefault</name>
-          <version>4.0.0+</version>
-          <type>boolean</type>
-          <description>If set to true, this profile will be active unless another profile in this
-            pom is activated using the command line -P option or by one of that profile's
-            activators.</description>
-        </field>
-        <field>
-          <name>jdk</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            Specifies that this profile will be activated when a matching JDK is detected.
-            For example, <code>1.4</code> only activates on JDKs versioned 1.4,
-            while <code>!1.4</code> matches any JDK that is not version 1.4. Ranges are supported too:
-            <code>[1.5,)</code> activates when the JDK is 1.5 minimum.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>os</name>
-          <version>4.0.0+</version>
-          <description>Specifies that this profile will be activated when matching operating system
-            attributes are detected.</description>
-          <association>
-            <type>ActivationOS</type>
-          </association>
-        </field>
-        <field>
-          <name>property</name>
-          <version>4.0.0+</version>
-          <description>Specifies that this profile will be activated when this system property is
-            specified.</description>
-          <association>
-            <type>ActivationProperty</type>
-          </association>
-        </field>
-        <field>
-          <name>file</name>
-          <version>4.0.0+</version>
-          <description>Specifies that this profile will be activated based on existence of a file.</description>
-          <association>
-            <type>ActivationFile</type>
-          </association>
-        </field>
-        <!--
-        This could be included once we teach Maven to deal with multiple versions of the model
-        <field>
-          <name>custom</name>
-          <version>4.0.0+</version>
-          <description>Describes a custom profile activation trigger, brought in via build
-            extension.</description>
-          <association>
-            <type>ActivationCustom</type>
-          </association>
-        </field>
-        -->
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>ActivationProperty</name>
-      <version>4.0.0+</version>
-      <description>This is the property specification used to activate a profile. If the value field
-        is empty, then the existence of the named property will activate the profile, otherwise it
-        does a case-sensitive match against the property value as well.</description>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <required>true</required>
-          <description>The name of the property to be used to activate a profile.</description>
-        </field>
-        <field>
-          <name>value</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>The value of the property required to activate a profile.</description>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>ActivationOS</name>
-      <version>4.0.0+</version>
-      <description>This is an activator which will detect an operating system's attributes in order
-        to activate its profile.</description>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            The name of the operating system to be used to activate the profile. This must be an exact match
-            of the <code>${os.name}</code> Java property, such as <code>Windows XP</code>.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>family</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            The general family of the OS to be used to activate the profile, such as
-            <code>windows</code> or <code>unix</code>.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>arch</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>The architecture of the operating system to be used to activate the
-          profile.</description>
-        </field>
-        <field>
-          <name>version</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>The version of the operating system to be used to activate the
-          profile.</description>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>ActivationFile</name>
-      <version>4.0.0+</version>
-      <description><![CDATA[This is the file specification used to activate the profile. The <code>missing</code> value
-        is the location of a file that needs to exist, and if it doesn't, the profile will be
-        activated. On the other hand, <code>exists</code> will test for the existence of the file and if it is
-        there, the profile will be activated.<br>
-        Variable interpolation for these file specifications is limited to <code>${basedir}</code>,
-        System properties and request properties.]]></description>
-      <fields>
-        <field>
-          <name>missing</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>The name of the file that must be missing to activate the
-          profile.</description>
-        </field>
-        <field>
-          <name>exists</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>The name of the file that must exist to activate the profile.</description>
-        </field>
-      </fields>
-    </class>
-    <!--
-    This can be put back in when we figure out how to have multiple model versions
-    <class>
-      <name>ActivationCustom</name>
-      <version>4.0.0+</version>
-      <description>This activation allows users to specify their own custom trigger for a profile.</description>
-      <fields>
-        <field>
-          <name>configuration</name>
-          <version>4.0.0+</version>
-          <type>DOM</type>
-          <description>The specification for triggering the profile according to the rules of the
-            custom activation type.</description>
-        </field>
-        <field>
-          <name>type</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>The type (role-hint) of activation which is to be used to activate the
-            profile.</description>
-        </field>
-      </fields>
-    </class>
-    -->
-    <!-- /BuildProfile support -->
-    <class xml.tagName="plugin" xdoc.anchorName="report_plugin" java.clone="deep">
-      <name>ReportPlugin</name>
-      <version>4.0.0+</version>
-      <superClass>ConfigurationContainer</superClass>
-      <description>
-        <![CDATA[
-        The <code>&lt;plugin&gt;</code> element in <code>&lt;reporting&gt;&lt;plugins&gt;</code> contains informations required for a report plugin.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <required>true</required>
-          <defaultValue>org.apache.maven.plugins</defaultValue>
-          <description>The group ID of the reporting plugin in the repository.</description>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <required>true</required>
-          <description>The artifact ID of the reporting plugin in the repository.</description>
-        </field>
-        <field>
-          <name>version</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            The version of the reporting plugin to be used. Starting with Maven 3, if no version is defined explicitly,
-            version is searched in <code>build/plugins</code> then in <code>build/pluginManagement</code>.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>reportSets</name>
-          <version>4.0.0+</version>
-          <description>
-            <![CDATA[
-            Multiple specifications of a set of reports, each having (possibly) different
-            configuration. This is the reporting parallel to an <code>execution</code> in the build.
-            ]]>
-          </description>
-          <association>
-            <type>ReportSet</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    private java.util.Map<String, ReportSet> reportSetMap = null;
-
-    /**
-     * Reset the <code>reportSetMap</code> field to <code>null</code>
-     */
-    public void flushReportSetMap()
-    {
-        this.reportSetMap = null;
-    }
-
-    /**
-     * @return a Map of reportSets field with <code>ReportSet#getId()</code> as key
-     * @see org.apache.maven.model.ReportSet#getId()
-     */
-    public java.util.Map<String, ReportSet> getReportSetsAsMap()
-    {
-        if ( reportSetMap == null )
-        {
-            reportSetMap = new java.util.LinkedHashMap<String, ReportSet>();
-            if ( getReportSets() != null )
-            {
-                for ( java.util.Iterator<ReportSet> i = getReportSets().iterator(); i.hasNext(); )
-                {
-                    ReportSet reportSet = (ReportSet) i.next();
-                    reportSetMap.put( reportSet.getId(), reportSet );
-                }
-            }
-        }
-
-        return reportSetMap;
-    }
-
-    /**
-     * @return the key of the report plugin, ie <code>groupId:artifactId</code>
-     */
-    public String getKey()
-    {
-        return constructKey( groupId, artifactId );
-    }
-
-    /**
-     * @param groupId The group ID of the plugin in the repository
-     * @param artifactId The artifact ID of the reporting plugin in the repository
-     * @return the key of the report plugin, ie <code>groupId:artifactId</code>
-     */
-    public static String constructKey( String groupId, String artifactId )
-    {
-        return groupId + ":" + artifactId;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class java.clone="deep">
-      <name>ReportSet</name>
-      <version>4.0.0+</version>
-      <superClass>ConfigurationContainer</superClass>
-      <description>Represents a set of reports and configuration to be used to generate them.</description>
-      <fields>
-        <field>
-          <name>id</name>
-          <type>String</type>
-          <required>true</required>
-          <description>The unique id for this report set, to be used during POM inheritance and profile injection
-            for merging of report sets.
-          </description>
-          <defaultValue>default</defaultValue>
-        </field>
-        <field>
-          <name>reports</name>
-          <version>4.0.0+</version>
-          <required>true</required>
-          <description>The list of reports from this plugin which should be generated from this set.</description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    @Override
-    public String toString()
-    {
-        return getId();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class java.clone="deep">
-      <name>Prerequisites</name>
-      <version>4.0.0+</version>
-      <description>Describes the prerequisites a project can have.</description>
-      <fields>
-        <field>
-          <name>maven</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <defaultValue>2.0</defaultValue>
-          <description><![CDATA[
-            For a plugin project (packaging is <code>maven-plugin</code>), the minimum version of
-            Maven required to use the resulting plugin.<br>
-            In Maven 2, this was also specifying the minimum version of Maven required to build a
-            project, but this usage is <b>deprecated</b> in Maven 3 and not checked any more: use
-            the <a href="https://maven.apache.org/enforcer/enforcer-rules/requireMavenVersion.html">Maven Enforcer Plugin's
-            <code>requireMavenVersion</code> rule</a> instead.
-            ]]>
-          </description>
-          <required>false</required>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>Relocation</name>
-      <version>4.0.0+</version>
-      <description>Describes where an artifact has moved to. If any of the values are omitted, it is
-        assumed to be the same as it was before.</description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <version>4.0.0+</version>
-          <description>The group ID the artifact has moved to.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>4.0.0+</version>
-          <description>The new artifact ID of the artifact.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>version</name>
-          <version>4.0.0+</version>
-          <description>The new version of the artifact.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>message</name>
-          <version>4.0.0+</version>
-          <description>An additional message to show the user about the move, such as the reason.</description>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>Extension</name>
-      <version>4.0.0+</version>
-      <description>Describes a build extension to utilise.</description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <version>4.0.0+</version>
-          <description>The group ID of the extension's artifact.</description>
-          <required>true</required>
-          <type>String</type>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>4.0.0+</version>
-          <description>The artifact ID of the extension.</description>
-          <required>true</required>
-          <type>String</type>
-        </field>
-        <field>
-          <name>version</name>
-          <version>4.0.0+</version>
-          <description>The version of the extension.</description>
-          <type>String</type>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    /**
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
-    public boolean equals( Object o )
-    {
-        if ( this == o )
-        {
-            return true;
-        }
-
-        if ( !( o instanceof Extension ) )
-        {
-            return false;
-        }
-
-        Extension e = (Extension) o;
-
-        if ( !equal( e.getArtifactId(), getArtifactId() ) )
-        {
-            return false;
-        }
-        else if ( !equal( e.getGroupId(), getGroupId() ) )
-        {
-            return false;
-        }
-        else if ( !equal( e.getVersion(), getVersion() ) )
-        {
-            return false;
-        }
-        return true;
-    }
-
-    private static <T> boolean equal( T obj1, T obj2 )
-    {
-        return ( obj1 != null ) ? obj1.equals( obj2 ) : obj2 == null;
-    }
-
-    /**
-     * @see java.lang.Object#hashCode()
-     */
-    public int hashCode()
-    {
-        int result = 17;
-        result = 37 * result + ( getArtifactId() != null ? getArtifactId().hashCode() : 0 );
-        result = 37 * result + ( getGroupId() != null ? getGroupId().hashCode() : 0 );
-        result = 37 * result + ( getVersion() != null ? getVersion().hashCode() : 0 );
-        return result;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class locationTracker="locations" java.clone="shallow">
-      <name>InputLocation</name>
-      <version>4.0.0+</version>
-      <fields>
-        <!-- line, column and source fields are auto-generated by Modello -->
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-
-    @Override
-    public String toString()
-    {
-        return getLineNumber() + " : " + getColumnNumber() + ", " + getSource();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class sourceTracker="source" java.clone="shallow">
-      <name>InputSource</name>
-      <version>4.0.0+</version>
-      <fields>
-        <field>
-          <name>modelId</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            The identifier of the POM in the format {@code <groupId>:<artifactId>:<version>}.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>location</name>
-          <version>4.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            The path/URL of the POM or {@code null} if unknown.
-            ]]>
-          </description>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>4.0.0+</version>
-          <code>
-            <![CDATA[
-    @Override
-    public String toString()
-    {
-        return getModelId() + " " + getLocation();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-  </classes>
-</model>
diff --git a/maven-model/src/site/apt/index.apt b/maven-model/src/site/apt/index.apt
index 0010f4f..680358f 100644
--- a/maven-model/src/site/apt/index.apt
+++ b/maven-model/src/site/apt/index.apt
@@ -27,12 +27,14 @@
 
 Maven Model
 
- This is strictly the model for Maven POM (Project Object Model), so really just plain objects. All the effective model
+ This is strictly the model for Maven POM (Project Object Model) in <<<org.apache.maven.model>>> package,
+ delegating content to {{{../api/maven-api-model/index.html}Maven 4 API immutable model}}. All the effective model
  building logic from multiple POMs and building context is done in {{{../maven-model-builder/}Maven Model Builder}}.
 
  The following are generated from this model:
 
-   * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser
+   * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser, <<<ToAPiV3()>>> and <<<ToApiV4()>>> transformers, and <<<v4>>> package
+     for Merger and v4 Reader and Writers for the Xpp3 XML parser,
 
    * A {{{./maven.html}Descriptor Reference}}
 
diff --git a/maven-model/src/site/site.xml b/maven-model/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-model/src/site/site.xml
+++ b/maven-model/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-model/src/test/java/org/apache/maven/model/ActivationFileTest.java b/maven-model/src/test/java/org/apache/maven/model/ActivationFileTest.java
index cbfdc2a..5f5dcd1 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ActivationFileTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ActivationFileTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code ActivationFile}.
  *
- * @author Benjamin Bentmann
  */
-public class ActivationFileTest
-{
+class ActivationFileTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new ActivationFile().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new ActivationFile().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new ActivationFile().equals(null));
 
-        new ActivationFile().equals( new ActivationFile() );
+        new ActivationFile().equals(new ActivationFile());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         ActivationFile thing = new ActivationFile();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new ActivationFile().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new ActivationFile().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ActivationOSTest.java b/maven-model/src/test/java/org/apache/maven/model/ActivationOSTest.java
index 3be5cd9..5ca7bec 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ActivationOSTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ActivationOSTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code ActivationOS}.
  *
- * @author Benjamin Bentmann
  */
-public class ActivationOSTest
-{
+class ActivationOSTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new ActivationOS().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new ActivationOS().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new ActivationOS().equals(null));
 
-        new ActivationOS().equals( new ActivationOS() );
+        new ActivationOS().equals(new ActivationOS());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         ActivationOS thing = new ActivationOS();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new ActivationOS().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new ActivationOS().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ActivationPropertyTest.java b/maven-model/src/test/java/org/apache/maven/model/ActivationPropertyTest.java
index 564adc0..32b69dc 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ActivationPropertyTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ActivationPropertyTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code ActivationProperty}.
  *
- * @author Benjamin Bentmann
  */
-public class ActivationPropertyTest
-{
+class ActivationPropertyTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new ActivationProperty().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new ActivationProperty().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new ActivationProperty().equals(null));
 
-        new ActivationProperty().equals( new ActivationProperty() );
+        new ActivationProperty().equals(new ActivationProperty());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         ActivationProperty thing = new ActivationProperty();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new ActivationProperty().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new ActivationProperty().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ActivationTest.java b/maven-model/src/test/java/org/apache/maven/model/ActivationTest.java
index 520c0a9..545aab5 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ActivationTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ActivationTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Activation}.
  *
- * @author Benjamin Bentmann
  */
-public class ActivationTest
-{
+class ActivationTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Activation().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Activation().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Activation().equals(null));
 
-        new Activation().equals( new Activation() );
+        new Activation().equals(new Activation());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Activation thing = new Activation();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Activation().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Activation().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/BuildTest.java b/maven-model/src/test/java/org/apache/maven/model/BuildTest.java
index 3a14bd3..3fd3b5f 100644
--- a/maven-model/src/test/java/org/apache/maven/model/BuildTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/BuildTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,37 @@
 /**
  * Tests {@code Build}.
  *
- * @author Benjamin Bentmann
  */
-public class BuildTest
-{
+class BuildTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Build().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Build().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Build().equals(null));
 
-        new Build().equals( new Build() );
+        new Build().equals(new Build());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Build thing = new Build();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Build().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Build().toString());
     }
 
+    public void testToStringNotNonsense() {
+        Build build = new Build();
+
+        String s = build.toString();
+
+        assert "Build {BuildBase {PluginConfiguration {PluginContainer {}}}}".equals(s) : s;
+    }
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/CiManagementTest.java b/maven-model/src/test/java/org/apache/maven/model/CiManagementTest.java
index ee6d41d..71a4027 100644
--- a/maven-model/src/test/java/org/apache/maven/model/CiManagementTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/CiManagementTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code CiManagement}.
  *
- * @author Benjamin Bentmann
  */
-public class CiManagementTest
-{
+class CiManagementTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new CiManagement().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new CiManagement().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new CiManagement().equals(null));
 
-        new CiManagement().equals( new CiManagement() );
+        new CiManagement().equals(new CiManagement());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         CiManagement thing = new CiManagement();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new CiManagement().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new CiManagement().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ContributorTest.java b/maven-model/src/test/java/org/apache/maven/model/ContributorTest.java
index e2f3dbb..f6ddcc4 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ContributorTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ContributorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Contributor}.
  *
- * @author Benjamin Bentmann
  */
-public class ContributorTest
-{
+class ContributorTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Contributor().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Contributor().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Contributor().equals(null));
 
-        new Contributor().equals( new Contributor() );
+        new Contributor().equals(new Contributor());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Contributor thing = new Contributor();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Contributor().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Contributor().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/DependencyManagementTest.java b/maven-model/src/test/java/org/apache/maven/model/DependencyManagementTest.java
index e63d224..1a32e0e 100644
--- a/maven-model/src/test/java/org/apache/maven/model/DependencyManagementTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/DependencyManagementTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -28,36 +28,46 @@
 /**
  * Tests {@code DependencyManagement}.
  *
- * @author Benjamin Bentmann
  */
-public class DependencyManagementTest
-{
+class DependencyManagementTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new DependencyManagement().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new DependencyManagement().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new DependencyManagement().equals(null));
 
-        new DependencyManagement().equals( new DependencyManagement() );
+        new DependencyManagement().equals(new DependencyManagement());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         DependencyManagement thing = new DependencyManagement();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new DependencyManagement().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new DependencyManagement().toString());
     }
 
+    @Test
+    void testDependencies() {
+        DependencyManagement dm = new DependencyManagement();
+        Dependency d1 = new Dependency();
+        d1.setGroupId("myGroupId");
+        assertNotNull(dm.getDependencies());
+        assertEquals(0, dm.getDependencies().size());
+        dm.addDependency(d1);
+        assertNotNull(dm.getDependencies());
+        assertEquals(1, dm.getDependencies().size());
+        dm.getDependencies().get(0).setArtifactId("myArtifactId");
+        assertEquals("myArtifactId", dm.getDependencies().get(0).getArtifactId());
+        dm.setDependencies(null);
+        assertNotNull(dm.getDependencies());
+        assertEquals(0, dm.getDependencies().size());
+    }
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/DependencyTest.java b/maven-model/src/test/java/org/apache/maven/model/DependencyTest.java
index 6b7bc3f..39d7bb3 100644
--- a/maven-model/src/test/java/org/apache/maven/model/DependencyTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/DependencyTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Dependency}.
  *
- * @author Benjamin Bentmann
  */
-public class DependencyTest
-{
+class DependencyTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Dependency().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Dependency().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Dependency().equals(null));
 
-        new Dependency().equals( new Dependency() );
+        new Dependency().equals(new Dependency());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Dependency thing = new Dependency();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Dependency().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Dependency().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/DeploymentRepositoryTest.java b/maven-model/src/test/java/org/apache/maven/model/DeploymentRepositoryTest.java
index c648ffd..8b25cc6 100644
--- a/maven-model/src/test/java/org/apache/maven/model/DeploymentRepositoryTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/DeploymentRepositoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code DeploymentRepository}.
  *
- * @author Benjamin Bentmann
  */
-public class DeploymentRepositoryTest
-{
+class DeploymentRepositoryTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new DeploymentRepository().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new DeploymentRepository().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new DeploymentRepository().equals(null));
 
-        new DeploymentRepository().equals( new DeploymentRepository() );
+        new DeploymentRepository().equals(new DeploymentRepository());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         DeploymentRepository thing = new DeploymentRepository();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new DeploymentRepository().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new DeploymentRepository().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/DeveloperTest.java b/maven-model/src/test/java/org/apache/maven/model/DeveloperTest.java
index 61d86f0..b6897ae 100644
--- a/maven-model/src/test/java/org/apache/maven/model/DeveloperTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/DeveloperTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Developer}.
  *
- * @author Benjamin Bentmann
  */
-public class DeveloperTest
-{
+class DeveloperTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Developer().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Developer().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Developer().equals(null));
 
-        new Developer().equals( new Developer() );
+        new Developer().equals(new Developer());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Developer thing = new Developer();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Developer().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Developer().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/DistributionManagementTest.java b/maven-model/src/test/java/org/apache/maven/model/DistributionManagementTest.java
index db8ba21..18c57a8 100644
--- a/maven-model/src/test/java/org/apache/maven/model/DistributionManagementTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/DistributionManagementTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code DistributionManagement}.
  *
- * @author Benjamin Bentmann
  */
-public class DistributionManagementTest
-{
+class DistributionManagementTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new DistributionManagement().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new DistributionManagement().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new DistributionManagement().equals(null));
 
-        new DistributionManagement().equals( new DistributionManagement() );
+        new DistributionManagement().equals(new DistributionManagement());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         DistributionManagement thing = new DistributionManagement();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new DistributionManagement().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new DistributionManagement().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ExclusionTest.java b/maven-model/src/test/java/org/apache/maven/model/ExclusionTest.java
index 90e4b74..625f20e 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ExclusionTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ExclusionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Exclusion}.
  *
- * @author Benjamin Bentmann
  */
-public class ExclusionTest
-{
+class ExclusionTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Exclusion().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Exclusion().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Exclusion().equals(null));
 
-        new Exclusion().equals( new Exclusion() );
+        new Exclusion().equals(new Exclusion());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Exclusion thing = new Exclusion();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Exclusion().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Exclusion().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ExtensionTest.java b/maven-model/src/test/java/org/apache/maven/model/ExtensionTest.java
index 218ff50..3afa12c 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ExtensionTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ExtensionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Extension}.
  *
- * @author Benjamin Bentmann
  */
-public class ExtensionTest
-{
+class ExtensionTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Extension().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Extension().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Extension().equals(null));
 
-        new Extension().equals( new Extension() );
+        new Extension().equals(new Extension());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Extension thing = new Extension();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Extension().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Extension().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/IssueManagementTest.java b/maven-model/src/test/java/org/apache/maven/model/IssueManagementTest.java
index 27e1eb0..16bd8a0 100644
--- a/maven-model/src/test/java/org/apache/maven/model/IssueManagementTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/IssueManagementTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,39 @@
 /**
  * Tests {@code IssueManagement}.
  *
- * @author Benjamin Bentmann
  */
-public class IssueManagementTest
-{
+class IssueManagementTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new IssueManagement().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new IssueManagement().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new IssueManagement().equals(null));
 
-        new IssueManagement().equals( new IssueManagement() );
+        new IssueManagement().equals(new IssueManagement());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         IssueManagement thing = new IssueManagement();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new IssueManagement().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new IssueManagement().toString());
     }
 
+    public void testToStringNotNonsense() {
+        IssueManagement im = new IssueManagement();
+        im.setSystem("Velociraptor");
+        im.setUrl("https://velo.localdomain");
+
+        String s = im.toString();
+
+        assert "IssueManagement {system=Velociraptor, url=https://velo.localdomain}".equals(s) : s;
+    }
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/LicenseTest.java b/maven-model/src/test/java/org/apache/maven/model/LicenseTest.java
index dd56616..c333a97 100644
--- a/maven-model/src/test/java/org/apache/maven/model/LicenseTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/LicenseTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,39 @@
 /**
  * Tests {@code License}.
  *
- * @author Benjamin Bentmann
  */
-public class LicenseTest
-{
+class LicenseTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new License().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new License().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new License().equals(null));
 
-        new License().equals( new License() );
+        new License().equals(new License());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         License thing = new License();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new License().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new License().toString());
     }
 
+    public void testToStringNotNonsense() {
+        License license = new License();
+        license.setName("Unlicense");
+        license.setUrl("http://lic.localdomain");
+
+        String s = license.toString();
+
+        assert "License {name=Unlicense, url=http://lic.localdomain}".equals(s) : s;
+    }
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/MailingListTest.java b/maven-model/src/test/java/org/apache/maven/model/MailingListTest.java
index 5de9edc..7e12221 100644
--- a/maven-model/src/test/java/org/apache/maven/model/MailingListTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/MailingListTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -28,36 +28,38 @@
 /**
  * Tests {@code MailingList}.
  *
- * @author Benjamin Bentmann
  */
-public class MailingListTest
-{
+class MailingListTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new MailingList().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new MailingList().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new MailingList().equals(null));
 
-        new MailingList().equals( new MailingList() );
+        new MailingList().equals(new MailingList());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         MailingList thing = new MailingList();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new MailingList().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new MailingList().toString());
     }
 
+    public void testToStringNotNonsense() {
+        MailingList list = new MailingList();
+        list.setName("modello-dev");
+
+        String s = list.toString();
+
+        assertEquals("MailingList {name=modello-dev, archive=null}", s);
+    }
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ModelTest.java b/maven-model/src/test/java/org/apache/maven/model/ModelTest.java
index 37adc82..76a1e82 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ModelTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ModelTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,46 +16,55 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Tests {@code Model}.
  *
- * @author Benjamin Bentmann
  */
-public class ModelTest
-{
+class ModelTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Model().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Model().equals( null ) );
-
-        new Model().equals( new Model() );
+    void testBuild() {
+        Model model = new Model();
+        Build build = new Build();
+        build.setOutputDirectory("myOutputDirectory");
+        model.setBuild(build);
+        Build build2 = model.getBuild();
+        assertNotNull(build2);
+        assertEquals("myOutputDirectory", build2.getOutputDirectory());
+        model.setBuild(null);
+        assertNull(model.getBuild());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsNullSafe() {
+        assertFalse(new Model().equals(null));
+
+        new Model().equals(new Model());
+    }
+
+    @Test
+    void testEqualsIdentity() {
         Model thing = new Model();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Model().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Model().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/NotifierTest.java b/maven-model/src/test/java/org/apache/maven/model/NotifierTest.java
index 026632a..33f1c13 100644
--- a/maven-model/src/test/java/org/apache/maven/model/NotifierTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/NotifierTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Notifier}.
  *
- * @author Benjamin Bentmann
  */
-public class NotifierTest
-{
+class NotifierTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Notifier().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Notifier().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Notifier().equals(null));
 
-        new Notifier().equals( new Notifier() );
+        new Notifier().equals(new Notifier());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Notifier thing = new Notifier();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Notifier().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Notifier().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/OrganizationTest.java b/maven-model/src/test/java/org/apache/maven/model/OrganizationTest.java
index ef19d2a..a001599 100644
--- a/maven-model/src/test/java/org/apache/maven/model/OrganizationTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/OrganizationTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -28,36 +28,57 @@
 /**
  * Tests {@code Organization}.
  *
- * @author Benjamin Bentmann
  */
-public class OrganizationTest
-{
+class OrganizationTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Organization().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Organization().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Organization().equals(null));
 
-        new Organization().equals( new Organization() );
+        new Organization().equals(new Organization());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Organization thing = new Organization();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Organization().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Organization().toString());
     }
 
+    public void testToStringNotNonsense11() {
+        Organization org = new Organization();
+        org.setName("Testing Maven Unit");
+        org.setUrl("https://maven.localdomain");
+
+        assertEquals("Organization {name=Testing Maven Unit, url=https://maven.localdomain}", org.toString());
+    }
+
+    public void testToStringNotNonsense10() {
+        Organization org = new Organization();
+        org.setName("Testing Maven Unit");
+
+        assertEquals("Organization {name=Testing Maven Unit, url=null}", org.toString());
+    }
+
+    public void testToStringNotNonsense01() {
+        Organization org = new Organization();
+        org.setUrl("https://maven.localdomain");
+
+        assertEquals("Organization {name=null, url=https://maven.localdomain}", org.toString());
+    }
+
+    public void testToStringNotNonsense00() {
+        Organization org = new Organization();
+
+        assertEquals("Organization {name=null, url=null}", org.toString());
+    }
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ParentTest.java b/maven-model/src/test/java/org/apache/maven/model/ParentTest.java
index d8690fc..79f3378 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ParentTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ParentTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Parent}.
  *
- * @author Benjamin Bentmann
  */
-public class ParentTest
-{
+class ParentTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Parent().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Parent().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Parent().equals(null));
 
-        new Parent().equals( new Parent() );
+        new Parent().equals(new Parent());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Parent thing = new Parent();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Parent().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Parent().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/PluginConfigurationTest.java b/maven-model/src/test/java/org/apache/maven/model/PluginConfigurationTest.java
index 3e52df7..996bf56 100644
--- a/maven-model/src/test/java/org/apache/maven/model/PluginConfigurationTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/PluginConfigurationTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code PluginConfiguration}.
  *
- * @author Benjamin Bentmann
  */
-public class PluginConfigurationTest
-{
+class PluginConfigurationTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new PluginConfiguration().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new PluginConfiguration().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new PluginConfiguration().equals(null));
 
-        new PluginConfiguration().equals( new PluginConfiguration() );
+        new PluginConfiguration().equals(new PluginConfiguration());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         PluginConfiguration thing = new PluginConfiguration();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new PluginConfiguration().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new PluginConfiguration().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/PluginContainerTest.java b/maven-model/src/test/java/org/apache/maven/model/PluginContainerTest.java
index ed4e9e3..bc4c614 100644
--- a/maven-model/src/test/java/org/apache/maven/model/PluginContainerTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/PluginContainerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code PluginContainer}.
  *
- * @author Benjamin Bentmann
  */
-public class PluginContainerTest
-{
+class PluginContainerTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new PluginContainer().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new PluginContainer().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new PluginContainer().equals(null));
 
-        new PluginContainer().equals( new PluginContainer() );
+        new PluginContainer().equals(new PluginContainer());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         PluginContainer thing = new PluginContainer();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new PluginContainer().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new PluginContainer().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/PluginExecutionTest.java b/maven-model/src/test/java/org/apache/maven/model/PluginExecutionTest.java
index 35b78bd..110ed25 100644
--- a/maven-model/src/test/java/org/apache/maven/model/PluginExecutionTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/PluginExecutionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code PluginExecution}.
  *
- * @author Benjamin Bentmann
  */
-public class PluginExecutionTest
-{
+class PluginExecutionTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new PluginExecution().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new PluginExecution().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new PluginExecution().equals(null));
 
-        new PluginExecution().equals( new PluginExecution() );
+        new PluginExecution().equals(new PluginExecution());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         PluginExecution thing = new PluginExecution();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new PluginExecution().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new PluginExecution().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/PluginManagementTest.java b/maven-model/src/test/java/org/apache/maven/model/PluginManagementTest.java
index b4d8266..c657890 100644
--- a/maven-model/src/test/java/org/apache/maven/model/PluginManagementTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/PluginManagementTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code PluginManagement}.
  *
- * @author Benjamin Bentmann
  */
-public class PluginManagementTest
-{
+class PluginManagementTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new PluginManagement().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new PluginManagement().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new PluginManagement().equals(null));
 
-        new PluginManagement().equals( new PluginManagement() );
+        new PluginManagement().equals(new PluginManagement());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         PluginManagement thing = new PluginManagement();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new PluginManagement().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new PluginManagement().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/PluginTest.java b/maven-model/src/test/java/org/apache/maven/model/PluginTest.java
index d8e345b..c023199 100644
--- a/maven-model/src/test/java/org/apache/maven/model/PluginTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/PluginTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Plugin}.
  *
- * @author Benjamin Bentmann
  */
-public class PluginTest
-{
+class PluginTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Plugin().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Plugin().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Plugin().equals(null));
 
-        new Plugin().equals( new Plugin() );
+        new Plugin().equals(new Plugin());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Plugin thing = new Plugin();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Plugin().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Plugin().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/PrerequisitesTest.java b/maven-model/src/test/java/org/apache/maven/model/PrerequisitesTest.java
index 2c91e47..c886fd8 100644
--- a/maven-model/src/test/java/org/apache/maven/model/PrerequisitesTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/PrerequisitesTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Prerequisites}.
  *
- * @author Benjamin Bentmann
  */
-public class PrerequisitesTest
-{
+class PrerequisitesTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Prerequisites().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Prerequisites().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Prerequisites().equals(null));
 
-        new Prerequisites().equals( new Prerequisites() );
+        new Prerequisites().equals(new Prerequisites());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Prerequisites thing = new Prerequisites();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Prerequisites().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Prerequisites().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ProfileTest.java b/maven-model/src/test/java/org/apache/maven/model/ProfileTest.java
index ac719e4..aa8b0db 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ProfileTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ProfileTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Profile}.
  *
- * @author Benjamin Bentmann
  */
-public class ProfileTest
-{
+class ProfileTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Profile().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Profile().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Profile().equals(null));
 
-        new Profile().equals( new Profile() );
+        new Profile().equals(new Profile());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Profile thing = new Profile();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Profile().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Profile().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/RelocationTest.java b/maven-model/src/test/java/org/apache/maven/model/RelocationTest.java
index ea825a6..9956b12 100644
--- a/maven-model/src/test/java/org/apache/maven/model/RelocationTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/RelocationTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Relocation}.
  *
- * @author Benjamin Bentmann
  */
-public class RelocationTest
-{
+class RelocationTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Relocation().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Relocation().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Relocation().equals(null));
 
-        new Relocation().equals( new Relocation() );
+        new Relocation().equals(new Relocation());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Relocation thing = new Relocation();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Relocation().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Relocation().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ReportPluginTest.java b/maven-model/src/test/java/org/apache/maven/model/ReportPluginTest.java
index 094d2d5..37f0acf 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ReportPluginTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ReportPluginTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code ReportPlugin}.
  *
- * @author Benjamin Bentmann
  */
-public class ReportPluginTest
-{
+class ReportPluginTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new ReportPlugin().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new ReportPlugin().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new ReportPlugin().equals(null));
 
-        new ReportPlugin().equals( new ReportPlugin() );
+        new ReportPlugin().equals(new ReportPlugin());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         ReportPlugin thing = new ReportPlugin();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new ReportPlugin().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new ReportPlugin().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ReportSetTest.java b/maven-model/src/test/java/org/apache/maven/model/ReportSetTest.java
index c0bb257..7314675 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ReportSetTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ReportSetTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code ReportSet}.
  *
- * @author Benjamin Bentmann
  */
-public class ReportSetTest
-{
+class ReportSetTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new ReportSet().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new ReportSet().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new ReportSet().equals(null));
 
-        new ReportSet().equals( new ReportSet() );
+        new ReportSet().equals(new ReportSet());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         ReportSet thing = new ReportSet();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new ReportSet().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new ReportSet().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ReportingTest.java b/maven-model/src/test/java/org/apache/maven/model/ReportingTest.java
index 3b04d02..8d3d7d9 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ReportingTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ReportingTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Reporting}.
  *
- * @author Benjamin Bentmann
  */
-public class ReportingTest
-{
+class ReportingTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Reporting().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Reporting().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Reporting().equals(null));
 
-        new Reporting().equals( new Reporting() );
+        new Reporting().equals(new Reporting());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Reporting thing = new Reporting();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Reporting().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Reporting().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/RepositoryPolicyTest.java b/maven-model/src/test/java/org/apache/maven/model/RepositoryPolicyTest.java
index 770bce2..24b9e04 100644
--- a/maven-model/src/test/java/org/apache/maven/model/RepositoryPolicyTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/RepositoryPolicyTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code RepositoryPolicy}.
  *
- * @author Benjamin Bentmann
  */
-public class RepositoryPolicyTest
-{
+class RepositoryPolicyTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new RepositoryPolicy().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new RepositoryPolicy().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new RepositoryPolicy().equals(null));
 
-        new RepositoryPolicy().equals( new RepositoryPolicy() );
+        new RepositoryPolicy().equals(new RepositoryPolicy());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         RepositoryPolicy thing = new RepositoryPolicy();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new RepositoryPolicy().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new RepositoryPolicy().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/RepositoryTest.java b/maven-model/src/test/java/org/apache/maven/model/RepositoryTest.java
index 62f32d7..afcc13b 100644
--- a/maven-model/src/test/java/org/apache/maven/model/RepositoryTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/RepositoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Repository}.
  *
- * @author Benjamin Bentmann
  */
-public class RepositoryTest
-{
+class RepositoryTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Repository().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Repository().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Repository().equals(null));
 
-        new Repository().equals( new Repository() );
+        new Repository().equals(new Repository());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Repository thing = new Repository();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Repository().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Repository().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ResourceTest.java b/maven-model/src/test/java/org/apache/maven/model/ResourceTest.java
index 3e5b1b3..7ed5294 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ResourceTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ResourceTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Resource}.
  *
- * @author Benjamin Bentmann
  */
-public class ResourceTest
-{
+class ResourceTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Resource().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Resource().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Resource().equals(null));
 
-        new Resource().equals( new Resource() );
+        new Resource().equals(new Resource());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Resource thing = new Resource();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Resource().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Resource().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/ScmTest.java b/maven-model/src/test/java/org/apache/maven/model/ScmTest.java
index a6ccc24..6927e6e 100644
--- a/maven-model/src/test/java/org/apache/maven/model/ScmTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/ScmTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -28,36 +28,38 @@
 /**
  * Tests {@code Scm}.
  *
- * @author Benjamin Bentmann
  */
-public class ScmTest
-{
+class ScmTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Scm().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Scm().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Scm().equals(null));
 
-        new Scm().equals( new Scm() );
+        new Scm().equals(new Scm());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Scm thing = new Scm();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Scm().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Scm().toString());
     }
 
+    public void testToStringNotNonsense() {
+        Scm scm = new Scm();
+        scm.setConnection("scm:git:git://git.localdomain/model");
+
+        String s = scm.toString();
+
+        assertEquals("Scm {connection=scm:git:git://git.localdomain/model}", s);
+    }
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/SerializationTest.java b/maven-model/src/test/java/org/apache/maven/model/SerializationTest.java
new file mode 100644
index 0000000..91daad7
--- /dev/null
+++ b/maven-model/src/test/java/org/apache/maven/model/SerializationTest.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class SerializationTest {
+
+    @Test
+    void testModelSerialization() throws Exception {
+        Model model;
+        try (InputStream is = getClass().getResourceAsStream("/xml/pom.xml")) {
+            model = new MavenXpp3Reader().read(is);
+        }
+
+        // Serialize an inner child here so that the BaseObject.childrenTracking is non null
+        Build build = model.getBuild();
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+            oos.writeObject(build);
+        }
+
+        Build build2;
+        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+        try (ObjectInputStream ois = new ObjectInputStream(bais)) {
+            build2 = (Build) ois.readObject();
+        }
+
+        assertNotNull(build2);
+    }
+}
diff --git a/maven-model/src/test/java/org/apache/maven/model/SiteTest.java b/maven-model/src/test/java/org/apache/maven/model/SiteTest.java
index 5fe4975..4156501 100644
--- a/maven-model/src/test/java/org/apache/maven/model/SiteTest.java
+++ b/maven-model/src/test/java/org/apache/maven/model/SiteTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.model;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.model;
 
 import org.junit.jupiter.api.Test;
 
@@ -28,36 +27,29 @@
 /**
  * Tests {@code Site}.
  *
- * @author Benjamin Bentmann
  */
-public class SiteTest
-{
+class SiteTest {
 
     @Test
-    public void testHashCodeNullSafe()
-    {
+    void testHashCodeNullSafe() {
         new Site().hashCode();
     }
 
     @Test
-    public void testEqualsNullSafe()
-    {
-        assertFalse( new Site().equals( null ) );
+    void testEqualsNullSafe() {
+        assertFalse(new Site().equals(null));
 
-        new Site().equals( new Site() );
+        new Site().equals(new Site());
     }
 
     @Test
-    public void testEqualsIdentity()
-    {
+    void testEqualsIdentity() {
         Site thing = new Site();
-        assertTrue( thing.equals( thing ) );
+        assertTrue(thing.equals(thing));
     }
 
     @Test
-    public void testToStringNullSafe()
-    {
-        assertNotNull( new Site().toString() );
+    void testToStringNullSafe() {
+        assertNotNull(new Site().toString());
     }
-
 }
diff --git a/maven-model/src/test/java/org/apache/maven/model/merge/MavenMergerTest.java b/maven-model/src/test/java/org/apache/maven/model/merge/MavenMergerTest.java
new file mode 100644
index 0000000..dca39aa
--- /dev/null
+++ b/maven-model/src/test/java/org/apache/maven/model/merge/MavenMergerTest.java
@@ -0,0 +1,433 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.merge;
+
+import java.util.Arrays;
+
+import org.apache.maven.api.model.Contributor;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.model.v4.MavenMerger;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.is;
+
+/**
+ * MavenMerger is based on same instances, subclasses should override KeyComputer per type
+ *
+ *
+ */
+class MavenMergerTest {
+    private MavenMerger mavenMerger = new MavenMerger();
+
+    @Test
+    void mergeArtifactId() {
+        Model target = Model.newBuilder().artifactId("TARGET").build();
+
+        Model source = Model.newBuilder().artifactId("SOURCE").build();
+
+        Model merged = mavenMerger.merge(target, source, true, null);
+        assertThat(merged.getArtifactId(), is("SOURCE"));
+
+        merged = mavenMerger.merge(target, source, false, null);
+        assertThat(merged.getArtifactId(), is("TARGET"));
+    }
+
+    @Test
+    void mergeSameContributors() {
+        Contributor contributor =
+                Contributor.newBuilder().email("contributor@maven.apache.org").build();
+
+        Model target =
+                Model.newBuilder().contributors(Arrays.asList(contributor)).build();
+
+        Model source =
+                Model.newBuilder().contributors(Arrays.asList(contributor)).build();
+
+        Model merged = mavenMerger.merge(target, source, true, null);
+
+        assertThat(merged.getContributors(), contains(contributor));
+    }
+
+    @Test
+    void mergeSameDependencies() {
+        Dependency dependency = Dependency.newBuilder()
+                .groupId("groupId")
+                .artifactId("artifactId")
+                .type("type")
+                .build();
+
+        Model target =
+                Model.newBuilder().dependencies(Arrays.asList(dependency)).build();
+
+        Model source =
+                Model.newBuilder().dependencies(Arrays.asList(dependency)).build();
+
+        Model merged = mavenMerger.merge(target, source, true, null);
+
+        assertThat(merged.getDependencies(), contains(dependency));
+    }
+
+    /*
+    @Test
+    public void mergeDescription()
+    {
+        Model target = new Model();
+        target.setDescription( "TARGET" );
+
+        Model source = new Model();
+        source.setDescription( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getDescription(), is( "SOURCE" ) );
+
+        target.setDescription( "TARGET" );
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getDescription(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void mergeSameDevelopers()
+    {
+        Developer developer = new Developer();
+        developer.setId( "devid" );
+
+        Model target = new Model();
+        target.setDevelopers( Arrays.asList( developer ) );
+
+        Model source = new Model();
+        source.setDevelopers( Arrays.asList( developer ) );
+
+        modelMerger.merge( target, source, true, null );
+
+        assertThat( target.getDevelopers(), contains( developer ) );
+    }
+
+    @Test
+    public void mergeSameExcludes()
+    {
+        PatternSet target = new PatternSet();
+        target.setExcludes( Arrays.asList( "first", "second", "third" ) );
+        PatternSet source = new PatternSet();
+        source.setExcludes( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.mergePatternSet_Excludes( target, source, true, null );
+
+        assertThat( target.getExcludes(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergeSameFilters()
+    {
+        Build target = new Build();
+        target.setFilters( Arrays.asList( "first", "second", "third" ) );
+        Build source = new Build();
+        source.setFilters( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.mergeBuild( target, source, true, null );
+
+        assertThat( target.getFilters(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergeSameGoals()
+    {
+        PluginExecution target = new PluginExecution();
+        target.setGoals( Arrays.asList( "first", "second", "third" ) );
+        PluginExecution source = new PluginExecution();
+        source.setGoals( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.mergePluginExecution( target, source, true, null );
+
+        assertThat( target.getGoals(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergeGroupId()
+    {
+        Model target = new Model();
+        target.setGroupId( "TARGET" );
+
+        Model source = new Model();
+        source.setGroupId( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getGroupId(), is( "SOURCE" ) );
+
+        target.setGroupId( "TARGET" );
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getGroupId(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void mergeInceptionYear()
+    {
+        Model target = new Model();
+        target.setInceptionYear( "TARGET" );
+
+        Model source = new Model();
+        source.setInceptionYear( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getInceptionYear(), is( "SOURCE" ) );
+
+        target.setInceptionYear( "TARGET" );
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getInceptionYear(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void mergeSameIncludes()
+    {
+        PatternSet target = new PatternSet();
+        target.setIncludes( Arrays.asList( "first", "second", "third" ) );
+        PatternSet source = new PatternSet();
+        source.setIncludes( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.mergePatternSet_Includes( target, source, true, null );
+
+        assertThat( target.getIncludes(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergeSameMailingLists()
+    {
+        MailingList mailingList = new MailingList();
+        mailingList.setName( "name" );
+
+        Model target = new Model();
+        target.setMailingLists( Arrays.asList( mailingList ) );
+
+        Model source = new Model();
+        source.setMailingLists( Arrays.asList( mailingList ) );
+
+        modelMerger.merge( target, source, true, null );
+
+        assertThat( target.getMailingLists(), contains( mailingList ) );
+    }
+
+    @Test
+    public void mergeModelVersion()
+    {
+        Model target = new Model();
+        target.setModelVersion( "TARGET" );
+
+        Model source = new Model();
+        source.setModelVersion( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getModelVersion(), is( "SOURCE" ) );
+
+        target.setModelVersion( "TARGET" );;
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getModelVersion(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void mergeSameModules()
+    {
+        Model target = new Model();
+        target.setModules( Arrays.asList( "first", "second", "third" ) );
+        Model source = new Model();
+        source.setModules( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.merge( target, source, true, null );
+
+        assertThat( target.getModules(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergeName()
+    {
+        Model target = new Model();
+        target.setName( "TARGET" );
+
+        Model source = new Model();
+        source.setName( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getName(), is( "SOURCE" ) );
+
+        target.setName( "TARGET" );;
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getName(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void mergeSameOtherArchives()
+    {
+        MailingList target = new MailingList();
+        target.setOtherArchives( Arrays.asList( "first", "second", "third" ) );
+        MailingList source = new MailingList();
+        source.setOtherArchives( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.mergeMailingList( target, source, true, null );
+
+        assertThat( target.getOtherArchives(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergePackaging()
+    {
+        Model target = new Model();
+        target.setPackaging( "TARGET" );
+
+        Model source = new Model();
+        source.setPackaging( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getPackaging(), is( "SOURCE" ) );
+
+        target.setPackaging( "TARGET" );;
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getPackaging(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void mergeSamePluginRepositories()
+    {
+        Repository repository = new Repository();
+        repository.setId( "repository" );
+
+        Model target = new Model();
+        target.setPluginRepositories( Arrays.asList( repository ) );
+
+        Model source = new Model();
+        source.setPluginRepositories( Arrays.asList( repository ) );
+
+        modelMerger.merge( target, source, true, null );
+
+        assertThat( target.getPluginRepositories(), contains( repository ) );
+    }
+
+    @Test
+    public void mergeSameProfiles()
+    {
+        Profile profile = new Profile();
+        profile.setId( "profile" );
+
+        Model target = new Model();
+        target.setProfiles( Arrays.asList( profile ) );
+
+        Model source = new Model();
+        source.setProfiles( Arrays.asList( profile ) );
+
+        modelMerger.merge( target, source, true, null );
+
+        assertThat( target.getProfiles(), contains( profile ) );
+    }
+
+    @Test
+    public void mergeSameReports()
+    {
+        ReportSet target = new ReportSet();
+        target.setReports( Arrays.asList( "first", "second", "third" ) );
+        ReportSet source = new ReportSet();
+        source.setReports( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.mergeReportSet( target, source, true, null );
+
+        assertThat( target.getReports(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergeSameRepositories()
+    {
+        Repository repository = new Repository();
+        repository.setId( "repository" );
+
+        Model target = new Model();
+        target.setRepositories( Arrays.asList( repository ) );
+
+        Model source = new Model();
+        source.setRepositories( Arrays.asList( repository ) );
+
+        modelMerger.merge( target, source, true, null );
+
+        assertThat( target.getRepositories(), contains( repository ) );
+    }
+
+    @Test
+    public void mergeSameRoles()
+    {
+        Contributor target = new Contributor();
+        target.setRoles( Arrays.asList( "first", "second", "third" ) );
+        Contributor source = new Contributor();
+        source.setRoles( Arrays.asList( "first", "second", "third" ) );
+
+        modelMerger.mergeContributor_Roles( target, source, true, null );
+
+        assertThat( target.getRoles(), contains( "first", "second", "third" ) );
+    }
+
+    @Test
+    public void mergeUrl()
+    {
+        Model target = new Model();
+        target.setUrl( "TARGET" );;
+
+        Model source = new Model();
+        source.setUrl( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getUrl(), is( "SOURCE" ) );
+
+        target.setUrl( "TARGET" );;
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getUrl(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void mergeVersion()
+    {
+        Model target = new Model();
+        target.setVersion( "TARGET" );;
+
+        Model source = new Model();
+        source.setVersion( "SOURCE" );
+
+        modelMerger.merge( target, source, true, null );
+        assertThat( target.getVersion(), is( "SOURCE" ) );
+
+        target.setVersion( "TARGET" );;
+        modelMerger.merge( target, source, false, null );
+        assertThat( target.getVersion(), is( "TARGET" ) );
+    }
+
+    @Test
+    public void testMergedModelSerialization() throws Exception {
+        Model target = new Model();
+        Model source = new Model();
+        target.setLicenses(new ArrayList<License>());
+        License lic1 = new License();
+        License lic2 = new License();
+        target.getLicenses().add(lic1);
+        source.setLicenses(new ArrayList<License>());
+        source.getLicenses().add(lic2);
+
+        new MavenMerger().mergeModel(target, source, false, null);
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        ObjectOutputStream oos = new ObjectOutputStream(baos);
+        oos.writeObject(target);
+    }
+     */
+}
diff --git a/maven-model/src/test/java/org/apache/maven/model/merge/ModelMergerTest.java b/maven-model/src/test/java/org/apache/maven/model/merge/ModelMergerTest.java
deleted file mode 100644
index f1aad04..0000000
--- a/maven-model/src/test/java/org/apache/maven/model/merge/ModelMergerTest.java
+++ /dev/null
@@ -1,450 +0,0 @@
-package org.apache.maven.model.merge;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.contains;
-import static org.hamcrest.Matchers.is;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.ByteArrayOutputStream;
-import java.io.ObjectOutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.apache.maven.model.Build;
-import org.apache.maven.model.Contributor;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Developer;
-import org.apache.maven.model.License;
-import org.apache.maven.model.MailingList;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.PatternSet;
-import org.apache.maven.model.PluginExecution;
-import org.apache.maven.model.Profile;
-import org.apache.maven.model.ReportSet;
-import org.apache.maven.model.Repository;
-import org.junit.jupiter.api.Test;
-
-/**
- * ModelMerger is based on same instances, subclasses should override KeyComputer per type
- *
- * @author Robert Scholte
- *
- */
-public class ModelMergerTest
-{
-    private ModelMerger modelMerger = new ModelMerger();
-
-    @Test
-    public void mergeArtifactId()
-    {
-        Model target = new Model();
-        target.setArtifactId( "TARGET" );
-
-        Model source = new Model();
-        source.setArtifactId( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getArtifactId(), is( "SOURCE" ) );
-
-        target.setArtifactId( "TARGET" );;
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getArtifactId(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeSameContributors()
-    {
-        Contributor contributor = new Contributor();
-        contributor.setEmail( "contributor@maven.apache.org" );
-
-        Model target = new Model();
-        target.setContributors( Arrays.asList( contributor ) );
-
-        Model source = new Model();
-        source.setContributors( Arrays.asList( contributor ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getContributors(), contains( contributor ) );
-    }
-
-    @Test
-    public void mergeSameDependencies()
-    {
-        Dependency dependency = new Dependency();
-        dependency.setGroupId( "groupId" );
-        dependency.setArtifactId( "artifactId" );
-        dependency.setType( "type" );
-
-        Model target = new Model();
-        target.setDependencies( Arrays.asList( dependency ) );
-
-        Model source = new Model();
-        source.setDependencies( Arrays.asList( dependency ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getDependencies(), contains( dependency ) );
-    }
-
-    @Test
-    public void mergeDescription()
-    {
-        Model target = new Model();
-        target.setDescription( "TARGET" );
-
-        Model source = new Model();
-        source.setDescription( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getDescription(), is( "SOURCE" ) );
-
-        target.setDescription( "TARGET" );
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getDescription(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeSameDevelopers()
-    {
-        Developer developer = new Developer();
-        developer.setId( "devid" );
-
-        Model target = new Model();
-        target.setDevelopers( Arrays.asList( developer ) );
-
-        Model source = new Model();
-        source.setDevelopers( Arrays.asList( developer ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getDevelopers(), contains( developer ) );
-    }
-
-    @Test
-    public void mergeSameExcludes()
-    {
-        PatternSet target = new PatternSet();
-        target.setExcludes( Arrays.asList( "first", "second", "third" ) );
-        PatternSet source = new PatternSet();
-        source.setExcludes( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.mergePatternSet_Excludes( target, source, true, null );
-
-        assertThat( target.getExcludes(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergeSameFilters()
-    {
-        Build target = new Build();
-        target.setFilters( Arrays.asList( "first", "second", "third" ) );
-        Build source = new Build();
-        source.setFilters( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.mergeBuild( target, source, true, null );
-
-        assertThat( target.getFilters(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergeSameGoals()
-    {
-        PluginExecution target = new PluginExecution();
-        target.setGoals( Arrays.asList( "first", "second", "third" ) );
-        PluginExecution source = new PluginExecution();
-        source.setGoals( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.mergePluginExecution( target, source, true, null );
-
-        assertThat( target.getGoals(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergeGroupId()
-    {
-        Model target = new Model();
-        target.setGroupId( "TARGET" );
-
-        Model source = new Model();
-        source.setGroupId( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getGroupId(), is( "SOURCE" ) );
-
-        target.setGroupId( "TARGET" );
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getGroupId(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeInceptionYear()
-    {
-        Model target = new Model();
-        target.setInceptionYear( "TARGET" );
-
-        Model source = new Model();
-        source.setInceptionYear( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getInceptionYear(), is( "SOURCE" ) );
-
-        target.setInceptionYear( "TARGET" );
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getInceptionYear(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeSameIncludes()
-    {
-        PatternSet target = new PatternSet();
-        target.setIncludes( Arrays.asList( "first", "second", "third" ) );
-        PatternSet source = new PatternSet();
-        source.setIncludes( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.mergePatternSet_Includes( target, source, true, null );
-
-        assertThat( target.getIncludes(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergeSameMailingLists()
-    {
-        MailingList mailingList = new MailingList();
-        mailingList.setName( "name" );
-
-        Model target = new Model();
-        target.setMailingLists( Arrays.asList( mailingList ) );
-
-        Model source = new Model();
-        source.setMailingLists( Arrays.asList( mailingList ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getMailingLists(), contains( mailingList ) );
-    }
-
-    @Test
-    public void mergeModelVersion()
-    {
-        Model target = new Model();
-        target.setModelVersion( "TARGET" );
-
-        Model source = new Model();
-        source.setModelVersion( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getModelVersion(), is( "SOURCE" ) );
-
-        target.setModelVersion( "TARGET" );;
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getModelVersion(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeSameModules()
-    {
-        Model target = new Model();
-        target.setModules( Arrays.asList( "first", "second", "third" ) );
-        Model source = new Model();
-        source.setModules( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getModules(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergeName()
-    {
-        Model target = new Model();
-        target.setName( "TARGET" );
-
-        Model source = new Model();
-        source.setName( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getName(), is( "SOURCE" ) );
-
-        target.setName( "TARGET" );;
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getName(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeSameOtherArchives()
-    {
-        MailingList target = new MailingList();
-        target.setOtherArchives( Arrays.asList( "first", "second", "third" ) );
-        MailingList source = new MailingList();
-        source.setOtherArchives( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.mergeMailingList( target, source, true, null );
-
-        assertThat( target.getOtherArchives(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergePackaging()
-    {
-        Model target = new Model();
-        target.setPackaging( "TARGET" );
-
-        Model source = new Model();
-        source.setPackaging( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getPackaging(), is( "SOURCE" ) );
-
-        target.setPackaging( "TARGET" );;
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getPackaging(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeSamePluginRepositories()
-    {
-        Repository repository = new Repository();
-        repository.setId( "repository" );
-
-        Model target = new Model();
-        target.setPluginRepositories( Arrays.asList( repository ) );
-
-        Model source = new Model();
-        source.setPluginRepositories( Arrays.asList( repository ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getPluginRepositories(), contains( repository ) );
-    }
-
-    @Test
-    public void mergeSameProfiles()
-    {
-        Profile profile = new Profile();
-        profile.setId( "profile" );
-
-        Model target = new Model();
-        target.setProfiles( Arrays.asList( profile ) );
-
-        Model source = new Model();
-        source.setProfiles( Arrays.asList( profile ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getProfiles(), contains( profile ) );
-    }
-
-    @Test
-    public void mergeSameReports()
-    {
-        ReportSet target = new ReportSet();
-        target.setReports( Arrays.asList( "first", "second", "third" ) );
-        ReportSet source = new ReportSet();
-        source.setReports( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.mergeReportSet( target, source, true, null );
-
-        assertThat( target.getReports(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergeSameRepositories()
-    {
-        Repository repository = new Repository();
-        repository.setId( "repository" );
-
-        Model target = new Model();
-        target.setRepositories( Arrays.asList( repository ) );
-
-        Model source = new Model();
-        source.setRepositories( Arrays.asList( repository ) );
-
-        modelMerger.merge( target, source, true, null );
-
-        assertThat( target.getRepositories(), contains( repository ) );
-    }
-
-    @Test
-    public void mergeSameRoles()
-    {
-        Contributor target = new Contributor();
-        target.setRoles( Arrays.asList( "first", "second", "third" ) );
-        Contributor source = new Contributor();
-        source.setRoles( Arrays.asList( "first", "second", "third" ) );
-
-        modelMerger.mergeContributor_Roles( target, source, true, null );
-
-        assertThat( target.getRoles(), contains( "first", "second", "third" ) );
-    }
-
-    @Test
-    public void mergeUrl()
-    {
-        Model target = new Model();
-        target.setUrl( "TARGET" );;
-
-        Model source = new Model();
-        source.setUrl( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getUrl(), is( "SOURCE" ) );
-
-        target.setUrl( "TARGET" );;
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getUrl(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void mergeVersion()
-    {
-        Model target = new Model();
-        target.setVersion( "TARGET" );;
-
-        Model source = new Model();
-        source.setVersion( "SOURCE" );
-
-        modelMerger.merge( target, source, true, null );
-        assertThat( target.getVersion(), is( "SOURCE" ) );
-
-        target.setVersion( "TARGET" );;
-        modelMerger.merge( target, source, false, null );
-        assertThat( target.getVersion(), is( "TARGET" ) );
-    }
-
-    @Test
-    public void testMergedModelSerialization() throws Exception {
-        Model target = new Model();
-        Model source = new Model();
-        target.setLicenses(new ArrayList<License>());
-        License lic1 = new License();
-        License lic2 = new License();
-        target.getLicenses().add(lic1);
-        source.setLicenses(new ArrayList<License>());
-        source.getLicenses().add(lic2);
-
-        new ModelMerger().mergeModel(target, source, false, null);
-
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ObjectOutputStream oos = new ObjectOutputStream(baos);
-        oos.writeObject(target);
-    }
-}
diff --git a/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java b/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java
new file mode 100644
index 0000000..371561f
--- /dev/null
+++ b/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.v4;
+
+import java.io.InputStream;
+import java.util.Collections;
+
+import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.model.PluginExecution;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class MavenModelVersionTest {
+
+    private static Model model;
+
+    @BeforeAll
+    static void setup() throws Exception {
+        try (InputStream is = MavenModelVersionTest.class.getResourceAsStream("/xml/pom.xml")) {
+            model = new MavenStaxReader().read(is);
+        }
+    }
+
+    @Test
+    void testV4Model() {
+        assertEquals("4.0.0", new MavenModelVersion().getModelVersion(model));
+    }
+
+    @Test
+    void testV4ModelVersion() {
+        Model m = model.withModelVersion("4.1.0");
+        assertEquals("4.0.0", new MavenModelVersion().getModelVersion(m));
+    }
+
+    @Test
+    void testV4ModelRoot() {
+        Model m = model.withRoot(true);
+        assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
+    }
+
+    @Test
+    void testV4ModelPreserveModelVersion() {
+        Model m = model.withPreserveModelVersion(true);
+        assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
+    }
+
+    @Test
+    void testV4ModelPriority() {
+        Model m = model.withBuild(Build.newInstance()
+                .withPlugins(Collections.singleton(Plugin.newInstance()
+                        .withExecutions(Collections.singleton(
+                                PluginExecution.newInstance().withPriority(5))))));
+        assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
+    }
+}
diff --git a/maven-model/src/test/java/org/apache/maven/model/v4/ModelXmlTest.java b/maven-model/src/test/java/org/apache/maven/model/v4/ModelXmlTest.java
new file mode 100644
index 0000000..ece1d04
--- /dev/null
+++ b/maven-model/src/test/java/org/apache/maven/model/v4/ModelXmlTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.v4;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.maven.api.model.Model;
+import org.apache.maven.api.model.Plugin;
+import org.apache.maven.api.xml.XmlNode;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class ModelXmlTest {
+
+    @Test
+    void testXmlRoundtripWithProperties() throws Exception {
+        Map<String, String> props = new LinkedHashMap<>();
+        props.put("javax.version", "3.1.0");
+        props.put("mockito.version", "1.10.19");
+        props.put("hamcret.version", "2.1");
+        props.put("lombok.version", "1.18.6");
+        props.put("junit.version", "4.12");
+        Model model = Model.newBuilder(true).properties(props).build();
+        String xml = toXml(model);
+
+        for (int i = 0; i < 10; i++) {
+            String newStr = toXml(fromXml(xml));
+            assertEquals(newStr, xml);
+        }
+    }
+
+    @Test
+    void testNamespaceInXmlNode() throws XMLStreamException {
+        String xml = "<project xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+                + "         xmlns=\"http://maven.apache.org/POM/4.0.0\"\n"
+                + "         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/POM/4.0.0\">\n"
+                + "  <build>\n"
+                + "    <plugins>\n"
+                + "      <plugin>\n"
+                + "         <m:configuration xmlns:m=\"http://maven.apache.org/POM/4.0.0\" xmlns=\"http://fabric8.io/fabric8-maven-plugin\">\n"
+                + "             <myConfig>foo</myConfig>\n"
+                + "         </m:configuration>\n"
+                + "      </plugin>\n"
+                + "    </plugins>\n"
+                + "  </build>\n"
+                + "</project>";
+
+        Model model = fromXml(xml);
+        Plugin plugin = model.getBuild().getPlugins().get(0);
+        XmlNode node = plugin.getConfiguration();
+        assertNotNull(node);
+        assertEquals("http://maven.apache.org/POM/4.0.0", node.getNamespaceUri());
+        assertEquals("m", node.getPrefix());
+        assertEquals("configuration", node.getName());
+        assertEquals(1, node.getChildren().size());
+        XmlNode myConfig = node.getChildren().get(0);
+        assertEquals("http://fabric8.io/fabric8-maven-plugin", myConfig.getNamespaceUri());
+        assertEquals("", myConfig.getPrefix());
+        assertEquals("myConfig", myConfig.getName());
+        String config = node.toString();
+        assertFalse(config.isEmpty());
+    }
+
+    String toXml(Model model) throws IOException, XMLStreamException {
+        StringWriter sw = new StringWriter();
+        MavenStaxWriter writer = new MavenStaxWriter();
+        writer.setAddLocationInformation(false);
+        writer.write(sw, model);
+        return sw.toString();
+    }
+
+    Model fromXml(String xml) throws XMLStreamException {
+        return new MavenStaxReader().read(new StringReader(xml));
+    }
+}
diff --git a/maven-model/src/test/java/org/apache/maven/model/v4/Xpp3DomPerfTest.java b/maven-model/src/test/java/org/apache/maven/model/v4/Xpp3DomPerfTest.java
new file mode 100644
index 0000000..e591122
--- /dev/null
+++ b/maven-model/src/test/java/org/apache/maven/model/v4/Xpp3DomPerfTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.model.v4;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.model.InputSource;
+import org.openjdk.jmh.annotations.*;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+/**
+ * <p>Xpp3DomPerfTest class.</p>
+ */
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.MILLISECONDS)
+@Warmup(iterations = 3)
+@Measurement(time = 10)
+public class Xpp3DomPerfTest {
+    @State(Scope.Benchmark)
+    public static class AdditionState {
+        List<Path> poms;
+
+        @Setup(Level.Iteration)
+        public void setUp() throws IOException {
+            Path userHome = Paths.get(System.getProperty("user.home"));
+            poms = Files.walk(userHome.resolve(".m2/repository/org/apache/maven"))
+                    .filter(p -> p.getFileName().toString().endsWith(".pom"))
+                    .collect(Collectors.toList());
+        }
+    }
+
+    @Benchmark
+    public int readWithStax(AdditionState state) throws IOException, XMLStreamException {
+        int i = 0;
+        for (Path pom : state.poms) {
+            try (InputStream is = Files.newInputStream(pom)) {
+                MavenStaxReader reader = new MavenStaxReader();
+                reader.setAddLocationInformation(false);
+                reader.read(is, true, new InputSource("id", pom.toString()));
+                i++;
+            } catch (XMLStreamException e) {
+                throw new RuntimeException("Error parsing: " + pom, e);
+            }
+        }
+        return i;
+    }
+
+    /**
+     * <p>main.</p>
+     *
+     * @param args a {@link String} object.
+     * @throws org.openjdk.jmh.runner.RunnerException if any.
+     */
+    public static void main(String... args) throws RunnerException {
+        Options opts = new OptionsBuilder().forks(1).build();
+        new Runner(opts).run();
+    }
+}
diff --git a/maven-model/src/test/resources/xml/pom.xml b/maven-model/src/test/resources/xml/pom.xml
new file mode 100644
index 0000000..01b6796
--- /dev/null
+++ b/maven-model/src/test/resources/xml/pom.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<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>org.apache.maven</groupId>
+    <artifactId>maven</artifactId>
+    <version>4.0.0-alpha-1-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-model</artifactId>
+
+  <name>Maven Model</name>
+  <description>Model for Maven POM (Project Object Model)</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-model</artifactId>
+      <version>4.0.0-alpha-1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-xml-impl</artifactId>
+      <version>4.0.0-alpha-1-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>3.2.0</version>
+        <executions>
+          <execution>
+            <id>copy-model</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>copy</goal>
+            </goals>
+            <configuration>
+              <artifactItems>
+                <artifactItem>
+                  <groupId>org.apache.maven</groupId>
+                  <artifactId>maven-api-model</artifactId>
+                  <version>4.0.0-alpha-1-SNAPSHOT</version>
+                  <type>mdo</type>
+                  <outputDirectory>target/mdo/</outputDirectory>
+                  <destFileName>maven.mdo</destFileName>
+                </artifactItem>
+              </artifactItems>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven</groupId>
+        <artifactId>modello-plugin-velocity</artifactId>
+        <version>4.0.0-alpha-1-SNAPSHOT</version>
+        <executions>
+          <execution>
+            <id>velocity</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <configuration>
+              <version>4.0.0</version>
+              <models>
+                <model>target/mdo/maven.mdo</model>
+              </models>
+              <templates>
+                <template>src/main/mdo/model-v3.vm</template>
+                <template>src/main/mdo/merger.vm</template>
+                <template>src/main/mdo/transformer.vm</template>
+                <template>src/main/mdo/reader.vm</template>
+                <template>src/main/mdo/reader-ex.vm</template>
+                <template>src/main/mdo/writer.vm</template>
+                <template>src/main/mdo/writer-ex.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV3=org.apache.maven.model</param>
+                <param>packageModelV4=org.apache.maven.api.model</param>
+                <param>packageToolV4=org.apache.maven.model.v4</param>
+              </params>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/package-info.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/maven-plugin-api/pom.xml b/maven-plugin-api/pom.xml
index be4b993..a5f8a86 100644
--- a/maven-plugin-api/pom.xml
+++ b/maven-plugin-api/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-plugin-api</artifactId>
@@ -36,6 +34,10 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-plugin</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
       <artifactId>maven-model</artifactId>
     </dependency>
     <dependency>
@@ -45,15 +47,21 @@
     <dependency>
       <groupId>org.eclipse.sisu</groupId>
       <artifactId>org.eclipse.sisu.plexus</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>org.codehaus.plexus</groupId>
+          <artifactId>plexus-utils</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-classworlds</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven.resolver</groupId>
+      <artifactId>maven-resolver-api</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
@@ -62,26 +70,71 @@
         <groupId>org.codehaus.modello</groupId>
         <artifactId>modello-maven-plugin</artifactId>
         <configuration>
-          <models>
-            <model>src/main/mdo/lifecycle.mdo</model>
-          </models>
-          <version>1.0.0</version>
+          <velocityBasedir>${project.basedir}/../src/mdo</velocityBasedir>
         </configuration>
         <executions>
           <execution>
-            <id>modello-site-doc</id>
-            <phase>pre-site</phase>
+            <id>velocity-lifecycle</id>
             <goals>
-              <goal>xdoc</goal>
+              <goal>velocity</goal>
             </goals>
+            <phase>generate-sources</phase>
             <configuration>
+              <templates>
+                <template>reader-stax.vm</template>
+                <template>writer-stax.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV4=org.apache.maven.api.plugin.descriptor.lifecycle</param>
+                <param>packageToolV4=org.apache.maven.plugin.lifecycle.io</param>
+              </params>
               <models>
-                <model>src/main/mdo/plugin.mdo</model>
+                <model>../api/maven-api-plugin/src/main/mdo/lifecycle.mdo</model>
               </models>
+              <version>1.0.0</version>
             </configuration>
           </execution>
+          <execution>
+            <id>velocity-plugin</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <templates>
+                <template>reader-stax.vm</template>
+                <template>writer-stax.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV3=org.apache.maven.plugin.descriptor</param>
+                <param>packageModelV4=org.apache.maven.api.plugin.descriptor</param>
+                <param>packageToolV4=org.apache.maven.plugin.descriptor.io</param>
+              </params>
+              <models>
+                <model>../api/maven-api-plugin/src/main/mdo/plugin.mdo</model>
+              </models>
+              <version>2.0.0</version>
+            </configuration>
+          </execution>
+          <execution>
+            <id>modello-site-docs</id>
+            <phase>none</phase>
+          </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <parameter>
+            <excludes>
+              <exclude>org.apache.maven.monitor.logging.DefaultLog</exclude>
+              <exclude>org.apache.maven.plugin.lifecycle</exclude>
+              <exclude>org.apache.maven.plugin.descriptor.PluginDescriptor#getLifecycleMapping(java.lang.String)</exclude>
+            </excludes>
+          </parameter>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojo.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojo.java
index 6a74a64..352caeb 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojo.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojo.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.Map;
 
@@ -136,13 +135,8 @@
  * @see <a href="https://maven.apache.org/guides/mini/guide-configuring-plugins.html" target="_blank">Guide to Configuring Plug-ins</a>
  * @see <a href="https://maven.apache.org/developers/mojo-api-specification.html" target="_blank">Mojo API Specification</a>
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
- * @author jdcasey
- * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
  */
-public abstract class AbstractMojo
-    implements Mojo, ContextEnabled
-{
+public abstract class AbstractMojo implements Mojo, ContextEnabled {
     /** Instance logger */
     private Log log;
 
@@ -150,8 +144,7 @@
     private Map pluginContext;
 
     @Override
-    public void setLog( Log log )
-    {
+    public void setLog(Log log) {
         this.log = log;
     }
 
@@ -169,10 +162,8 @@
      * @see org.apache.maven.plugin.Mojo#getLog()
      */
     @Override
-    public Log getLog()
-    {
-        if ( log == null )
-        {
+    public Log getLog() {
+        if (log == null) {
             log = new SystemStreamLog();
         }
 
@@ -180,14 +171,12 @@
     }
 
     @Override
-    public Map getPluginContext()
-    {
+    public Map getPluginContext() {
         return pluginContext;
     }
 
     @Override
-    public void setPluginContext( Map pluginContext )
-    {
+    public void setPluginContext(Map pluginContext) {
         this.pluginContext = pluginContext;
     }
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java
index e8df309..9c88815 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/AbstractMojoExecutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,27 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 /**
  * Base exception.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public abstract class AbstractMojoExecutionException
-    extends Exception
-{
+public abstract class AbstractMojoExecutionException extends Exception {
     protected Object source;
 
     protected String longMessage;
 
-    public AbstractMojoExecutionException( String message )
-    {
-        super( message );
+    public AbstractMojoExecutionException(String message) {
+        super(message);
     }
 
-    public AbstractMojoExecutionException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public AbstractMojoExecutionException(String message, Throwable cause) {
+        super(message, cause);
     }
 
     /**
@@ -48,18 +42,15 @@
      *              A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
      * @since 3.8.3
      */
-    public AbstractMojoExecutionException( Throwable cause )
-    {
-        super( cause );
+    public AbstractMojoExecutionException(Throwable cause) {
+        super(cause);
     }
 
-    public String getLongMessage()
-    {
+    public String getLongMessage() {
         return longMessage;
     }
 
-    public Object getSource()
-    {
+    public Object getSource() {
         return source;
     }
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/ContextEnabled.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/ContextEnabled.java
index 6851698..9cd49ab 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/ContextEnabled.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/ContextEnabled.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.Map;
 
@@ -26,16 +25,14 @@
  * project's source root and project's attachment.<br>
  * The plugin manager would pull the context out of the plugin container context, and populate it into the Mojo.
  *
- * @author jdcasey
  */
-public interface ContextEnabled
-{
+public interface ContextEnabled {
     /**
      * Set a new shared context <code>Map</code> to a mojo before executing it.
      *
      * @param pluginContext a new <code>Map</code>
      */
-    void setPluginContext( Map pluginContext );
+    void setPluginContext(Map pluginContext);
 
     /**
      * @return a <code>Map</code> stored in the plugin container's context.
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/Mojo.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/Mojo.java
index aa277f9..1e12dd6 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/Mojo.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/Mojo.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import org.apache.maven.plugin.logging.Log;
 
@@ -29,10 +28,8 @@
  * Also included is the <code>setLog(...)</code> method, which simply allows Maven to inject a logging mechanism which
  * will allow the Mojo to communicate to the outside world through standard Maven channels.
  *
- * @author Jason van Zyl
  */
-public interface Mojo
-{
+public interface Mojo {
     /** The component <code>role</code> hint for Plexus container */
     String ROLE = Mojo.class.getName();
 
@@ -46,8 +43,7 @@
      * @throws MojoFailureException if an expected problem (such as a compilation failure) occurs.
      * Throwing this exception causes a "BUILD FAILURE" message to be displayed.
      */
-    void execute()
-        throws MojoExecutionException, MojoFailureException;
+    void execute() throws MojoExecutionException, MojoFailureException;
 
     /**
      * Inject a standard <code>Maven</code> logging mechanism to allow this <code>Mojo</code> to communicate events
@@ -56,7 +52,7 @@
      * @param log a new logger
      *
      */
-    void setLog( Log log );
+    void setLog(Log log);
 
     /**
      * Furnish access to the standard Maven logging mechanism which is managed in this base class.
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java
index 6d08989..8a07b2b 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoExecutionException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 /**
  * An exception occurring during the execution of a plugin.<br>
  * Throwing this exception causes a "BUILD ERROR" message to be displayed.
  *
- * @author Brett Porter
  */
-public class MojoExecutionException
-    extends AbstractMojoExecutionException
-{
+public class MojoExecutionException extends AbstractMojoExecutionException {
     /**
      * Construct a new <code>MojoExecutionException</code> exception providing the source and a short and long message:
      * these messages are used to improve the message written at the end of Maven build.
@@ -36,9 +32,8 @@
      * @param shortMessage
      * @param longMessage
      */
-    public MojoExecutionException( Object source, String shortMessage, String longMessage )
-    {
-        super( shortMessage );
+    public MojoExecutionException(Object source, String shortMessage, String longMessage) {
+        super(shortMessage);
         this.source = source;
         this.longMessage = longMessage;
     }
@@ -50,9 +45,8 @@
      * @param message
      * @param cause
      */
-    public MojoExecutionException( String message, Exception cause )
-    {
-        super( message, cause );
+    public MojoExecutionException(String message, Exception cause) {
+        super(message, cause);
     }
 
     /**
@@ -62,9 +56,8 @@
      * @param message
      * @param cause
      */
-    public MojoExecutionException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public MojoExecutionException(String message, Throwable cause) {
+        super(message, cause);
     }
 
     /**
@@ -72,9 +65,8 @@
      *
      * @param message
      */
-    public MojoExecutionException( String message )
-    {
-        super( message );
+    public MojoExecutionException(String message) {
+        super(message);
     }
 
     /**
@@ -84,9 +76,7 @@
      *              A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
      * @since 3.8.3
      */
-    public MojoExecutionException( Throwable cause )
-    {
-        super( cause );
+    public MojoExecutionException(Throwable cause) {
+        super(cause);
     }
-
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java
index 72faec6..8fe2d35 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoFailureException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,16 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 /**
  * An exception occurring during the execution of a plugin (such as a compilation failure).<br>
  * Throwing this exception causes a "BUILD FAILURE" message to be displayed.
  *
- * @author Brett Porter
  */
-public class MojoFailureException
-    extends AbstractMojoExecutionException
-{
+public class MojoFailureException extends AbstractMojoExecutionException {
     /**
      * Construct a new <code>MojoFailureException</code> exception providing the source and a short and long message:
      * these messages are used to improve the message written at the end of Maven build.
@@ -36,9 +32,8 @@
      * @param shortMessage
      * @param longMessage
      */
-    public MojoFailureException( Object source, String shortMessage, String longMessage )
-    {
-        super( shortMessage );
+    public MojoFailureException(Object source, String shortMessage, String longMessage) {
+        super(shortMessage);
         this.source = source;
         this.longMessage = longMessage;
     }
@@ -48,9 +43,8 @@
      *
      * @param message
      */
-    public MojoFailureException( String message )
-    {
-        super( message );
+    public MojoFailureException(String message) {
+        super(message);
     }
 
     /**
@@ -61,9 +55,8 @@
      * @param cause
      * @since 2.0.9
      */
-    public MojoFailureException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public MojoFailureException(String message, Throwable cause) {
+        super(message, cause);
     }
 
     /**
@@ -73,9 +66,7 @@
      *              A {@code null} value is permitted, and indicates that the cause is nonexistent or unknown.
      * @since 3.8.3
      */
-    public MojoFailureException( Throwable cause )
-    {
-        super( cause );
+    public MojoFailureException(Throwable cause) {
+        super(cause);
     }
-
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoNotFoundException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoNotFoundException.java
index cd97fb7..b895a28 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoNotFoundException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/MojoNotFoundException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin;
 
 import java.util.Iterator;
 import java.util.List;
@@ -28,55 +27,44 @@
 /**
  * MojoNotFoundException
  */
-public class MojoNotFoundException
-    extends Exception
-{
+public class MojoNotFoundException extends Exception {
     private String goal;
 
     private PluginDescriptor pluginDescriptor;
 
-    public MojoNotFoundException( String goal, PluginDescriptor pluginDescriptor )
-    {
-        super( toMessage( goal, pluginDescriptor ) );
+    public MojoNotFoundException(String goal, PluginDescriptor pluginDescriptor) {
+        super(toMessage(goal, pluginDescriptor));
 
         this.goal = goal;
         this.pluginDescriptor = pluginDescriptor;
     }
 
-    public String getGoal()
-    {
+    public String getGoal() {
         return goal;
     }
 
-    public PluginDescriptor getPluginDescriptor()
-    {
+    public PluginDescriptor getPluginDescriptor() {
         return pluginDescriptor;
     }
 
-    private static String toMessage( String goal, PluginDescriptor pluginDescriptor )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
+    private static String toMessage(String goal, PluginDescriptor pluginDescriptor) {
+        StringBuilder buffer = new StringBuilder(256);
 
-        buffer.append( "Could not find goal '" ).append( goal ).append( '\'' );
+        buffer.append("Could not find goal '").append(goal).append('\'');
 
-        if ( pluginDescriptor != null )
-        {
-            buffer.append( " in plugin " ).append( pluginDescriptor.getId() );
+        if (pluginDescriptor != null) {
+            buffer.append(" in plugin ").append(pluginDescriptor.getId());
 
-            buffer.append( " among available goals " );
+            buffer.append(" among available goals ");
             List<MojoDescriptor> mojos = pluginDescriptor.getMojos();
-            if ( mojos != null )
-            {
-                for ( Iterator<MojoDescriptor> it = mojos.iterator(); it.hasNext(); )
-                {
+            if (mojos != null) {
+                for (Iterator<MojoDescriptor> it = mojos.iterator(); it.hasNext(); ) {
                     MojoDescriptor mojo = it.next();
-                    if ( mojo != null )
-                    {
-                        buffer.append( mojo.getGoal() );
+                    if (mojo != null) {
+                        buffer.append(mojo.getGoal());
                     }
-                    if ( it.hasNext() )
-                    {
-                        buffer.append( ", " );
+                    if (it.hasNext()) {
+                        buffer.append(", ");
                     }
                 }
             }
@@ -84,5 +72,4 @@
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateMojoDescriptorException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateMojoDescriptorException.java
index 8f78e33..a5492d2 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateMojoDescriptorException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateMojoDescriptorException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,20 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 /**
  * DuplicateMojoDescriptorException
  */
-public class DuplicateMojoDescriptorException
-    extends InvalidPluginDescriptorException
-{
+public class DuplicateMojoDescriptorException extends InvalidPluginDescriptorException {
 
-    public DuplicateMojoDescriptorException( String goalPrefix, String goal, String existingImplementation,
-                                             String newImplementation )
-    {
-        super( "Goal: " + goal + " already exists in the plugin descriptor for prefix: " + goalPrefix
-            + System.lineSeparator() + "Existing implementation is: " + existingImplementation
-            + System.lineSeparator() + "Conflicting implementation is: " + newImplementation );
+    public DuplicateMojoDescriptorException(
+            String goalPrefix, String goal, String existingImplementation, String newImplementation) {
+        super("Goal: " + goal + " already exists in the plugin descriptor for prefix: " + goalPrefix
+                + System.lineSeparator() + "Existing implementation is: " + existingImplementation
+                + System.lineSeparator() + "Conflicting implementation is: " + newImplementation);
     }
-
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateParameterException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateParameterException.java
index 69fea1c..fe2bb8c 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateParameterException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/DuplicateParameterException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,17 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 /**
  * DuplicateParameterException
  */
-public class DuplicateParameterException
-    extends InvalidPluginDescriptorException
-{
+public class DuplicateParameterException extends InvalidPluginDescriptorException {
 
-    public DuplicateParameterException( String message )
-    {
-        super( message );
+    public DuplicateParameterException(String message) {
+        super(message);
     }
-
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidParameterException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidParameterException.java
index 557a3d5..3028743 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidParameterException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidParameterException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,20 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 /**
- * @author Jason van Zyl
  */
-public class InvalidParameterException
-    extends InvalidPluginDescriptorException
-{
-    public InvalidParameterException( String element, int i )
-    {
-        super( "The " + element + " element in parameter # " + i + " is invalid. It cannot be null." );
+public class InvalidParameterException extends InvalidPluginDescriptorException {
+    public InvalidParameterException(String element, int i) {
+        super("The " + element + " element in parameter # " + i + " is invalid. It cannot be null.");
     }
 
-    public InvalidParameterException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public InvalidParameterException(String message, Throwable cause) {
+        super(message, cause);
     }
-}
\ No newline at end of file
+}
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidPluginDescriptorException.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidPluginDescriptorException.java
index f63fd26..85d1928 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidPluginDescriptorException.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/InvalidPluginDescriptorException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,24 +16,20 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 import org.codehaus.plexus.configuration.PlexusConfigurationException;
 
 /**
  * InvalidPluginDescriptorException
  */
-public class InvalidPluginDescriptorException
-    extends PlexusConfigurationException
-{
+public class InvalidPluginDescriptorException extends PlexusConfigurationException {
 
-    public InvalidPluginDescriptorException( String message, Throwable cause )
-    {
-        super( message, cause );
+    public InvalidPluginDescriptorException(String message, Throwable cause) {
+        super(message, cause);
     }
 
-    public InvalidPluginDescriptorException( String message )
-    {
-        super( message );
+    public InvalidPluginDescriptorException(String message) {
+        super(message);
     }
-
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/MojoDescriptor.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/MojoDescriptor.java
index f32fbe4..12fe547 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/MojoDescriptor.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/MojoDescriptor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,12 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 import org.apache.maven.plugin.Mojo;
 import org.codehaus.plexus.component.repository.ComponentDescriptor;
@@ -39,10 +39,7 @@
  * TODO is there a need for the delegation of MavenMojoDescriptor to this?
  * Why not just extend ComponentDescriptor here?
  */
-public class MojoDescriptor
-    extends ComponentDescriptor<Mojo>
-    implements Cloneable
-{
+public class MojoDescriptor extends ComponentDescriptor<Mojo> implements Cloneable {
     /** The Plexus component type */
     public static final String MAVEN_PLUGIN = "maven-plugin";
 
@@ -88,8 +85,8 @@
     private String executeLifecycle;
 
     /**
-     * Specify the version when the Mojo was deprecated to the API. Similar to Javadoc deprecated. This will trigger a
-     * warning when a user tries to configure a parameter marked as deprecated.
+     * Description with reason of Mojo deprecation. Similar to Javadoc {@code @deprecated}.
+     * This will trigger a warning when a user tries to use a Mojo marked as deprecated.
      */
     private String deprecated;
 
@@ -139,16 +136,45 @@
      */
     private boolean threadSafe = false;
 
+    private boolean v4Api = false;
+
     /**
      * Default constructor.
      */
-    public MojoDescriptor()
-    {
+    public MojoDescriptor() {
         this.parameters = new ArrayList<>();
-        setInstantiationStrategy( DEFAULT_INSTANTIATION_STRATEGY );
-        setComponentFactory( DEFAULT_LANGUAGE );
+        setInstantiationStrategy(DEFAULT_INSTANTIATION_STRATEGY);
+        setComponentFactory(DEFAULT_LANGUAGE);
     }
 
+    public MojoDescriptor(PluginDescriptor pd, org.apache.maven.api.plugin.descriptor.MojoDescriptor md) {
+        this();
+        this.setPluginDescriptor(pd);
+        this.setGoal(md.getGoal());
+        this.setExecuteGoal(md.getExecuteGoal());
+        this.setExecuteLifecycle(md.getExecuteLifecycle());
+        this.setExecutePhase(md.getExecutePhase());
+        this.setDeprecated(md.getDeprecated());
+        this.setLanguage(md.getLanguage());
+        this.setAggregator(md.isAggregator());
+        this.setDependencyCollectionRequired(md.getDependencyCollection());
+        this.setDependencyResolutionRequired(md.getDependencyResolution());
+        this.setComponentConfigurator(md.getConfigurator());
+        this.setInheritedByDefault(md.isInheritedByDefault());
+        this.setPhase(md.getPhase());
+        this.setOnlineRequired(md.isOnlineRequired());
+        this.setProjectRequired(md.isProjectRequired());
+        this.setSince(md.getSince());
+        this.setThreadSafe(true);
+        this.setV4Api(true);
+        this.setImplementation(md.getImplementation());
+        try {
+            this.setParameters(md.getParameters().stream().map(Parameter::new).collect(Collectors.toList()));
+        } catch (DuplicateParameterException e) {
+            throw new IllegalArgumentException(e);
+        }
+        this.mojoDescriptorV4 = md;
+    }
     // ----------------------------------------------------------------------
     //
     // ----------------------------------------------------------------------
@@ -156,32 +182,28 @@
     /**
      * @return the language of this Mojo, i.e. <code>java</code>
      */
-    public String getLanguage()
-    {
+    public String getLanguage() {
         return getComponentFactory();
     }
 
     /**
      * @param language the new language
      */
-    public void setLanguage( String language )
-    {
-        setComponentFactory( language );
+    public void setLanguage(String language) {
+        setComponentFactory(language);
     }
 
     /**
-     * @return <code>true</code> if the Mojo is deprecated, <code>false</code> otherwise.
+     * @return Description with reason of a Mojo deprecation.
      */
-    public String getDeprecated()
-    {
+    public String getDeprecated() {
         return deprecated;
     }
 
     /**
-     * @param deprecated <code>true</code> to deprecate the Mojo, <code>false</code> otherwise.
+     * @param deprecated Description with reason of a Mojo deprecation.
      */
-    public void setDeprecated( String deprecated )
-    {
+    public void setDeprecated(String deprecated) {
         this.deprecated = deprecated;
     }
 
@@ -189,22 +211,18 @@
      * @return the list of parameters copy. Any change to returned list is NOT reflected on this instance. To add
      * parameters, use {@link #addParameter(Parameter)} method.
      */
-    public List<Parameter> getParameters()
-    {
-        return new ArrayList<>( parameters  );
+    public List<Parameter> getParameters() {
+        return new ArrayList<>(parameters);
     }
 
     /**
      * @param parameters the new list of parameters
      * @throws DuplicateParameterException if any
      */
-    public void setParameters( List<Parameter> parameters )
-        throws DuplicateParameterException
-    {
+    public void setParameters(List<Parameter> parameters) throws DuplicateParameterException {
         this.parameters.clear();
-        for ( Parameter parameter : parameters )
-        {
-            addParameter( parameter );
+        for (Parameter parameter : parameters) {
+            addParameter(parameter);
         }
     }
 
@@ -212,17 +230,14 @@
      * @param parameter add a new parameter
      * @throws DuplicateParameterException if any
      */
-    public void addParameter( Parameter parameter )
-        throws DuplicateParameterException
-    {
-        if ( parameters.contains( parameter ) )
-        {
-            throw new DuplicateParameterException( parameter.getName()
-                + " has been declared multiple times in mojo with goal: " + getGoal() + " (implementation: "
-                + getImplementation() + ")" );
+    public void addParameter(Parameter parameter) throws DuplicateParameterException {
+        if (parameters.contains(parameter)) {
+            throw new DuplicateParameterException(parameter.getName()
+                    + " has been declared multiple times in mojo with goal: " + getGoal() + " (implementation: "
+                    + getImplementation() + ")");
         }
 
-        parameters.add( parameter );
+        parameters.add(parameter);
     }
 
     /**
@@ -230,13 +245,11 @@
      * {@link #parameters} list on each call. In other words, the map returned is built on fly and is a copy.
      * Any change to this map is NOT reflected on list and other way around!
      */
-    public Map<String, Parameter> getParameterMap()
-    {
+    public Map<String, Parameter> getParameterMap() {
         LinkedHashMap<String, Parameter> parameterMap = new LinkedHashMap<>();
 
-        for ( Parameter pd : parameters )
-        {
-            parameterMap.put( pd.getName(), pd );
+        for (Parameter pd : parameters) {
+            parameterMap.put(pd.getName(), pd);
         }
 
         return parameterMap;
@@ -249,13 +262,11 @@
     /**
      * @param requiresDependencyResolution the new required dependencies in a specified scope
      */
-    public void setDependencyResolutionRequired( String requiresDependencyResolution )
-    {
+    public void setDependencyResolutionRequired(String requiresDependencyResolution) {
         this.dependencyResolutionRequired = requiresDependencyResolution;
     }
 
-    public String getDependencyResolutionRequired()
-    {
+    public String getDependencyResolutionRequired() {
         return dependencyResolutionRequired;
     }
 
@@ -264,16 +275,14 @@
      * TODO the name is not intelligible
      */
     @Deprecated
-    public String isDependencyResolutionRequired()
-    {
+    public String isDependencyResolutionRequired() {
         return dependencyResolutionRequired;
     }
 
     /**
      * @since 3.0-alpha-3
      */
-    public void setDependencyCollectionRequired( String requiresDependencyCollection )
-    {
+    public void setDependencyCollectionRequired(String requiresDependencyCollection) {
         this.dependencyCollectionRequired = requiresDependencyCollection;
     }
 
@@ -287,8 +296,7 @@
      * @return The scope of (transitive) dependencies that should be collected or {@code null} if none.
      * @since 3.0-alpha-3
      */
-    public String getDependencyCollectionRequired()
-    {
+    public String getDependencyCollectionRequired() {
         return dependencyCollectionRequired;
     }
 
@@ -300,16 +308,14 @@
      * @param requiresProject <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code>
      * otherwise.
      */
-    public void setProjectRequired( boolean requiresProject )
-    {
+    public void setProjectRequired(boolean requiresProject) {
         this.projectRequired = requiresProject;
     }
 
     /**
      * @return <code>true</code> if the Mojo needs a Maven project to be executed, <code>false</code> otherwise.
      */
-    public boolean isProjectRequired()
-    {
+    public boolean isProjectRequired() {
         return projectRequired;
     }
 
@@ -320,8 +326,7 @@
     /**
      * @param requiresOnline <code>true</code> if the Mojo is online, <code>false</code> otherwise.
      */
-    public void setOnlineRequired( boolean requiresOnline )
-    {
+    public void setOnlineRequired(boolean requiresOnline) {
         this.onlineRequired = requiresOnline;
     }
 
@@ -330,8 +335,7 @@
      */
     // blech! this isn't even intelligible as a method name. provided for
     // consistency...
-    public boolean isOnlineRequired()
-    {
+    public boolean isOnlineRequired() {
         return onlineRequired;
     }
 
@@ -339,107 +343,93 @@
      * @return <code>true</code> if the Mojo is online, <code>false</code> otherwise.
      */
     // more english-friendly method...keep the code clean! :)
-    public boolean requiresOnline()
-    {
+    public boolean requiresOnline() {
         return onlineRequired;
     }
 
     /**
      * @return the bound phase name of the Mojo
      */
-    public String getPhase()
-    {
+    public String getPhase() {
         return phase;
     }
 
     /**
      * @param phase the new bound phase name of the Mojo
      */
-    public void setPhase( String phase )
-    {
+    public void setPhase(String phase) {
         this.phase = phase;
     }
 
     /**
      * @return the version when the Mojo was added to the API
      */
-    public String getSince()
-    {
+    public String getSince() {
         return since;
     }
 
     /**
      * @param since the new version when the Mojo was added to the API
      */
-    public void setSince( String since )
-    {
+    public void setSince(String since) {
         this.since = since;
     }
 
     /**
      * @return The goal name of the Mojo
      */
-    public String getGoal()
-    {
+    public String getGoal() {
         return goal;
     }
 
     /**
      * @param goal The new goal name of the Mojo
      */
-    public void setGoal( String goal )
-    {
+    public void setGoal(String goal) {
         this.goal = goal;
     }
 
     /**
      * @return the invocation phase of the Mojo
      */
-    public String getExecutePhase()
-    {
+    public String getExecutePhase() {
         return executePhase;
     }
 
     /**
      * @param executePhase the new invocation phase of the Mojo
      */
-    public void setExecutePhase( String executePhase )
-    {
+    public void setExecutePhase(String executePhase) {
         this.executePhase = executePhase;
     }
 
     /**
      * @return <code>true</code> if the Mojo uses <code>always</code> for the <code>executionStrategy</code>
      */
-    public boolean alwaysExecute()
-    {
-        return MULTI_PASS_EXEC_STRATEGY.equals( executionStrategy );
+    public boolean alwaysExecute() {
+        return MULTI_PASS_EXEC_STRATEGY.equals(executionStrategy);
     }
 
     /**
      * @return the execution strategy
      */
-    public String getExecutionStrategy()
-    {
+    public String getExecutionStrategy() {
         return executionStrategy;
     }
 
     /**
      * @param executionStrategy the new execution strategy
      */
-    public void setExecutionStrategy( String executionStrategy )
-    {
+    public void setExecutionStrategy(String executionStrategy) {
         this.executionStrategy = executionStrategy;
     }
 
     /**
      * @return the mojo configuration
      */
-    public PlexusConfiguration getMojoConfiguration()
-    {
-        if ( mojoConfiguration == null )
-        {
-            mojoConfiguration = new XmlPlexusConfiguration( "configuration" );
+    public PlexusConfiguration getMojoConfiguration() {
+        if (mojoConfiguration == null) {
+            mojoConfiguration = new XmlPlexusConfiguration("configuration");
         }
         return mojoConfiguration;
     }
@@ -447,28 +437,24 @@
     /**
      * @param mojoConfiguration a new mojo configuration
      */
-    public void setMojoConfiguration( PlexusConfiguration mojoConfiguration )
-    {
+    public void setMojoConfiguration(PlexusConfiguration mojoConfiguration) {
         this.mojoConfiguration = mojoConfiguration;
     }
 
     /** {@inheritDoc} */
-    public String getRole()
-    {
-        return Mojo.ROLE;
+    public String getRole() {
+        return isV4Api() ? "org.apache.maven.api.plugin.Mojo" : Mojo.ROLE;
     }
 
     /** {@inheritDoc} */
-    public String getRoleHint()
-    {
+    public String getRoleHint() {
         return getId();
     }
 
     /**
      * @return the id of the mojo, based on the goal name
      */
-    public String getId()
-    {
+    public String getId() {
         return getPluginDescriptor().getId() + ":" + getGoal();
     }
 
@@ -477,87 +463,75 @@
      * @see PluginDescriptor#getGoalPrefix()
      * @see #getGoal()
      */
-    public String getFullGoalName()
-    {
+    public String getFullGoalName() {
         return getPluginDescriptor().getGoalPrefix() + ":" + getGoal();
     }
 
     /** {@inheritDoc} */
-    public String getComponentType()
-    {
+    public String getComponentType() {
         return MAVEN_PLUGIN;
     }
 
     /**
      * @return the plugin descriptor
      */
-    public PluginDescriptor getPluginDescriptor()
-    {
+    public PluginDescriptor getPluginDescriptor() {
         return pluginDescriptor;
     }
 
     /**
      * @param pluginDescriptor the new plugin descriptor
      */
-    public void setPluginDescriptor( PluginDescriptor pluginDescriptor )
-    {
+    public void setPluginDescriptor(PluginDescriptor pluginDescriptor) {
         this.pluginDescriptor = pluginDescriptor;
     }
 
     /**
      * @return <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
      */
-    public boolean isInheritedByDefault()
-    {
+    public boolean isInheritedByDefault() {
         return inheritedByDefault;
     }
 
     /**
      * @param inheritedByDefault <code>true</code> if the Mojo is inherited, <code>false</code> otherwise.
      */
-    public void setInheritedByDefault( boolean inheritedByDefault )
-    {
+    public void setInheritedByDefault(boolean inheritedByDefault) {
         this.inheritedByDefault = inheritedByDefault;
     }
 
     /** {@inheritDoc} */
-    public boolean equals( Object object )
-    {
-        if ( this == object )
-        {
+    public boolean equals(Object object) {
+        if (this == object) {
             return true;
         }
 
-        if ( object instanceof MojoDescriptor )
-        {
+        if (object instanceof MojoDescriptor) {
             MojoDescriptor other = (MojoDescriptor) object;
 
-            return Objects.equals( getPluginDescriptor(), other.getPluginDescriptor() )
-                    && Objects.equals( getGoal(), other.getGoal() );
+            return Objects.equals(getPluginDescriptor(), other.getPluginDescriptor())
+                    && Objects.equals(getGoal(), other.getGoal());
         }
 
         return false;
     }
 
     /** {@inheritDoc} */
-    public int hashCode()
-    {
-        return Objects.hash( getGoal(), getPluginDescriptor() );
+    public int hashCode() {
+        return Objects.hash(getGoal(), getPluginDescriptor());
     }
 
     /**
      * @return the invocation lifecycle of the Mojo
      */
-    public String getExecuteLifecycle()
-    {
+    public String getExecuteLifecycle() {
         return executeLifecycle;
     }
 
     /**
      * @param executeLifecycle the new invocation lifecycle of the Mojo
      */
-    public void setExecuteLifecycle( String executeLifecycle )
-    {
+    public void setExecuteLifecycle(String executeLifecycle) {
         this.executeLifecycle = executeLifecycle;
     }
 
@@ -565,8 +539,7 @@
      * @param aggregator <code>true</code> if the Mojo uses the Maven project and its child modules,
      * <code>false</code> otherwise.
      */
-    public void setAggregator( boolean aggregator )
-    {
+    public void setAggregator(boolean aggregator) {
         this.aggregator = aggregator;
     }
 
@@ -574,16 +547,14 @@
      * @return <code>true</code> if the Mojo uses the Maven project and its child modules,
      * <code>false</code> otherwise.
      */
-    public boolean isAggregator()
-    {
+    public boolean isAggregator() {
         return aggregator;
     }
 
     /**
      * @return <code>true</code> if the Mojo cannot be invoked directly, <code>false</code> otherwise.
      */
-    public boolean isDirectInvocationOnly()
-    {
+    public boolean isDirectInvocationOnly() {
         return directInvocationOnly;
     }
 
@@ -591,50 +562,43 @@
      * @param directInvocationOnly <code>true</code> if the Mojo cannot be invoked directly,
      * <code>false</code> otherwise.
      */
-    public void setDirectInvocationOnly( boolean directInvocationOnly )
-    {
+    public void setDirectInvocationOnly(boolean directInvocationOnly) {
         this.directInvocationOnly = directInvocationOnly;
     }
 
     /**
      * @return <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
      */
-    public boolean isRequiresReports()
-    {
+    public boolean isRequiresReports() {
         return requiresReports;
     }
 
     /**
      * @param requiresReports <code>true</code> if the Mojo needs reports to run, <code>false</code> otherwise.
      */
-    public void setRequiresReports( boolean requiresReports )
-    {
+    public void setRequiresReports(boolean requiresReports) {
         this.requiresReports = requiresReports;
     }
 
     /**
      * @param executeGoal the new invocation goal of the Mojo
      */
-    public void setExecuteGoal( String executeGoal )
-    {
+    public void setExecuteGoal(String executeGoal) {
         this.executeGoal = executeGoal;
     }
 
     /**
      * @return the invocation goal of the Mojo
      */
-    public String getExecuteGoal()
-    {
+    public String getExecuteGoal() {
         return executeGoal;
     }
 
-
     /**
      * @return True if the <code>Mojo</code> is thread-safe and can be run safely in parallel
      * @since 3.0-beta-2
      */
-    public boolean isThreadSafe()
-    {
+    public boolean isThreadSafe() {
         return threadSafe;
     }
 
@@ -642,34 +606,72 @@
      * @param threadSafe indicates that the mojo is thread-safe and can be run safely in parallel
      * @since 3.0-beta-2
      */
-    public void setThreadSafe( boolean threadSafe )
-    {
+    public void setThreadSafe(boolean threadSafe) {
         this.threadSafe = threadSafe;
     }
 
     /**
      * @return {@code true} if this mojo forks either a goal or the lifecycle, {@code false} otherwise.
      */
-    public boolean isForking()
-    {
-        return ( getExecuteGoal() != null && getExecuteGoal().length() > 0 )
-            || ( getExecutePhase() != null && getExecutePhase().length() > 0 );
+    public boolean isForking() {
+        return (getExecuteGoal() != null && getExecuteGoal().length() > 0)
+                || (getExecutePhase() != null && getExecutePhase().length() > 0);
+    }
+
+    public boolean isV4Api() {
+        return v4Api;
+    }
+
+    public void setV4Api(boolean v4Api) {
+        this.v4Api = v4Api;
     }
 
     /**
      * Creates a shallow copy of this mojo descriptor.
      */
     @Override
-    public MojoDescriptor clone()
-    {
-        try
-        {
+    public MojoDescriptor clone() {
+        try {
             return (MojoDescriptor) super.clone();
-        }
-        catch ( CloneNotSupportedException e )
-        {
-            throw new UnsupportedOperationException( e );
+        } catch (CloneNotSupportedException e) {
+            throw new UnsupportedOperationException(e);
         }
     }
 
+    private volatile org.apache.maven.api.plugin.descriptor.MojoDescriptor mojoDescriptorV4;
+
+    public org.apache.maven.api.plugin.descriptor.MojoDescriptor getMojoDescriptorV4() {
+        if (mojoDescriptorV4 == null) {
+            synchronized (this) {
+                if (mojoDescriptorV4 == null) {
+                    mojoDescriptorV4 = org.apache.maven.api.plugin.descriptor.MojoDescriptor.newBuilder()
+                            .goal(goal)
+                            .description(getDescription())
+                            .implementation(getImplementation())
+                            .language(getLanguage())
+                            .phase(phase)
+                            .executeGoal(executeGoal)
+                            .executeLifecycle(executeLifecycle)
+                            .executePhase(executePhase)
+                            .aggregator(aggregator)
+                            .dependencyResolution(dependencyResolutionRequired)
+                            .dependencyCollection(dependencyCollectionRequired)
+                            .projectRequired(projectRequired)
+                            .onlineRequired(onlineRequired)
+                            .inheritedByDefault(inheritedByDefault)
+                            .since(since)
+                            .deprecated(deprecated)
+                            .configurator(getComponentConfigurator())
+                            .parameters(getParameters().stream()
+                                    .filter(p -> p.getRequirement() == null)
+                                    .map(Parameter::getParameterV4)
+                                    .collect(Collectors.toList()))
+                            .id(getId())
+                            .fullGoalName(getFullGoalName())
+                            .build();
+                }
+            }
+        }
+        return mojoDescriptorV4;
+    }
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Parameter.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Parameter.java
index 14fd2f0..0249b1d 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Parameter.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Parameter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,13 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 /**
- * @author Jason van Zyl
  */
-public class Parameter
-    implements Cloneable
-{
+public class Parameter implements Cloneable {
     private String alias;
 
     private String name;
@@ -53,138 +49,130 @@
     //
     // ----------------------------------------------------------------------
 
-    public String getName()
-    {
+    public Parameter() {}
+
+    public Parameter(org.apache.maven.api.plugin.descriptor.Parameter p) {
+        this.setAlias(p.getAlias());
+        this.setName(p.getName());
+        this.setRequired(p.isRequired());
+        this.setEditable(p.isEditable());
+        this.setDescription(p.getDescription());
+        this.setExpression(p.getExpression());
+        this.setDeprecated(p.getDeprecated());
+        this.setDefaultValue(p.getDefaultValue());
+        this.setType(p.getType());
+        this.setSince(p.getSince());
+    }
+
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    public String getName() {
         return name;
     }
 
-    public void setName( String name )
-    {
+    public void setName(String name) {
         this.name = name;
     }
 
-    public String getType()
-    {
+    public String getType() {
         return type;
     }
 
-    public void setType( String type )
-    {
+    public void setType(String type) {
         this.type = type;
     }
 
-    public boolean isRequired()
-    {
+    public boolean isRequired() {
         return required;
     }
 
-    public void setRequired( boolean required )
-    {
+    public void setRequired(boolean required) {
         this.required = required;
     }
 
-    public String getDescription()
-    {
+    public String getDescription() {
         return description;
     }
 
-    public void setDescription( String description )
-    {
+    public void setDescription(String description) {
         this.description = description;
     }
 
-    public String getExpression()
-    {
+    public String getExpression() {
         return expression;
     }
 
-    public void setExpression( String expression )
-    {
+    public void setExpression(String expression) {
         this.expression = expression;
     }
 
-    public String getDeprecated()
-    {
+    public String getDeprecated() {
         return deprecated;
     }
 
-    public void setDeprecated( String deprecated )
-    {
+    public void setDeprecated(String deprecated) {
         this.deprecated = deprecated;
     }
 
-    public int hashCode()
-    {
+    public int hashCode() {
         return name.hashCode();
     }
 
-    public boolean equals( Object other )
-    {
-        return ( other instanceof Parameter ) && getName().equals( ( (Parameter) other ).getName() );
+    public boolean equals(Object other) {
+        return (other instanceof Parameter) && getName().equals(((Parameter) other).getName());
     }
 
-    public String getAlias()
-    {
+    public String getAlias() {
         return alias;
     }
 
-    public void setAlias( String alias )
-    {
+    public void setAlias(String alias) {
         this.alias = alias;
     }
 
-    public boolean isEditable()
-    {
+    public boolean isEditable() {
         return editable;
     }
 
-    public void setEditable( boolean editable )
-    {
+    public void setEditable(boolean editable) {
         this.editable = editable;
     }
 
-    public void setDefaultValue( String defaultValue )
-    {
+    public void setDefaultValue(String defaultValue) {
         this.defaultValue = defaultValue;
     }
 
-    public String getDefaultValue()
-    {
+    public String getDefaultValue() {
         return defaultValue;
     }
 
-    public String toString()
-    {
+    public String toString() {
         return "Mojo parameter [name: '" + getName() + "'; alias: '" + getAlias() + "']";
     }
 
-    public Requirement getRequirement()
-    {
+    public Requirement getRequirement() {
         return requirement;
     }
 
-    public void setRequirement( Requirement requirement )
-    {
+    public void setRequirement(Requirement requirement) {
         this.requirement = requirement;
     }
 
-    public String getImplementation()
-    {
+    public String getImplementation() {
         return implementation;
     }
 
-    public void setImplementation( String implementation )
-    {
+    public void setImplementation(String implementation) {
         this.implementation = implementation;
     }
 
-    public String getSince()
-    {
+    public String getSince() {
         return since;
     }
 
-    public void setSince( String since )
-    {
+    public void setSince(String since) {
         this.since = since;
     }
 
@@ -192,16 +180,26 @@
      * Creates a shallow copy of this parameter.
      */
     @Override
-    public Parameter clone()
-    {
-        try
-        {
+    public Parameter clone() {
+        try {
             return (Parameter) super.clone();
-        }
-        catch ( CloneNotSupportedException e )
-        {
-            throw new UnsupportedOperationException( e );
+        } catch (CloneNotSupportedException e) {
+            throw new UnsupportedOperationException(e);
         }
     }
 
+    public org.apache.maven.api.plugin.descriptor.Parameter getParameterV4() {
+        return org.apache.maven.api.plugin.descriptor.Parameter.newBuilder()
+                .alias(alias)
+                .name(name)
+                .type(type)
+                .required(required)
+                .editable(editable)
+                .description(description)
+                .expression(expression)
+                .deprecated(deprecated)
+                .defaultValue(defaultValue)
+                .since(since)
+                .build();
+    }
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
index 2d4e1ef..482fcda 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,41 +16,44 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
-import org.apache.maven.artifact.Artifact;
-import org.apache.maven.artifact.ArtifactUtils;
-import org.apache.maven.model.Plugin;
-import org.apache.maven.plugin.lifecycle.Lifecycle;
-import org.apache.maven.plugin.lifecycle.LifecycleConfiguration;
-import org.apache.maven.plugin.lifecycle.io.xpp3.LifecycleMappingsXpp3Reader;
-import org.codehaus.plexus.classworlds.realm.ClassRealm;
-import org.codehaus.plexus.component.repository.ComponentSetDescriptor;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.Reader;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.nio.file.Files;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.plugin.descriptor.lifecycle.Lifecycle;
+import org.apache.maven.api.plugin.descriptor.lifecycle.LifecycleConfiguration;
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.artifact.ArtifactUtils;
+import org.apache.maven.model.Plugin;
+import org.apache.maven.plugin.lifecycle.io.LifecycleStaxReader;
+import org.codehaus.plexus.classworlds.realm.ClassRealm;
+import org.codehaus.plexus.component.repository.ComponentDescriptor;
+import org.codehaus.plexus.component.repository.ComponentSetDescriptor;
+import org.eclipse.aether.graph.DependencyNode;
 
 /**
- * @author Jason van Zyl
  */
-public class PluginDescriptor
-    extends ComponentSetDescriptor
-    implements Cloneable
-{
+public class PluginDescriptor extends ComponentSetDescriptor implements Cloneable {
 
     private static final String LIFECYCLE_DESCRIPTOR = "META-INF/maven/lifecycle.xml";
 
+    private static final Pattern PATTERN_FILTER_1 = Pattern.compile("-?(maven|plugin)-?");
+
     private String groupId;
 
     private String artifactId;
@@ -67,6 +68,8 @@
 
     private List<Artifact> artifacts;
 
+    private DependencyNode dependencyNode;
+
     private ClassRealm classRealm;
 
     // calculated on-demand.
@@ -80,6 +83,8 @@
 
     private String requiredMavenVersion;
 
+    private String requiredJavaVersion;
+
     private Plugin plugin;
 
     private Artifact pluginArtifact;
@@ -90,57 +95,109 @@
     //
     // ----------------------------------------------------------------------
 
-    @SuppressWarnings( { "unchecked", "rawtypes" } )
-    public List<MojoDescriptor> getMojos()
-    {
+    public PluginDescriptor() {}
+
+    public PluginDescriptor(PluginDescriptor original) {
+        this.setGroupId(original.getGroupId());
+        this.setArtifactId(original.getArtifactId());
+        this.setVersion(original.getVersion());
+        this.setGoalPrefix(original.getGoalPrefix());
+        this.setInheritedByDefault(original.isInheritedByDefault());
+        this.setName(original.getName());
+        this.setDescription(original.getDescription());
+        this.setRequiredMavenVersion(original.getRequiredMavenVersion());
+        this.setRequiredJavaVersion(original.getRequiredJavaVersion());
+        this.setPluginArtifact(ArtifactUtils.copyArtifactSafe(original.getPluginArtifact()));
+        this.setComponents(clone(original.getMojos(), this));
+        this.setId(original.getId());
+        this.setIsolatedRealm(original.isIsolatedRealm());
+        this.setSource(original.getSource());
+        this.setDependencies(original.getDependencies());
+        this.setDependencyNode(original.getDependencyNode());
+    }
+
+    private static List<ComponentDescriptor<?>> clone(List<MojoDescriptor> mojos, PluginDescriptor pluginDescriptor) {
+        List<ComponentDescriptor<?>> clones = null;
+        if (mojos != null) {
+            clones = new ArrayList<>(mojos.size());
+            for (MojoDescriptor mojo : mojos) {
+                MojoDescriptor clone = mojo.clone();
+                clone.setPluginDescriptor(pluginDescriptor);
+                clones.add(clone);
+            }
+        }
+        return clones;
+    }
+
+    public PluginDescriptor(org.apache.maven.api.plugin.descriptor.PluginDescriptor original) {
+        this.setGroupId(original.getGroupId());
+        this.setArtifactId(original.getArtifactId());
+        this.setVersion(original.getVersion());
+        this.setGoalPrefix(original.getGoalPrefix());
+        this.setInheritedByDefault(original.isInheritedByDefault());
+        this.setName(original.getName());
+        this.setDescription(original.getDescription());
+        this.setRequiredMavenVersion(original.getRequiredMavenVersion());
+        this.setRequiredJavaVersion(original.getRequiredJavaVersion());
+        this.setPluginArtifact(null); // TODO: v4
+        this.setComponents(Collections.emptyList()); // TODO: v4
+        this.setComponents(original.getMojos().stream()
+                .map(m -> new MojoDescriptor(this, m))
+                .collect(Collectors.toList()));
+        this.setId(original.getId());
+        this.setIsolatedRealm(original.isIsolatedRealm());
+        this.setSource(null);
+        this.setDependencies(Collections.emptyList()); // TODO: v4
+        this.setDependencyNode(null); // TODO: v4
+        this.pluginDescriptorV4 = original;
+    }
+
+    // ----------------------------------------------------------------------
+    //
+    // ----------------------------------------------------------------------
+
+    @SuppressWarnings({"unchecked", "rawtypes"})
+    public List<MojoDescriptor> getMojos() {
         return (List) getComponents();
     }
 
-    public void addMojo( MojoDescriptor mojoDescriptor )
-        throws DuplicateMojoDescriptorException
-    {
+    public void addMojo(MojoDescriptor mojoDescriptor) throws DuplicateMojoDescriptorException {
         MojoDescriptor existing = null;
         // this relies heavily on the equals() and hashCode() for ComponentDescriptor,
         // which uses role:roleHint for identity...and roleHint == goalPrefix:goal.
         // role does not vary for Mojos.
         List<MojoDescriptor> mojos = getMojos();
 
-        if ( mojos != null && mojos.contains( mojoDescriptor ) )
-        {
-            int indexOf = mojos.indexOf( mojoDescriptor );
+        if (mojos != null && mojos.contains(mojoDescriptor)) {
+            int indexOf = mojos.indexOf(mojoDescriptor);
 
-            existing = mojos.get( indexOf );
+            existing = mojos.get(indexOf);
         }
 
-        if ( existing != null )
-        {
-            throw new DuplicateMojoDescriptorException( getGoalPrefix(), mojoDescriptor.getGoal(),
-                                                        existing.getImplementation(),
-                                                        mojoDescriptor.getImplementation() );
-        }
-        else
-        {
-            addComponentDescriptor( mojoDescriptor );
+        if (existing != null) {
+            throw new DuplicateMojoDescriptorException(
+                    getGoalPrefix(),
+                    mojoDescriptor.getGoal(),
+                    existing.getImplementation(),
+                    mojoDescriptor.getImplementation());
+        } else {
+            addComponentDescriptor(mojoDescriptor);
         }
     }
 
-    public String getGroupId()
-    {
+    public String getGroupId() {
         return groupId;
     }
 
-    public void setGroupId( String groupId )
-    {
+    public void setGroupId(String groupId) {
         this.groupId = groupId;
     }
 
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return artifactId;
     }
 
-    public void setArtifactId( String artifactId )
-    {
+    public void setArtifactId(String artifactId) {
         this.artifactId = artifactId;
     }
 
@@ -148,28 +205,23 @@
     // Dependencies
     // ----------------------------------------------------------------------
 
-    public static String constructPluginKey( String groupId, String artifactId, String version )
-    {
+    public static String constructPluginKey(String groupId, String artifactId, String version) {
         return groupId + ":" + artifactId + ":" + version;
     }
 
-    public String getPluginLookupKey()
-    {
+    public String getPluginLookupKey() {
         return groupId + ":" + artifactId;
     }
 
-    public String getId()
-    {
-        return constructPluginKey( groupId, artifactId, version );
+    public String getId() {
+        return constructPluginKey(groupId, artifactId, version);
     }
 
-    public static String getDefaultPluginArtifactId( String id )
-    {
+    public static String getDefaultPluginArtifactId(String id) {
         return "maven-" + id + "-plugin";
     }
 
-    public static String getDefaultPluginGroupId()
-    {
+    public static String getDefaultPluginGroupId() {
         return "org.apache.maven.plugins";
     }
 
@@ -178,55 +230,43 @@
      *
      * TODO move to plugin-tools-api as a default only
      */
-    public static String getGoalPrefixFromArtifactId( String artifactId )
-    {
-        if ( "maven-plugin-plugin".equals( artifactId ) )
-        {
+    public static String getGoalPrefixFromArtifactId(String artifactId) {
+        if ("maven-plugin-plugin".equals(artifactId)) {
             return "plugin";
-        }
-        else
-        {
-            return artifactId.replaceAll( "-?maven-?", "" ).replaceAll( "-?plugin-?", "" );
+        } else {
+            return PATTERN_FILTER_1.matcher(artifactId).replaceAll("");
         }
     }
 
-    public String getGoalPrefix()
-    {
+    public String getGoalPrefix() {
         return goalPrefix;
     }
 
-    public void setGoalPrefix( String goalPrefix )
-    {
+    public void setGoalPrefix(String goalPrefix) {
         this.goalPrefix = goalPrefix;
     }
 
-    public void setVersion( String version )
-    {
+    public void setVersion(String version) {
         this.version = version;
     }
 
-    public String getVersion()
-    {
+    public String getVersion() {
         return version;
     }
 
-    public void setSource( String source )
-    {
+    public void setSource(String source) {
         this.source = source;
     }
 
-    public String getSource()
-    {
+    public String getSource() {
         return source;
     }
 
-    public boolean isInheritedByDefault()
-    {
+    public boolean isInheritedByDefault() {
         return inheritedByDefault;
     }
 
-    public void setInheritedByDefault( boolean inheritedByDefault )
-    {
+    public void setInheritedByDefault(boolean inheritedByDefault) {
         this.inheritedByDefault = inheritedByDefault;
     }
 
@@ -236,187 +276,165 @@
      *
      * @return The plugin artifacts, never {@code null}.
      */
-    public List<Artifact> getArtifacts()
-    {
+    public List<Artifact> getArtifacts() {
         return artifacts;
     }
 
-    public void setArtifacts( List<Artifact> artifacts )
-    {
+    public void setArtifacts(List<Artifact> artifacts) {
         this.artifacts = artifacts;
 
         // clear the calculated artifactMap
         artifactMap = null;
     }
 
+    public DependencyNode getDependencyNode() {
+        return dependencyNode;
+    }
+
+    public void setDependencyNode(DependencyNode dependencyNode) {
+        this.dependencyNode = dependencyNode;
+    }
+
     /**
      * The map of artifacts accessible by the versionlessKey, i.e. groupId:artifactId
      *
      * @return a Map of artifacts, never {@code null}
      * @see #getArtifacts()
      */
-    public Map<String, Artifact> getArtifactMap()
-    {
-        if ( artifactMap == null )
-        {
-            artifactMap = ArtifactUtils.artifactMapByVersionlessId( getArtifacts() );
+    public Map<String, Artifact> getArtifactMap() {
+        if (artifactMap == null) {
+            artifactMap = ArtifactUtils.artifactMapByVersionlessId(getArtifacts());
         }
 
         return artifactMap;
     }
 
-    public boolean equals( Object object )
-    {
-        if ( this == object )
-        {
+    public boolean equals(Object object) {
+        if (this == object) {
             return true;
         }
 
-        return object instanceof PluginDescriptor && getId().equals( ( (PluginDescriptor) object ).getId() );
+        return object instanceof PluginDescriptor && getId().equals(((PluginDescriptor) object).getId());
     }
 
-    public int hashCode()
-    {
+    public int hashCode() {
         return 10 + getId().hashCode();
     }
 
-    public MojoDescriptor getMojo( String goal )
-    {
-        if ( getMojos() == null )
-        {
+    public MojoDescriptor getMojo(String goal) {
+        if (getMojos() == null) {
             return null; // no mojo in this POM
         }
 
         // TODO could we use a map? Maybe if the parent did that for components too, as this is too vulnerable to
         // changes above not being propagated to the map
-        for ( MojoDescriptor desc : getMojos() )
-        {
-            if ( goal.equals( desc.getGoal() ) )
-            {
+        for (MojoDescriptor desc : getMojos()) {
+            if (goal.equals(desc.getGoal())) {
                 return desc;
             }
         }
         return null;
     }
 
-    public void setClassRealm( ClassRealm classRealm )
-    {
+    public void setClassRealm(ClassRealm classRealm) {
         this.classRealm = classRealm;
     }
 
-    public ClassRealm getClassRealm()
-    {
+    public ClassRealm getClassRealm() {
         return classRealm;
     }
 
-    public void setIntroducedDependencyArtifacts( Set<Artifact> introducedDependencyArtifacts )
-    {
+    public void setIntroducedDependencyArtifacts(Set<Artifact> introducedDependencyArtifacts) {
         this.introducedDependencyArtifacts = introducedDependencyArtifacts;
     }
 
-    public Set<Artifact> getIntroducedDependencyArtifacts()
-    {
-        return ( introducedDependencyArtifacts != null )
-            ? introducedDependencyArtifacts
-            : Collections.emptySet();
+    public Set<Artifact> getIntroducedDependencyArtifacts() {
+        return (introducedDependencyArtifacts != null) ? introducedDependencyArtifacts : Collections.emptySet();
     }
 
-    public void setName( String name )
-    {
+    public void setName(String name) {
         this.name = name;
     }
 
-    public String getName()
-    {
+    public String getName() {
         return name;
     }
 
-    public void setDescription( String description )
-    {
+    public void setDescription(String description) {
         this.description = description;
     }
 
-    public String getDescription()
-    {
+    public String getDescription() {
         return description;
     }
 
-    public void setRequiredMavenVersion( String requiredMavenVersion )
-    {
+    public void setRequiredMavenVersion(String requiredMavenVersion) {
         this.requiredMavenVersion = requiredMavenVersion;
     }
 
-    public String getRequiredMavenVersion()
-    {
+    public String getRequiredMavenVersion() {
         return requiredMavenVersion;
     }
 
-    public void setPlugin( Plugin plugin )
-    {
+    public void setRequiredJavaVersion(String requiredJavaVersion) {
+        this.requiredJavaVersion = requiredJavaVersion;
+    }
+
+    public String getRequiredJavaVersion() {
+        return requiredJavaVersion;
+    }
+
+    public void setPlugin(Plugin plugin) {
         this.plugin = plugin;
     }
 
-    public Plugin getPlugin()
-    {
+    public Plugin getPlugin() {
         return plugin;
     }
 
-    public Artifact getPluginArtifact()
-    {
+    public Artifact getPluginArtifact() {
         return pluginArtifact;
     }
 
-    public void setPluginArtifact( Artifact pluginArtifact )
-    {
+    public void setPluginArtifact(Artifact pluginArtifact) {
         this.pluginArtifact = pluginArtifact;
     }
 
-    public Lifecycle getLifecycleMapping( String lifecycleId )
-        throws IOException, XmlPullParserException
-    {
-        if ( lifecycleMappings == null )
-        {
+    public Lifecycle getLifecycleMapping(String lifecycleId) throws IOException, XMLStreamException {
+        return getLifecycleMappings().get(lifecycleId);
+    }
+
+    public Map<String, Lifecycle> getLifecycleMappings() throws IOException, XMLStreamException {
+        if (lifecycleMappings == null) {
             LifecycleConfiguration lifecycleConfiguration;
 
-            try ( Reader reader = ReaderFactory.newXmlReader( getDescriptorStream( LIFECYCLE_DESCRIPTOR ) ) )
-            {
-                lifecycleConfiguration = new LifecycleMappingsXpp3Reader().read( reader );
+            try (InputStream input = getDescriptorStream(LIFECYCLE_DESCRIPTOR)) {
+                lifecycleConfiguration = new LifecycleStaxReader().read(input);
             }
 
             lifecycleMappings = new HashMap<>();
 
-            for ( Lifecycle lifecycle : lifecycleConfiguration.getLifecycles() )
-            {
-                lifecycleMappings.put( lifecycle.getId(), lifecycle );
+            for (Lifecycle lifecycle : lifecycleConfiguration.getLifecycles()) {
+                lifecycleMappings.put(lifecycle.getId(), lifecycle);
             }
         }
-
-        return lifecycleMappings.get( lifecycleId );
+        return lifecycleMappings;
     }
 
-    private InputStream getDescriptorStream( String descriptor )
-        throws IOException
-    {
-        File pluginFile = ( pluginArtifact != null ) ? pluginArtifact.getFile() : null;
-        if ( pluginFile == null )
-        {
-            throw new IllegalStateException( "plugin main artifact has not been resolved for " + getId() );
+    private InputStream getDescriptorStream(String descriptor) throws IOException {
+        File pluginFile = (pluginArtifact != null) ? pluginArtifact.getFile() : null;
+        if (pluginFile == null) {
+            throw new IllegalStateException("plugin main artifact has not been resolved for " + getId());
         }
 
-        if ( pluginFile.isFile() )
-        {
-            try
-            {
-                return new URL( "jar:" + pluginFile.toURI() + "!/" + descriptor ).openStream();
+        if (pluginFile.isFile()) {
+            try {
+                return new URL("jar:" + pluginFile.toURI() + "!/" + descriptor).openStream();
+            } catch (MalformedURLException e) {
+                throw new IllegalStateException(e);
             }
-            catch ( MalformedURLException e )
-            {
-                throw new IllegalStateException( e );
-            }
-        }
-        else
-        {
-            return new FileInputStream( new File( pluginFile, descriptor ) );
+        } else {
+            return Files.newInputStream(new File(pluginFile, descriptor).toPath());
         }
     }
 
@@ -424,26 +442,46 @@
      * Creates a shallow copy of this plugin descriptor.
      */
     @Override
-    public PluginDescriptor clone()
-    {
-        try
-        {
+    public PluginDescriptor clone() {
+        try {
             return (PluginDescriptor) super.clone();
-        }
-        catch ( CloneNotSupportedException e )
-        {
-            throw new UnsupportedOperationException( e );
+        } catch (CloneNotSupportedException e) {
+            throw new UnsupportedOperationException(e);
         }
     }
 
-    public void addMojos( List<MojoDescriptor> mojos )
-        throws DuplicateMojoDescriptorException
-    {
-        for ( MojoDescriptor mojoDescriptor : mojos )
-        {
-            addMojo( mojoDescriptor );
+    public void addMojos(List<MojoDescriptor> mojos) throws DuplicateMojoDescriptorException {
+        for (MojoDescriptor mojoDescriptor : mojos) {
+            addMojo(mojoDescriptor);
         }
-
     }
 
+    private volatile org.apache.maven.api.plugin.descriptor.PluginDescriptor pluginDescriptorV4;
+
+    public org.apache.maven.api.plugin.descriptor.PluginDescriptor getPluginDescriptorV4() {
+        if (pluginDescriptorV4 == null) {
+            synchronized (this) {
+                if (pluginDescriptorV4 == null) {
+                    pluginDescriptorV4 = org.apache.maven.api.plugin.descriptor.PluginDescriptor.newBuilder()
+                            .namespaceUri(null)
+                            .modelEncoding(null)
+                            .name(name)
+                            .description(description)
+                            .groupId(groupId)
+                            .artifactId(artifactId)
+                            .version(version)
+                            .goalPrefix(goalPrefix)
+                            .isolatedRealm(isIsolatedRealm())
+                            .inheritedByDefault(inheritedByDefault)
+                            .requiredJavaVersion(requiredJavaVersion)
+                            .requiredMavenVersion(requiredMavenVersion)
+                            .mojos(getMojos().stream()
+                                    .map(MojoDescriptor::getMojoDescriptorV4)
+                                    .collect(Collectors.toList()))
+                            .build();
+                }
+            }
+        }
+        return pluginDescriptorV4;
+    }
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java
index 5747d16..89d31b7 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,355 +16,433 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.Reader;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
+import com.ctc.wstx.stax.WstxInputFactory;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+import org.apache.maven.internal.xml.XmlPlexusConfiguration;
+import org.apache.maven.plugin.descriptor.io.PluginDescriptorStaxReader;
 import org.codehaus.plexus.component.repository.ComponentDependency;
 import org.codehaus.plexus.component.repository.ComponentRequirement;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
 import org.codehaus.plexus.configuration.PlexusConfigurationException;
-import org.codehaus.plexus.configuration.xml.XmlPlexusConfiguration;
-import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
 
 /**
- * @author Jason van Zyl
  */
-public class PluginDescriptorBuilder
-{
-    public PluginDescriptor build( Reader reader )
-        throws PlexusConfigurationException
-    {
-        return build( reader, null );
+public class PluginDescriptorBuilder {
+
+    public static final String PLUGIN_2_0_0 = "http://maven.apache.org/PLUGIN/2.0.0";
+    private static final int BUFFER_SIZE = 8192;
+
+    public interface StreamSupplier {
+        InputStream open() throws IOException;
     }
 
-    public PluginDescriptor build( Reader reader, String source )
-        throws PlexusConfigurationException
-    {
-        return build( source, buildConfiguration( reader ) );
+    public interface ReaderSupplier {
+        Reader open() throws IOException;
     }
 
-    private PluginDescriptor build( String source, PlexusConfiguration c )
-        throws PlexusConfigurationException
-    {
+    /**
+     * @deprecated use {@link #build(ReaderSupplier)}
+     */
+    @Deprecated
+    public PluginDescriptor build(Reader reader) throws PlexusConfigurationException {
+        return build(reader, null);
+    }
+
+    /**
+     * @deprecated use {@link #build(ReaderSupplier, String)}
+     */
+    @Deprecated
+    public PluginDescriptor build(Reader reader, String source) throws PlexusConfigurationException {
+        return build(() -> reader, source);
+    }
+
+    public PluginDescriptor build(ReaderSupplier readerSupplier) throws PlexusConfigurationException {
+        return build(readerSupplier, null);
+    }
+
+    public PluginDescriptor build(ReaderSupplier readerSupplier, String source) throws PlexusConfigurationException {
+        try (BufferedReader br = new BufferedReader(readerSupplier.open(), BUFFER_SIZE)) {
+            br.mark(BUFFER_SIZE);
+            XMLStreamReader xsr = WstxInputFactory.newFactory().createXMLStreamReader(br);
+            xsr.nextTag();
+            String nsUri = xsr.getNamespaceURI();
+            try (BufferedReader br2 = reset(readerSupplier, br)) {
+                xsr = WstxInputFactory.newFactory().createXMLStreamReader(br2);
+                return build(source, nsUri, xsr);
+            }
+        } catch (XMLStreamException | IOException e) {
+            throw new PlexusConfigurationException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #build(StreamSupplier, String)}
+     */
+    @Deprecated
+    public PluginDescriptor build(InputStream input, String source) throws PlexusConfigurationException {
+        return build(() -> input, source);
+    }
+
+    public PluginDescriptor build(StreamSupplier inputSupplier) throws PlexusConfigurationException {
+        return build(inputSupplier, null);
+    }
+
+    public PluginDescriptor build(StreamSupplier inputSupplier, String source) throws PlexusConfigurationException {
+        try (BufferedInputStream bis = new BufferedInputStream(inputSupplier.open(), BUFFER_SIZE)) {
+            bis.mark(BUFFER_SIZE);
+            XMLStreamReader xsr = WstxInputFactory.newFactory().createXMLStreamReader(bis);
+            xsr.nextTag();
+            String nsUri = xsr.getNamespaceURI();
+            try (BufferedInputStream bis2 = reset(inputSupplier, bis)) {
+                xsr = WstxInputFactory.newFactory().createXMLStreamReader(bis2);
+                return build(source, nsUri, xsr);
+            }
+        } catch (XMLStreamException | IOException e) {
+            throw new PlexusConfigurationException(e.getMessage(), e);
+        }
+    }
+
+    private static BufferedInputStream reset(StreamSupplier inputSupplier, BufferedInputStream bis) throws IOException {
+        try {
+            bis.reset();
+            return bis;
+        } catch (IOException e) {
+            return new BufferedInputStream(inputSupplier.open(), BUFFER_SIZE);
+        }
+    }
+
+    private static BufferedReader reset(ReaderSupplier readerSupplier, BufferedReader br) throws IOException {
+        try {
+            br.reset();
+            return br;
+        } catch (IOException e) {
+            return new BufferedReader(readerSupplier.open(), BUFFER_SIZE);
+        }
+    }
+
+    private PluginDescriptor build(String source, String nsUri, XMLStreamReader xsr)
+            throws XMLStreamException, PlexusConfigurationException {
+        if (PLUGIN_2_0_0.equals(nsUri)) {
+            org.apache.maven.api.plugin.descriptor.PluginDescriptor pd =
+                    new PluginDescriptorStaxReader().read(xsr, true);
+            return new PluginDescriptor(pd);
+        } else {
+            XmlNode node = XmlNodeBuilder.build(xsr, true, null);
+            PlexusConfiguration cfg = XmlPlexusConfiguration.toPlexusConfiguration(node);
+            return build(source, cfg);
+        }
+    }
+
+    private PluginDescriptor build(String source, PlexusConfiguration c) throws PlexusConfigurationException {
         PluginDescriptor pluginDescriptor = new PluginDescriptor();
 
-        pluginDescriptor.setSource( source );
-        pluginDescriptor.setGroupId( extractGroupId( c ) );
-        pluginDescriptor.setArtifactId( extractArtifactId( c ) );
-        pluginDescriptor.setVersion( extractVersion( c ) );
-        pluginDescriptor.setGoalPrefix( extractGoalPrefix( c ) );
+        pluginDescriptor.setSource(source);
+        pluginDescriptor.setGroupId(extractGroupId(c));
+        pluginDescriptor.setArtifactId(extractArtifactId(c));
+        pluginDescriptor.setVersion(extractVersion(c));
+        pluginDescriptor.setGoalPrefix(extractGoalPrefix(c));
 
-        pluginDescriptor.setName( extractName( c ) );
-        pluginDescriptor.setDescription( extractDescription( c ) );
+        pluginDescriptor.setName(extractName(c));
+        pluginDescriptor.setDescription(extractDescription(c));
 
-        pluginDescriptor.setIsolatedRealm( extractIsolatedRealm( c ) );
-        pluginDescriptor.setInheritedByDefault( extractInheritedByDefault( c ) );
+        pluginDescriptor.setIsolatedRealm(extractIsolatedRealm(c));
+        pluginDescriptor.setInheritedByDefault(extractInheritedByDefault(c));
+        pluginDescriptor.setRequiredJavaVersion(extractRequiredJavaVersion(c).orElse(null));
+        pluginDescriptor.setRequiredMavenVersion(extractRequiredMavenVersion(c).orElse(null));
 
-        pluginDescriptor.addMojos( extractMojos( c, pluginDescriptor ) );
+        pluginDescriptor.addMojos(extractMojos(c, pluginDescriptor));
 
-        pluginDescriptor.setDependencies( extractComponentDependencies( c ) );
+        pluginDescriptor.setDependencies(extractComponentDependencies(c));
 
         return pluginDescriptor;
     }
 
-    private String extractGroupId( PlexusConfiguration c )
-    {
-        return c.getChild( "groupId" ).getValue();
+    private String extractGroupId(PlexusConfiguration c) {
+        return c.getChild("groupId").getValue();
     }
 
-    private String extractArtifactId( PlexusConfiguration c )
-    {
-        return c.getChild( "artifactId" ).getValue();
+    private String extractArtifactId(PlexusConfiguration c) {
+        return c.getChild("artifactId").getValue();
     }
 
-    private String extractVersion( PlexusConfiguration c )
-    {
-        return c.getChild( "version" ).getValue();
+    private String extractVersion(PlexusConfiguration c) {
+        return c.getChild("version").getValue();
     }
 
-    private String extractGoalPrefix( PlexusConfiguration c )
-    {
-        return c.getChild( "goalPrefix" ).getValue();
+    private String extractGoalPrefix(PlexusConfiguration c) {
+        return c.getChild("goalPrefix").getValue();
     }
 
-    private String extractName( PlexusConfiguration c )
-    {
-        return c.getChild( "name" ).getValue();
+    private String extractName(PlexusConfiguration c) {
+        return c.getChild("name").getValue();
     }
 
-    private String extractDescription( PlexusConfiguration c )
-    {
-        return c.getChild( "description" ).getValue();
+    private String extractDescription(PlexusConfiguration c) {
+        return c.getChild("description").getValue();
     }
 
-    private List<MojoDescriptor> extractMojos( PlexusConfiguration c, PluginDescriptor pluginDescriptor )
-        throws PlexusConfigurationException
-    {
+    private List<MojoDescriptor> extractMojos(PlexusConfiguration c, PluginDescriptor pluginDescriptor)
+            throws PlexusConfigurationException {
         List<MojoDescriptor> mojos = new ArrayList<>();
 
-        PlexusConfiguration[] mojoConfigurations = c.getChild( "mojos" ).getChildren( "mojo" );
+        PlexusConfiguration[] mojoConfigurations = c.getChild("mojos").getChildren("mojo");
 
-        for ( PlexusConfiguration component : mojoConfigurations )
-        {
-            mojos.add( buildComponentDescriptor( component, pluginDescriptor ) );
-
+        for (PlexusConfiguration component : mojoConfigurations) {
+            mojos.add(buildComponentDescriptor(component, pluginDescriptor));
         }
         return mojos;
     }
 
-    private boolean extractInheritedByDefault( PlexusConfiguration c )
-    {
-        String inheritedByDefault = c.getChild( "inheritedByDefault" ).getValue();
+    private boolean extractInheritedByDefault(PlexusConfiguration c) {
+        String inheritedByDefault = c.getChild("inheritedByDefault").getValue();
 
-        if ( inheritedByDefault != null )
-        {
-            return Boolean.parseBoolean( inheritedByDefault );
+        if (inheritedByDefault != null) {
+            return Boolean.parseBoolean(inheritedByDefault);
         }
         return false;
     }
 
-    private boolean extractIsolatedRealm( PlexusConfiguration c )
-    {
-        String isolatedRealm = c.getChild( "isolatedRealm" ).getValue();
+    private boolean extractIsolatedRealm(PlexusConfiguration c) {
+        String isolatedRealm = c.getChild("isolatedRealm").getValue();
 
-        if ( isolatedRealm != null )
-        {
-            return Boolean.parseBoolean( isolatedRealm );
+        if (isolatedRealm != null) {
+            return Boolean.parseBoolean(isolatedRealm);
         }
         return false;
     }
 
-    private List<ComponentDependency> extractComponentDependencies( PlexusConfiguration c )
-    {
+    private Optional<String> extractRequiredJavaVersion(PlexusConfiguration c) {
+        return Optional.ofNullable(c.getChild("requiredJavaVersion")).map(PlexusConfiguration::getValue);
+    }
 
-        PlexusConfiguration[] dependencyConfigurations = c.getChild( "dependencies" ).getChildren( "dependency" );
+    private Optional<String> extractRequiredMavenVersion(PlexusConfiguration c) {
+        return Optional.ofNullable(c.getChild("requiredMavenVersion")).map(PlexusConfiguration::getValue);
+    }
+
+    private List<ComponentDependency> extractComponentDependencies(PlexusConfiguration c) {
+
+        PlexusConfiguration[] dependencyConfigurations =
+                c.getChild("dependencies").getChildren("dependency");
 
         List<ComponentDependency> dependencies = new ArrayList<>();
 
-        for ( PlexusConfiguration d : dependencyConfigurations )
-        {
-            dependencies.add( extractComponentDependency( d ) );
+        for (PlexusConfiguration d : dependencyConfigurations) {
+            dependencies.add(extractComponentDependency(d));
         }
         return dependencies;
     }
 
-    private ComponentDependency extractComponentDependency( PlexusConfiguration d )
-    {
+    private ComponentDependency extractComponentDependency(PlexusConfiguration d) {
         ComponentDependency cd = new ComponentDependency();
 
-        cd.setArtifactId( extractArtifactId( d ) );
+        cd.setArtifactId(extractArtifactId(d));
 
-        cd.setGroupId( extractGroupId( d ) );
+        cd.setGroupId(extractGroupId(d));
 
-        cd.setType( d.getChild( "type" ).getValue() );
+        cd.setType(d.getChild("type").getValue());
 
-        cd.setVersion( extractVersion( d ) );
+        cd.setVersion(extractVersion(d));
         return cd;
     }
 
-    @SuppressWarnings( "checkstyle:methodlength" )
-    public MojoDescriptor buildComponentDescriptor( PlexusConfiguration c, PluginDescriptor pluginDescriptor )
-        throws PlexusConfigurationException
-    {
+    @SuppressWarnings("checkstyle:methodlength")
+    public MojoDescriptor buildComponentDescriptor(PlexusConfiguration c, PluginDescriptor pluginDescriptor)
+            throws PlexusConfigurationException {
         MojoDescriptor mojo = new MojoDescriptor();
-        mojo.setPluginDescriptor( pluginDescriptor );
+        mojo.setPluginDescriptor(pluginDescriptor);
 
-        mojo.setGoal( c.getChild( "goal" ).getValue() );
+        mojo.setGoal(c.getChild("goal").getValue());
 
-        mojo.setImplementation( c.getChild( "implementation" ).getValue() );
+        mojo.setImplementation(c.getChild("implementation").getValue());
 
-        PlexusConfiguration langConfig = c.getChild( "language" );
+        PlexusConfiguration langConfig = c.getChild("language");
 
-        if ( langConfig != null )
-        {
-            mojo.setLanguage( langConfig.getValue() );
+        if (langConfig != null) {
+            mojo.setLanguage(langConfig.getValue());
         }
 
-        PlexusConfiguration configuratorConfig = c.getChild( "configurator" );
+        PlexusConfiguration configuratorConfig = c.getChild("configurator");
 
-        if ( configuratorConfig != null )
-        {
-            mojo.setComponentConfigurator( configuratorConfig.getValue() );
+        if (configuratorConfig != null) {
+            mojo.setComponentConfigurator(configuratorConfig.getValue());
         }
 
-        PlexusConfiguration composerConfig = c.getChild( "composer" );
+        PlexusConfiguration composerConfig = c.getChild("composer");
 
-        if ( composerConfig != null )
-        {
-            mojo.setComponentComposer( composerConfig.getValue() );
+        if (composerConfig != null) {
+            mojo.setComponentComposer(composerConfig.getValue());
         }
 
-        String since = c.getChild( "since" ).getValue();
+        String since = c.getChild("since").getValue();
 
-        if ( since != null )
-        {
-            mojo.setSince( since );
+        if (since != null) {
+            mojo.setSince(since);
         }
 
-        PlexusConfiguration deprecated = c.getChild( "deprecated", false );
+        PlexusConfiguration deprecated = c.getChild("deprecated", false);
 
-        if ( deprecated != null )
-        {
-            mojo.setDeprecated( deprecated.getValue() );
+        if (deprecated != null) {
+            mojo.setDeprecated(deprecated.getValue());
         }
 
-        String phase = c.getChild( "phase" ).getValue();
+        String phase = c.getChild("phase").getValue();
 
-        if ( phase != null )
-        {
-            mojo.setPhase( phase );
+        if (phase != null) {
+            mojo.setPhase(phase);
         }
 
-        String executePhase = c.getChild( "executePhase" ).getValue();
+        String executePhase = c.getChild("executePhase").getValue();
 
-        if ( executePhase != null )
-        {
-            mojo.setExecutePhase( executePhase );
+        if (executePhase != null) {
+            mojo.setExecutePhase(executePhase);
         }
 
-        String executeMojo = c.getChild( "executeGoal" ).getValue();
+        String executeMojo = c.getChild("executeGoal").getValue();
 
-        if ( executeMojo != null )
-        {
-            mojo.setExecuteGoal( executeMojo );
+        if (executeMojo != null) {
+            mojo.setExecuteGoal(executeMojo);
         }
 
-        String executeLifecycle = c.getChild( "executeLifecycle" ).getValue();
+        String executeLifecycle = c.getChild("executeLifecycle").getValue();
 
-        if ( executeLifecycle != null )
-        {
-            mojo.setExecuteLifecycle( executeLifecycle );
+        if (executeLifecycle != null) {
+            mojo.setExecuteLifecycle(executeLifecycle);
         }
 
-        mojo.setInstantiationStrategy( c.getChild( "instantiationStrategy" ).getValue() );
+        mojo.setInstantiationStrategy(c.getChild("instantiationStrategy").getValue());
 
-        mojo.setDescription( extractDescription( c ) );
+        mojo.setDescription(extractDescription(c));
 
-        PlexusConfiguration dependencyResolution = c.getChild( "requiresDependencyResolution", false );
+        PlexusConfiguration dependencyResolution = c.getChild("requiresDependencyResolution", false);
 
-        if ( dependencyResolution != null )
-        {
-            mojo.setDependencyResolutionRequired( dependencyResolution.getValue() );
+        if (dependencyResolution != null) {
+            mojo.setDependencyResolutionRequired(dependencyResolution.getValue());
         }
 
-        PlexusConfiguration dependencyCollection = c.getChild( "requiresDependencyCollection", false );
+        PlexusConfiguration dependencyCollection = c.getChild("requiresDependencyCollection", false);
 
-        if ( dependencyCollection != null )
-        {
-            mojo.setDependencyCollectionRequired( dependencyCollection.getValue() );
+        if (dependencyCollection != null) {
+            mojo.setDependencyCollectionRequired(dependencyCollection.getValue());
         }
 
-        String directInvocationOnly = c.getChild( "requiresDirectInvocation" ).getValue();
+        String directInvocationOnly = c.getChild("requiresDirectInvocation").getValue();
 
-        if ( directInvocationOnly != null )
-        {
-            mojo.setDirectInvocationOnly( Boolean.parseBoolean( directInvocationOnly ) );
+        if (directInvocationOnly != null) {
+            mojo.setDirectInvocationOnly(Boolean.parseBoolean(directInvocationOnly));
         }
 
-        String requiresProject = c.getChild( "requiresProject" ).getValue();
+        String requiresProject = c.getChild("requiresProject").getValue();
 
-        if ( requiresProject != null )
-        {
-            mojo.setProjectRequired( Boolean.parseBoolean( requiresProject ) );
+        if (requiresProject != null) {
+            mojo.setProjectRequired(Boolean.parseBoolean(requiresProject));
         }
 
-        String requiresReports = c.getChild( "requiresReports" ).getValue();
+        String requiresReports = c.getChild("requiresReports").getValue();
 
-        if ( requiresReports != null )
-        {
-            mojo.setRequiresReports( Boolean.parseBoolean( requiresReports ) );
+        if (requiresReports != null) {
+            mojo.setRequiresReports(Boolean.parseBoolean(requiresReports));
         }
 
-        String aggregator = c.getChild( "aggregator" ).getValue();
+        String aggregator = c.getChild("aggregator").getValue();
 
-        if ( aggregator != null )
-        {
-            mojo.setAggregator( Boolean.parseBoolean( aggregator ) );
+        if (aggregator != null) {
+            mojo.setAggregator(Boolean.parseBoolean(aggregator));
         }
 
-        String requiresOnline = c.getChild( "requiresOnline" ).getValue();
+        String requiresOnline = c.getChild("requiresOnline").getValue();
 
-        if ( requiresOnline != null )
-        {
-            mojo.setOnlineRequired( Boolean.parseBoolean( requiresOnline ) );
+        if (requiresOnline != null) {
+            mojo.setOnlineRequired(Boolean.parseBoolean(requiresOnline));
         }
 
-        String inheritedByDefault = c.getChild( "inheritedByDefault" ).getValue();
+        String inheritedByDefault = c.getChild("inheritedByDefault").getValue();
 
-        if ( inheritedByDefault != null )
-        {
-            mojo.setInheritedByDefault( Boolean.parseBoolean( inheritedByDefault ) );
+        if (inheritedByDefault != null) {
+            mojo.setInheritedByDefault(Boolean.parseBoolean(inheritedByDefault));
         }
 
-        String threadSafe = c.getChild( "threadSafe" ).getValue();
+        String threadSafe = c.getChild("threadSafe").getValue();
 
-        if ( threadSafe != null )
-        {
-            mojo.setThreadSafe( Boolean.parseBoolean( threadSafe ) );
+        if (threadSafe != null) {
+            mojo.setThreadSafe(Boolean.parseBoolean(threadSafe));
+        }
+
+        String v4Api = c.getChild("v4Api").getValue();
+
+        if (v4Api != null) {
+            mojo.setV4Api(Boolean.parseBoolean(v4Api));
         }
 
         // ----------------------------------------------------------------------
         // Configuration
         // ----------------------------------------------------------------------
 
-        PlexusConfiguration mojoConfig = c.getChild( "configuration" );
-        mojo.setMojoConfiguration( mojoConfig );
+        PlexusConfiguration mojoConfig = c.getChild("configuration");
+        mojo.setMojoConfiguration(mojoConfig);
 
         // ----------------------------------------------------------------------
         // Parameters
         // ----------------------------------------------------------------------
 
-        PlexusConfiguration[] parameterConfigurations = c.getChild( "parameters" ).getChildren( "parameter" );
+        PlexusConfiguration[] parameterConfigurations = c.getChild("parameters").getChildren("parameter");
 
         List<Parameter> parameters = new ArrayList<>();
 
-        for ( PlexusConfiguration d : parameterConfigurations )
-        {
+        for (PlexusConfiguration d : parameterConfigurations) {
             Parameter parameter = new Parameter();
 
-            parameter.setName( extractName( d ) );
+            parameter.setName(extractName(d));
 
-            parameter.setAlias( d.getChild( "alias" ).getValue() );
+            parameter.setAlias(d.getChild("alias").getValue());
 
-            parameter.setType( d.getChild( "type" ).getValue() );
+            parameter.setType(d.getChild("type").getValue());
 
-            String required = d.getChild( "required" ).getValue();
+            String required = d.getChild("required").getValue();
 
-            parameter.setRequired( Boolean.parseBoolean( required ) );
+            parameter.setRequired(Boolean.parseBoolean(required));
 
-            PlexusConfiguration editableConfig = d.getChild( "editable" );
+            PlexusConfiguration editableConfig = d.getChild("editable");
 
             // we need the null check for pre-build legacy plugins...
-            if ( editableConfig != null )
-            {
-                String editable = d.getChild( "editable" ).getValue();
+            if (editableConfig != null) {
+                String editable = d.getChild("editable").getValue();
 
-                parameter.setEditable( editable == null || Boolean.parseBoolean( editable ) );
+                parameter.setEditable(editable == null || Boolean.parseBoolean(editable));
             }
 
-            parameter.setDescription( extractDescription( d ) );
+            parameter.setDescription(extractDescription(d));
 
-            parameter.setDeprecated( d.getChild( "deprecated" ).getValue() );
+            parameter.setDeprecated(d.getChild("deprecated").getValue());
 
-            parameter.setImplementation( d.getChild( "implementation" ).getValue() );
+            parameter.setImplementation(d.getChild("implementation").getValue());
 
-            parameter.setSince( d.getChild( "since" ).getValue() );
+            parameter.setSince(d.getChild("since").getValue());
 
-            PlexusConfiguration paramConfig = mojoConfig.getChild( parameter.getName(), false );
-            if ( paramConfig != null )
-            {
-                parameter.setExpression( paramConfig.getValue( null ) );
-                parameter.setDefaultValue( paramConfig.getAttribute( "default-value" ) );
+            PlexusConfiguration paramConfig = mojoConfig.getChild(parameter.getName(), false);
+            if (paramConfig != null) {
+                parameter.setExpression(paramConfig.getValue(null));
+                parameter.setDefaultValue(paramConfig.getAttribute("default-value"));
             }
 
-            parameters.add( parameter );
+            parameters.add(parameter);
         }
 
-        mojo.setParameters( parameters );
+        mojo.setParameters(parameters);
 
         // TODO this should not need to be handed off...
 
@@ -374,19 +450,18 @@
         // Requirements
         // ----------------------------------------------------------------------
 
-        PlexusConfiguration[] requirements = c.getChild( "requirements" ).getChildren( "requirement" );
+        PlexusConfiguration[] requirements = c.getChild("requirements").getChildren("requirement");
 
-        for ( PlexusConfiguration requirement : requirements )
-        {
+        for (PlexusConfiguration requirement : requirements) {
             ComponentRequirement cr = new ComponentRequirement();
 
-            cr.setRole( requirement.getChild( "role" ).getValue() );
+            cr.setRole(requirement.getChild("role").getValue());
 
-            cr.setRoleHint( requirement.getChild( "role-hint" ).getValue() );
+            cr.setRoleHint(requirement.getChild("role-hint").getValue());
 
-            cr.setFieldName( requirement.getChild( "field-name" ).getValue() );
+            cr.setFieldName(requirement.getChild("field-name").getValue());
 
-            mojo.addRequirement( cr );
+            mojo.addRequirement(cr);
         }
 
         return mojo;
@@ -396,16 +471,21 @@
     //
     // ----------------------------------------------------------------------
 
-    public PlexusConfiguration buildConfiguration( Reader configuration )
-        throws PlexusConfigurationException
-    {
-        try
-        {
-            return new XmlPlexusConfiguration( Xpp3DomBuilder.build( configuration ) );
+    public PlexusConfiguration buildConfiguration(Reader configuration) throws PlexusConfigurationException {
+        try {
+            XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(configuration);
+            return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeBuilder.build(reader, true, null));
+        } catch (XMLStreamException e) {
+            throw new PlexusConfigurationException(e.getMessage(), e);
         }
-        catch ( IOException | XmlPullParserException e )
-        {
-            throw new PlexusConfigurationException( e.getMessage(), e );
+    }
+
+    public PlexusConfiguration buildConfiguration(InputStream configuration) throws PlexusConfigurationException {
+        try {
+            XMLStreamReader reader = WstxInputFactory.newFactory().createXMLStreamReader(configuration);
+            return XmlPlexusConfiguration.toPlexusConfiguration(XmlNodeBuilder.build(reader, true, null));
+        } catch (XMLStreamException e) {
+            throw new PlexusConfigurationException(e.getMessage(), e);
         }
     }
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Requirement.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Requirement.java
index 1526b03..39f2d7c 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Requirement.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/Requirement.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,38 +16,32 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 /**
  * Describes a component requirement.
  *
- * @author <a href="mailto:brett@apache.org">Brett Porter</a>
  */
-public class Requirement
-    implements Cloneable
-{
+public class Requirement implements Cloneable {
     private final String role;
 
     private final String roleHint;
 
-    public Requirement( String role )
-    {
+    public Requirement(String role) {
         this.role = role;
         this.roleHint = null;
     }
 
-    public Requirement( String role, String roleHint )
-    {
+    public Requirement(String role, String roleHint) {
         this.role = role;
         this.roleHint = roleHint;
     }
 
-    public String getRole()
-    {
+    public String getRole() {
         return role;
     }
 
-    public String getRoleHint()
-    {
+    public String getRoleHint() {
         return roleHint;
     }
 
@@ -57,16 +49,11 @@
      * Creates a shallow copy of this requirement.
      */
     @Override
-    public Requirement clone()
-    {
-        try
-        {
+    public Requirement clone() {
+        try {
             return (Requirement) super.clone();
-        }
-        catch ( CloneNotSupportedException e )
-        {
-            throw new UnsupportedOperationException( e );
+        } catch (CloneNotSupportedException e) {
+            throw new UnsupportedOperationException(e);
         }
     }
-
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/Log.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/Log.java
index a2cf2a0..f28a3af 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/Log.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/Log.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.logging;
 
 /**
  * This interface supplies the API for providing feedback to the user from the <code>Mojo</code>, using standard
@@ -27,11 +26,9 @@
  * convenience, to enable developers to pass things like <code>java.lang.StringBuffer</code> directly into the logger,
  * rather than formatting first by calling <code>toString()</code>.
  *
- * @author jdcasey
  *
  */
-public interface Log
-{
+public interface Log {
     /**
      * @return true if the <b>debug</b> error level is enabled
      */
@@ -42,7 +39,7 @@
      *
      * @param content
      */
-    void debug( CharSequence content );
+    void debug(CharSequence content);
 
     /**
      * Send a message (and accompanying exception) to the user in the <b>debug</b> error level.<br>
@@ -51,7 +48,7 @@
      * @param content
      * @param error
      */
-    void debug( CharSequence content, Throwable error );
+    void debug(CharSequence content, Throwable error);
 
     /**
      * Send an exception to the user in the <b>debug</b> error level.<br>
@@ -59,7 +56,7 @@
      *
      * @param error
      */
-    void debug( Throwable error );
+    void debug(Throwable error);
 
     /**
      * @return true if the <b>info</b> error level is enabled
@@ -71,7 +68,7 @@
      *
      * @param content
      */
-    void info( CharSequence content );
+    void info(CharSequence content);
 
     /**
      * Send a message (and accompanying exception) to the user in the <b>info</b> error level.<br>
@@ -80,7 +77,7 @@
      * @param content
      * @param error
      */
-    void info( CharSequence content, Throwable error );
+    void info(CharSequence content, Throwable error);
 
     /**
      * Send an exception to the user in the <b>info</b> error level.<br>
@@ -88,7 +85,7 @@
      *
      * @param error
      */
-    void info( Throwable error );
+    void info(Throwable error);
 
     /**
      * @return true if the <b>warn</b> error level is enabled
@@ -100,7 +97,7 @@
      *
      * @param content
      */
-    void warn( CharSequence content );
+    void warn(CharSequence content);
 
     /**
      * Send a message (and accompanying exception) to the user in the <b>warn</b> error level.<br>
@@ -109,7 +106,7 @@
      * @param content
      * @param error
      */
-    void warn( CharSequence content, Throwable error );
+    void warn(CharSequence content, Throwable error);
 
     /**
      * Send an exception to the user in the <b>warn</b> error level.<br>
@@ -117,7 +114,7 @@
      *
      * @param error
      */
-    void warn( Throwable error );
+    void warn(Throwable error);
 
     /**
      * @return true if the <b>error</b> error level is enabled
@@ -129,7 +126,7 @@
      *
      * @param content
      */
-    void error( CharSequence content );
+    void error(CharSequence content);
 
     /**
      * Send a message (and accompanying exception) to the user in the <b>error</b> error level.<br>
@@ -138,7 +135,7 @@
      * @param content
      * @param error
      */
-    void error( CharSequence content, Throwable error );
+    void error(CharSequence content, Throwable error);
 
     /**
      * Send an exception to the user in the <b>error</b> error level.<br>
@@ -146,5 +143,5 @@
      *
      * @param error
      */
-    void error( Throwable error );
+    void error(Throwable error);
 }
diff --git a/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/SystemStreamLog.java b/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/SystemStreamLog.java
index 885eead..e42b663 100644
--- a/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/SystemStreamLog.java
+++ b/maven-plugin-api/src/main/java/org/apache/maven/plugin/logging/SystemStreamLog.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.logging;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.logging;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -25,124 +24,108 @@
 /**
  * Logger with "standard" output and error output stream.
  *
- * @author jdcasey
  *
  */
-public class SystemStreamLog
-    implements Log
-{
+public class SystemStreamLog implements Log {
     /**
      * @see org.apache.maven.plugin.logging.Log#debug(java.lang.CharSequence)
      */
-    public void debug( CharSequence content )
-    {
-        print( "debug", content );
+    public void debug(CharSequence content) {
+        print("debug", content);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#debug(java.lang.CharSequence, java.lang.Throwable)
      */
-    public void debug( CharSequence content, Throwable error )
-    {
-        print( "debug", content, error );
+    public void debug(CharSequence content, Throwable error) {
+        print("debug", content, error);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#debug(java.lang.Throwable)
      */
-    public void debug( Throwable error )
-    {
-        print( "debug", error );
+    public void debug(Throwable error) {
+        print("debug", error);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#info(java.lang.CharSequence)
      */
-    public void info( CharSequence content )
-    {
-        print( "info", content );
+    public void info(CharSequence content) {
+        print("info", content);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#info(java.lang.CharSequence, java.lang.Throwable)
      */
-    public void info( CharSequence content, Throwable error )
-    {
-        print( "info", content, error );
+    public void info(CharSequence content, Throwable error) {
+        print("info", content, error);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#info(java.lang.Throwable)
      */
-    public void info( Throwable error )
-    {
-        print( "info", error );
+    public void info(Throwable error) {
+        print("info", error);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#warn(java.lang.CharSequence)
      */
-    public void warn( CharSequence content )
-    {
-        print( "warn", content );
+    public void warn(CharSequence content) {
+        print("warn", content);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#warn(java.lang.CharSequence, java.lang.Throwable)
      */
-    public void warn( CharSequence content, Throwable error )
-    {
-        print( "warn", content, error );
+    public void warn(CharSequence content, Throwable error) {
+        print("warn", content, error);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#warn(java.lang.Throwable)
      */
-    public void warn( Throwable error )
-    {
-        print( "warn", error );
+    public void warn(Throwable error) {
+        print("warn", error);
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#error(java.lang.CharSequence)
      */
-    public void error( CharSequence content )
-    {
-        System.err.println( "[error] " + content.toString() );
+    public void error(CharSequence content) {
+        System.err.println("[error] " + content.toString());
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#error(java.lang.CharSequence, java.lang.Throwable)
      */
-    public void error( CharSequence content, Throwable error )
-    {
+    public void error(CharSequence content, Throwable error) {
         StringWriter sWriter = new StringWriter();
-        PrintWriter pWriter = new PrintWriter( sWriter );
+        PrintWriter pWriter = new PrintWriter(sWriter);
 
-        error.printStackTrace( pWriter );
+        error.printStackTrace(pWriter);
 
-        System.err.println( "[error] " + content.toString()
-                            + System.lineSeparator() + System.lineSeparator() + sWriter.toString() );
+        System.err.println(
+                "[error] " + content.toString() + System.lineSeparator() + System.lineSeparator() + sWriter.toString());
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#error(java.lang.Throwable)
      */
-    public void error( Throwable error )
-    {
+    public void error(Throwable error) {
         StringWriter sWriter = new StringWriter();
-        PrintWriter pWriter = new PrintWriter( sWriter );
+        PrintWriter pWriter = new PrintWriter(sWriter);
 
-        error.printStackTrace( pWriter );
+        error.printStackTrace(pWriter);
 
-        System.err.println( "[error] " + sWriter.toString() );
+        System.err.println("[error] " + sWriter.toString());
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#isDebugEnabled()
      */
-    public boolean isDebugEnabled()
-    {
+    public boolean isDebugEnabled() {
         // TODO Not sure how best to set these for this implementation...
         return false;
     }
@@ -150,50 +133,44 @@
     /**
      * @see org.apache.maven.plugin.logging.Log#isInfoEnabled()
      */
-    public boolean isInfoEnabled()
-    {
+    public boolean isInfoEnabled() {
         return true;
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#isWarnEnabled()
      */
-    public boolean isWarnEnabled()
-    {
+    public boolean isWarnEnabled() {
         return true;
     }
 
     /**
      * @see org.apache.maven.plugin.logging.Log#isErrorEnabled()
      */
-    public boolean isErrorEnabled()
-    {
+    public boolean isErrorEnabled() {
         return true;
     }
 
-    private void print( String prefix, CharSequence content )
-    {
-        System.out.println( "[" + prefix + "] " + content.toString() );
+    private void print(String prefix, CharSequence content) {
+        System.out.println("[" + prefix + "] " + content.toString());
     }
 
-    private void print( String prefix, Throwable error )
-    {
+    private void print(String prefix, Throwable error) {
         StringWriter sWriter = new StringWriter();
-        PrintWriter pWriter = new PrintWriter( sWriter );
+        PrintWriter pWriter = new PrintWriter(sWriter);
 
-        error.printStackTrace( pWriter );
+        error.printStackTrace(pWriter);
 
-        System.out.println( "[" + prefix + "] " + sWriter.toString() );
+        System.out.println("[" + prefix + "] " + sWriter.toString());
     }
 
-    private void print( String prefix, CharSequence content, Throwable error )
-    {
+    private void print(String prefix, CharSequence content, Throwable error) {
         StringWriter sWriter = new StringWriter();
-        PrintWriter pWriter = new PrintWriter( sWriter );
+        PrintWriter pWriter = new PrintWriter(sWriter);
 
-        error.printStackTrace( pWriter );
+        error.printStackTrace(pWriter);
 
-        System.out.println( "[" + prefix + "] " + content.toString()
-                            + System.lineSeparator() + System.lineSeparator() + sWriter.toString() );
+        System.out.println("[" + prefix + "] " + content.toString() + System.lineSeparator() + System.lineSeparator()
+                + sWriter.toString());
     }
 }
diff --git a/maven-plugin-api/src/main/mdo/lifecycle.mdo b/maven-plugin-api/src/main/mdo/lifecycle.mdo
deleted file mode 100644
index 7dfce74..0000000
--- a/maven-plugin-api/src/main/mdo/lifecycle.mdo
+++ /dev/null
@@ -1,129 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<model xmlns="http://codehaus-plexus.github.io/MODELLO/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/1.0.0 http://codehaus-plexus.github.io/modello/xsd/modello-1.0.0.xsd"
-  xml.namespace="http://maven.apache.org/LIFECYCLE/${version}"
-  xml.schemaLocation="http://maven.apache.org/xsd/lifecycle-${version}.xsd">
-  <id>lifecycle-mappings</id>
-  <name>LifecycleMappings</name>
-  <description><![CDATA[
-    Configuration of custom lifecycle mappings for the plugin, as generally stored in
-    <code>META-INF/maven/lifecycle.xml</code> in a plugin's jar artifact.
-  ]]></description>
-  <defaults>
-    <default>
-      <key>package</key>
-      <value>org.apache.maven.plugin.lifecycle</value>
-    </default>
-  </defaults>
-  <classes>
-    <class rootElement="true" xml.tagName="lifecycles" xsd.compositor="sequence">
-      <name>LifecycleConfiguration</name>
-      <version>1.0.0</version>
-      <description><![CDATA[Root element of the <code>lifecycle.xml</code> file.]]></description>
-      <fields>
-        <field>
-          <name>lifecycles</name>
-          <version>1.0.0</version>
-          <association xml.itemsStyle="flat">
-            <type>Lifecycle</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class>
-      <name>Lifecycle</name>
-      <version>1.0.0</version>
-      <description><![CDATA[
-        A custom lifecycle mapping definition.
-      ]]></description>
-      <fields>
-        <field>
-          <name>id</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The ID of this lifecycle, for identification in the mojo descriptor.</description>
-        </field>
-        <field>
-          <name>phases</name>
-          <version>1.0.0</version>
-          <description>The phase mappings for this lifecycle.</description>
-          <association>
-            <type>Phase</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-    <class>
-      <name>Phase</name>
-      <version>1.0.0</version>
-      <description>A phase mapping definition.</description>
-      <fields>
-        <field>
-          <name>id</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The ID of this phase, e.g., &lt;code&gt;generate-sources&lt;/code&gt;.</description>
-        </field>
-        <field>
-          <name>executions</name>
-          <version>1.0.0</version>
-          <description>The goals to execute within the phase.</description>
-          <association>
-            <type>Execution</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>configuration</name>
-          <version>1.0.0</version>
-          <type>DOM</type>
-          <description>Configuration to pass to all goals run in this phase.</description>
-        </field>
-      </fields>
-    </class>
-    <class>
-      <name>Execution</name>
-      <version>1.0.0</version>
-      <description>A set of goals to execute.</description>
-      <fields>
-        <field>
-          <name>configuration</name>
-          <version>1.0.0</version>
-          <type>DOM</type>
-          <description>Configuration to pass to the goals.</description>
-        </field>
-        <field>
-          <name>goals</name>
-          <version>1.0.0</version>
-          <description>The goals to execute.</description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-  </classes>
-</model>
diff --git a/maven-plugin-api/src/main/mdo/plugin.mdo b/maven-plugin-api/src/main/mdo/plugin.mdo
deleted file mode 100644
index ee80045..0000000
--- a/maven-plugin-api/src/main/mdo/plugin.mdo
+++ /dev/null
@@ -1,525 +0,0 @@
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<model xmlns="http://codehaus-plexus.github.io/MODELLO/1.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/1.4.0 http://codehaus-plexus.github.io/modello/xsd/modello-1.4.0.xsd">
-  <id>plugin</id>
-  <name>PluginDescriptor</name>
-  <description><![CDATA[
-    Plugin descriptor, stored in <code>META-INF/maven/plugin.xml</code> in a plugin's jar artifact.
-    This descriptor is generally generated from plugin sources, using
-    <a href="/plugins/maven-plugin-plugin/">maven-plugin-plugin</a>.
-    <p><i>Notice:</i> this documentation is generated from a Modello model but the code executed is not generated
-    from this descriptor. Please report if you find anything wrong.</p>
-  ]]></description>
-  <defaults>
-    <default>
-      <key>package</key>
-      <value>plugin descriptor XML documentation (no java generation)</value><!-- intentionally non-buildable value -->
-    </default>
-  </defaults>
-  <classes>
-    <class rootElement="true" xml.tagName="plugin">
-      <name>PluginDescriptor</name>
-      <version>1.0.0</version>
-      <description><![CDATA[Root element of the <code>plugin.xml</code> file.]]></description>
-      <!-- see o.a.m.plugin.descriptor.PluginDescriptor -->
-      <fields>
-        <field>
-          <name>name</name>
-          <version>1.0.0</version>
-          <description>Name of the plugin.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>description</name>
-          <version>1.0.0</version>
-          <description>Description of the plugin.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>groupId</name>
-          <version>1.0.0</version>
-          <description>The group id of the plugin.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <version>1.0.0</version>
-          <description>The artifact id of the plugin.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>version</name>
-          <version>1.0.0</version>
-          <description>The version of the plugin.</description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>goalPrefix</name>
-          <version>1.0.0</version>
-          <description></description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>isolatedRealm</name>
-          <version>1.0.0</version>
-          <description></description>
-          <type>boolean</type>
-          <defaultValue>false</defaultValue>
-        </field>
-        <field>
-          <name>inheritedByDefault</name>
-          <version>1.0.0</version>
-          <description></description>
-          <type>boolean</type>
-          <defaultValue>true</defaultValue>
-        </field>
-        <field xdoc.separator="blank">
-          <name>mojos</name>
-          <version>1.0.0</version>
-          <association>
-            <type>MojoDescriptor</type>
-            <multiplicity>*</multiplicity>
-          </association>
-          <description>Description of each Mojo provided by the plugin.</description>
-        </field>
-        <field xdoc.separator="blank">
-          <name>dependencies</name>
-          <version>1.0.0</version>
-          <association>
-            <type>Dependency</type>
-            <multiplicity>*</multiplicity>
-          </association>
-          <description>
-            A set of dependencies which the plugin requires in order to function. This enables the plugin to function
-            independently of its POM (or at least to declare the libraries it needs to run).
-          </description>
-        </field>
-      </fields>
-    </class>
-
-    <class>
-      <name>MojoDescriptor</name>
-      <version>1.0.0</version>
-      <description><![CDATA[
-        A Mojo description.
-      ]]></description>
-      <!-- see o.a.m.plugin.descriptor.MojoDescriptor -->
-      <fields>
-        <field>
-          <name>goal</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>
-            The goal name for the Mojo, that users will reference from the command line to execute the Mojo directly,
-            or inside a POM in order to provide Mojo-specific configuration.
-          </description>
-        </field>
-        <field>
-          <name>description</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The description of this Mojo's functionality.</description>
-        </field>
-        <field>
-          <name>implementation</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>
-            The Mojo's fully-qualified class name (or script path in the case of non-Java Mojos).
-          </description>
-        </field>
-        <field>
-          <name>language</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <defaultValue>java</defaultValue>
-          <description>The implementation language for this Mojo (java, beanshell, etc.).</description>
-        </field>
-        <field>
-          <name>phase</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description><![CDATA[
-            Defines a default phase to bind a mojo execution to if the user does not explicitly set a phase in the POM.
-            <i>Note:</i> This will not automagically make a mojo run when the plugin declaration is added
-            to the POM. It merely enables the user to omit the <code>&lt;phase&gt;</code> element from the
-            surrounding <code>&lt;execution&gt;</code> element.
-          ]]></description>
-        </field>
-        <field>
-          <name>executePhase</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>Reference the invocation phase of the Mojo.</description>
-        </field>
-        <field>
-          <name>executeGoal</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>Reference the invocation goal of the Mojo.</description>
-        </field>
-        <field>
-          <name>executeLifecycle</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description></description>
-        </field>
-        <field>
-          <name>requiresDependencyResolution</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <defaultValue>runtime</defaultValue>
-          <description><![CDATA[
-            Flags this Mojo as requiring the dependencies in the specified class path to be resolved before it can
-            execute: <code>compile</code>, <code>runtime</code>, <code>test</code>,
-            <code>compile+runtime</code> (since Maven 3.0) or <code>runtime+system</code> (since Maven 3.0)
-          ]]></description>
-        </field>
-        <field>
-          <name>requiresDependencyCollection</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description><![CDATA[
-            Flags this mojo as requiring information about the dependencies that would make up the specified class
-            path. As the name suggests, this is similar to requiresDependencyResolution and supports the same values.
-            The important difference is this will not resolve the files for the dependencies, i.e. the artifacts
-            associated with a Maven project can lack a file. As such, this annotation is meant for mojos that only
-            want to analyze the set of transitive dependencies, in particular during early lifecycle phases where
-            full dependency resolution might fail due to projects which haven't been built yet.
-          ]]></description>
-        </field>
-        <field>
-          <name>requiresDirectInvocation</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>Flags this Mojo to be invoked directly only.</description>
-          <defaultValue>false</defaultValue>
-        </field>
-        <field>
-          <name>requiresProject</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>Flags this Mojo to require running inside of a project.</description>
-          <defaultValue>true</defaultValue>
-        </field>
-        <field>
-          <name>requiresReports</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>Flags this Mojo to require running inside of a reports context. Unsupported since Maven 3.0.</description>
-          <defaultValue>false</defaultValue>
-        </field>
-        <field>
-          <name>requiresOnline</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>Flags this Mojo to require online mode for its operation.</description>
-          <defaultValue>false</defaultValue>
-        </field>
-        <field>
-          <name>aggregator</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>
-            Flags this Mojo to run it in a multi-module way, i.e. aggregate the build with the set of projects
-            listed as modules.
-          </description>
-          <defaultValue>false</defaultValue>
-        </field>
-        <field>
-          <name>inheritedByDefault</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>Specify that the Mojo is inherited.</description>
-          <defaultValue>true</defaultValue>
-        </field>
-        <field>
-          <name>threadSafe</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>
-            Marks this mojo as being thread-safe, i.e. the mojo safely supports concurrent execution during parallel
-            builds. Mojos without this annotation will make Maven output a warning when used during a parallel build
-            session. Since Maven 3.0.
-          </description>
-          <defaultValue>false</defaultValue>
-        </field>
-        <field>
-          <name>instantiationStrategy</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <defaultValue>per-lookup</defaultValue>
-          <description>Specify the instantiation strategy.</description>
-        </field>
-        <field>
-          <name>executionStrategy</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description><![CDATA[
-            Specify the execution strategy: <code>once-per-session</code>, <code>always</code>.
-          ]]></description>
-          <defaultValue>once-per-session</defaultValue>
-        </field>
-        <field>
-          <name>since</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>Specify the version when the Mojo was added to the API. Similar to Javadoc since.</description>
-        </field>
-        <field>
-          <name>deprecated</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>
-            Specify the version when the Mojo was deprecated to the API. Similar to Javadoc deprecated. This will
-            trigger a warning when a user tries to configure a parameter marked as deprecated.
-          </description>
-        </field>
-        <field>
-          <name>configurator</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>
-            The configurator type to use when injecting parameter values into this Mojo. The value is normally deduced
-            from the Mojo's implementation language, but can be specified to allow a custom ComponentConfigurator
-            implementation to be used.
-          </description>
-        </field>
-        <field>
-          <name>composer</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description></description>
-        </field>
-        <field xdoc.separator="blank">
-          <name>parameters</name>
-          <version>1.0.0</version>
-          <description></description>
-          <association>
-            <type>Parameter</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>configuration</name>
-          <version>1.0.0</version>
-          <description></description>
-          <association xml.tagName="paramName">
-            <type>Configuration</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>requirements</name>
-          <version>1.0.0</version>
-          <description></description>
-          <association>
-            <type>Requirement</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-    </class>
-
-    <class>
-      <name>Parameter</name>
-      <version>1.0.0</version>
-      <description>A phase mapping definition.</description>
-      <!-- see o.a.m.plugin.descriptor.Parameter -->
-      <fields>
-        <field>
-          <name>name</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <required>true</required>
-          <description>
-            The name of the parameter, to be used while configuring this parameter from the Mojo's declared defaults
-            or from the POM.
-          </description>
-        </field>
-        <field>
-          <name>alias</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>
-            Specifies an alias which can be used to configure this parameter from the POM.
-            This is primarily useful to improve user-friendliness, where Mojo field names are not intuitive to the
-            user or are otherwise not conducive to configuration via the POM.
-          </description>
-        </field>
-        <field>
-          <name>type</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <required>true</required>
-          <description>
-            The Java type for this parameter. This is used to validate the result of any expressions used to calculate
-            the value which should be injected into the Mojo for this parameter.
-          </description>
-        </field>
-        <field>
-          <name>required</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <description>
-            Whether this parameter is required for the Mojo to function. This is used to validate the configuration
-            for a Mojo before it is injected, and before the Mojo is executed from some half-state.
-          </description>
-        </field>
-        <field>
-          <name>editable</name>
-          <version>1.0.0</version>
-          <type>boolean</type>
-          <defaultValue>true</defaultValue>
-          <description><![CDATA[
-            Specifies that this parameter can be configured directly by the user (as in the case of POM-specified
-            configuration). This is useful when you want to force the user to use common POM elements rather than
-            plugin configurations, as in the case where you want to use the artifact's final name as a parameter. In
-            this case, you want the user to modify <code>&lt;build&gt;&lt;finalName/&gt;&lt;/build&gt;</code> rather
-            than specifying a value for finalName directly in the plugin configuration section. It is also useful to
-            ensure that - for example - a List-typed parameter which expects items of type Artifact doesn't get a List
-            full of Strings.
-          ]]></description>
-        </field>
-        <field>
-          <name>implementation</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description></description>
-        </field>
-        <field>
-          <name>description</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The description of this parameter's use inside the Mojo.</description>
-        </field>
-        <field>
-          <name>since</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>Specify the version when the parameter was added to the API. Similar to Javadoc since.</description>
-        </field>
-        <field>
-          <name>deprecated</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>
-            Specify the version when the parameter was deprecated to the API. Similar to Javadoc deprecated.
-            This will trigger a warning when a user tries to configure a parameter marked as deprecated.
-          </description>
-        </field>
-      </fields>
-    </class>
-
-    <class>
-      <name>Configuration</name>
-      <version>1.0.0</version>
-      <description>A parameter configuration.</description>
-      <!-- see o.a.m.plugin.descriptor.Parameter -->
-      <fields>
-        <field xml.content="true">
-          <name>expression</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>Parameter expression, to let user override default value with a system property, pom property or settings property.</description>
-        </field>
-        <field xml.attribute="true" xml.tagName="implementation">
-          <name>implementation</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description></description>
-        </field>
-        <field xml.attribute="true" xml.tagName="default-value">
-          <name>defaultValue</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The default value, as an expression that will be evaluated at injection or run-time.</description>
-        </field>
-      </fields>
-    </class>
-
-    <class>
-      <name>Requirement</name>
-      <version>1.0.0</version>
-      <description>Describes a component requirement.</description>
-      <!-- see o.a.m.plugin.descriptor.Requirement -->
-      <fields>
-        <field>
-          <name>role</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description></description>
-        </field>
-        <field xml.tagName="role-hint">
-          <name>roleHint</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description></description>
-        </field>
-        <field xml.tagName="field-name">
-          <name>fieldName</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The field name which has this requirement.</description>
-        </field>
-      </fields>
-    </class>
-
-    <class>
-      <name>Dependency</name>
-      <version>1.0.0</version>
-      <description>Definition of a dependency, needed by the plugin at runtime.</description>
-      <fields>
-        <field>
-          <name>groupId</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The group id of the dependency.</description>
-        </field>
-        <field>
-          <name>artifactId</name>
-          <required>true</required>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The artifact id of the dependency.</description>
-        </field>
-        <field>
-          <name>version</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <description>The version of the dependency.</description>
-        </field>
-        <field>
-          <name>type</name>
-          <version>1.0.0</version>
-          <type>String</type>
-          <defaultValue>jar</defaultValue>
-          <description>The type of dependency.</description>
-        </field>
-      </fields>
-    </class>
-  </classes>
-</model>
diff --git a/maven-plugin-api/src/site/apt/index.apt b/maven-plugin-api/src/site/apt/index.apt
index 6eb5955..e7a16ae 100644
--- a/maven-plugin-api/src/site/apt/index.apt
+++ b/maven-plugin-api/src/site/apt/index.apt
@@ -25,7 +25,13 @@
 
 Maven Plugin API
 
- The API for plugins - composed of goals implemented by Mojos - development.
+ The API for plugins - composed of goals implemented by Mojos - development:
+
+ * goal code extends {{{./apidocs/org/apache/maven/plugin/AbstractMojo.html}<<<AbstractMojo>>> base class}} that implements {{{./apidocs/org/apache/maven/plugin/Mojo.html}<<<Mojo>>> interface}},
+
+ * {{{./apidocs/org/apache/maven/plugin/logging/Log.html}<<<Log>>> interface}} provides easy logging for the goal.
+
+ []
 
  A plugin is described in a {{{./plugin.html}<<<META-INF/maven/plugin.xml>>> plugin descriptor}},
  generally generated from plugin sources using {{{/plugin-tools/maven-plugin-plugin/}maven-plugin-plugin}}.
@@ -34,6 +40,6 @@
 
  * {{{/developers/mojo-api-specification.html}Mojo API Specification}}
 
- * {{{/plugin-tools/}plugin-tools}}
+ * {{{/plugin-tools/}Plugin Tools}} that provide {{{/plugin-tools/maven-plugin-plugin/}maven-plugin-plugin}} to generate the {{{./plugin.html}<<<META-INF/maven/plugin.xml>>> plugin descriptor}}
 
- * {{{/plugin-testing/}plugin-testing}}
+ * {{{/plugin-testing/}Plugin Testing}} frameworks
diff --git a/maven-plugin-api/src/site/site.xml b/maven-plugin-api/src/site/site.xml
index 224f30e..1cbf42b 100644
--- a/maven-plugin-api/src/site/site.xml
+++ b/maven-plugin-api/src/site/site.xml
@@ -27,13 +27,13 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
     <menu name="Reference">
-      <item name="lifecycle.xml" href="lifecycle-mappings.html"/>
-      <item name="plugin.xml" href="plugin.html"/>
+      <item name="META-INF/maven/lifecycle.xml" href="lifecycle-mappings.html"/>
+      <item name="META-INF/maven/plugin.xml" href="plugin.html"/>
     </menu>
 
     <menu ref="parent"/>
diff --git a/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/MojoDescriptorTest.java b/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/MojoDescriptorTest.java
index 0aec7d3..26cffce 100644
--- a/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/MojoDescriptorTest.java
+++ b/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/MojoDescriptorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,36 +16,35 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 import org.junit.jupiter.api.Test;
 
-import java.util.List;
-import java.util.Map;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class MojoDescriptorTest
-{
+class MojoDescriptorTest {
     @Test
-    public void getParameterMap() throws DuplicateParameterException
-    {
+    void getParameterMap() throws DuplicateParameterException {
         MojoDescriptor mojoDescriptor = new MojoDescriptor();
         Parameter param1 = new Parameter();
-        param1.setName( "param1" );
-        param1.setDefaultValue( "value1" );
-        mojoDescriptor.addParameter( param1 );
+        param1.setName("param1");
+        param1.setDefaultValue("value1");
+        mojoDescriptor.addParameter(param1);
 
-        assertEquals( 1, mojoDescriptor.getParameters().size() );
+        assertEquals(1, mojoDescriptor.getParameters().size());
 
-        assertEquals( mojoDescriptor.getParameters().size(), mojoDescriptor.getParameterMap().size() );
+        assertEquals(
+                mojoDescriptor.getParameters().size(),
+                mojoDescriptor.getParameterMap().size());
 
         Parameter param2 = new Parameter();
-        param2.setName( "param2" );
-        param2.setDefaultValue( "value2" );
-        mojoDescriptor.addParameter( param2 );
+        param2.setName("param2");
+        param2.setDefaultValue("value2");
+        mojoDescriptor.addParameter(param2);
 
-        assertEquals( 2, mojoDescriptor.getParameters().size() );
-        assertEquals( mojoDescriptor.getParameters().size(), mojoDescriptor.getParameterMap().size() );
+        assertEquals(2, mojoDescriptor.getParameters().size());
+        assertEquals(
+                mojoDescriptor.getParameters().size(),
+                mojoDescriptor.getParameterMap().size());
     }
-
-}
\ No newline at end of file
+}
diff --git a/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilderTest.java b/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilderTest.java
index 88d2490..f983936 100644
--- a/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilderTest.java
+++ b/maven-plugin-api/src/test/java/org/apache/maven/plugin/descriptor/PluginDescriptorBuilderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.plugin.descriptor;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,15 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.plugin.descriptor;
 
 import java.io.IOException;
-import java.io.Reader;
+import java.io.InputStream;
 
 import org.codehaus.plexus.component.repository.ComponentDependency;
 import org.codehaus.plexus.component.repository.ComponentRequirement;
 import org.codehaus.plexus.configuration.PlexusConfiguration;
 import org.codehaus.plexus.configuration.PlexusConfigurationException;
-import org.codehaus.plexus.util.ReaderFactory;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -38,102 +36,95 @@
 /**
  * Tests {@link PluginDescriptorBuilder}.
  *
- * @author Benjamin Bentmann
  */
-public class PluginDescriptorBuilderTest
-{
+class PluginDescriptorBuilderTest {
 
-    private PluginDescriptor build( String resource )
-        throws IOException, PlexusConfigurationException
-    {
-        Reader reader = ReaderFactory.newXmlReader( getClass().getResourceAsStream( resource ) );
-
-        return new PluginDescriptorBuilder().build( reader );
+    private PluginDescriptor build(String resource) throws IOException, PlexusConfigurationException {
+        try (InputStream is = getClass().getResourceAsStream(resource)) {
+            return new PluginDescriptorBuilder().build(is, null);
+        }
     }
 
     @Test
-    public void testBuildReader()
-        throws Exception
-    {
-        PluginDescriptor pd = build( "/plugin.xml" );
+    void testBuildReader() throws Exception {
+        PluginDescriptor pd = build("/plugin.xml");
 
-        assertEquals( "org.apache.maven.plugins", pd.getGroupId() );
-        assertEquals( "maven-jar-plugin", pd.getArtifactId() );
-        assertEquals( "2.3-SNAPSHOT", pd.getVersion() );
-        assertEquals( "jar", pd.getGoalPrefix() );
-        assertEquals( "plugin-description", pd.getDescription() );
-        assertFalse( pd.isIsolatedRealm() );
-        assertTrue( pd.isInheritedByDefault() );
-        assertEquals( 2, pd.getMojos().size() );
-        assertEquals( 1, pd.getDependencies().size() );
+        assertEquals("org.apache.maven.plugins", pd.getGroupId());
+        assertEquals("maven-jar-plugin", pd.getArtifactId());
+        assertEquals("2.3-SNAPSHOT", pd.getVersion());
+        assertEquals("jar", pd.getGoalPrefix());
+        assertEquals("plugin-description", pd.getDescription());
+        assertFalse(pd.isIsolatedRealm());
+        assertTrue(pd.isInheritedByDefault());
+        assertEquals(2, pd.getMojos().size());
+        assertEquals(1, pd.getDependencies().size());
 
-        MojoDescriptor md = pd.getMojos().get( 0 );
+        MojoDescriptor md = pd.getMojos().get(0);
 
-        assertEquals( "jar", md.getGoal() );
-        assertEquals( "mojo-description", md.getDescription() );
-        assertEquals( "runtime", md.getDependencyResolutionRequired() );
-        assertEquals( "test", md.getDependencyCollectionRequired() );
-        assertFalse( md.isAggregator() );
-        assertFalse( md.isDirectInvocationOnly() );
-        assertTrue( md.isInheritedByDefault() );
-        assertFalse( md.isOnlineRequired() );
-        assertTrue( md.isProjectRequired() );
-        assertFalse( md.isThreadSafe() );
-        assertEquals( "package", md.getPhase() );
-        assertEquals( "org.apache.maven.plugin.jar.JarMojo", md.getImplementation() );
-        assertEquals( "antrun", md.getComponentConfigurator() );
-        assertEquals( "java", md.getLanguage() );
-        assertEquals( "per-lookup", md.getInstantiationStrategy() );
-        assertEquals( "some-goal", md.getExecuteGoal() );
-        assertEquals( "generate-sources", md.getExecutePhase() );
-        assertEquals( "cobertura", md.getExecuteLifecycle() );
-        assertEquals( "2.2", md.getSince() );
-        assertEquals( "deprecated-mojo", md.getDeprecated() );
-        assertEquals( 1, md.getRequirements().size() );
-        assertEquals( 1, md.getParameters().size() );
+        assertEquals("jar", md.getGoal());
+        assertEquals("mojo-description", md.getDescription());
+        assertEquals("runtime", md.getDependencyResolutionRequired());
+        assertEquals("test", md.getDependencyCollectionRequired());
+        assertFalse(md.isAggregator());
+        assertFalse(md.isDirectInvocationOnly());
+        assertTrue(md.isInheritedByDefault());
+        assertFalse(md.isOnlineRequired());
+        assertTrue(md.isProjectRequired());
+        assertFalse(md.isThreadSafe());
+        assertEquals("package", md.getPhase());
+        assertEquals("org.apache.maven.plugin.jar.JarMojo", md.getImplementation());
+        assertEquals("antrun", md.getComponentConfigurator());
+        assertEquals("java", md.getLanguage());
+        assertEquals("per-lookup", md.getInstantiationStrategy());
+        assertEquals("some-goal", md.getExecuteGoal());
+        assertEquals("generate-sources", md.getExecutePhase());
+        assertEquals("cobertura", md.getExecuteLifecycle());
+        assertEquals("2.2", md.getSince());
+        assertEquals("deprecated-mojo", md.getDeprecated());
+        assertEquals(1, md.getRequirements().size());
+        assertEquals(1, md.getParameters().size());
 
-        assertNotNull( md.getMojoConfiguration() );
-        assertEquals( 1, md.getMojoConfiguration().getChildCount() );
+        assertNotNull(md.getMojoConfiguration());
+        assertEquals(1, md.getMojoConfiguration().getChildCount());
 
-        PlexusConfiguration pc = md.getMojoConfiguration().getChild( 0 );
+        PlexusConfiguration pc = md.getMojoConfiguration().getChild(0);
 
-        assertEquals( "${jar.finalName}", pc.getValue() );
-        assertEquals( "${project.build.finalName}", pc.getAttribute( "default-value" ) );
-        assertEquals( "java.lang.String", pc.getAttribute( "implementation" ) );
+        assertEquals("${jar.finalName}", pc.getValue());
+        assertEquals("${project.build.finalName}", pc.getAttribute("default-value"));
+        assertEquals("java.lang.String", pc.getAttribute("implementation"));
 
-        Parameter mp = md.getParameters().get( 0 );
+        Parameter mp = md.getParameters().get(0);
 
-        assertEquals( "finalName", mp.getName() );
-        assertEquals( "jarName", mp.getAlias() );
-        assertEquals( "java.lang.String", mp.getType() );
-        assertEquals( "java.lang.String", mp.getImplementation() );
-        assertTrue( mp.isEditable() );
-        assertFalse( mp.isRequired() );
-        assertEquals( "parameter-description", mp.getDescription() );
-        assertEquals( "deprecated-parameter", mp.getDeprecated() );
-        assertEquals( "${jar.finalName}", mp.getExpression() );
-        assertEquals( "${project.build.finalName}", mp.getDefaultValue() );
-        assertEquals( "3.0.0", mp.getSince() );
+        assertEquals("finalName", mp.getName());
+        assertEquals("jarName", mp.getAlias());
+        assertEquals("java.lang.String", mp.getType());
+        assertEquals("java.lang.String", mp.getImplementation());
+        assertTrue(mp.isEditable());
+        assertFalse(mp.isRequired());
+        assertEquals("parameter-description", mp.getDescription());
+        assertEquals("deprecated-parameter", mp.getDeprecated());
+        assertEquals("${jar.finalName}", mp.getExpression());
+        assertEquals("${project.build.finalName}", mp.getDefaultValue());
+        assertEquals("3.0.0", mp.getSince());
 
-        ComponentRequirement cr = md.getRequirements().get( 0 );
+        ComponentRequirement cr = md.getRequirements().get(0);
 
-        assertEquals( "org.codehaus.plexus.archiver.Archiver", cr.getRole() );
-        assertEquals( "jar", cr.getRoleHint() );
-        assertEquals( "jarArchiver", cr.getFieldName() );
+        assertEquals("org.codehaus.plexus.archiver.Archiver", cr.getRole());
+        assertEquals("jar", cr.getRoleHint());
+        assertEquals("jarArchiver", cr.getFieldName());
 
-        ComponentDependency cd = pd.getDependencies().get( 0 );
+        ComponentDependency cd = pd.getDependencies().get(0);
 
-        assertEquals( "org.apache.maven", cd.getGroupId() );
-        assertEquals( "maven-plugin-api", cd.getArtifactId() );
-        assertEquals( "2.0.6", cd.getVersion() );
-        assertEquals( "jar", cd.getType() );
+        assertEquals("org.apache.maven", cd.getGroupId());
+        assertEquals("maven-plugin-api", cd.getArtifactId());
+        assertEquals("2.0.6", cd.getVersion());
+        assertEquals("jar", cd.getType());
 
-        md = pd.getMojos().get( 1 );
+        md = pd.getMojos().get(1);
 
-        assertEquals( "war", md.getGoal() );
-        assertNull( md.getDependencyResolutionRequired() );
-        assertNull( md.getDependencyCollectionRequired() );
-        assertTrue( md.isThreadSafe() );
+        assertEquals("war", md.getGoal());
+        assertNull(md.getDependencyResolutionRequired());
+        assertNull(md.getDependencyCollectionRequired());
+        assertTrue(md.isThreadSafe());
     }
-
 }
diff --git a/maven-repository-metadata/pom.xml b/maven-repository-metadata/pom.xml
index d989e0b..422b2e4 100644
--- a/maven-repository-metadata/pom.xml
+++ b/maven-repository-metadata/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-repository-metadata</artifactId>
@@ -36,7 +34,15 @@
   <dependencies>
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
+      <artifactId>plexus-xml</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-xml-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.woodstox</groupId>
+      <artifactId>woodstox-core</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.maven.resolver</groupId>
@@ -51,11 +57,52 @@
         <groupId>org.codehaus.modello</groupId>
         <artifactId>modello-maven-plugin</artifactId>
         <configuration>
-          <version>1.1.0</version>
+          <version>1.2.0</version>
           <models>
             <model>src/main/mdo/metadata.mdo</model>
           </models>
+          <params>
+            <param>forcedIOModelVersion=1.1.0</param>
+            <param>packageModelV3=org.apache.maven.artifact.repository.metadata</param>
+            <param>packageModelV4=org.apache.maven.artifact.repository.metadata.v4</param>
+            <param>packageToolV4=org.apache.maven.artifact.repository.metadata.io</param>
+          </params>
+          <velocityBasedir>${project.basedir}/../src/mdo</velocityBasedir>
         </configuration>
+        <executions>
+          <execution>
+            <id>modello</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <configuration>
+              <version>1.2.0</version>
+              <models>
+                <model>src/main/mdo/metadata.mdo</model>
+              </models>
+              <templates>
+                <template>model.vm</template>
+                <template>reader-stax.vm</template>
+                <template>writer-stax.vm</template>
+              </templates>
+            </configuration>
+          </execution>
+          <execution>
+            <id>modello-v3</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <configuration>
+              <version>1.1.0</version>
+              <models>
+                <model>src/main/mdo/metadata.mdo</model>
+              </models>
+              <templates>
+                <template>model-v3.vm</template>
+              </templates>
+            </configuration>
+          </execution>
+        </executions>
       </plugin>
     </plugins>
   </build>
diff --git a/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/BaseObject.java b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/BaseObject.java
new file mode 100644
index 0000000..c206298
--- /dev/null
+++ b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/BaseObject.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata;
+
+import java.io.Serializable;
+
+public abstract class BaseObject implements Serializable, Cloneable {
+    protected transient ChildrenTracking childrenTracking;
+
+    protected Object delegate;
+
+    public BaseObject() {}
+
+    public BaseObject(Object delegate, BaseObject parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent != null ? parent::replace : null;
+    }
+
+    public BaseObject(Object delegate, ChildrenTracking parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent;
+    }
+
+    public Object getDelegate() {
+        return delegate;
+    }
+
+    public void update(Object newDelegate) {
+        if (delegate != newDelegate) {
+            if (childrenTracking != null) {
+                childrenTracking.replace(delegate, newDelegate);
+            }
+            delegate = newDelegate;
+        }
+    }
+
+    protected boolean replace(Object oldDelegate, Object newDelegate) {
+        return false;
+    }
+
+    @FunctionalInterface
+    protected interface ChildrenTracking {
+        boolean replace(Object oldDelegate, Object newDelegate);
+    }
+}
diff --git a/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader.java b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader.java
new file mode 100644
index 0000000..359ea41
--- /dev/null
+++ b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Reader.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata.io.xpp3;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.maven.artifact.repository.metadata.Metadata;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * Provide public methods from {@link MetadataStaxReader}
+ *
+ * @deprecated Maven 3 compatability - please use {@link MetadataStaxReader}
+ */
+@Deprecated
+public class MetadataXpp3Reader {
+
+    private final MetadataStaxReader delegate;
+
+    /**
+     * Default constructor
+     */
+    public MetadataXpp3Reader() {
+        delegate = new MetadataStaxReader();
+    }
+
+    /**
+     * Constructor with ContentTransformer
+     *
+     * @param contentTransformer a transformer
+     */
+    public MetadataXpp3Reader(ContentTransformer contentTransformer) {
+        delegate = new MetadataStaxReader(contentTransformer::transform);
+    }
+
+    /**
+     * Returns the state of the "add default entities" flag.
+     *
+     * @return boolean a field value
+     */
+    public boolean getAddDefaultEntities() {
+        return delegate.getAddDefaultEntities();
+    }
+
+    /**
+     * Sets the state of the "add default entities" flag.
+     *
+     * @param addDefaultEntities a addDefaultEntities object.
+     */
+    public void setAddDefaultEntities(boolean addDefaultEntities) {
+        delegate.setAddDefaultEntities(addDefaultEntities);
+    }
+
+    /**
+     * Method read.
+     *
+     * @param reader a reader object.
+     * @param strict a strict object.
+     * @return Metadata
+     * @throws IOException            IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     *                                any.
+     */
+    public Metadata read(Reader reader, boolean strict) throws IOException, XmlPullParserException {
+        try {
+            return new Metadata(delegate.read(reader, strict));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param reader a reader object.
+     * @return Metadata
+     * @throws IOException            IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     *                                any.
+     */
+    public Metadata read(Reader reader) throws IOException, XmlPullParserException {
+        try {
+            return new Metadata(delegate.read(reader));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param in     a in object.
+     * @param strict a strict object.
+     * @return Metadata
+     * @throws IOException            IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     *                                any.
+     */
+    public Metadata read(InputStream in, boolean strict) throws IOException, XmlPullParserException {
+        try {
+            return new Metadata(delegate.read(in, strict));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @return Metadata
+     * @throws IOException            IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     *                                any.
+     */
+    public Metadata read(InputStream in) throws IOException, XmlPullParserException {
+        try {
+            return new Metadata(delegate.read(in));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @return Metadata
+     * @throws IOException            IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     *                                any.
+     */
+    public Metadata read(XMLStreamReader parser, boolean strict) throws IOException, XmlPullParserException {
+        try {
+            return new Metadata(delegate.read(parser, strict));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * {@link MetadataStaxReader.ContentTransformer}
+     */
+    public interface ContentTransformer {
+        /**
+         * Interpolate the value read from the xpp3 document
+         *
+         * @param source    The source value
+         * @param fieldName A description of the field being interpolated. The implementation may use this to
+         *                  log stuff.
+         * @return The interpolated value.
+         */
+        String transform(String source, String fieldName);
+    }
+}
diff --git a/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Writer.java b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Writer.java
new file mode 100644
index 0000000..0929c10
--- /dev/null
+++ b/maven-repository-metadata/src/main/java/org/apache/maven/artifact/repository/metadata/io/xpp3/MetadataXpp3Writer.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.artifact.repository.metadata.io.xpp3;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.maven.artifact.repository.metadata.Metadata;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxWriter;
+
+/**
+ * Provide public methods from {@link MetadataStaxWriter}
+ *
+ * @deprecated Maven 3 compatability - please use {@link MetadataStaxWriter}
+ */
+@Deprecated
+public class MetadataXpp3Writer {
+
+    private final MetadataStaxWriter delegate;
+
+    /**
+     * Default constructor
+     */
+    public MetadataXpp3Writer() {
+        delegate = new MetadataStaxWriter();
+    }
+
+    /**
+     * Method setFileComment.
+     *
+     * @param fileComment a fileComment object.
+     */
+    public void setFileComment(String fileComment) {
+        delegate.setFileComment(fileComment);
+    }
+
+    /**
+     * Method write.
+     *
+     * @param writer   a writer object
+     * @param metadata a Metadata object
+     * @throws java.io.IOException java.io.IOException if any
+     */
+    public void write(Writer writer, Metadata metadata) throws java.io.IOException {
+        try {
+            delegate.write(writer, metadata.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    /**
+     * Method write.
+     *
+     * @param stream a stream object
+     * @param metadata a Metadata object
+     * @throws java.io.IOException java.io.IOException if any
+     */
+    public void write(OutputStream stream, Metadata metadata) throws java.io.IOException {
+        try {
+            delegate.write(stream, metadata.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+}
diff --git a/maven-repository-metadata/src/main/mdo/metadata.mdo b/maven-repository-metadata/src/main/mdo/metadata.mdo
index 6ce381d..e9c39f8 100644
--- a/maven-repository-metadata/src/main/mdo/metadata.mdo
+++ b/maven-repository-metadata/src/main/mdo/metadata.mdo
@@ -19,7 +19,7 @@
 
 <model xmlns="http://codehaus-plexus.github.io/MODELLO/1.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/1.4.0 http://codehaus-plexus.github.io/modello/xsd/modello-1.4.0.xsd"
-  xsd.namespace="http://maven.apache.org/METADATA/${version}"
+  xml.namespace="http://maven.apache.org/METADATA/${version}"
   xml.schemaLocation="https://maven.apache.org/xsd/repository-metadata-${version}.xsd">
   <id>repository-metadata</id>
   <name>Metadata</name>
@@ -35,11 +35,11 @@
     </default>
   </defaults>
   <classes>
-    <class rootElement="true" java.clone="deep">
+    <class rootElement="true" xml.tagName="metadata" java.clone="deep">
       <name>Metadata</name>
       <version>1.0.0+</version>
       <fields>
-        <field xml.attribute="true">
+        <field xml.attribute="true" xml.tagName="modelVersion">
           <name>modelVersion</name>
           <version>1.1.0+</version>
           <type>String</type>
@@ -74,10 +74,7 @@
         <field xdoc.separator="blank">
           <name>plugins</name>
           <version>1.0.0+</version>
-          <description>The set of plugins when this directory represents a "groupId" (deprecated)</description>
-          <annotations>
-            <annotation>@Deprecated</annotation>
-          </annotations>
+          <description>The set of plugins when this directory represents a "groupId".</description>
           <association>
             <type>Plugin</type>
             <multiplicity>*</multiplicity>
@@ -86,7 +83,7 @@
       </fields>
       <codeSegments>
         <codeSegment>
-          <version>1.0.0+</version>
+          <version>1.0.0/1.1.0</version>
           <code><![CDATA[
     private String getSnapshotVersionKey( SnapshotVersion sv )
     {
@@ -299,7 +296,7 @@
       </fields>
       <codeSegments>
         <codeSegment>
-          <version>1.0.0+</version>
+          <version>1.0.0/1.1.0</version>
           <code><![CDATA[
     public void updateTimestamp()
     {
@@ -383,10 +380,7 @@
     <class java.clone="deep">
       <name>Plugin</name>
       <version>1.0.0+</version>
-      <description>Mapping information for a single plugin within this group (deprecated).</description>
-      <annotations>
-        <annotation>@Deprecated</annotation>
-      </annotations>
+      <description>Mapping information for a single plugin within this group.</description>
       <comment>NOTE: plugin version is _NOT_ included here, since it is resolved using a separate algorithm in plugins' artifact.</comment>
       <fields>
         <field>
diff --git a/maven-repository-metadata/src/site/apt/index.apt b/maven-repository-metadata/src/site/apt/index.apt
index 75f067a..56fc874 100644
--- a/maven-repository-metadata/src/site/apt/index.apt
+++ b/maven-repository-metadata/src/site/apt/index.apt
@@ -55,9 +55,5 @@
 
    * a {{{./repository-metadata.html}Descriptor Reference}}.
  
- Notice: data about plugins in a directory representing a groupId is deprecated and will be removed in a future Maven version.
-~~ logic behind this:
-~~ 1. MNG-7266: maven-compat will be removed from future Maven version
-~~ 2. this will remove the code that updates plugins data: see MNG-7375/MPLUGIN-384 https://maven.apache.org/ref/3.8.4/maven-compat/apidocs/org/apache/maven/artifact/repository/metadata/GroupRepositoryMetadata.html
-~~ 3. this will lead to inconsistent data: removing it will be safer/more clear
-~~ but this logic still remains to be confirmed by clear consensus of the whole team
+ For more information see this page: {{{https://maven.apache.org/repositories/metadata.html}Maven Metadata}}.
+
diff --git a/maven-repository-metadata/src/site/site.xml b/maven-repository-metadata/src/site/site.xml
index c24e143..8ffe43d 100644
--- a/maven-repository-metadata/src/site/site.xml
+++ b/maven-repository-metadata/src/site/site.xml
@@ -27,8 +27,8 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
-      <!--item name="Source Xref" href="xref/index.html"/-->
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
 
diff --git a/maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java b/maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java
index ccdadbf..b2d6d78 100644
--- a/maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java
+++ b/maven-repository-metadata/src/test/java/org/apache/maven/artifact/repository/metadata/MetadataTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.artifact.repository.metadata;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,204 +16,225 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.artifact.repository.metadata;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.TimeZone;
 
+import com.ctc.wstx.stax.WstxInputFactory;
+import com.ctc.wstx.stax.WstxOutputFactory;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxWriter;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-class MetadataTest
-{
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class MetadataTest {
 
     Artifact artifact;
 
     Metadata target;
 
     @BeforeEach
-    void before()
-    {
-        artifact = new DefaultArtifact( "myGroup:myArtifact:1.0-SNAPSHOT" );
-        target = createMetadataFromArtifact( artifact );
+    void before() {
+        artifact = new DefaultArtifact("myGroup:myArtifact:1.0-SNAPSHOT");
+        target = createMetadataFromArtifact(artifact);
     }
 
     /*--- START test common metadata ---*/
     @Test
-    void mergeEmptyMetadata()
-        throws Exception
-    {
+    void mergeEmptyMetadata() throws Exception {
         Metadata metadata = new Metadata();
-        assertFalse( metadata.merge( new Metadata() ) );
+        assertFalse(metadata.merge(new Metadata()));
     }
 
     @Test
-    void mergeDifferentGAV()
-        throws Exception
-    {
+    void mergeDifferentGAV() throws Exception {
         // merge implicitly assumes that merge is only called on the same GAV and does not perform any validation here!
         Metadata source = new Metadata();
-        source.setArtifactId( "source-artifact" );
-        source.setGroupId( "source-group" );
-        source.setVersion( "2.0" );
-        assertFalse( target.merge( source ) );
-        assertEquals( "myArtifact", target.getArtifactId() );
-        assertEquals( "myGroup", target.getGroupId() );
-        assertEquals( "1.0-SNAPSHOT", target.getVersion() );
+        source.setArtifactId("source-artifact");
+        source.setGroupId("source-group");
+        source.setVersion("2.0");
+        assertFalse(target.merge(source));
+        assertEquals("myArtifact", target.getArtifactId());
+        assertEquals("myGroup", target.getGroupId());
+        assertEquals("1.0-SNAPSHOT", target.getVersion());
     }
     /*--- END test common metadata ---*/
 
     /*--- START test "groupId/artifactId/version" metadata ---*/
     @Test
-    void mergeSnapshotWithEmptyList()
-        throws Exception
-    {
+    void mergeSnapshotWithEmptyList() throws Exception {
         Snapshot snapshot = new Snapshot();
-        snapshot.setBuildNumber( 3 );
-        snapshot.setTimestamp( "20200710.072412" );
-        target.getVersioning().setSnapshot( snapshot );
-        target.getVersioning().setLastUpdated( "20200921071745" );
+        snapshot.setBuildNumber(3);
+        snapshot.setTimestamp("20200710.072412");
+        target.getVersioning().setSnapshot(snapshot);
+        target.getVersioning().setLastUpdated("20200921071745");
         SnapshotVersion sv = new SnapshotVersion();
-        sv.setClassifier( "sources" );
-        sv.setExtension( "jar" );
-        sv.setUpdated( "20200710072412" );
-        target.getVersioning().addSnapshotVersion( sv );
+        sv.setClassifier("sources");
+        sv.setExtension("jar");
+        sv.setUpdated("20200710072412");
+        target.getVersioning().addSnapshotVersion(sv);
 
-        Metadata source = createMetadataFromArtifact( artifact );
+        Metadata source = createMetadataFromArtifact(artifact);
         // nothing should be actually changed, but still merge returns true
-        assertTrue( target.merge( source ) );
+        assertTrue(target.merge(source));
 
         // NOTE! Merge updates last updated to source
-        assertEquals( "20200921071745", source.getVersioning().getLastUpdated() );
+        assertEquals("20200921071745", source.getVersioning().getLastUpdated());
 
-        assertEquals( "myArtifact", target.getArtifactId() );
-        assertEquals( "myGroup", target.getGroupId() );
+        assertEquals("myArtifact", target.getArtifactId());
+        assertEquals("myGroup", target.getGroupId());
 
-        assertEquals( 3, target.getVersioning().getSnapshot().getBuildNumber() );
-        assertEquals( "20200710.072412", target.getVersioning().getSnapshot().getTimestamp() );
+        assertEquals(3, target.getVersioning().getSnapshot().getBuildNumber());
+        assertEquals("20200710.072412", target.getVersioning().getSnapshot().getTimestamp());
 
-        assertEquals( 1, target.getVersioning().getSnapshotVersions().size() );
-        assertEquals( "sources", target.getVersioning().getSnapshotVersions().get( 0 ).getClassifier() );
-        assertEquals( "jar", target.getVersioning().getSnapshotVersions().get( 0 ).getExtension() );
-        assertEquals( "20200710072412", target.getVersioning().getSnapshotVersions().get( 0 ).getUpdated() );
+        assertEquals(1, target.getVersioning().getSnapshotVersions().size());
+        assertEquals(
+                "sources", target.getVersioning().getSnapshotVersions().get(0).getClassifier());
+        assertEquals("jar", target.getVersioning().getSnapshotVersions().get(0).getExtension());
+        assertEquals(
+                "20200710072412",
+                target.getVersioning().getSnapshotVersions().get(0).getUpdated());
     }
 
     @Test
-    void mergeWithSameSnapshotWithDifferentVersionsAndNewerLastUpdated()
-    {
-        Metadata source = createMetadataFromArtifact( artifact );
-        Date before = new Date( System.currentTimeMillis() - 5000 );
-        Date after = new Date( System.currentTimeMillis() );
-        addSnapshotVersion( target.getVersioning(), "jar", before, "1", 1 );
+    void mergeWithSameSnapshotWithDifferentVersionsAndNewerLastUpdated() {
+        Metadata source = createMetadataFromArtifact(artifact);
+        Date before = new Date(System.currentTimeMillis() - 5000);
+        Date after = new Date(System.currentTimeMillis());
+        addSnapshotVersion(target.getVersioning(), "jar", before, "1", 1);
         SnapshotVersion sv2 =
-            addSnapshotVersion( source.getVersioning(), "jar", after, "1.0-" + formatDate( after, true ) + "-2", 2 );
+                addSnapshotVersion(source.getVersioning(), "jar", after, "1.0-" + formatDate(after, true) + "-2", 2);
         SnapshotVersion sv3 =
-            addSnapshotVersion( source.getVersioning(), "pom", after, "1.0-" + formatDate( after, true ) + "-2", 2 );
-        assertTrue( target.merge( source ) );
+                addSnapshotVersion(source.getVersioning(), "pom", after, "1.0-" + formatDate(after, true) + "-2", 2);
+        assertTrue(target.merge(source));
         Versioning actualVersioning = target.getVersioning();
-        assertEquals( 2, actualVersioning.getSnapshotVersions().size() );
-        assertEquals( sv2, actualVersioning.getSnapshotVersions().get( 0 ) );
-        assertEquals( sv3, actualVersioning.getSnapshotVersions().get( 1 ) );
-        assertEquals( formatDate( after, false ), actualVersioning.getLastUpdated() );
-        assertEquals( formatDate( after, true ), actualVersioning.getSnapshot().getTimestamp() );
-        assertEquals( 2, actualVersioning.getSnapshot().getBuildNumber() );
+        assertEquals(2, actualVersioning.getSnapshotVersions().size());
+        assertEquals(sv2, actualVersioning.getSnapshotVersions().get(0));
+        assertEquals(sv3, actualVersioning.getSnapshotVersions().get(1));
+        assertEquals(formatDate(after, false), actualVersioning.getLastUpdated());
+        assertEquals(formatDate(after, true), actualVersioning.getSnapshot().getTimestamp());
+        assertEquals(2, actualVersioning.getSnapshot().getBuildNumber());
     }
 
     @Test
-    void mergeWithSameSnapshotWithDifferentVersionsAndOlderLastUpdated()
-    {
-        Metadata source = createMetadataFromArtifact( artifact );
-        Date before = new Date( System.currentTimeMillis() - 5000 );
-        Date after = new Date( System.currentTimeMillis() );
-        SnapshotVersion sv1 = addSnapshotVersion( target.getVersioning(), after, artifact );
-        addSnapshotVersion( source.getVersioning(), before, artifact );
+    void mergeWithSameSnapshotWithDifferentVersionsAndOlderLastUpdated() {
+        Metadata source = createMetadataFromArtifact(artifact);
+        Date before = new Date(System.currentTimeMillis() - 5000);
+        Date after = new Date(System.currentTimeMillis());
+        SnapshotVersion sv1 = addSnapshotVersion(target.getVersioning(), after, artifact);
+        addSnapshotVersion(source.getVersioning(), before, artifact);
         // nothing should be updated, as the target was already updated at a later date than source
-        assertFalse( target.merge( source ) );
-        assertEquals( 1, target.getVersioning().getSnapshotVersions().size() );
-        assertEquals( sv1, target.getVersioning().getSnapshotVersions().get( 0 ) );
-        assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
-        assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
+        assertFalse(target.merge(source));
+        assertEquals(1, target.getVersioning().getSnapshotVersions().size());
+        assertEquals(sv1, target.getVersioning().getSnapshotVersions().get(0));
+        assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
+        assertEquals(
+                formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
     }
 
     @Test
-    void mergeWithSameSnapshotWithSameVersionAndTimestamp()
-    {
-        Metadata source = createMetadataFromArtifact( artifact );
+    void mergeWithSameSnapshotWithSameVersionAndTimestamp() {
+        Metadata source = createMetadataFromArtifact(artifact);
         Date date = new Date();
-        addSnapshotVersion( target.getVersioning(), date, artifact );
-        SnapshotVersion sv1 = addSnapshotVersion( source.getVersioning(), date, artifact );
+        addSnapshotVersion(target.getVersioning(), date, artifact);
+        SnapshotVersion sv1 = addSnapshotVersion(source.getVersioning(), date, artifact);
         // although nothing has changed merge returns true, as the last modified date is equal
         // TODO: improve merge here?
-        assertTrue( target.merge( source ) );
-        assertEquals( 1, target.getVersioning().getSnapshotVersions().size() );
-        assertEquals( sv1, target.getVersioning().getSnapshotVersions().get( 0 ) );
-        assertEquals( formatDate( date, false ), target.getVersioning().getLastUpdated() );
-        assertEquals( formatDate( date, true ), target.getVersioning().getSnapshot().getTimestamp() );
+        assertTrue(target.merge(source));
+        assertEquals(1, target.getVersioning().getSnapshotVersions().size());
+        assertEquals(sv1, target.getVersioning().getSnapshotVersions().get(0));
+        assertEquals(formatDate(date, false), target.getVersioning().getLastUpdated());
+        assertEquals(
+                formatDate(date, true), target.getVersioning().getSnapshot().getTimestamp());
     }
 
     @Test
-    void mergeLegacyWithSnapshotLegacy()
-    {
-        Metadata source = createMetadataFromArtifact( artifact );
-        Date before = new Date( System.currentTimeMillis() - 5000 );
-        Date after = new Date( System.currentTimeMillis() );
+    void mergeLegacyWithSnapshotLegacy() {
+        Metadata source = createMetadataFromArtifact(artifact);
+        Date before = new Date(System.currentTimeMillis() - 5000);
+        Date after = new Date(System.currentTimeMillis());
         // legacy metadata did not have "versioning.snapshotVersions"
-        addSnapshotVersionLegacy( target.getVersioning(), before, 1 );
-        addSnapshotVersionLegacy( source.getVersioning(), after, 2 );
+        addSnapshotVersionLegacy(target.getVersioning(), before, 1);
+        addSnapshotVersionLegacy(source.getVersioning(), after, 2);
         // although nothing has changed merge returns true, as the last modified date is equal
         // TODO: improve merge here?
-        assertTrue( target.merge( source ) );
-        assertEquals( 0, target.getVersioning().getSnapshotVersions().size() );
-        assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
-        assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
+        assertTrue(target.merge(source));
+        assertEquals(0, target.getVersioning().getSnapshotVersions().size());
+        assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
+        assertEquals(
+                formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
     }
 
     @Test
-    void mergeLegacyWithSnapshot()
-    {
-        Metadata source = createMetadataFromArtifact( artifact );
-        Date before = new Date( System.currentTimeMillis() - 5000 );
-        Date after = new Date( System.currentTimeMillis() );
+    void mergeLegacyWithSnapshot() {
+        Metadata source = createMetadataFromArtifact(artifact);
+        Date before = new Date(System.currentTimeMillis() - 5000);
+        Date after = new Date(System.currentTimeMillis());
         // legacy metadata did not have "versioning.snapshotVersions"
-        addSnapshotVersionLegacy( target.getVersioning(), before, 1 );
-        addSnapshotVersion( source.getVersioning(), after, artifact );
+        addSnapshotVersionLegacy(target.getVersioning(), before, 1);
+        addSnapshotVersion(source.getVersioning(), after, artifact);
         // although nothing has changed merge returns true, as the last modified date is equal
         // TODO: improve merge here?
-        assertTrue( target.merge( source ) );
+        assertTrue(target.merge(source));
         // never convert from legacy format to v1.1 format
-        assertEquals( 0, target.getVersioning().getSnapshotVersions().size() );
-        assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
-        assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
+        assertEquals(0, target.getVersioning().getSnapshotVersions().size());
+        assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
+        assertEquals(
+                formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
     }
 
     @Test
-    void mergeWithSnapshotLegacy()
-    {
-        Metadata source = createMetadataFromArtifact( artifact );
-        Date before = new Date( System.currentTimeMillis() - 5000 );
-        Date after = new Date( System.currentTimeMillis() );
-        addSnapshotVersion( target.getVersioning(), before, artifact );
+    void mergeWithSnapshotLegacy() {
+        Metadata source = createMetadataFromArtifact(artifact);
+        Date before = new Date(System.currentTimeMillis() - 5000);
+        Date after = new Date(System.currentTimeMillis());
+        addSnapshotVersion(target.getVersioning(), before, artifact);
         // legacy metadata did not have "versioning.snapshotVersions"
-        addSnapshotVersionLegacy( source.getVersioning(), after, 2 );
+        addSnapshotVersionLegacy(source.getVersioning(), after, 2);
         // although nothing has changed merge returns true, as the last modified date is equal
         // TODO: improve merge here?
-        assertTrue( target.merge( source ) );
+        assertTrue(target.merge(source));
         // the result must be legacy format as well
-        assertEquals( 0, target.getVersioning().getSnapshotVersions().size() );
-        assertEquals( formatDate( after, false ), target.getVersioning().getLastUpdated() );
-        assertEquals( formatDate( after, true ), target.getVersioning().getSnapshot().getTimestamp() );
-        assertEquals( 2, target.getVersioning().getSnapshot().getBuildNumber() );
+        assertEquals(0, target.getVersioning().getSnapshotVersions().size());
+        assertEquals(formatDate(after, false), target.getVersioning().getLastUpdated());
+        assertEquals(
+                formatDate(after, true), target.getVersioning().getSnapshot().getTimestamp());
+        assertEquals(2, target.getVersioning().getSnapshot().getBuildNumber());
     }
     /*-- END test "groupId/artifactId/version" metadata ---*/
 
+    @Test
+    void testRoundtrip() throws Exception {
+        System.setProperty(XMLInputFactory.class.getName(), WstxInputFactory.class.getName());
+        System.setProperty(XMLOutputFactory.class.getName(), WstxOutputFactory.class.getName());
+
+        Metadata source = new Metadata(org.apache.maven.artifact.repository.metadata.v4.Metadata.newBuilder(
+                        createMetadataFromArtifact(artifact).getDelegate(), true)
+                .modelEncoding("UTF-16")
+                .build());
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        new MetadataStaxWriter().write(baos, source.getDelegate());
+        Metadata source2 =
+                new Metadata(new MetadataStaxReader().read(new ByteArrayInputStream(baos.toByteArray()), true));
+        assertNotNull(source2);
+    }
+
     /*-- START helper methods to populate metadata objects ---*/
     private static final String SNAPSHOT = "SNAPSHOT";
 
@@ -223,67 +242,62 @@
 
     private static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmss";
 
-    private static String formatDate( Date date, boolean forSnapshotTimestamp )
-    {
+    private static String formatDate(Date date, boolean forSnapshotTimestamp) {
         // logic from metadata.mdo, class "Versioning"
-        TimeZone timezone = TimeZone.getTimeZone( "UTC" );
+        TimeZone timezone = TimeZone.getTimeZone("UTC");
         DateFormat fmt =
-            new SimpleDateFormat( forSnapshotTimestamp ? DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT : DEFAULT_DATE_FORMAT );
-        fmt.setCalendar( new GregorianCalendar() );
-        fmt.setTimeZone( timezone );
-        return fmt.format( date );
+                new SimpleDateFormat(forSnapshotTimestamp ? DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT : DEFAULT_DATE_FORMAT);
+        fmt.setCalendar(new GregorianCalendar());
+        fmt.setTimeZone(timezone);
+        return fmt.format(date);
     }
 
-    private static Metadata createMetadataFromArtifact( Artifact artifact )
-    {
+    private static Metadata createMetadataFromArtifact(Artifact artifact) {
         Metadata metadata = new Metadata();
-        metadata.setArtifactId( artifact.getArtifactId() );
-        metadata.setGroupId( artifact.getGroupId() );
-        metadata.setVersion( artifact.getVersion() );
-        metadata.setVersioning( new Versioning() );
+        metadata.setArtifactId(artifact.getArtifactId());
+        metadata.setGroupId(artifact.getGroupId());
+        metadata.setVersion(artifact.getVersion());
+        metadata.setVersioning(new Versioning());
         return metadata;
     }
 
-    private static SnapshotVersion addSnapshotVersion( Versioning versioning, Date timestamp, Artifact artifact )
-    {
+    private static SnapshotVersion addSnapshotVersion(Versioning versioning, Date timestamp, Artifact artifact) {
         int buildNumber = 1;
         // this generates timestamped versions like maven-resolver-provider:
         // https://github.com/apache/maven/blob/03df5f7c639db744a3597c7175c92c8e2a27767b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java#L79
         String version = artifact.getVersion();
-        String qualifier = formatDate( timestamp, true ) + '-' + buildNumber;
-        version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier;
-        return addSnapshotVersion( versioning, artifact.getExtension(), timestamp, version, buildNumber );
+        String qualifier = formatDate(timestamp, true) + '-' + buildNumber;
+        version = version.substring(0, version.length() - SNAPSHOT.length()) + qualifier;
+        return addSnapshotVersion(versioning, artifact.getExtension(), timestamp, version, buildNumber);
     }
 
-    private static SnapshotVersion addSnapshotVersion( Versioning versioning, String extension, Date timestamp,
-                                                       String version, int buildNumber )
-    {
+    private static SnapshotVersion addSnapshotVersion(
+            Versioning versioning, String extension, Date timestamp, String version, int buildNumber) {
         Snapshot snapshot = new Snapshot();
-        snapshot.setBuildNumber( buildNumber );
-        snapshot.setTimestamp( formatDate( timestamp, true ) );
+        snapshot.setBuildNumber(buildNumber);
+        snapshot.setTimestamp(formatDate(timestamp, true));
 
         SnapshotVersion sv = new SnapshotVersion();
-        sv.setExtension( extension );
-        sv.setVersion( version );
-        sv.setUpdated( formatDate( timestamp, false ) );
-        versioning.addSnapshotVersion( sv );
+        sv.setExtension(extension);
+        sv.setVersion(version);
+        sv.setUpdated(formatDate(timestamp, false));
+        versioning.addSnapshotVersion(sv);
 
         // make the new snapshot the current one
-        versioning.setSnapshot( snapshot );
-        versioning.setLastUpdatedTimestamp( timestamp );
+        versioning.setSnapshot(snapshot);
+        versioning.setLastUpdatedTimestamp(timestamp);
         return sv;
     }
 
     // the format written by Maven 2
     // (https://maven.apache.org/ref/2.2.1/maven-repository-metadata/repository-metadata.html)
-    private static void addSnapshotVersionLegacy( Versioning versioning, Date timestamp, int buildNumber )
-    {
+    private static void addSnapshotVersionLegacy(Versioning versioning, Date timestamp, int buildNumber) {
         Snapshot snapshot = new Snapshot();
-        snapshot.setBuildNumber( buildNumber );
-        snapshot.setTimestamp( formatDate( timestamp, true ) );
+        snapshot.setBuildNumber(buildNumber);
+        snapshot.setTimestamp(formatDate(timestamp, true));
 
-        versioning.setSnapshot( snapshot );
-        versioning.setLastUpdatedTimestamp( timestamp );
+        versioning.setSnapshot(snapshot);
+        versioning.setLastUpdatedTimestamp(timestamp);
     }
     /*-- END helper methods to populate metadata objects ---*/
-}
\ No newline at end of file
+}
diff --git a/maven-resolver-provider/pom.xml b/maven-resolver-provider/pom.xml
index 5b416a4..3fa1082 100644
--- a/maven-resolver-provider/pom.xml
+++ b/maven-resolver-provider/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-resolver-provider</artifactId>
@@ -71,17 +69,13 @@
       <artifactId>maven-resolver-impl</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
       <groupId>javax.inject</groupId>
       <artifactId>javax.inject</artifactId>
     </dependency>
     <dependency>
       <groupId>com.google.inject</groupId>
       <artifactId>guice</artifactId>
-      <classifier>no_aop</classifier>
+      <classifier>classes</classifier>
       <optional>true</optional>
       <exclusions>
         <exclusion>
@@ -95,6 +89,10 @@
       </exclusions>
     </dependency>
     <dependency>
+      <groupId>org.ow2.asm</groupId>
+      <artifactId>asm</artifactId>
+    </dependency>
+    <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
       <optional>true</optional>
@@ -152,8 +150,16 @@
         <groupId>org.eclipse.sisu</groupId>
         <artifactId>sisu-maven-plugin</artifactId>
       </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <excludes>
+            <exclude>**/package-info.java</exclude>
+          </excludes>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
 </project>
-
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java
index af1eebf..b3a7371 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorReaderDelegate.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -45,111 +44,101 @@
 
 /**
  * Populates Aether {@link ArtifactDescriptorResult} from Maven project {@link Model}.
- *
+ * <p>
  * <strong>Note:</strong> This class is part of work in progress and can be changed or removed without notice.
  * @since 3.2.4
  */
-public class ArtifactDescriptorReaderDelegate
-{
-    public void populateResult( RepositorySystemSession session, ArtifactDescriptorResult result, Model model )
-    {
+public class ArtifactDescriptorReaderDelegate {
+    public void populateResult(RepositorySystemSession session, ArtifactDescriptorResult result, Model model) {
         ArtifactTypeRegistry stereotypes = session.getArtifactTypeRegistry();
 
-        for ( Repository r : model.getRepositories() )
-        {
-            result.addRepository( ArtifactDescriptorUtils.toRemoteRepository( r ) );
+        for (Repository r : model.getRepositories()) {
+            result.addRepository(ArtifactDescriptorUtils.toRemoteRepository(r));
         }
 
-        for ( org.apache.maven.model.Dependency dependency : model.getDependencies() )
-        {
-            result.addDependency( convert( dependency, stereotypes ) );
+        for (org.apache.maven.model.Dependency dependency : model.getDependencies()) {
+            result.addDependency(convert(dependency, stereotypes));
         }
 
         DependencyManagement mgmt = model.getDependencyManagement();
-        if ( mgmt != null )
-        {
-            for ( org.apache.maven.model.Dependency dependency : mgmt.getDependencies() )
-            {
-                result.addManagedDependency( convert( dependency, stereotypes ) );
+        if (mgmt != null) {
+            for (org.apache.maven.model.Dependency dependency : mgmt.getDependencies()) {
+                result.addManagedDependency(convert(dependency, stereotypes));
             }
         }
 
         Map<String, Object> properties = new LinkedHashMap<>();
 
         Prerequisites prerequisites = model.getPrerequisites();
-        if ( prerequisites != null )
-        {
-            properties.put( "prerequisites.maven", prerequisites.getMaven() );
+        if (prerequisites != null) {
+            properties.put("prerequisites.maven", prerequisites.getMaven());
         }
 
         List<License> licenses = model.getLicenses();
-        properties.put( "license.count", licenses.size() );
-        for ( int i = 0; i < licenses.size(); i++ )
-        {
-            License license = licenses.get( i );
-            properties.put( "license." + i + ".name", license.getName() );
-            properties.put( "license." + i + ".url", license.getUrl() );
-            properties.put( "license." + i + ".comments", license.getComments() );
-            properties.put( "license." + i + ".distribution", license.getDistribution() );
+        properties.put("license.count", licenses.size());
+        for (int i = 0; i < licenses.size(); i++) {
+            License license = licenses.get(i);
+            properties.put("license." + i + ".name", license.getName());
+            properties.put("license." + i + ".url", license.getUrl());
+            properties.put("license." + i + ".comments", license.getComments());
+            properties.put("license." + i + ".distribution", license.getDistribution());
         }
 
-        result.setProperties( properties );
+        result.setProperties(properties);
 
-        setArtifactProperties( result, model );
+        setArtifactProperties(result, model);
     }
 
-    private Dependency convert( org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes )
-    {
-        ArtifactType stereotype = stereotypes.get( dependency.getType() );
-        if ( stereotype == null )
-        {
-            stereotype = new DefaultArtifactType( dependency.getType() );
+    private Dependency convert(org.apache.maven.model.Dependency dependency, ArtifactTypeRegistry stereotypes) {
+        ArtifactType stereotype = stereotypes.get(dependency.getType());
+        if (stereotype == null) {
+            stereotype = new DefaultArtifactType(dependency.getType());
         }
 
-        boolean system = dependency.getSystemPath() != null && dependency.getSystemPath().length() > 0;
+        boolean system = dependency.getSystemPath() != null
+                && !dependency.getSystemPath().isEmpty();
 
         Map<String, String> props = null;
-        if ( system )
-        {
-            props = Collections.singletonMap( ArtifactProperties.LOCAL_PATH, dependency.getSystemPath() );
+        if (system) {
+            props = Collections.singletonMap(ArtifactProperties.LOCAL_PATH, dependency.getSystemPath());
         }
 
-        Artifact artifact =
-            new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), dependency.getClassifier(), null,
-                                 dependency.getVersion(), props, stereotype );
+        Artifact artifact = new DefaultArtifact(
+                dependency.getGroupId(),
+                dependency.getArtifactId(),
+                dependency.getClassifier(),
+                null,
+                dependency.getVersion(),
+                props,
+                stereotype);
 
-        List<Exclusion> exclusions = new ArrayList<>( dependency.getExclusions().size() );
-        for ( org.apache.maven.model.Exclusion exclusion : dependency.getExclusions() )
-        {
-            exclusions.add( convert( exclusion ) );
+        List<Exclusion> exclusions = new ArrayList<>(dependency.getExclusions().size());
+        for (org.apache.maven.model.Exclusion exclusion : dependency.getExclusions()) {
+            exclusions.add(convert(exclusion));
         }
 
-        return new Dependency( artifact, dependency.getScope(),
-                                            dependency.getOptional() != null
-                                                ? dependency.isOptional()
-                                                : null,
-                                            exclusions );
+        return new Dependency(
+                artifact,
+                dependency.getScope(),
+                dependency.getOptional() != null ? dependency.isOptional() : null,
+                exclusions);
     }
 
-    private Exclusion convert( org.apache.maven.model.Exclusion exclusion )
-    {
-        return new Exclusion( exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*" );
+    private Exclusion convert(org.apache.maven.model.Exclusion exclusion) {
+        return new Exclusion(exclusion.getGroupId(), exclusion.getArtifactId(), "*", "*");
     }
 
-    private void setArtifactProperties( ArtifactDescriptorResult result, Model model )
-    {
+    private void setArtifactProperties(ArtifactDescriptorResult result, Model model) {
         String downloadUrl = null;
         DistributionManagement distMgmt = model.getDistributionManagement();
-        if ( distMgmt != null )
-        {
+        if (distMgmt != null) {
             downloadUrl = distMgmt.getDownloadUrl();
         }
-        if ( downloadUrl != null && downloadUrl.length() > 0 )
-        {
+        if (downloadUrl != null && !downloadUrl.isEmpty()) {
             Artifact artifact = result.getArtifact();
-            Map<String, String> props = new HashMap<>( artifact.getProperties() );
-            props.put( ArtifactProperties.DOWNLOAD_URL, downloadUrl );
-            result.setArtifact( artifact.setProperties( props ) );
+            Map<String, String> props = new HashMap<>(artifact.getProperties());
+            props.put(ArtifactProperties.DOWNLOAD_URL, downloadUrl);
+            result.setArtifact(artifact.setProperties(props));
         }
     }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorUtils.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorUtils.java
index 17fbb10..244bd6b 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorUtils.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ArtifactDescriptorUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
 import org.apache.maven.model.Repository;
@@ -30,59 +29,48 @@
  * <strong>Warning:</strong> This is an internal utility class that is only public for technical reasons, it is not part
  * of the public API. In particular, this class can be changed or deleted without prior notice.
  *
- * @author Benjamin Bentmann
  */
-public class ArtifactDescriptorUtils
-{
+public class ArtifactDescriptorUtils {
 
-    public static Artifact toPomArtifact( Artifact artifact )
-    {
+    public static Artifact toPomArtifact(Artifact artifact) {
         Artifact pomArtifact = artifact;
 
-        if ( pomArtifact.getClassifier().length() > 0 || !"pom".equals( pomArtifact.getExtension() ) )
-        {
+        if (!pomArtifact.getClassifier().isEmpty() || !"pom".equals(pomArtifact.getExtension())) {
             pomArtifact =
-                new DefaultArtifact( artifact.getGroupId(), artifact.getArtifactId(), "pom", artifact.getVersion() );
+                    new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), "pom", artifact.getVersion());
         }
 
         return pomArtifact;
     }
 
-    public static RemoteRepository toRemoteRepository( Repository repository )
-    {
+    public static RemoteRepository toRemoteRepository(Repository repository) {
         RemoteRepository.Builder builder =
-            new RemoteRepository.Builder( repository.getId(), repository.getLayout(), repository.getUrl() );
-        builder.setSnapshotPolicy( toRepositoryPolicy( repository.getSnapshots() ) );
-        builder.setReleasePolicy( toRepositoryPolicy( repository.getReleases() ) );
+                new RemoteRepository.Builder(repository.getId(), repository.getLayout(), repository.getUrl());
+        builder.setSnapshotPolicy(toRepositoryPolicy(repository.getSnapshots()));
+        builder.setReleasePolicy(toRepositoryPolicy(repository.getReleases()));
         return builder.build();
     }
 
-    public static RepositoryPolicy toRepositoryPolicy( org.apache.maven.model.RepositoryPolicy policy )
-    {
+    public static RepositoryPolicy toRepositoryPolicy(org.apache.maven.model.RepositoryPolicy policy) {
         boolean enabled = true;
-        String checksums = toRepositoryChecksumPolicy( ArtifactRepositoryPolicy.DEFAULT_CHECKSUM_POLICY );
+        String checksums = toRepositoryChecksumPolicy(ArtifactRepositoryPolicy.DEFAULT_CHECKSUM_POLICY);
         String updates = RepositoryPolicy.UPDATE_POLICY_DAILY;
 
-        if ( policy != null )
-        {
+        if (policy != null) {
             enabled = policy.isEnabled();
-            if ( policy.getUpdatePolicy() != null )
-            {
+            if (policy.getUpdatePolicy() != null) {
                 updates = policy.getUpdatePolicy();
             }
-            if ( policy.getChecksumPolicy() != null )
-            {
+            if (policy.getChecksumPolicy() != null) {
                 checksums = policy.getChecksumPolicy();
             }
         }
 
-        return new RepositoryPolicy( enabled, updates, checksums );
+        return new RepositoryPolicy(enabled, updates, checksums);
     }
 
-    public static String toRepositoryChecksumPolicy( final String artifactRepositoryPolicy )
-    {
-        switch ( artifactRepositoryPolicy )
-        {
+    public static String toRepositoryChecksumPolicy(final String artifactRepositoryPolicy) {
+        switch (artifactRepositoryPolicy) {
             case ArtifactRepositoryPolicy.CHECKSUM_POLICY_FAIL:
                 return RepositoryPolicy.CHECKSUM_POLICY_FAIL;
             case ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE:
@@ -90,8 +78,7 @@
             case ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN:
                 return RepositoryPolicy.CHECKSUM_POLICY_WARN;
             default:
-                throw new IllegalArgumentException( "unknown repository checksum policy: " + artifactRepositoryPolicy );
+                throw new IllegalArgumentException("unknown repository checksum policy: " + artifactRepositoryPolicy);
         }
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java
index 3811365..0d40d70 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
 
 import java.util.LinkedHashSet;
 import java.util.Map;
@@ -25,10 +28,6 @@
 import java.util.Properties;
 import java.util.Set;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.model.DistributionManagement;
 import org.apache.maven.model.Model;
 import org.apache.maven.model.Relocation;
@@ -69,13 +68,11 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger( DefaultArtifactDescriptorReader.class );
+public class DefaultArtifactDescriptorReader implements ArtifactDescriptorReader {
+    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultArtifactDescriptorReader.class);
 
     private final RemoteRepositoryManager remoteRepositoryManager;
     private final VersionResolver versionResolver;
@@ -93,238 +90,214 @@
             ArtifactResolver artifactResolver,
             ModelBuilder modelBuilder,
             RepositoryEventDispatcher repositoryEventDispatcher,
-            ModelCacheFactory modelCacheFactory )
-    {
-        this.remoteRepositoryManager = Objects.requireNonNull( remoteRepositoryManager,
-                "remoteRepositoryManager cannot be null" );
-        this.versionResolver = Objects.requireNonNull( versionResolver, "versionResolver cannot be null" );
-        this.versionRangeResolver =
-                Objects.requireNonNull( versionRangeResolver, "versionRangeResolver cannot be null" );
-        this.artifactResolver = Objects.requireNonNull( artifactResolver, "artifactResolver cannot be null" );
-        this.modelBuilder = Objects.requireNonNull( modelBuilder, "modelBuilder cannot be null" );
-        this.repositoryEventDispatcher = Objects.requireNonNull( repositoryEventDispatcher,
-                "repositoryEventDispatcher cannot be null" );
-        this.modelCacheFactory = Objects.requireNonNull( modelCacheFactory,
-                "modelCacheFactory cannot be null" );
+            ModelCacheFactory modelCacheFactory) {
+        this.remoteRepositoryManager =
+                Objects.requireNonNull(remoteRepositoryManager, "remoteRepositoryManager cannot be null");
+        this.versionResolver = Objects.requireNonNull(versionResolver, "versionResolver cannot be null");
+        this.versionRangeResolver = Objects.requireNonNull(versionRangeResolver, "versionRangeResolver cannot be null");
+        this.artifactResolver = Objects.requireNonNull(artifactResolver, "artifactResolver cannot be null");
+        this.modelBuilder = Objects.requireNonNull(modelBuilder, "modelBuilder cannot be null");
+        this.repositoryEventDispatcher =
+                Objects.requireNonNull(repositoryEventDispatcher, "repositoryEventDispatcher cannot be null");
+        this.modelCacheFactory = Objects.requireNonNull(modelCacheFactory, "modelCacheFactory cannot be null");
     }
 
-    public ArtifactDescriptorResult readArtifactDescriptor( RepositorySystemSession session,
-                                                            ArtifactDescriptorRequest request )
-        throws ArtifactDescriptorException
-    {
-        ArtifactDescriptorResult result = new ArtifactDescriptorResult( request );
+    @Override
+    public ArtifactDescriptorResult readArtifactDescriptor(
+            RepositorySystemSession session, ArtifactDescriptorRequest request) throws ArtifactDescriptorException {
+        ArtifactDescriptorResult result = new ArtifactDescriptorResult(request);
 
-        Model model = loadPom( session, request, result );
-        if ( model != null )
-        {
+        Model model = loadPom(session, request, result);
+        if (model != null) {
             Map<String, Object> config = session.getConfigProperties();
             ArtifactDescriptorReaderDelegate delegate =
-                (ArtifactDescriptorReaderDelegate) config.get( ArtifactDescriptorReaderDelegate.class.getName() );
+                    (ArtifactDescriptorReaderDelegate) config.get(ArtifactDescriptorReaderDelegate.class.getName());
 
-            if ( delegate == null )
-            {
+            if (delegate == null) {
                 delegate = new ArtifactDescriptorReaderDelegate();
             }
 
-            delegate.populateResult( session, result, model );
+            delegate.populateResult(session, result, model);
         }
 
         return result;
     }
 
-    private Model loadPom( RepositorySystemSession session, ArtifactDescriptorRequest request,
-                           ArtifactDescriptorResult result )
-        throws ArtifactDescriptorException
-    {
-        RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
+    private Model loadPom(
+            RepositorySystemSession session, ArtifactDescriptorRequest request, ArtifactDescriptorResult result)
+            throws ArtifactDescriptorException {
+        RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
 
         Set<String> visited = new LinkedHashSet<>();
-        for ( Artifact a = request.getArtifact();; )
-        {
-            Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( a );
-            try
-            {
+        for (Artifact a = request.getArtifact(); ; ) {
+            Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact(a);
+            try {
                 VersionRequest versionRequest =
-                    new VersionRequest( a, request.getRepositories(), request.getRequestContext() );
-                versionRequest.setTrace( trace );
-                VersionResult versionResult = versionResolver.resolveVersion( session, versionRequest );
+                        new VersionRequest(a, request.getRepositories(), request.getRequestContext());
+                versionRequest.setTrace(trace);
+                VersionResult versionResult = versionResolver.resolveVersion(session, versionRequest);
 
-                a = a.setVersion( versionResult.getVersion() );
+                a = a.setVersion(versionResult.getVersion());
 
                 versionRequest =
-                    new VersionRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
-                versionRequest.setTrace( trace );
-                versionResult = versionResolver.resolveVersion( session, versionRequest );
+                        new VersionRequest(pomArtifact, request.getRepositories(), request.getRequestContext());
+                versionRequest.setTrace(trace);
+                versionResult = versionResolver.resolveVersion(session, versionRequest);
 
-                pomArtifact = pomArtifact.setVersion( versionResult.getVersion() );
-            }
-            catch ( VersionResolutionException e )
-            {
-                result.addException( e );
-                throw new ArtifactDescriptorException( result );
+                pomArtifact = pomArtifact.setVersion(versionResult.getVersion());
+            } catch (VersionResolutionException e) {
+                result.addException(e);
+                throw new ArtifactDescriptorException(result);
             }
 
-            if ( !visited.add( a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getBaseVersion() ) )
-            {
+            if (!visited.add(a.getGroupId() + ':' + a.getArtifactId() + ':' + a.getBaseVersion())) {
                 RepositoryException exception =
-                    new RepositoryException( "Artifact relocations form a cycle: " + visited );
-                invalidDescriptor( session, trace, a, exception );
-                if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
-                {
+                        new RepositoryException("Artifact relocations form a cycle: " + visited);
+                invalidDescriptor(session, trace, a, exception);
+                if ((getPolicy(session, a, request) & ArtifactDescriptorPolicy.IGNORE_INVALID) != 0) {
                     return null;
                 }
-                result.addException( exception );
-                throw new ArtifactDescriptorException( result );
+                result.addException(exception);
+                throw new ArtifactDescriptorException(result);
             }
 
             ArtifactResult resolveResult;
-            try
-            {
+            try {
                 ArtifactRequest resolveRequest =
-                    new ArtifactRequest( pomArtifact, request.getRepositories(), request.getRequestContext() );
-                resolveRequest.setTrace( trace );
-                resolveResult = artifactResolver.resolveArtifact( session, resolveRequest );
+                        new ArtifactRequest(pomArtifact, request.getRepositories(), request.getRequestContext());
+                resolveRequest.setTrace(trace);
+                resolveResult = artifactResolver.resolveArtifact(session, resolveRequest);
                 pomArtifact = resolveResult.getArtifact();
-                result.setRepository( resolveResult.getRepository() );
-            }
-            catch ( ArtifactResolutionException e )
-            {
-                if ( e.getCause() instanceof ArtifactNotFoundException )
-                {
-                    missingDescriptor( session, trace, a, (Exception) e.getCause() );
-                    if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_MISSING ) != 0 )
-                    {
+                result.setRepository(resolveResult.getRepository());
+            } catch (ArtifactResolutionException e) {
+                if (e.getCause() instanceof ArtifactNotFoundException) {
+                    missingDescriptor(session, trace, a, (Exception) e.getCause());
+                    if ((getPolicy(session, a, request) & ArtifactDescriptorPolicy.IGNORE_MISSING) != 0) {
                         return null;
                     }
                 }
-                result.addException( e );
-                throw new ArtifactDescriptorException( result );
+                result.addException(e);
+                throw new ArtifactDescriptorException(result);
             }
 
             Model model;
 
             // TODO hack: don't rebuild model if it was already loaded during reactor resolution
             final WorkspaceReader workspace = session.getWorkspaceReader();
-            if ( workspace instanceof MavenWorkspaceReader )
-            {
-                model = ( (MavenWorkspaceReader) workspace ).findModel( pomArtifact );
-                if ( model != null )
-                {
+            if (workspace instanceof MavenWorkspaceReader) {
+                model = ((MavenWorkspaceReader) workspace).findModel(pomArtifact);
+                if (model != null) {
                     return model;
                 }
             }
 
-            try
-            {
+            try {
                 ModelBuildingRequest modelRequest = new DefaultModelBuildingRequest();
-                modelRequest.setValidationLevel( ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL );
-                modelRequest.setProcessPlugins( false );
-                modelRequest.setTwoPhaseBuilding( false );
-                modelRequest.setSystemProperties( toProperties( session.getSystemProperties() ) );
-                modelRequest.setUserProperties( toProperties( session.getUserProperties() ) );
-                modelRequest.setModelCache( modelCacheFactory.createCache( session ) );
-                modelRequest.setModelResolver( new DefaultModelResolver( session, trace.newChild( modelRequest ),
-                                                                         request.getRequestContext(), artifactResolver,
-                                                                         versionRangeResolver, remoteRepositoryManager,
-                                                                         request.getRepositories() ) );
-                if ( resolveResult.getRepository() instanceof WorkspaceRepository )
-                {
-                    modelRequest.setPomFile( pomArtifact.getFile() );
-                }
-                else
-                {
-                    modelRequest.setModelSource( new ArtifactModelSource( pomArtifact.getFile(),
-                                                                          pomArtifact.getGroupId(),
-                                                                          pomArtifact.getArtifactId(),
-                                                                          pomArtifact.getVersion() ) );
+                modelRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
+                modelRequest.setProcessPlugins(false);
+                modelRequest.setTwoPhaseBuilding(false);
+                // This merge is on purpose because otherwise user properties would override model
+                // properties in dependencies the user does not know. See MNG-7563 for details.
+                modelRequest.setSystemProperties(
+                        toProperties(session.getUserProperties(), session.getSystemProperties()));
+                modelRequest.setUserProperties(new Properties());
+                modelRequest.setModelCache(modelCacheFactory.createCache(session));
+                modelRequest.setModelResolver(new DefaultModelResolver(
+                        session,
+                        trace.newChild(modelRequest),
+                        request.getRequestContext(),
+                        artifactResolver,
+                        versionRangeResolver,
+                        remoteRepositoryManager,
+                        request.getRepositories()));
+                if (resolveResult.getRepository() instanceof WorkspaceRepository) {
+                    modelRequest.setPomFile(pomArtifact.getFile());
+                } else {
+                    modelRequest.setModelSource(new ArtifactModelSource(
+                            pomArtifact.getFile(),
+                            pomArtifact.getGroupId(),
+                            pomArtifact.getArtifactId(),
+                            pomArtifact.getVersion()));
                 }
 
-                model = modelBuilder.build( modelRequest ).getEffectiveModel();
-            }
-            catch ( ModelBuildingException e )
-            {
-                for ( ModelProblem problem : e.getProblems() )
-                {
-                    if ( problem.getException() instanceof UnresolvableModelException )
-                    {
-                        result.addException( problem.getException() );
-                        throw new ArtifactDescriptorException( result );
+                model = modelBuilder.build(modelRequest).getEffectiveModel();
+            } catch (ModelBuildingException e) {
+                for (ModelProblem problem : e.getProblems()) {
+                    if (problem.getException() instanceof UnresolvableModelException) {
+                        result.addException(problem.getException());
+                        throw new ArtifactDescriptorException(result);
                     }
                 }
-                invalidDescriptor( session, trace, a, e );
-                if ( ( getPolicy( session, a, request ) & ArtifactDescriptorPolicy.IGNORE_INVALID ) != 0 )
-                {
+                invalidDescriptor(session, trace, a, e);
+                if ((getPolicy(session, a, request) & ArtifactDescriptorPolicy.IGNORE_INVALID) != 0) {
                     return null;
                 }
-                result.addException( e );
-                throw new ArtifactDescriptorException( result );
+                result.addException(e);
+                throw new ArtifactDescriptorException(result);
             }
 
-            Relocation relocation = getRelocation( model );
+            Relocation relocation = getRelocation(model);
 
-            if ( relocation != null )
-            {
-                result.addRelocation( a );
-                a =
-                    new RelocatedArtifact( a, relocation.getGroupId(), relocation.getArtifactId(),
-                                           relocation.getVersion(), relocation.getMessage() );
-                result.setArtifact( a );
-            }
-            else
-            {
+            if (relocation != null) {
+                result.addRelocation(a);
+                a = new RelocatedArtifact(
+                        a,
+                        relocation.getGroupId(),
+                        relocation.getArtifactId(),
+                        relocation.getVersion(),
+                        relocation.getMessage());
+                result.setArtifact(a);
+            } else {
                 return model;
             }
         }
     }
 
-    private Properties toProperties( Map<String, String> map )
-    {
+    private Properties toProperties(Map<String, String> dominant, Map<String, String> recessive) {
         Properties props = new Properties();
-        props.putAll( map );
+        if (recessive != null) {
+            props.putAll(recessive);
+        }
+        if (dominant != null) {
+            props.putAll(dominant);
+        }
         return props;
     }
 
-    private Relocation getRelocation( Model model )
-    {
+    private Relocation getRelocation(Model model) {
         Relocation relocation = null;
         DistributionManagement distMgmt = model.getDistributionManagement();
-        if ( distMgmt != null )
-        {
+        if (distMgmt != null) {
             relocation = distMgmt.getRelocation();
         }
         return relocation;
     }
 
-    private void missingDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
-                                    Exception exception )
-    {
-        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_MISSING );
-        event.setTrace( trace );
-        event.setArtifact( artifact );
-        event.setException( exception );
+    private void missingDescriptor(
+            RepositorySystemSession session, RequestTrace trace, Artifact artifact, Exception exception) {
+        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DESCRIPTOR_MISSING);
+        event.setTrace(trace);
+        event.setArtifact(artifact);
+        event.setException(exception);
 
-        repositoryEventDispatcher.dispatch( event.build() );
+        repositoryEventDispatcher.dispatch(event.build());
     }
 
-    private void invalidDescriptor( RepositorySystemSession session, RequestTrace trace, Artifact artifact,
-                                    Exception exception )
-    {
-        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.ARTIFACT_DESCRIPTOR_INVALID );
-        event.setTrace( trace );
-        event.setArtifact( artifact );
-        event.setException( exception );
+    private void invalidDescriptor(
+            RepositorySystemSession session, RequestTrace trace, Artifact artifact, Exception exception) {
+        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.ARTIFACT_DESCRIPTOR_INVALID);
+        event.setTrace(trace);
+        event.setArtifact(artifact);
+        event.setException(exception);
 
-        repositoryEventDispatcher.dispatch( event.build() );
+        repositoryEventDispatcher.dispatch(event.build());
     }
 
-    private int getPolicy( RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request )
-    {
+    private int getPolicy(RepositorySystemSession session, Artifact a, ArtifactDescriptorRequest request) {
         ArtifactDescriptorPolicy policy = session.getArtifactDescriptorPolicy();
-        if ( policy == null )
-        {
+        if (policy == null) {
             return ArtifactDescriptorPolicy.STRICT;
         }
-        return policy.getPolicy( session, new ArtifactDescriptorPolicyRequest( a, request.getRequestContext() ) );
+        return policy.getPolicy(session, new ArtifactDescriptorPolicyRequest(a, request.getRequestContext()));
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java
index 339bc08..7b2831e 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCache.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,10 +16,12 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.util.Map;
 import java.util.Objects;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Supplier;
 
 import org.apache.maven.building.Source;
 import org.apache.maven.model.building.ModelCache;
@@ -30,72 +30,75 @@
 /**
  * A model builder cache backed by the repository system cache.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultModelCache
-    implements ModelCache
-{
+public class DefaultModelCache implements ModelCache {
 
     private static final String KEY = DefaultModelCache.class.getName();
 
-    private final Map<Object, Object> cache;
+    private final Map<Object, Supplier<?>> cache;
 
-    public static ModelCache newInstance( RepositorySystemSession session )
-    {
-        Map<Object, Object> cache;
-        if ( session.getCache() == null )
-        {
+    public static ModelCache newInstance(RepositorySystemSession session) {
+        Map<Object, Supplier<?>> cache;
+        if (session.getCache() == null) {
             cache = new ConcurrentHashMap<>();
-        }
-        else
-        {
-            cache = ( Map ) session.getCache().get( session, KEY );
-            if ( cache == null )
-            {
+        } else {
+            cache = (Map) session.getCache().get(session, KEY);
+            if (cache == null) {
                 cache = new ConcurrentHashMap<>();
-                session.getCache().put( session, KEY, cache );
+                session.getCache().put(session, KEY, cache);
             }
         }
-        return new DefaultModelCache( cache );
+        return new DefaultModelCache(cache);
     }
 
-    private DefaultModelCache( Map<Object, Object> cache )
-    {
+    private DefaultModelCache(Map<Object, Supplier<?>> cache) {
         this.cache = cache;
     }
 
-    public Object get( Source path, String tag )
-    {
-        return get( new SourceCacheKey( path, tag ) );
+    public Object get(Source path, String tag) {
+        return get(new SourceCacheKey(path, tag));
     }
 
-    public void put( Source path, String tag, Object data )
-    {
-        put( new SourceCacheKey( path, tag ), data );
+    public void put(Source path, String tag, Object data) {
+        put(new SourceCacheKey(path, tag), data);
     }
 
-    public Object get( String groupId, String artifactId, String version, String tag )
-    {
-        return get( new GavCacheKey( groupId, artifactId, version, tag ) );
+    @Override
+    public Object get(String groupId, String artifactId, String version, String tag) {
+        return get(new GavCacheKey(groupId, artifactId, version, tag));
     }
 
-    public void put( String groupId, String artifactId, String version, String tag, Object data )
-    {
-        put( new GavCacheKey( groupId, artifactId, version, tag ), data );
+    @Override
+    public void put(String groupId, String artifactId, String version, String tag, Object data) {
+        put(new GavCacheKey(groupId, artifactId, version, tag), data);
     }
 
-    protected Object get( Object key )
-    {
-        return cache.get( key );
+    protected Object get(Object key) {
+        Supplier<?> s = cache.get(key);
+        return s != null ? s.get() : null;
     }
 
-    protected void put( Object key, Object data )
-    {
-        cache.put( key, data );
+    protected void put(Object key, Object data) {
+        cache.put(key, () -> data);
     }
 
-    static class GavCacheKey
-    {
+    @Override
+    public Object computeIfAbsent(
+            String groupId, String artifactId, String version, String tag, Supplier<Supplier<?>> data) {
+        return computeIfAbsent(new GavCacheKey(groupId, artifactId, version, tag), data);
+    }
+
+    @Override
+    public Object computeIfAbsent(Source path, String tag, Supplier<Supplier<?>> data) {
+        return computeIfAbsent(new SourceCacheKey(path, tag), data);
+    }
+
+    protected Object computeIfAbsent(Object key, Supplier<Supplier<?>> data) {
+        Supplier<?> s = cache.computeIfAbsent(key, k -> data.get());
+        return s != null ? s.get() : null;
+    }
+
+    static class GavCacheKey {
 
         private final String gav;
 
@@ -103,111 +106,87 @@
 
         private final int hash;
 
-        GavCacheKey( String groupId, String artifactId, String version, String tag )
-        {
-            this( gav( groupId, artifactId, version ), tag );
+        GavCacheKey(String groupId, String artifactId, String version, String tag) {
+            this(gav(groupId, artifactId, version), tag);
         }
 
-        GavCacheKey( String gav, String tag )
-        {
+        GavCacheKey(String gav, String tag) {
             this.gav = gav;
             this.tag = tag;
-            this.hash = Objects.hash( gav, tag );
+            this.hash = Objects.hash(gav, tag);
         }
 
-        private static String gav( String groupId, String artifactId, String version )
-        {
+        private static String gav(String groupId, String artifactId, String version) {
             StringBuilder sb = new StringBuilder();
-            if ( groupId != null )
-            {
-                sb.append( groupId );
+            if (groupId != null) {
+                sb.append(groupId);
             }
-            sb.append( ":" );
-            if ( artifactId != null )
-            {
-                sb.append( artifactId );
+            sb.append(":");
+            if (artifactId != null) {
+                sb.append(artifactId);
             }
-            sb.append( ":" );
-            if ( version != null )
-            {
-                sb.append( version );
+            sb.append(":");
+            if (version != null) {
+                sb.append(version);
             }
             return sb.toString();
         }
 
         @Override
-        public boolean equals( Object obj )
-        {
-            if ( this == obj )
-            {
+        public boolean equals(Object obj) {
+            if (this == obj) {
                 return true;
             }
-            if ( null == obj || !getClass().equals( obj.getClass() ) )
-            {
+            if (null == obj || !getClass().equals(obj.getClass())) {
                 return false;
             }
             GavCacheKey that = (GavCacheKey) obj;
-            return Objects.equals( this.gav, that.gav ) && Objects.equals( this.tag, that.tag );
+            return Objects.equals(this.gav, that.gav) && Objects.equals(this.tag, that.tag);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hash;
         }
 
         @Override
-        public String toString()
-        {
-            return "GavCacheKey{"
-                    + "gav='" + gav + '\''
-                    + ", tag='" + tag + '\''
-                    + '}';
+        public String toString() {
+            return "GavCacheKey{" + "gav='" + gav + '\'' + ", tag='" + tag + '\'' + '}';
         }
     }
 
-    private static final class SourceCacheKey
-    {
+    private static final class SourceCacheKey {
         private final Source source;
 
         private final String tag;
 
         private final int hash;
 
-        SourceCacheKey( Source source, String tag )
-        {
+        SourceCacheKey(Source source, String tag) {
             this.source = source;
             this.tag = tag;
-            this.hash = Objects.hash( source, tag );
+            this.hash = Objects.hash(source, tag);
         }
 
         @Override
-        public String toString()
-        {
-            return "SourceCacheKey{"
-                    + "source=" + source
-                    + ", tag='" + tag + '\''
-                    + '}';
+        public String toString() {
+            return "SourceCacheKey{" + "source=" + source + ", tag='" + tag + '\'' + '}';
         }
 
         @Override
-        public boolean equals( Object obj )
-        {
-            if ( this == obj )
-            {
+        public boolean equals(Object obj) {
+            if (this == obj) {
                 return true;
             }
-            if ( null == obj || !getClass().equals( obj.getClass() ) )
-            {
+            if (null == obj || !getClass().equals(obj.getClass())) {
                 return false;
             }
             SourceCacheKey that = (SourceCacheKey) obj;
-            return Objects.equals( this.source, that.source ) && Objects.equals( this.tag, that.tag );
+            return Objects.equals(this.source, that.source) && Objects.equals(this.tag, that.tag);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hash;
         }
     }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCacheFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCacheFactory.java
index 785a4e0..e23ef59 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCacheFactory.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelCacheFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -30,12 +29,9 @@
  */
 @Singleton
 @Named
-public class DefaultModelCacheFactory implements ModelCacheFactory
-{
+public class DefaultModelCacheFactory implements ModelCacheFactory {
     @Override
-    public ModelCache createCache( RepositorySystemSession session )
-    {
-        return DefaultModelCache.newInstance( session );
+    public ModelCache createCache(RepositorySystemSession session) {
+        return DefaultModelCache.newInstance(session);
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java
index f23bfe4..bdd1e5b 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultModelResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -25,10 +24,11 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Parent;
-import org.apache.maven.model.Repository;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Parent;
+import org.apache.maven.api.model.Repository;
 import org.apache.maven.model.building.ArtifactModelSource;
 import org.apache.maven.model.building.ModelSource;
 import org.apache.maven.model.resolution.InvalidRepositoryException;
@@ -52,12 +52,9 @@
  * A model resolver to assist building of dependency POMs. This resolver gives priority to those repositories that have
  * been initially specified and repositories discovered in dependency POMs are recessively merged into the search chain.
  *
- * @author Benjamin Bentmann
  * @see DefaultArtifactDescriptorReader
  */
-class DefaultModelResolver
-    implements ModelResolver
-{
+class DefaultModelResolver implements ModelResolver {
 
     private final RepositorySystemSession session;
 
@@ -77,10 +74,14 @@
 
     private final Set<String> repositoryIds;
 
-    DefaultModelResolver( RepositorySystemSession session, RequestTrace trace, String context,
-                          ArtifactResolver resolver, VersionRangeResolver versionRangeResolver,
-                          RemoteRepositoryManager remoteRepositoryManager, List<RemoteRepository> repositories )
-    {
+    DefaultModelResolver(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            String context,
+            ArtifactResolver resolver,
+            VersionRangeResolver versionRangeResolver,
+            RemoteRepositoryManager remoteRepositoryManager,
+            List<RemoteRepository> repositories) {
         this.session = session;
         this.trace = trace;
         this.context = context;
@@ -88,189 +89,202 @@
         this.versionRangeResolver = versionRangeResolver;
         this.remoteRepositoryManager = remoteRepositoryManager;
         this.repositories = repositories;
-        this.externalRepositories = Collections.unmodifiableList( new ArrayList<>( repositories ) );
+        this.externalRepositories = Collections.unmodifiableList(new ArrayList<>(repositories));
 
         this.repositoryIds = new HashSet<>();
     }
 
-    private DefaultModelResolver( DefaultModelResolver original )
-    {
+    private DefaultModelResolver(DefaultModelResolver original) {
         this.session = original.session;
         this.trace = original.trace;
         this.context = original.context;
         this.resolver = original.resolver;
         this.versionRangeResolver = original.versionRangeResolver;
         this.remoteRepositoryManager = original.remoteRepositoryManager;
-        this.repositories = new ArrayList<>( original.repositories );
+        this.repositories = new ArrayList<>(original.repositories);
         this.externalRepositories = original.externalRepositories;
-        this.repositoryIds = new HashSet<>( original.repositoryIds );
+        this.repositoryIds = new HashSet<>(original.repositoryIds);
     }
 
     @Override
-    public void addRepository( Repository repository )
-        throws InvalidRepositoryException
-    {
-        addRepository( repository, false );
+    public void addRepository(Repository repository) throws InvalidRepositoryException {
+        addRepository(repository, false);
     }
 
     @Override
-    public void addRepository( final Repository repository, boolean replace )
-        throws InvalidRepositoryException
-    {
-        if ( session.isIgnoreArtifactDescriptorRepositories() )
-        {
+    public void addRepository(final Repository repository, boolean replace) throws InvalidRepositoryException {
+        if (session.isIgnoreArtifactDescriptorRepositories()) {
             return;
         }
 
-        if ( !repositoryIds.add( repository.getId() ) )
-        {
-            if ( !replace )
-            {
+        if (!repositoryIds.add(repository.getId())) {
+            if (!replace) {
                 return;
             }
 
-            removeMatchingRepository( repositories, repository.getId() );
+            removeMatchingRepository(repositories, repository.getId());
         }
 
-        List<RemoteRepository> newRepositories =
-            Collections.singletonList( ArtifactDescriptorUtils.toRemoteRepository( repository ) );
+        List<RemoteRepository> newRepositories = Collections.singletonList(
+                ArtifactDescriptorUtils.toRemoteRepository(new org.apache.maven.model.Repository(repository)));
 
-        this.repositories =
-            remoteRepositoryManager.aggregateRepositories( session, repositories, newRepositories, true );
+        this.repositories = remoteRepositoryManager.aggregateRepositories(session, repositories, newRepositories, true);
     }
 
-    private static void removeMatchingRepository( Iterable<RemoteRepository> repositories, final String id )
-    {
+    private static void removeMatchingRepository(Iterable<RemoteRepository> repositories, final String id) {
         Iterator<RemoteRepository> iterator = repositories.iterator();
-        while ( iterator.hasNext() )
-        {
+        while (iterator.hasNext()) {
             RemoteRepository remoteRepository = iterator.next();
-            if ( remoteRepository.getId().equals( id ) )
-            {
+            if (remoteRepository.getId().equals(id)) {
                 iterator.remove();
             }
         }
     }
 
     @Override
-    public ModelResolver newCopy()
-    {
-        return new DefaultModelResolver( this );
+    public ModelResolver newCopy() {
+        return new DefaultModelResolver(this);
     }
 
     @Override
-    public ModelSource resolveModel( String groupId, String artifactId, String version )
-        throws UnresolvableModelException
-    {
-        Artifact pomArtifact = new DefaultArtifact( groupId, artifactId, "", "pom", version );
+    public ModelSource resolveModel(String groupId, String artifactId, String version)
+            throws UnresolvableModelException {
+        Artifact pomArtifact = new DefaultArtifact(groupId, artifactId, "", "pom", version);
 
-        try
-        {
-            ArtifactRequest request = new ArtifactRequest( pomArtifact, repositories, context );
-            request.setTrace( trace );
-            pomArtifact = resolver.resolveArtifact( session, request ).getArtifact();
-        }
-        catch ( ArtifactResolutionException e )
-        {
-            throw new UnresolvableModelException( e.getMessage(), groupId, artifactId, version, e );
+        try {
+            ArtifactRequest request = new ArtifactRequest(pomArtifact, repositories, context);
+            request.setTrace(trace);
+            pomArtifact = resolver.resolveArtifact(session, request).getArtifact();
+        } catch (ArtifactResolutionException e) {
+            throw new UnresolvableModelException(e.getMessage(), groupId, artifactId, version, e);
         }
 
-        return new ArtifactModelSource( pomArtifact.getFile(), groupId, artifactId, version );
+        return new ArtifactModelSource(pomArtifact.getFile(), groupId, artifactId, version);
     }
 
     @Override
-    public ModelSource resolveModel( final Parent parent )
-        throws UnresolvableModelException
-    {
-        try
-        {
-            final Artifact artifact = new DefaultArtifact( parent.getGroupId(), parent.getArtifactId(), "", "pom",
-                                                           parent.getVersion() );
+    public ModelSource resolveModel(final Parent parent, final AtomicReference<Parent> modified)
+            throws UnresolvableModelException {
+        try {
+            final Artifact artifact =
+                    new DefaultArtifact(parent.getGroupId(), parent.getArtifactId(), "", "pom", parent.getVersion());
 
-            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest( artifact, repositories, context );
-            versionRangeRequest.setTrace( trace );
+            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, repositories, context);
+            versionRangeRequest.setTrace(trace);
 
             final VersionRangeResult versionRangeResult =
-                versionRangeResolver.resolveVersionRange( session, versionRangeRequest );
+                    versionRangeResolver.resolveVersionRange(session, versionRangeRequest);
 
-            if ( versionRangeResult.getHighestVersion() == null )
-            {
+            if (versionRangeResult.getHighestVersion() == null) {
                 throw new UnresolvableModelException(
-                    String.format( "No versions matched the requested parent version range '%s'",
-                                   parent.getVersion() ),
-                    parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-
+                        String.format(
+                                "No versions matched the requested parent version range '%s'", parent.getVersion()),
+                        parent.getGroupId(),
+                        parent.getArtifactId(),
+                        parent.getVersion());
             }
 
-            if ( versionRangeResult.getVersionConstraint() != null
-                     && versionRangeResult.getVersionConstraint().getRange() != null
-                     && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null )
-            {
+            if (versionRangeResult.getVersionConstraint() != null
+                    && versionRangeResult.getVersionConstraint().getRange() != null
+                    && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
                 // Message below is checked for in the MNG-2199 core IT.
                 throw new UnresolvableModelException(
-                    String.format( "The requested parent version range '%s' does not specify an upper bound",
-                                   parent.getVersion() ),
-                    parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-
+                        String.format(
+                                "The requested parent version range '%s' does not specify an upper bound",
+                                parent.getVersion()),
+                        parent.getGroupId(),
+                        parent.getArtifactId(),
+                        parent.getVersion());
             }
 
-            parent.setVersion( versionRangeResult.getHighestVersion().toString() );
+            String newVersion = versionRangeResult.getHighestVersion().toString();
+            if (!parent.getVersion().equals(newVersion)) {
+                modified.set(parent.withVersion(newVersion));
+            }
 
-            return resolveModel( parent.getGroupId(), parent.getArtifactId(), parent.getVersion() );
-        }
-        catch ( final VersionRangeResolutionException e )
-        {
-            throw new UnresolvableModelException( e.getMessage(), parent.getGroupId(), parent.getArtifactId(),
-                                                  parent.getVersion(), e );
-
+            return resolveModel(parent.getGroupId(), parent.getArtifactId(), newVersion);
+        } catch (final VersionRangeResolutionException e) {
+            throw new UnresolvableModelException(
+                    e.getMessage(), parent.getGroupId(), parent.getArtifactId(), parent.getVersion(), e);
         }
     }
 
     @Override
-    public ModelSource resolveModel( final Dependency dependency )
-        throws UnresolvableModelException
-    {
-        try
-        {
-            final Artifact artifact = new DefaultArtifact( dependency.getGroupId(), dependency.getArtifactId(), "",
-                                                           "pom", dependency.getVersion() );
+    public ModelSource resolveModel(final Dependency dependency, AtomicReference<Dependency> modified)
+            throws UnresolvableModelException {
+        try {
+            final Artifact artifact = new DefaultArtifact(
+                    dependency.getGroupId(), dependency.getArtifactId(), "", "pom", dependency.getVersion());
 
-            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest( artifact, repositories, context );
-            versionRangeRequest.setTrace( trace );
+            final VersionRangeRequest versionRangeRequest = new VersionRangeRequest(artifact, repositories, context);
+            versionRangeRequest.setTrace(trace);
 
             final VersionRangeResult versionRangeResult =
-                versionRangeResolver.resolveVersionRange( session, versionRangeRequest );
+                    versionRangeResolver.resolveVersionRange(session, versionRangeRequest);
 
-            if ( versionRangeResult.getHighestVersion() == null )
-            {
+            if (versionRangeResult.getHighestVersion() == null) {
                 throw new UnresolvableModelException(
-                    String.format( "No versions matched the requested dependency version range '%s'",
-                                   dependency.getVersion() ),
-                    dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
-
+                        String.format(
+                                "No versions matched the requested dependency version range '%s'",
+                                dependency.getVersion()),
+                        dependency.getGroupId(),
+                        dependency.getArtifactId(),
+                        dependency.getVersion());
             }
 
-            if ( versionRangeResult.getVersionConstraint() != null
-                     && versionRangeResult.getVersionConstraint().getRange() != null
-                     && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null )
-            {
+            if (versionRangeResult.getVersionConstraint() != null
+                    && versionRangeResult.getVersionConstraint().getRange() != null
+                    && versionRangeResult.getVersionConstraint().getRange().getUpperBound() == null) {
                 // Message below is checked for in the MNG-4463 core IT.
                 throw new UnresolvableModelException(
-                    String.format( "The requested dependency version range '%s' does not specify an upper bound",
-                                   dependency.getVersion() ),
-                    dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
-
+                        String.format(
+                                "The requested dependency version range '%s' does not specify an upper bound",
+                                dependency.getVersion()),
+                        dependency.getGroupId(),
+                        dependency.getArtifactId(),
+                        dependency.getVersion());
             }
 
-            dependency.setVersion( versionRangeResult.getHighestVersion().toString() );
+            String newVersion = versionRangeResult.getHighestVersion().toString();
+            if (!dependency.getVersion().equals(newVersion)) {
+                modified.set(dependency.withVersion(newVersion));
+            }
 
-            return resolveModel( dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion() );
+            return resolveModel(dependency.getGroupId(), dependency.getArtifactId(), newVersion);
+        } catch (VersionRangeResolutionException e) {
+            throw new UnresolvableModelException(
+                    e.getMessage(), dependency.getGroupId(), dependency.getArtifactId(), dependency.getVersion(), e);
         }
-        catch ( VersionRangeResolutionException e )
-        {
-            throw new UnresolvableModelException( e.getMessage(), dependency.getGroupId(), dependency.getArtifactId(),
-                                                  dependency.getVersion(), e );
+    }
 
+    @Override
+    public ModelSource resolveModel(org.apache.maven.model.Parent parent) throws UnresolvableModelException {
+        AtomicReference<org.apache.maven.api.model.Parent> resolvedParent = new AtomicReference<>();
+        ModelSource result = resolveModel(parent.getDelegate(), resolvedParent);
+        if (resolvedParent.get() != null) {
+            parent.setVersion(resolvedParent.get().getVersion());
         }
+        return result;
+    }
+
+    @Override
+    public ModelSource resolveModel(org.apache.maven.model.Dependency dependency) throws UnresolvableModelException {
+        AtomicReference<org.apache.maven.api.model.Dependency> resolvedDependency = new AtomicReference<>();
+        ModelSource result = resolveModel(dependency.getDelegate(), resolvedDependency);
+        if (resolvedDependency.get() != null) {
+            dependency.setVersion(resolvedDependency.get().getVersion());
+        }
+        return result;
+    }
+
+    @Override
+    public void addRepository(org.apache.maven.model.Repository repository) throws InvalidRepositoryException {
+        addRepository(repository.getDelegate());
+    }
+
+    @Override
+    public void addRepository(org.apache.maven.model.Repository repository, boolean replace)
+            throws InvalidRepositoryException {
+        addRepository(repository.getDelegate(), replace);
     }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java
index dfc7181..c8ca6bd 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionRangeResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,9 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.maven.artifact.ArtifactUtils;
 import org.apache.maven.artifact.repository.metadata.Versioning;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
 import org.eclipse.aether.RepositoryEvent;
 import org.eclipse.aether.RepositoryEvent.EventType;
 import org.eclipse.aether.RepositorySystemSession;
@@ -43,29 +56,14 @@
 import org.eclipse.aether.version.InvalidVersionSpecificationException;
 import org.eclipse.aether.version.Version;
 import org.eclipse.aether.version.VersionConstraint;
+import org.eclipse.aether.version.VersionRange;
 import org.eclipse.aether.version.VersionScheme;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
 /**
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultVersionRangeResolver
-    implements VersionRangeResolver
-{
+public class DefaultVersionRangeResolver implements VersionRangeResolver {
 
     private static final String MAVEN_METADATA_XML = "maven-metadata.xml";
 
@@ -75,119 +73,115 @@
     private final VersionScheme versionScheme;
 
     @Inject
-    public DefaultVersionRangeResolver( MetadataResolver metadataResolver,
-                                        SyncContextFactory syncContextFactory,
-                                        RepositoryEventDispatcher repositoryEventDispatcher,
-                                        VersionScheme versionScheme )
-    {
-        this.metadataResolver = Objects.requireNonNull( metadataResolver, "metadataResolver cannot be null" );
-        this.syncContextFactory = Objects.requireNonNull( syncContextFactory, "syncContextFactory cannot be null" );
-        this.repositoryEventDispatcher = Objects.requireNonNull( repositoryEventDispatcher,
-                "repositoryEventDispatcher cannot be null" );
-        this.versionScheme = Objects.requireNonNull( versionScheme, "versionScheme cannot be null" );
+    public DefaultVersionRangeResolver(
+            MetadataResolver metadataResolver,
+            SyncContextFactory syncContextFactory,
+            RepositoryEventDispatcher repositoryEventDispatcher,
+            VersionScheme versionScheme) {
+        this.metadataResolver = Objects.requireNonNull(metadataResolver, "metadataResolver cannot be null");
+        this.syncContextFactory = Objects.requireNonNull(syncContextFactory, "syncContextFactory cannot be null");
+        this.repositoryEventDispatcher =
+                Objects.requireNonNull(repositoryEventDispatcher, "repositoryEventDispatcher cannot be null");
+        this.versionScheme = Objects.requireNonNull(versionScheme, "versionScheme cannot be null");
     }
-    public VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request )
-        throws VersionRangeResolutionException
-    {
-        VersionRangeResult result = new VersionRangeResult( request );
+
+    @Override
+    public VersionRangeResult resolveVersionRange(RepositorySystemSession session, VersionRangeRequest request)
+            throws VersionRangeResolutionException {
+        VersionRangeResult result = new VersionRangeResult(request);
 
         VersionConstraint versionConstraint;
-        try
-        {
-            versionConstraint = versionScheme.parseVersionConstraint( request.getArtifact().getVersion() );
-        }
-        catch ( InvalidVersionSpecificationException e )
-        {
-            result.addException( e );
-            throw new VersionRangeResolutionException( result );
+        try {
+            versionConstraint =
+                    versionScheme.parseVersionConstraint(request.getArtifact().getVersion());
+        } catch (InvalidVersionSpecificationException e) {
+            result.addException(e);
+            throw new VersionRangeResolutionException(result);
         }
 
-        result.setVersionConstraint( versionConstraint );
+        result.setVersionConstraint(versionConstraint);
 
-        if ( versionConstraint.getRange() == null )
-        {
-            result.addVersion( versionConstraint.getVersion() );
-        }
-        else
-        {
-            Map<String, ArtifactRepository> versionIndex = getVersions( session, result, request );
+        if (versionConstraint.getRange() == null) {
+            result.addVersion(versionConstraint.getVersion());
+        } else {
+            VersionRange.Bound lowerBound = versionConstraint.getRange().getLowerBound();
+            if (lowerBound != null
+                    && lowerBound.equals(versionConstraint.getRange().getUpperBound())) {
+                result.addVersion(lowerBound.getVersion());
+            } else {
+                Map<String, ArtifactRepository> versionIndex = getVersions(session, result, request);
 
-            List<Version> versions = new ArrayList<>();
-            for ( Map.Entry<String, ArtifactRepository> v : versionIndex.entrySet() )
-            {
-                try
-                {
-                    Version ver = versionScheme.parseVersion( v.getKey() );
-                    if ( versionConstraint.containsVersion( ver ) )
-                    {
-                        versions.add( ver );
-                        result.setRepository( ver, v.getValue() );
+                List<Version> versions = new ArrayList<>();
+                for (Map.Entry<String, ArtifactRepository> v : versionIndex.entrySet()) {
+                    try {
+                        Version ver = versionScheme.parseVersion(v.getKey());
+                        if (versionConstraint.containsVersion(ver)) {
+                            versions.add(ver);
+                            result.setRepository(ver, v.getValue());
+                        }
+                    } catch (InvalidVersionSpecificationException e) {
+                        result.addException(e);
                     }
                 }
-                catch ( InvalidVersionSpecificationException e )
-                {
-                    result.addException( e );
-                }
-            }
 
-            Collections.sort( versions );
-            result.setVersions( versions );
+                Collections.sort(versions);
+                result.setVersions(versions);
+            }
         }
 
         return result;
     }
 
-    private Map<String, ArtifactRepository> getVersions( RepositorySystemSession session, VersionRangeResult result,
-                                                         VersionRangeRequest request )
-    {
-        RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
+    private Map<String, ArtifactRepository> getVersions(
+            RepositorySystemSession session, VersionRangeResult result, VersionRangeRequest request) {
+        RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
 
         Map<String, ArtifactRepository> versionIndex = new HashMap<>();
 
-        Metadata metadata =
-            new DefaultMetadata( request.getArtifact().getGroupId(), request.getArtifact().getArtifactId(),
-                                 MAVEN_METADATA_XML, Metadata.Nature.RELEASE_OR_SNAPSHOT );
+        Metadata metadata = new DefaultMetadata(
+                request.getArtifact().getGroupId(),
+                request.getArtifact().getArtifactId(),
+                MAVEN_METADATA_XML,
+                Metadata.Nature.RELEASE_OR_SNAPSHOT);
 
-        List<MetadataRequest> metadataRequests = new ArrayList<>( request.getRepositories().size() );
+        List<MetadataRequest> metadataRequests =
+                new ArrayList<>(request.getRepositories().size());
 
-        metadataRequests.add( new MetadataRequest( metadata, null, request.getRequestContext() ) );
+        metadataRequests.add(new MetadataRequest(metadata, null, request.getRequestContext()));
 
-        for ( RemoteRepository repository : request.getRepositories() )
-        {
-            MetadataRequest metadataRequest = new MetadataRequest( metadata, repository, request.getRequestContext() );
-            metadataRequest.setDeleteLocalCopyIfMissing( true );
-            metadataRequest.setTrace( trace );
-            metadataRequests.add( metadataRequest );
+        for (RemoteRepository repository : request.getRepositories()) {
+            MetadataRequest metadataRequest = new MetadataRequest(metadata, repository, request.getRequestContext());
+            metadataRequest.setDeleteLocalCopyIfMissing(true);
+            metadataRequest.setTrace(trace);
+            metadataRequests.add(metadataRequest);
         }
 
-        List<MetadataResult> metadataResults = metadataResolver.resolveMetadata( session, metadataRequests );
+        List<MetadataResult> metadataResults = metadataResolver.resolveMetadata(session, metadataRequests);
 
         WorkspaceReader workspace = session.getWorkspaceReader();
-        if ( workspace != null )
-        {
-            List<String> versions = workspace.findVersions( request.getArtifact() );
-            for ( String version : versions )
-            {
-                versionIndex.put( version, workspace.getRepository() );
+        if (workspace != null) {
+            List<String> versions = workspace.findVersions(request.getArtifact());
+            for (String version : versions) {
+                versionIndex.put(version, workspace.getRepository());
             }
         }
 
-        for ( MetadataResult metadataResult : metadataResults )
-        {
-            result.addException( metadataResult.getException() );
+        for (MetadataResult metadataResult : metadataResults) {
+            result.addException(metadataResult.getException());
 
             ArtifactRepository repository = metadataResult.getRequest().getRepository();
-            if ( repository == null )
-            {
+            if (repository == null) {
                 repository = session.getLocalRepository();
             }
 
-            Versioning versioning = readVersions( session, trace, metadataResult.getMetadata(), repository, result );
-            for ( String version : versioning.getVersions() )
-            {
-                if ( !versionIndex.containsKey( version ) )
-                {
-                    versionIndex.put( version, repository );
+            Versioning versioning = readVersions(session, trace, metadataResult.getMetadata(), repository, result);
+
+            versioning = filterVersionsByRepositoryType(
+                    versioning, metadataResult.getRequest().getRepository());
+
+            for (String version : versioning.getVersions()) {
+                if (!versionIndex.containsKey(version)) {
+                    versionIndex.put(version, repository);
                 }
             }
         }
@@ -195,47 +189,63 @@
         return versionIndex;
     }
 
-    private Versioning readVersions( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
-                                     ArtifactRepository repository, VersionRangeResult result )
-    {
+    private Versioning readVersions(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            Metadata metadata,
+            ArtifactRepository repository,
+            VersionRangeResult result) {
         Versioning versioning = null;
-        try
-        {
-            if ( metadata != null )
-            {
-                try ( SyncContext syncContext = syncContextFactory.newInstance( session, true ) )
-                {
-                    syncContext.acquire( null, Collections.singleton( metadata ) );
+        try {
+            if (metadata != null) {
+                try (SyncContext syncContext = syncContextFactory.newInstance(session, true)) {
+                    syncContext.acquire(null, Collections.singleton(metadata));
 
-                    if ( metadata.getFile() != null && metadata.getFile().exists() )
-                    {
-                        try ( InputStream in = new FileInputStream( metadata.getFile() ) )
-                        {
-                            versioning = new MetadataXpp3Reader().read( in, false ).getVersioning();
+                    if (metadata.getFile() != null && metadata.getFile().exists()) {
+                        try (InputStream in =
+                                Files.newInputStream(metadata.getFile().toPath())) {
+                            versioning = new Versioning(
+                                    new MetadataStaxReader().read(in, false).getVersioning());
                         }
                     }
                 }
             }
-        }
-        catch ( Exception e )
-        {
-            invalidMetadata( session, trace, metadata, repository, e );
-            result.addException( e );
+        } catch (Exception e) {
+            invalidMetadata(session, trace, metadata, repository, e);
+            result.addException(e);
         }
 
-        return ( versioning != null ) ? versioning : new Versioning();
+        return (versioning != null) ? versioning : new Versioning();
     }
 
-    private void invalidMetadata( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
-                                  ArtifactRepository repository, Exception exception )
-    {
-        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID );
-        event.setTrace( trace );
-        event.setMetadata( metadata );
-        event.setException( exception );
-        event.setRepository( repository );
+    private Versioning filterVersionsByRepositoryType(Versioning versioning, RemoteRepository remoteRepository) {
+        if (remoteRepository == null) {
+            return versioning;
+        }
 
-        repositoryEventDispatcher.dispatch( event.build() );
+        Versioning filteredVersions = versioning.clone();
+
+        for (String version : versioning.getVersions()) {
+            if (!remoteRepository.getPolicy(ArtifactUtils.isSnapshot(version)).isEnabled()) {
+                filteredVersions.removeVersion(version);
+            }
+        }
+
+        return filteredVersions;
     }
 
-}
\ No newline at end of file
+    private void invalidMetadata(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            Metadata metadata,
+            ArtifactRepository repository,
+            Exception exception) {
+        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INVALID);
+        event.setTrace(trace);
+        event.setMetadata(metadata);
+        event.setException(exception);
+        event.setRepository(repository);
+
+        repositoryEventDispatcher.dispatch(event.build());
+    }
+}
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java
index e70a8b9..4b54afc 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionResolver.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,27 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 import org.apache.maven.artifact.repository.metadata.Snapshot;
 import org.apache.maven.artifact.repository.metadata.SnapshotVersion;
 import org.apache.maven.artifact.repository.metadata.Versioning;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
-import org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
 import org.eclipse.aether.RepositoryCache;
 import org.eclipse.aether.RepositoryEvent;
 import org.eclipse.aether.RepositoryEvent.EventType;
@@ -49,29 +62,11 @@
 import org.eclipse.aether.spi.synccontext.SyncContextFactory;
 import org.eclipse.aether.util.ConfigUtils;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
 /**
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultVersionResolver
-    implements VersionResolver
-{
+public class DefaultVersionResolver implements VersionResolver {
 
     private static final String MAVEN_METADATA_XML = "maven-metadata.xml";
 
@@ -86,334 +81,290 @@
     private final RepositoryEventDispatcher repositoryEventDispatcher;
 
     @Inject
-    public DefaultVersionResolver( MetadataResolver metadataResolver, SyncContextFactory syncContextFactory,
-                            RepositoryEventDispatcher repositoryEventDispatcher )
-    {
-        this.metadataResolver = Objects.requireNonNull( metadataResolver, "metadataResolver cannot be null" );
-        this.syncContextFactory = Objects.requireNonNull( syncContextFactory, "syncContextFactory cannot be null" );
-        this.repositoryEventDispatcher = Objects.requireNonNull( repositoryEventDispatcher,
-                "repositoryEventDispatcher cannot be null" );
+    public DefaultVersionResolver(
+            MetadataResolver metadataResolver,
+            SyncContextFactory syncContextFactory,
+            RepositoryEventDispatcher repositoryEventDispatcher) {
+        this.metadataResolver = Objects.requireNonNull(metadataResolver, "metadataResolver cannot be null");
+        this.syncContextFactory = Objects.requireNonNull(syncContextFactory, "syncContextFactory cannot be null");
+        this.repositoryEventDispatcher =
+                Objects.requireNonNull(repositoryEventDispatcher, "repositoryEventDispatcher cannot be null");
     }
 
-    @SuppressWarnings( "checkstyle:methodlength" )
-    public VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request )
-        throws VersionResolutionException
-    {
-        RequestTrace trace = RequestTrace.newChild( request.getTrace(), request );
+    @SuppressWarnings("checkstyle:methodlength")
+    @Override
+    public VersionResult resolveVersion(RepositorySystemSession session, VersionRequest request)
+            throws VersionResolutionException {
+        RequestTrace trace = RequestTrace.newChild(request.getTrace(), request);
 
         Artifact artifact = request.getArtifact();
 
         String version = artifact.getVersion();
 
-        VersionResult result = new VersionResult( request );
+        VersionResult result = new VersionResult(request);
 
         Key cacheKey = null;
         RepositoryCache cache = session.getCache();
-        if ( cache != null && !ConfigUtils.getBoolean( session, false, "aether.versionResolver.noCache" ) )
-        {
-            cacheKey = new Key( session, request );
+        if (cache != null && !ConfigUtils.getBoolean(session, false, "aether.versionResolver.noCache")) {
+            cacheKey = new Key(session, request);
 
-            Object obj = cache.get( session, cacheKey );
-            if ( obj instanceof Record )
-            {
+            Object obj = cache.get(session, cacheKey);
+            if (obj instanceof Record) {
                 Record record = (Record) obj;
-                result.setVersion( record.version );
+                result.setVersion(record.version);
                 result.setRepository(
-                    getRepository( session, request.getRepositories(), record.repoClass, record.repoId ) );
+                        getRepository(session, request.getRepositories(), record.repoClass, record.repoId));
                 return result;
             }
         }
 
         Metadata metadata;
 
-        if ( RELEASE.equals( version ) )
-        {
-            metadata = new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), MAVEN_METADATA_XML,
-                                            Metadata.Nature.RELEASE );
-        }
-        else if ( LATEST.equals( version ) )
-        {
-            metadata = new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), MAVEN_METADATA_XML,
-                                            Metadata.Nature.RELEASE_OR_SNAPSHOT );
-        }
-        else if ( version.endsWith( SNAPSHOT ) )
-        {
+        if (RELEASE.equals(version)) {
+            metadata = new DefaultMetadata(
+                    artifact.getGroupId(), artifact.getArtifactId(), MAVEN_METADATA_XML, Metadata.Nature.RELEASE);
+        } else if (LATEST.equals(version)) {
+            metadata = new DefaultMetadata(
+                    artifact.getGroupId(),
+                    artifact.getArtifactId(),
+                    MAVEN_METADATA_XML,
+                    Metadata.Nature.RELEASE_OR_SNAPSHOT);
+        } else if (version.endsWith(SNAPSHOT)) {
             WorkspaceReader workspace = session.getWorkspaceReader();
-            if ( workspace != null && workspace.findVersions( artifact ).contains( version ) )
-            {
+            if (workspace != null && workspace.findVersions(artifact).contains(version)) {
                 metadata = null;
-                result.setRepository( workspace.getRepository() );
+                result.setRepository(workspace.getRepository());
+            } else {
+                metadata = new DefaultMetadata(
+                        artifact.getGroupId(),
+                        artifact.getArtifactId(),
+                        version,
+                        MAVEN_METADATA_XML,
+                        Metadata.Nature.SNAPSHOT);
             }
-            else
-            {
-                metadata =
-                    new DefaultMetadata( artifact.getGroupId(), artifact.getArtifactId(), version, MAVEN_METADATA_XML,
-                                         Metadata.Nature.SNAPSHOT );
-            }
-        }
-        else
-        {
+        } else {
             metadata = null;
         }
 
-        if ( metadata == null )
-        {
-            result.setVersion( version );
-        }
-        else
-        {
-            List<MetadataRequest> metadataReqs = new ArrayList<>( request.getRepositories().size() );
+        if (metadata == null) {
+            result.setVersion(version);
+        } else {
+            List<MetadataRequest> metadataReqs =
+                    new ArrayList<>(request.getRepositories().size());
 
-            metadataReqs.add( new MetadataRequest( metadata, null, request.getRequestContext() ) );
+            metadataReqs.add(new MetadataRequest(metadata, null, request.getRequestContext()));
 
-            for ( RemoteRepository repository : request.getRepositories() )
-            {
+            for (RemoteRepository repository : request.getRepositories()) {
                 MetadataRequest metadataRequest =
-                    new MetadataRequest( metadata, repository, request.getRequestContext() );
-                metadataRequest.setDeleteLocalCopyIfMissing( true );
-                metadataRequest.setFavorLocalRepository( true );
-                metadataRequest.setTrace( trace );
-                metadataReqs.add( metadataRequest );
+                        new MetadataRequest(metadata, repository, request.getRequestContext());
+                metadataRequest.setDeleteLocalCopyIfMissing(true);
+                metadataRequest.setFavorLocalRepository(true);
+                metadataRequest.setTrace(trace);
+                metadataReqs.add(metadataRequest);
             }
 
-            List<MetadataResult> metadataResults = metadataResolver.resolveMetadata( session, metadataReqs );
+            List<MetadataResult> metadataResults = metadataResolver.resolveMetadata(session, metadataReqs);
 
             Map<String, VersionInfo> infos = new HashMap<>();
 
-            for ( MetadataResult metadataResult : metadataResults )
-            {
-                result.addException( metadataResult.getException() );
+            for (MetadataResult metadataResult : metadataResults) {
+                result.addException(metadataResult.getException());
 
                 ArtifactRepository repository = metadataResult.getRequest().getRepository();
-                if ( repository == null )
-                {
+                if (repository == null) {
                     repository = session.getLocalRepository();
                 }
 
-                Versioning v = readVersions( session, trace, metadataResult.getMetadata(), repository, result );
-                merge( artifact, infos, v, repository );
+                Versioning v = readVersions(session, trace, metadataResult.getMetadata(), repository, result);
+                merge(artifact, infos, v, repository);
             }
 
-            if ( RELEASE.equals( version ) )
-            {
-                resolve( result, infos, RELEASE );
-            }
-            else if ( LATEST.equals( version ) )
-            {
-                if ( !resolve( result, infos, LATEST ) )
-                {
-                    resolve( result, infos, RELEASE );
+            if (RELEASE.equals(version)) {
+                resolve(result, infos, RELEASE);
+            } else if (LATEST.equals(version)) {
+                if (!resolve(result, infos, LATEST)) {
+                    resolve(result, infos, RELEASE);
                 }
 
-                if ( result.getVersion() != null && result.getVersion().endsWith( SNAPSHOT ) )
-                {
+                if (result.getVersion() != null && result.getVersion().endsWith(SNAPSHOT)) {
                     VersionRequest subRequest = new VersionRequest();
-                    subRequest.setArtifact( artifact.setVersion( result.getVersion() ) );
-                    if ( result.getRepository() instanceof RemoteRepository )
-                    {
+                    subRequest.setArtifact(artifact.setVersion(result.getVersion()));
+                    if (result.getRepository() instanceof RemoteRepository) {
                         RemoteRepository r = (RemoteRepository) result.getRepository();
-                        subRequest.setRepositories( Collections.singletonList( r ) );
+                        subRequest.setRepositories(Collections.singletonList(r));
+                    } else {
+                        subRequest.setRepositories(request.getRepositories());
                     }
-                    else
-                    {
-                        subRequest.setRepositories( request.getRepositories() );
-                    }
-                    VersionResult subResult = resolveVersion( session, subRequest );
-                    result.setVersion( subResult.getVersion() );
-                    result.setRepository( subResult.getRepository() );
-                    for ( Exception exception : subResult.getExceptions() )
-                    {
-                        result.addException( exception );
+                    VersionResult subResult = resolveVersion(session, subRequest);
+                    result.setVersion(subResult.getVersion());
+                    result.setRepository(subResult.getRepository());
+                    for (Exception exception : subResult.getExceptions()) {
+                        result.addException(exception);
                     }
                 }
-            }
-            else
-            {
-                String key = SNAPSHOT + getKey( artifact.getClassifier(), artifact.getExtension() );
-                merge( infos, SNAPSHOT, key );
-                if ( !resolve( result, infos, key ) )
-                {
-                    result.setVersion( version );
+            } else {
+                String key = SNAPSHOT + getKey(artifact.getClassifier(), artifact.getExtension());
+                merge(infos, SNAPSHOT, key);
+                if (!resolve(result, infos, key)) {
+                    result.setVersion(version);
                 }
             }
 
-            if ( StringUtils.isEmpty( result.getVersion() ) )
-            {
-                throw new VersionResolutionException( result );
+            if (result.getVersion() == null || result.getVersion().isEmpty()) {
+                throw new VersionResolutionException(result);
             }
         }
 
-        if ( cacheKey != null && metadata != null && isSafelyCacheable( session, artifact ) )
-        {
-            cache.put( session, cacheKey, new Record( result.getVersion(), result.getRepository() ) );
+        if (cacheKey != null && metadata != null && isSafelyCacheable(session, artifact)) {
+            cache.put(session, cacheKey, new Record(result.getVersion(), result.getRepository()));
         }
 
         return result;
     }
 
-    private boolean resolve( VersionResult result, Map<String, VersionInfo> infos, String key )
-    {
-        VersionInfo info = infos.get( key );
-        if ( info != null )
-        {
-            result.setVersion( info.version );
-            result.setRepository( info.repository );
+    private boolean resolve(VersionResult result, Map<String, VersionInfo> infos, String key) {
+        VersionInfo info = infos.get(key);
+        if (info != null) {
+            result.setVersion(info.version);
+            result.setRepository(info.repository);
         }
         return info != null;
     }
 
-    private Versioning readVersions( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
-                                     ArtifactRepository repository, VersionResult result )
-    {
+    private Versioning readVersions(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            Metadata metadata,
+            ArtifactRepository repository,
+            VersionResult result) {
         Versioning versioning = null;
-        try
-        {
-            if ( metadata != null )
-            {
-                try ( SyncContext syncContext = syncContextFactory.newInstance( session, true ) )
-                {
-                    syncContext.acquire( null, Collections.singleton( metadata ) );
+        try {
+            if (metadata != null) {
+                try (SyncContext syncContext = syncContextFactory.newInstance(session, true)) {
+                    syncContext.acquire(null, Collections.singleton(metadata));
 
-                    if ( metadata.getFile() != null && metadata.getFile().exists() )
-                    {
-                        try ( InputStream in = new FileInputStream( metadata.getFile() ) )
-                        {
-                            versioning = new MetadataXpp3Reader().read( in, false ).getVersioning();
+                    if (metadata.getFile() != null && metadata.getFile().exists()) {
+                        try (InputStream in =
+                                Files.newInputStream(metadata.getFile().toPath())) {
+                            versioning = new Versioning(
+                                    new MetadataStaxReader().read(in, false).getVersioning());
 
                             /*
                             NOTE: Users occasionally misuse the id "local" for remote repos which screws up the metadata
                             of the local repository. This is especially troublesome during snapshot resolution so we try
                             to handle that gracefully.
                              */
-                            if ( versioning != null && repository instanceof LocalRepository
-                                     && versioning.getSnapshot() != null
-                                     && versioning.getSnapshot().getBuildNumber() > 0 )
-                            {
+                            if (versioning != null
+                                    && repository instanceof LocalRepository
+                                    && versioning.getSnapshot() != null
+                                    && versioning.getSnapshot().getBuildNumber() > 0) {
                                 final Versioning repaired = new Versioning();
-                                repaired.setLastUpdated( versioning.getLastUpdated() );
-                                repaired.setSnapshot( new Snapshot() );
-                                repaired.getSnapshot().setLocalCopy( true );
+                                repaired.setLastUpdated(versioning.getLastUpdated());
+                                repaired.setSnapshot(new Snapshot());
+                                repaired.getSnapshot().setLocalCopy(true);
                                 versioning = repaired;
-                                throw new IOException( "Snapshot information corrupted with remote repository data"
-                                                           + ", please verify that no remote repository uses the id '"
-                                                           + repository.getId() + "'" );
-
+                                throw new IOException("Snapshot information corrupted with remote repository data"
+                                        + ", please verify that no remote repository uses the id '"
+                                        + repository.getId() + "'");
                             }
                         }
                     }
                 }
             }
-        }
-        catch ( Exception e )
-        {
-            invalidMetadata( session, trace, metadata, repository, e );
-            result.addException( e );
+        } catch (Exception e) {
+            invalidMetadata(session, trace, metadata, repository, e);
+            result.addException(e);
         }
 
-        return ( versioning != null ) ? versioning : new Versioning();
+        return (versioning != null) ? versioning : new Versioning();
     }
 
-    private void invalidMetadata( RepositorySystemSession session, RequestTrace trace, Metadata metadata,
-                                  ArtifactRepository repository, Exception exception )
-    {
-        RepositoryEvent.Builder event = new RepositoryEvent.Builder( session, EventType.METADATA_INVALID );
-        event.setTrace( trace );
-        event.setMetadata( metadata );
-        event.setException( exception );
-        event.setRepository( repository );
+    private void invalidMetadata(
+            RepositorySystemSession session,
+            RequestTrace trace,
+            Metadata metadata,
+            ArtifactRepository repository,
+            Exception exception) {
+        RepositoryEvent.Builder event = new RepositoryEvent.Builder(session, EventType.METADATA_INVALID);
+        event.setTrace(trace);
+        event.setMetadata(metadata);
+        event.setException(exception);
+        event.setRepository(repository);
 
-        repositoryEventDispatcher.dispatch( event.build() );
+        repositoryEventDispatcher.dispatch(event.build());
     }
 
-    private void merge( Artifact artifact, Map<String, VersionInfo> infos, Versioning versioning,
-                        ArtifactRepository repository )
-    {
-        if ( StringUtils.isNotEmpty( versioning.getRelease() ) )
-        {
-            merge( RELEASE, infos, versioning.getLastUpdated(), versioning.getRelease(), repository );
+    private void merge(
+            Artifact artifact, Map<String, VersionInfo> infos, Versioning versioning, ArtifactRepository repository) {
+        if (versioning.getRelease() != null && !versioning.getRelease().isEmpty()) {
+            merge(RELEASE, infos, versioning.getLastUpdated(), versioning.getRelease(), repository);
         }
 
-        if ( StringUtils.isNotEmpty( versioning.getLatest() ) )
-        {
-            merge( LATEST, infos, versioning.getLastUpdated(), versioning.getLatest(), repository );
+        if (versioning.getLatest() != null && !versioning.getLatest().isEmpty()) {
+            merge(LATEST, infos, versioning.getLastUpdated(), versioning.getLatest(), repository);
         }
 
-        for ( SnapshotVersion sv : versioning.getSnapshotVersions() )
-        {
-            if ( StringUtils.isNotEmpty( sv.getVersion() ) )
-            {
-                String key = getKey( sv.getClassifier(), sv.getExtension() );
-                merge( SNAPSHOT + key, infos, sv.getUpdated(), sv.getVersion(), repository );
+        for (SnapshotVersion sv : versioning.getSnapshotVersions()) {
+            if (sv.getVersion() != null && !sv.getVersion().isEmpty()) {
+                String key = getKey(sv.getClassifier(), sv.getExtension());
+                merge(SNAPSHOT + key, infos, sv.getUpdated(), sv.getVersion(), repository);
             }
         }
 
         Snapshot snapshot = versioning.getSnapshot();
-        if ( snapshot != null && versioning.getSnapshotVersions().isEmpty() )
-        {
+        if (snapshot != null && versioning.getSnapshotVersions().isEmpty()) {
             String version = artifact.getVersion();
-            if ( snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0 )
-            {
+            if (snapshot.getTimestamp() != null && snapshot.getBuildNumber() > 0) {
                 String qualifier = snapshot.getTimestamp() + '-' + snapshot.getBuildNumber();
-                version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier;
+                version = version.substring(0, version.length() - SNAPSHOT.length()) + qualifier;
             }
-            merge( SNAPSHOT, infos, versioning.getLastUpdated(), version, repository );
+            merge(SNAPSHOT, infos, versioning.getLastUpdated(), version, repository);
         }
     }
 
-    private void merge( String key, Map<String, VersionInfo> infos, String timestamp, String version,
-                        ArtifactRepository repository )
-    {
-        VersionInfo info = infos.get( key );
-        if ( info == null )
-        {
-            info = new VersionInfo( timestamp, version, repository );
-            infos.put( key, info );
-        }
-        else if ( info.isOutdated( timestamp ) )
-        {
+    private void merge(
+            String key,
+            Map<String, VersionInfo> infos,
+            String timestamp,
+            String version,
+            ArtifactRepository repository) {
+        VersionInfo info = infos.get(key);
+        if (info == null) {
+            info = new VersionInfo(timestamp, version, repository);
+            infos.put(key, info);
+        } else if (info.isOutdated(timestamp)) {
             info.version = version;
             info.repository = repository;
             info.timestamp = timestamp;
         }
     }
 
-    private void merge( Map<String, VersionInfo> infos, String srcKey, String dstKey )
-    {
-        VersionInfo srcInfo = infos.get( srcKey );
-        VersionInfo dstInfo = infos.get( dstKey );
+    private void merge(Map<String, VersionInfo> infos, String srcKey, String dstKey) {
+        VersionInfo srcInfo = infos.get(srcKey);
+        VersionInfo dstInfo = infos.get(dstKey);
 
-        if ( dstInfo == null || ( srcInfo != null && dstInfo.isOutdated( srcInfo.timestamp )
-            && srcInfo.repository != dstInfo.repository ) )
-        {
-            infos.put( dstKey, srcInfo );
+        if (dstInfo == null
+                || (srcInfo != null
+                        && dstInfo.isOutdated(srcInfo.timestamp)
+                        && srcInfo.repository != dstInfo.repository)) {
+            infos.put(dstKey, srcInfo);
         }
     }
 
-    private String getKey( String classifier, String extension )
-    {
-        return StringUtils.clean( classifier ) + ':' + StringUtils.clean( extension );
+    private String getKey(String classifier, String extension) {
+        return (classifier == null ? "" : classifier.trim()) + ':' + (extension == null ? "" : extension.trim());
     }
 
-    private ArtifactRepository getRepository( RepositorySystemSession session,
-                                              List<RemoteRepository> repositories, Class<?> repoClass,
-                                              String repoId )
-    {
-        if ( repoClass != null )
-        {
-            if ( WorkspaceRepository.class.isAssignableFrom( repoClass ) )
-            {
+    private ArtifactRepository getRepository(
+            RepositorySystemSession session, List<RemoteRepository> repositories, Class<?> repoClass, String repoId) {
+        if (repoClass != null) {
+            if (WorkspaceRepository.class.isAssignableFrom(repoClass)) {
                 return session.getWorkspaceReader().getRepository();
-            }
-            else if ( LocalRepository.class.isAssignableFrom( repoClass ) )
-            {
+            } else if (LocalRepository.class.isAssignableFrom(repoClass)) {
                 return session.getLocalRepository();
-            }
-            else
-            {
-                for ( RemoteRepository repository : repositories )
-                {
-                    if ( repoId.equals( repository.getId() ) )
-                    {
+            } else {
+                for (RemoteRepository repository : repositories) {
+                    if (repoId.equals(repository.getId())) {
                         return repository;
                     }
                 }
@@ -422,26 +373,23 @@
         return null;
     }
 
-    private boolean isSafelyCacheable( RepositorySystemSession session, Artifact artifact )
-    {
+    private boolean isSafelyCacheable(RepositorySystemSession session, Artifact artifact) {
         /*
          * The workspace/reactor is in flux so we better not assume definitive information for any of its
          * artifacts/projects.
          */
 
         WorkspaceReader workspace = session.getWorkspaceReader();
-        if ( workspace == null )
-        {
+        if (workspace == null) {
             return true;
         }
 
-        Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact( artifact );
+        Artifact pomArtifact = ArtifactDescriptorUtils.toPomArtifact(artifact);
 
-        return workspace.findArtifact( pomArtifact ) == null;
+        return workspace.findArtifact(pomArtifact) == null;
     }
 
-    private static class VersionInfo
-    {
+    private static class VersionInfo {
 
         String timestamp;
 
@@ -449,22 +397,18 @@
 
         ArtifactRepository repository;
 
-        VersionInfo( String timestamp, String version, ArtifactRepository repository )
-        {
-            this.timestamp = ( timestamp != null ) ? timestamp : "";
+        VersionInfo(String timestamp, String version, ArtifactRepository repository) {
+            this.timestamp = (timestamp != null) ? timestamp : "";
             this.version = version;
             this.repository = repository;
         }
 
-        boolean isOutdated( String timestamp )
-        {
-            return timestamp != null && timestamp.compareTo( this.timestamp ) > 0;
+        boolean isOutdated(String timestamp) {
+            return timestamp != null && timestamp.compareTo(this.timestamp) > 0;
         }
-
     }
 
-    private static class Key
-    {
+    private static class Key {
 
         private final String groupId;
 
@@ -486,8 +430,7 @@
 
         private final int hashCode;
 
-        Key( RepositorySystemSession session, VersionRequest request )
-        {
+        Key(RepositorySystemSession session, VersionRequest request) {
             Artifact artifact = request.getArtifact();
             groupId = artifact.getGroupId();
             artifactId = artifact.getArtifactId();
@@ -496,19 +439,15 @@
             version = artifact.getVersion();
             localRepo = session.getLocalRepository().getBasedir();
             WorkspaceReader reader = session.getWorkspaceReader();
-            workspace = ( reader != null ) ? reader.getRepository() : null;
-            repositories = new ArrayList<>( request.getRepositories().size() );
+            workspace = (reader != null) ? reader.getRepository() : null;
+            repositories = new ArrayList<>(request.getRepositories().size());
             boolean repoMan = false;
-            for ( RemoteRepository repository : request.getRepositories() )
-            {
-                if ( repository.isRepositoryManager() )
-                {
+            for (RemoteRepository repository : request.getRepositories()) {
+                if (repository.isRepositoryManager()) {
                     repoMan = true;
-                    repositories.addAll( repository.getMirroredRepositories() );
-                }
-                else
-                {
-                    repositories.add( repository );
+                    repositories.addAll(repository.getMirroredRepositories());
+                } else {
+                    repositories.add(repository);
                 }
             }
             context = repoMan ? request.getRequestContext() : "";
@@ -525,54 +464,47 @@
         }
 
         @Override
-        public boolean equals( Object obj )
-        {
-            if ( obj == this )
-            {
+        public boolean equals(Object obj) {
+            if (obj == this) {
                 return true;
-            }
-            else if ( obj == null || !getClass().equals( obj.getClass() ) )
-            {
+            } else if (obj == null || !getClass().equals(obj.getClass())) {
                 return false;
             }
 
             Key that = (Key) obj;
-            return artifactId.equals( that.artifactId ) && groupId.equals( that.groupId ) && classifier.equals(
-                that.classifier ) && extension.equals( that.extension ) && version.equals( that.version )
-                && context.equals( that.context ) && localRepo.equals( that.localRepo )
-                && Objects.equals( workspace, that.workspace ) && repositories.equals( that.repositories );
+            return artifactId.equals(that.artifactId)
+                    && groupId.equals(that.groupId)
+                    && classifier.equals(that.classifier)
+                    && extension.equals(that.extension)
+                    && version.equals(that.version)
+                    && context.equals(that.context)
+                    && localRepo.equals(that.localRepo)
+                    && Objects.equals(workspace, that.workspace)
+                    && repositories.equals(that.repositories);
         }
 
         @Override
-        public int hashCode()
-        {
+        public int hashCode() {
             return hashCode;
         }
-
     }
 
-    private static class Record
-    {
+    private static class Record {
         final String version;
 
         final String repoId;
 
         final Class<?> repoClass;
 
-        Record( String version, ArtifactRepository repository )
-        {
+        Record(String version, ArtifactRepository repository) {
             this.version = version;
-            if ( repository != null )
-            {
+            if (repository != null) {
                 repoId = repository.getId();
                 repoClass = repository.getClass();
-            }
-            else
-            {
+            } else {
                 repoId = null;
                 repoClass = null;
             }
         }
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionSchemeProvider.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionSchemeProvider.java
index 6c7f5ef..8bebb05 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionSchemeProvider.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/DefaultVersionSchemeProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,32 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.eclipse.aether.util.version.GenericVersionScheme;
-import org.eclipse.aether.version.VersionScheme;
+package org.apache.maven.repository.internal;
 
 import javax.inject.Named;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 
+import org.eclipse.aether.util.version.GenericVersionScheme;
+import org.eclipse.aether.version.VersionScheme;
+
 /**
  * Default version scheme provider: provides singleton {@link GenericVersionScheme} instance.
  */
 @Singleton
 @Named
-public final class DefaultVersionSchemeProvider
-        implements Provider<VersionScheme>
-{
+public final class DefaultVersionSchemeProvider implements Provider<VersionScheme> {
     private final GenericVersionScheme genericVersionScheme;
 
-    public DefaultVersionSchemeProvider()
-    {
+    public DefaultVersionSchemeProvider() {
         this.genericVersionScheme = new GenericVersionScheme();
     }
 
     @Override
-    public VersionScheme get()
-    {
+    public VersionScheme get() {
         return genericVersionScheme;
     }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java
index 453e4d2..99b9bb3 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -33,132 +32,105 @@
 import org.eclipse.aether.artifact.Artifact;
 
 /**
- * @author Benjamin Bentmann
+ * Maven local GAV level metadata.
  */
-final class LocalSnapshotMetadata
-    extends MavenMetadata
-{
+final class LocalSnapshotMetadata extends MavenMetadata {
 
     private final Collection<Artifact> artifacts = new ArrayList<>();
 
-    private final boolean legacyFormat;
-
-    LocalSnapshotMetadata( Artifact artifact, boolean legacyFormat, Date timestamp )
-    {
-        super( createMetadata( artifact, legacyFormat ), null, timestamp );
-        this.legacyFormat = legacyFormat;
+    LocalSnapshotMetadata(Artifact artifact, Date timestamp) {
+        super(createMetadata(artifact), null, timestamp);
     }
 
-    LocalSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat, Date timestamp )
-    {
-        super( metadata, file, timestamp );
-        this.legacyFormat = legacyFormat;
+    LocalSnapshotMetadata(Metadata metadata, File file, Date timestamp) {
+        super(metadata, file, timestamp);
     }
 
-    private static Metadata createMetadata( Artifact artifact, boolean legacyFormat )
-    {
+    private static Metadata createMetadata(Artifact artifact) {
         Snapshot snapshot = new Snapshot();
-        snapshot.setLocalCopy( true );
+        snapshot.setLocalCopy(true);
         Versioning versioning = new Versioning();
-        versioning.setSnapshot( snapshot );
+        versioning.setSnapshot(snapshot);
 
         Metadata metadata = new Metadata();
-        metadata.setVersioning( versioning );
-        metadata.setGroupId( artifact.getGroupId() );
-        metadata.setArtifactId( artifact.getArtifactId() );
-        metadata.setVersion( artifact.getBaseVersion() );
-
-        if ( !legacyFormat )
-        {
-            metadata.setModelVersion( "1.1.0" );
-        }
-
+        metadata.setVersioning(versioning);
+        metadata.setGroupId(artifact.getGroupId());
+        metadata.setArtifactId(artifact.getArtifactId());
+        metadata.setVersion(artifact.getBaseVersion());
+        metadata.setModelVersion("1.1.0");
         return metadata;
     }
 
-    public void bind( Artifact artifact )
-    {
-        artifacts.add( artifact );
+    public void bind(Artifact artifact) {
+        artifacts.add(artifact);
     }
 
-    public MavenMetadata setFile( File file )
-    {
-        return new LocalSnapshotMetadata( metadata, file, legacyFormat, timestamp );
+    @Override
+    public MavenMetadata setFile(File file) {
+        return new LocalSnapshotMetadata(metadata, file, timestamp);
     }
 
-    public Object getKey()
-    {
+    public Object getKey() {
         return getGroupId() + ':' + getArtifactId() + ':' + getVersion();
     }
 
-    public static Object getKey( Artifact artifact )
-    {
+    public static Object getKey(Artifact artifact) {
         return artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion();
     }
 
     @Override
-    protected void merge( Metadata recessive )
-    {
-        metadata.getVersioning().setLastUpdatedTimestamp( timestamp );
+    protected void merge(Metadata recessive) {
+        metadata.getVersioning().setLastUpdatedTimestamp(timestamp);
 
-        if ( !legacyFormat )
-        {
-            String lastUpdated = metadata.getVersioning().getLastUpdated();
+        String lastUpdated = metadata.getVersioning().getLastUpdated();
 
-            Map<String, SnapshotVersion> versions = new LinkedHashMap<>();
+        Map<String, SnapshotVersion> versions = new LinkedHashMap<>();
 
-            for ( Artifact artifact : artifacts )
-            {
-                SnapshotVersion sv = new SnapshotVersion();
-                sv.setClassifier( artifact.getClassifier() );
-                sv.setExtension( artifact.getExtension() );
-                sv.setVersion( getVersion() );
-                sv.setUpdated( lastUpdated );
-                versions.put( getKey( sv.getClassifier(), sv.getExtension() ), sv );
-            }
+        for (Artifact artifact : artifacts) {
+            SnapshotVersion sv = new SnapshotVersion();
+            sv.setClassifier(artifact.getClassifier());
+            sv.setExtension(artifact.getExtension());
+            sv.setVersion(getVersion());
+            sv.setUpdated(lastUpdated);
+            versions.put(getKey(sv.getClassifier(), sv.getExtension()), sv);
+        }
 
-            Versioning versioning = recessive.getVersioning();
-            if ( versioning != null )
-            {
-                for ( SnapshotVersion sv : versioning.getSnapshotVersions() )
-                {
-                    String key = getKey( sv.getClassifier(), sv.getExtension() );
-                    if ( !versions.containsKey( key ) )
-                    {
-                        versions.put( key, sv );
-                    }
+        Versioning versioning = recessive.getVersioning();
+        if (versioning != null) {
+            for (SnapshotVersion sv : versioning.getSnapshotVersions()) {
+                String key = getKey(sv.getClassifier(), sv.getExtension());
+                if (!versions.containsKey(key)) {
+                    versions.put(key, sv);
                 }
             }
-
-            metadata.getVersioning().setSnapshotVersions( new ArrayList<>( versions.values() ) );
         }
 
+        metadata.getVersioning().setSnapshotVersions(new ArrayList<>(versions.values()));
+
         artifacts.clear();
     }
 
-    private String getKey( String classifier, String extension )
-    {
+    private String getKey(String classifier, String extension) {
         return classifier + ':' + extension;
     }
 
-    public String getGroupId()
-    {
+    @Override
+    public String getGroupId() {
         return metadata.getGroupId();
     }
 
-    public String getArtifactId()
-    {
+    @Override
+    public String getArtifactId() {
         return metadata.getArtifactId();
     }
 
-    public String getVersion()
-    {
+    @Override
+    public String getVersion() {
         return metadata.getVersion();
     }
 
-    public Nature getNature()
-    {
+    @Override
+    public Nature getNature() {
         return Nature.SNAPSHOT;
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java
index 75b4e6b..ad08a4c 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/LocalSnapshotMetadataGenerator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -33,55 +32,46 @@
 import org.eclipse.aether.util.ConfigUtils;
 
 /**
- * @author Benjamin Bentmann
+ * Maven local GAV level metadata generator.
+ * <p>
+ * Local snapshot metadata contains non-transformed snapshot version.
  */
-class LocalSnapshotMetadataGenerator
-    implements MetadataGenerator
-{
+class LocalSnapshotMetadataGenerator implements MetadataGenerator {
 
     private Map<Object, LocalSnapshotMetadata> snapshots;
 
-    private final boolean legacyFormat;
-
     private final Date timestamp;
 
-    LocalSnapshotMetadataGenerator( RepositorySystemSession session, InstallRequest request )
-    {
-        legacyFormat = ConfigUtils.getBoolean( session.getConfigProperties(), false, "maven.metadata.legacy" );
-
-        timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" );
+    LocalSnapshotMetadataGenerator(RepositorySystemSession session, InstallRequest request) {
+        timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
 
         snapshots = new LinkedHashMap<>();
     }
 
-    public Collection<? extends Metadata> prepare( Collection<? extends Artifact> artifacts )
-    {
-        for ( Artifact artifact : artifacts )
-        {
-            if ( artifact.isSnapshot() )
-            {
-                Object key = LocalSnapshotMetadata.getKey( artifact );
-                LocalSnapshotMetadata snapshotMetadata = snapshots.get( key );
-                if ( snapshotMetadata == null )
-                {
-                    snapshotMetadata = new LocalSnapshotMetadata( artifact, legacyFormat, timestamp );
-                    snapshots.put( key, snapshotMetadata );
+    @Override
+    public Collection<? extends Metadata> prepare(Collection<? extends Artifact> artifacts) {
+        for (Artifact artifact : artifacts) {
+            if (artifact.isSnapshot()) {
+                Object key = LocalSnapshotMetadata.getKey(artifact);
+                LocalSnapshotMetadata snapshotMetadata = snapshots.get(key);
+                if (snapshotMetadata == null) {
+                    snapshotMetadata = new LocalSnapshotMetadata(artifact, timestamp);
+                    snapshots.put(key, snapshotMetadata);
                 }
-                snapshotMetadata.bind( artifact );
+                snapshotMetadata.bind(artifact);
             }
         }
 
         return Collections.emptyList();
     }
 
-    public Artifact transformArtifact( Artifact artifact )
-    {
+    @Override
+    public Artifact transformArtifact(Artifact artifact) {
         return artifact;
     }
 
-    public Collection<? extends Metadata> finish( Collection<? extends Artifact> artifacts )
-    {
+    @Override
+    public Collection<? extends Metadata> finish(Collection<? extends Artifact> artifacts) {
         return snapshots.values();
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java
index bdddc70..7c8c07b 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,32 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
-import org.apache.maven.artifact.repository.metadata.Metadata;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Writer;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.WriterFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
-import org.eclipse.aether.RepositoryException;
-import org.eclipse.aether.metadata.AbstractMetadata;
-import org.eclipse.aether.metadata.MergeableMetadata;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
 import java.io.IOException;
-import java.io.Reader;
-import java.io.Writer;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Map;
 
+import org.apache.maven.artifact.repository.metadata.Metadata;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxReader;
+import org.apache.maven.artifact.repository.metadata.io.MetadataStaxWriter;
+import org.eclipse.aether.RepositoryException;
+import org.eclipse.aether.metadata.AbstractMetadata;
+import org.eclipse.aether.metadata.MergeableMetadata;
+
 /**
- * @author Benjamin Bentmann
  */
-abstract class MavenMetadata
-    extends AbstractMetadata
-    implements MergeableMetadata
-{
+abstract class MavenMetadata extends AbstractMetadata implements MergeableMetadata {
 
     static final String MAVEN_METADATA_XML = "maven-metadata.xml";
 
@@ -55,87 +50,68 @@
 
     private boolean merged;
 
-    protected MavenMetadata( Metadata metadata, File file, Date timestamp )
-    {
+    protected MavenMetadata(Metadata metadata, File file, Date timestamp) {
         this.metadata = metadata;
         this.file = file;
         this.timestamp = timestamp;
     }
 
-    public String getType()
-    {
+    @Override
+    public String getType() {
         return MAVEN_METADATA_XML;
     }
 
-    public File getFile()
-    {
+    @Override
+    public File getFile() {
         return file;
     }
 
-    public void merge( File existing, File result )
-        throws RepositoryException
-    {
-        Metadata recessive = read( existing );
+    @Override
+    public void merge(File existing, File result) throws RepositoryException {
+        Metadata recessive = read(existing);
 
-        merge( recessive );
+        merge(recessive);
 
-        write( result, metadata );
+        write(result, metadata);
 
         merged = true;
     }
 
-    public boolean isMerged()
-    {
+    @Override
+    public boolean isMerged() {
         return merged;
     }
 
-    protected abstract void merge( Metadata recessive );
+    protected abstract void merge(Metadata recessive);
 
-    static Metadata read( File metadataFile )
-        throws RepositoryException
-    {
-        if ( metadataFile.length() <= 0 )
-        {
+    static Metadata read(File metadataFile) throws RepositoryException {
+        if (metadataFile.length() <= 0) {
             return new Metadata();
         }
 
-        try ( Reader reader = ReaderFactory.newXmlReader( metadataFile ) )
-        {
-            return new MetadataXpp3Reader().read( reader, false );
-        }
-        catch ( IOException e )
-        {
-            throw new RepositoryException( "Could not read metadata " + metadataFile + ": " + e.getMessage(), e );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new RepositoryException( "Could not parse metadata " + metadataFile + ": " + e.getMessage(), e );
+        try (InputStream input = Files.newInputStream(metadataFile.toPath())) {
+            return new Metadata(new MetadataStaxReader().read(input, false));
+        } catch (IOException | XMLStreamException e) {
+            throw new RepositoryException("Could not parse metadata " + metadataFile + ": " + e.getMessage(), e);
         }
     }
 
-    private void write( File metadataFile, Metadata metadata )
-        throws RepositoryException
-    {
+    private void write(File metadataFile, Metadata metadata) throws RepositoryException {
         metadataFile.getParentFile().mkdirs();
-        try ( Writer writer = WriterFactory.newXmlWriter( metadataFile ) )
-        {
-            new MetadataXpp3Writer().write( writer, metadata );
-        }
-        catch ( IOException e )
-        {
-            throw new RepositoryException( "Could not write metadata " + metadataFile + ": " + e.getMessage(), e );
+        try (OutputStream output = Files.newOutputStream(metadataFile.toPath())) {
+            new MetadataStaxWriter().write(output, metadata.getDelegate());
+        } catch (IOException | XMLStreamException e) {
+            throw new RepositoryException("Could not write metadata " + metadataFile + ": " + e.getMessage(), e);
         }
     }
 
-    public Map<String, String> getProperties()
-    {
+    @Override
+    public Map<String, String> getProperties() {
         return Collections.emptyMap();
     }
 
     @Override
-    public org.eclipse.aether.metadata.Metadata setProperties( Map<String, String> properties )
-    {
+    public org.eclipse.aether.metadata.Metadata setProperties(Map<String, String> properties) {
         return this;
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java
index fd420de..a8b5f08 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenRepositorySystemUtils.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,10 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.Properties;
+package org.apache.maven.repository.internal;
 
 import org.eclipse.aether.DefaultRepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
 import org.eclipse.aether.artifact.DefaultArtifactType;
 import org.eclipse.aether.collection.DependencyGraphTransformer;
 import org.eclipse.aether.collection.DependencyManager;
@@ -43,81 +42,110 @@
 import org.eclipse.aether.util.graph.traverser.FatArtifactTraverser;
 import org.eclipse.aether.util.repository.SimpleArtifactDescriptorPolicy;
 
+import static java.util.Objects.requireNonNull;
+
 /**
  * A utility class to assist in setting up a Maven-like repository system. <em>Note:</em> This component is meant to
  * assist those clients that employ the repository system outside of an IoC container, Maven plugins should instead
  * always use regular dependency injection to acquire the repository system.
  *
- * @author Benjamin Bentmann
  */
-public final class MavenRepositorySystemUtils
-{
+public final class MavenRepositorySystemUtils {
 
-    private MavenRepositorySystemUtils()
-    {
+    private MavenRepositorySystemUtils() {
         // hide constructor
     }
 
     /**
+     * This method is deprecated, nobody should use it.
+     *
+     * @deprecated This method is here only for legacy uses (like UTs), nothing else should use it.
+     */
+    @Deprecated
+    public static DefaultRepositorySystemSession newSession() {
+        DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
+
+        DependencyTraverser depTraverser = new FatArtifactTraverser();
+        session.setDependencyTraverser(depTraverser);
+
+        DependencyManager depManager = new ClassicDependencyManager();
+        session.setDependencyManager(depManager);
+
+        DependencySelector depFilter = new AndDependencySelector(
+                new ScopeDependencySelector("test", "provided"),
+                new OptionalDependencySelector(),
+                new ExclusionDependencySelector());
+        session.setDependencySelector(depFilter);
+
+        DependencyGraphTransformer transformer = new ConflictResolver(
+                new NearestVersionSelector(), new JavaScopeSelector(),
+                new SimpleOptionalitySelector(), new JavaScopeDeriver());
+        transformer = new ChainedDependencyGraphTransformer(transformer, new JavaDependencyContextRefiner());
+        session.setDependencyGraphTransformer(transformer);
+
+        session.setArtifactTypeRegistry(newArtifactTypeRegistry());
+
+        session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(true, true));
+
+        return session;
+    }
+
+    /**
+     * Creates new Maven-like {@link ArtifactTypeRegistry}. This method should not be used from Maven.
+     *
+     * @since 4.0.0
+     */
+    public static ArtifactTypeRegistry newArtifactTypeRegistry() {
+        DefaultArtifactTypeRegistry stereotypes = new DefaultArtifactTypeRegistry();
+        stereotypes.add(new DefaultArtifactType("pom"));
+        stereotypes.add(new DefaultArtifactType("maven-plugin", "jar", "", "java"));
+        stereotypes.add(new DefaultArtifactType("jar", "jar", "", "java"));
+        stereotypes.add(new DefaultArtifactType("ejb", "jar", "", "java"));
+        stereotypes.add(new DefaultArtifactType("ejb-client", "jar", "client", "java"));
+        stereotypes.add(new DefaultArtifactType("test-jar", "jar", "tests", "java"));
+        stereotypes.add(new DefaultArtifactType("javadoc", "jar", "javadoc", "java"));
+        stereotypes.add(new DefaultArtifactType("java-source", "jar", "sources", "java", false, false));
+        stereotypes.add(new DefaultArtifactType("war", "war", "", "java", false, true));
+        stereotypes.add(new DefaultArtifactType("ear", "ear", "", "java", false, true));
+        stereotypes.add(new DefaultArtifactType("rar", "rar", "", "java", false, true));
+        stereotypes.add(new DefaultArtifactType("par", "par", "", "java", false, true));
+        return stereotypes;
+    }
+
+    /**
      * Creates a new Maven-like repository system session by initializing the session with values typical for
      * Maven-based resolution. In more detail, this method configures settings relevant for the processing of dependency
      * graphs, most other settings remain at their generic default value. Use the various setters to further configure
      * the session with authentication, mirror, proxy and other information required for your environment.
      *
      * @return The new repository system session, never {@code null}.
+     * @since 4.0.0
      */
-    public static DefaultRepositorySystemSession newSession()
-    {
-        DefaultRepositorySystemSession session = new DefaultRepositorySystemSession();
+    public static SessionBuilder newSession(SessionBuilder session, ArtifactTypeRegistry artifactTypeRegistry) {
+        requireNonNull(session, "null sessionBuilder");
+        requireNonNull(artifactTypeRegistry, "null artifactTypeRegistry");
 
         DependencyTraverser depTraverser = new FatArtifactTraverser();
-        session.setDependencyTraverser( depTraverser );
+        session.setDependencyTraverser(depTraverser);
 
         DependencyManager depManager = new ClassicDependencyManager();
-        session.setDependencyManager( depManager );
+        session.setDependencyManager(depManager);
 
-        DependencySelector depFilter =
-            new AndDependencySelector( new ScopeDependencySelector( "test", "provided" ),
-                                       new OptionalDependencySelector(), new ExclusionDependencySelector() );
-        session.setDependencySelector( depFilter );
+        DependencySelector depFilter = new AndDependencySelector(
+                new ScopeDependencySelector("test", "provided"),
+                new OptionalDependencySelector(),
+                new ExclusionDependencySelector());
+        session.setDependencySelector(depFilter);
 
-        DependencyGraphTransformer transformer =
-            new ConflictResolver( new NearestVersionSelector(), new JavaScopeSelector(),
-                                  new SimpleOptionalitySelector(), new JavaScopeDeriver() );
-        transformer = new ChainedDependencyGraphTransformer( transformer, new JavaDependencyContextRefiner() );
-        session.setDependencyGraphTransformer( transformer );
+        DependencyGraphTransformer transformer = new ConflictResolver(
+                new NearestVersionSelector(), new JavaScopeSelector(),
+                new SimpleOptionalitySelector(), new JavaScopeDeriver());
+        transformer = new ChainedDependencyGraphTransformer(transformer, new JavaDependencyContextRefiner());
+        session.setDependencyGraphTransformer(transformer);
+        session.setArtifactTypeRegistry(artifactTypeRegistry);
 
-        DefaultArtifactTypeRegistry stereotypes = new DefaultArtifactTypeRegistry();
-        stereotypes.add( new DefaultArtifactType( "pom" ) );
-        stereotypes.add( new DefaultArtifactType( "maven-plugin", "jar", "", "java" ) );
-        stereotypes.add( new DefaultArtifactType( "jar", "jar", "", "java" ) );
-        stereotypes.add( new DefaultArtifactType( "ejb", "jar", "", "java" ) );
-        stereotypes.add( new DefaultArtifactType( "ejb-client", "jar", "client", "java" ) );
-        stereotypes.add( new DefaultArtifactType( "test-jar", "jar", "tests", "java" ) );
-        stereotypes.add( new DefaultArtifactType( "javadoc", "jar", "javadoc", "java" ) );
-        stereotypes.add( new DefaultArtifactType( "java-source", "jar", "sources", "java", false, false ) );
-        stereotypes.add( new DefaultArtifactType( "war", "war", "", "java", false, true ) );
-        stereotypes.add( new DefaultArtifactType( "ear", "ear", "", "java", false, true ) );
-        stereotypes.add( new DefaultArtifactType( "rar", "rar", "", "java", false, true ) );
-        stereotypes.add( new DefaultArtifactType( "par", "par", "", "java", false, true ) );
-        session.setArtifactTypeRegistry( stereotypes );
-
-        session.setArtifactDescriptorPolicy( new SimpleArtifactDescriptorPolicy( true, true ) );
-
-        final Properties systemProperties = new Properties();
-
-        // MNG-5670 guard against ConcurrentModificationException
-        // MNG-6053 guard against key without value
-        Properties sysProp = System.getProperties();
-        synchronized ( sysProp )
-        {
-            systemProperties.putAll( sysProp );
-        }
-
-        session.setSystemProperties( systemProperties );
-        session.setConfigProperties( systemProperties );
+        session.setArtifactDescriptorPolicy(new SimpleArtifactDescriptorPolicy(true, true));
 
         return session;
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java
deleted file mode 100644
index 60dbf16..0000000
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenResolverModule.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package org.apache.maven.repository.internal;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-import com.google.inject.name.Names;
-import org.apache.maven.model.building.DefaultModelBuilderFactory;
-import org.apache.maven.model.building.ModelBuilder;
-import org.eclipse.aether.impl.ArtifactDescriptorReader;
-import org.eclipse.aether.impl.MetadataGeneratorFactory;
-import org.eclipse.aether.impl.VersionRangeResolver;
-import org.eclipse.aether.impl.VersionResolver;
-import org.eclipse.aether.impl.guice.AetherModule;
-import org.eclipse.aether.version.VersionScheme;
-
-/**
- * MavenResolverModule
- */
-public final class MavenResolverModule
-    extends AbstractModule
-{
-
-    @Override
-    protected void configure()
-    {
-        install( new AetherModule() );
-        bind( VersionScheme.class ).toProvider( new DefaultVersionSchemeProvider() );
-        bind( ArtifactDescriptorReader.class ).to( DefaultArtifactDescriptorReader.class ).in( Singleton.class );
-        bind( VersionResolver.class ).to( DefaultVersionResolver.class ).in( Singleton.class );
-        bind( VersionRangeResolver.class ).to( DefaultVersionRangeResolver.class ).in( Singleton.class );
-        bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "snapshot" ) )
-            .to( SnapshotMetadataGeneratorFactory.class ).in( Singleton.class );
-        bind( MetadataGeneratorFactory.class ).annotatedWith( Names.named( "versions" ) )
-            .to( VersionsMetadataGeneratorFactory.class ).in( Singleton.class );
-        bind( ModelBuilder.class ).toInstance( new DefaultModelBuilderFactory().newInstance() );
-        bind( ModelCacheFactory.class ).to( DefaultModelCacheFactory.class ).in( Singleton.class );
-    }
-
-    @Provides
-    @Singleton
-    Set<MetadataGeneratorFactory> provideMetadataGeneratorFactories(
-        @Named( "snapshot" ) MetadataGeneratorFactory snapshot,
-        @Named( "versions" ) MetadataGeneratorFactory versions )
-    {
-        Set<MetadataGeneratorFactory> factories = new HashSet<>( 2 );
-        factories.add( snapshot );
-        factories.add( versions );
-        return Collections.unmodifiableSet( factories );
-    }
-
-}
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java
index 35d4d42..23160a9 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenSnapshotMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -28,74 +27,59 @@
 import org.eclipse.aether.artifact.Artifact;
 
 /**
- * @author Hervé Boutemy
  */
-abstract class MavenSnapshotMetadata
-    extends MavenMetadata
-{
+abstract class MavenSnapshotMetadata extends MavenMetadata {
     static final String SNAPSHOT = "SNAPSHOT";
 
     protected final Collection<Artifact> artifacts = new ArrayList<>();
 
-    protected final boolean legacyFormat;
-
-    protected MavenSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat, Date timestamp )
-    {
-        super( metadata, file, timestamp );
-        this.legacyFormat = legacyFormat;
+    protected MavenSnapshotMetadata(Metadata metadata, File file, Date timestamp) {
+        super(metadata, file, timestamp);
     }
 
-    protected static Metadata createRepositoryMetadata( Artifact artifact, boolean legacyFormat )
-    {
+    protected static Metadata createRepositoryMetadata(Artifact artifact) {
         Metadata metadata = new Metadata();
-        if ( !legacyFormat )
-        {
-            metadata.setModelVersion( "1.1.0" );
-        }
-        metadata.setGroupId( artifact.getGroupId() );
-        metadata.setArtifactId( artifact.getArtifactId() );
-        metadata.setVersion( artifact.getBaseVersion() );
+        metadata.setModelVersion("1.1.0");
+        metadata.setGroupId(artifact.getGroupId());
+        metadata.setArtifactId(artifact.getArtifactId());
+        metadata.setVersion(artifact.getBaseVersion());
 
         return metadata;
     }
 
-    public void bind( Artifact artifact )
-    {
-        artifacts.add( artifact );
+    public void bind(Artifact artifact) {
+        artifacts.add(artifact);
     }
 
-    public Object getKey()
-    {
+    public Object getKey() {
         return getGroupId() + ':' + getArtifactId() + ':' + getVersion();
     }
 
-    public static Object getKey( Artifact artifact )
-    {
+    public static Object getKey(Artifact artifact) {
         return artifact.getGroupId() + ':' + artifact.getArtifactId() + ':' + artifact.getBaseVersion();
     }
 
-    protected String getKey( String classifier, String extension )
-    {
+    protected String getKey(String classifier, String extension) {
         return classifier + ':' + extension;
     }
 
-    public String getGroupId()
-    {
+    @Override
+    public String getGroupId() {
         return metadata.getGroupId();
     }
 
-    public String getArtifactId()
-    {
+    @Override
+    public String getArtifactId() {
         return metadata.getArtifactId();
     }
 
-    public String getVersion()
-    {
+    @Override
+    public String getVersion() {
         return metadata.getVersion();
     }
 
-    public Nature getNature()
-    {
+    @Override
+    public Nature getNature() {
         return Nature.SNAPSHOT;
     }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java
index c87f723..48fea8b 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/MavenWorkspaceReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import org.apache.maven.model.Model;
 import org.eclipse.aether.artifact.Artifact;
@@ -26,10 +25,7 @@
 /**
  * MavenWorkspaceReader
  */
-public interface MavenWorkspaceReader
-    extends WorkspaceReader
-{
+public interface MavenWorkspaceReader extends WorkspaceReader {
 
-    Model findModel( Artifact artifact );
-
-}
\ No newline at end of file
+    Model findModel(Artifact artifact);
+}
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ModelCacheFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ModelCacheFactory.java
index 0e42990..0f44f77 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ModelCacheFactory.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/ModelCacheFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import org.apache.maven.model.building.ModelCache;
 import org.eclipse.aether.RepositorySystemSession;
@@ -25,9 +24,7 @@
 /**
  * Factory for {@link ModelCache} objects.
  */
-public interface ModelCacheFactory
-{
+public interface ModelCacheFactory {
 
-    ModelCache createCache( RepositorySystemSession session );
-
+    ModelCache createCache(RepositorySystemSession session);
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadata.java
index 7a6c45a..18fdbba 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadata.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -27,91 +26,84 @@
 
 import org.apache.maven.artifact.repository.metadata.Metadata;
 import org.apache.maven.artifact.repository.metadata.Plugin;
-import org.apache.maven.repository.internal.PluginsMetadataInfoProvider.PluginInfo;
-import org.eclipse.aether.artifact.Artifact;
 
 /**
- * Plugin G level metadata.
+ * Maven G level metadata.
  */
-final class PluginsMetadata
-    extends MavenMetadata
-{
+final class PluginsMetadata extends MavenMetadata {
+    static final class PluginInfo {
+        final String groupId;
+
+        private final String artifactId;
+
+        private final String goalPrefix;
+
+        private final String name;
+
+        PluginInfo(String groupId, String artifactId, String goalPrefix, String name) {
+            this.groupId = groupId;
+            this.artifactId = artifactId;
+            this.goalPrefix = goalPrefix;
+            this.name = name;
+        }
+    }
+
     private final PluginInfo pluginInfo;
 
-    PluginsMetadata( PluginInfo pluginInfo, Date timestamp )
-    {
-        super( createRepositoryMetadata( pluginInfo ), null, timestamp );
+    PluginsMetadata(PluginInfo pluginInfo, Date timestamp) {
+        super(createRepositoryMetadata(pluginInfo), null, timestamp);
         this.pluginInfo = pluginInfo;
     }
 
-    PluginsMetadata( PluginInfo pluginInfo, File file, Date timestamp )
-    {
-        super( createRepositoryMetadata( pluginInfo ), file, timestamp );
+    PluginsMetadata(PluginInfo pluginInfo, File file, Date timestamp) {
+        super(createRepositoryMetadata(pluginInfo), file, timestamp);
         this.pluginInfo = pluginInfo;
     }
 
-    private static Metadata createRepositoryMetadata( PluginInfo pluginInfo )
-    {
+    private static Metadata createRepositoryMetadata(PluginInfo pluginInfo) {
         Metadata result = new Metadata();
         Plugin plugin = new Plugin();
-        plugin.setPrefix( pluginInfo.getPluginPrefix() );
-        plugin.setArtifactId( pluginInfo.getPluginArtifactId() );
-        plugin.setName( pluginInfo.getPluginName() );
-        result.getPlugins().add( plugin );
+        plugin.setPrefix(pluginInfo.goalPrefix);
+        plugin.setArtifactId(pluginInfo.artifactId);
+        plugin.setName(pluginInfo.name);
+        result.getPlugins().add(plugin);
         return result;
     }
 
     @Override
-    protected void merge( Metadata recessive )
-    {
+    protected void merge(Metadata recessive) {
         List<Plugin> recessivePlugins = recessive.getPlugins();
         List<Plugin> plugins = metadata.getPlugins();
-        if ( !plugins.isEmpty() )
-        {
+        if (!plugins.isEmpty()) {
             LinkedHashMap<String, Plugin> mergedPlugins = new LinkedHashMap<>();
-            recessivePlugins.forEach( p -> mergedPlugins.put( p.getPrefix(), p ) );
-            plugins.forEach( p -> mergedPlugins.put( p.getPrefix(), p ) );
-            metadata.setPlugins( new ArrayList<>( mergedPlugins.values() ) );
+            recessivePlugins.forEach(p -> mergedPlugins.put(p.getPrefix(), p));
+            plugins.forEach(p -> mergedPlugins.put(p.getPrefix(), p));
+            metadata.setPlugins(new ArrayList<>(mergedPlugins.values()));
         }
     }
 
-    public Object getKey()
-    {
-        return getGroupId();
-    }
-
-    public static Object getKey( Artifact artifact )
-    {
-        return artifact.getGroupId();
+    @Override
+    public MavenMetadata setFile(File file) {
+        return new PluginsMetadata(pluginInfo, file, timestamp);
     }
 
     @Override
-    public MavenMetadata setFile( File file )
-    {
-        return new PluginsMetadata( pluginInfo, file, timestamp );
+    public String getGroupId() {
+        return pluginInfo.groupId;
     }
 
     @Override
-    public String getGroupId()
-    {
-        return pluginInfo.getPluginGroupId();
-    }
-
-    @Override
-    public String getArtifactId()
-    {
+    public String getArtifactId() {
         return "";
     }
 
     @Override
-    public String getVersion()
-    {
+    public String getVersion() {
         return "";
     }
 
     @Override
-    public Nature getNature()
-    {
+    public Nature getNature() {
         return Nature.RELEASE_OR_SNAPSHOT;
     }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGenerator.java
index 4f35568..5886807 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGenerator.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGenerator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.jar.JarFile;
+import java.util.zip.ZipEntry;
 
-import org.apache.maven.repository.internal.PluginsMetadataInfoProvider.PluginInfo;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+import org.apache.maven.repository.internal.PluginsMetadata.PluginInfo;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.deployment.DeployRequest;
@@ -35,44 +41,29 @@
 import org.eclipse.aether.metadata.Metadata;
 import org.eclipse.aether.util.ConfigUtils;
 
-import static java.util.Objects.requireNonNull;
-
 /**
- * Plugin G level metadata.
+ * Maven G level metadata generator.
+ * <p>
+ * Plugin metadata contains G level list of "prefix" to A mapping for plugins present under this G.
  */
-class PluginsMetadataGenerator
-    implements MetadataGenerator
-{
-    private final PluginsMetadataInfoProvider pluginsMetadataInfoProvider;
-
-    private final Map<Object, PluginsMetadata> plugins;
+class PluginsMetadataGenerator implements MetadataGenerator {
+    private static final String PLUGIN_DESCRIPTOR_LOCATION = "META-INF/maven/plugin.xml";
 
     private final Map<Object, PluginsMetadata> processedPlugins;
 
     private final Date timestamp;
 
-    PluginsMetadataGenerator( PluginsMetadataInfoProvider pluginsMetadataInfoProvider,
-                              RepositorySystemSession session,
-                              InstallRequest request )
-    {
-        this( pluginsMetadataInfoProvider, session, request.getMetadata() );
+    PluginsMetadataGenerator(RepositorySystemSession session, InstallRequest request) {
+        this(session, request.getMetadata());
     }
 
-    PluginsMetadataGenerator( PluginsMetadataInfoProvider pluginsMetadataInfoProvider,
-                              RepositorySystemSession session,
-                              DeployRequest request )
-    {
-        this( pluginsMetadataInfoProvider, session, request.getMetadata() );
+    PluginsMetadataGenerator(RepositorySystemSession session, DeployRequest request) {
+        this(session, request.getMetadata());
     }
 
-    private PluginsMetadataGenerator( PluginsMetadataInfoProvider pluginsMetadataInfoProvider,
-                                      RepositorySystemSession session,
-                                      Collection<? extends Metadata> metadatas )
-    {
-        this.pluginsMetadataInfoProvider = requireNonNull( pluginsMetadataInfoProvider );
-        this.plugins = new LinkedHashMap<>();
+    private PluginsMetadataGenerator(RepositorySystemSession session, Collection<? extends Metadata> metadatas) {
         this.processedPlugins = new LinkedHashMap<>();
-        this.timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" );
+        this.timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
 
         /*
          * NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which
@@ -80,51 +71,76 @@
          * same version index. Allowing the caller to pass in metadata from a previous deployment allows to re-establish
          * the association between the artifacts of the same project.
          */
-        for ( Iterator<? extends Metadata> it = metadatas.iterator(); it.hasNext(); )
-        {
+        for (Iterator<? extends Metadata> it = metadatas.iterator(); it.hasNext(); ) {
             Metadata metadata = it.next();
-            if ( metadata instanceof PluginsMetadata )
-            {
+            if (metadata instanceof PluginsMetadata) {
                 it.remove();
-                PluginsMetadata pluginMetadata = ( PluginsMetadata ) metadata;
-                processedPlugins.put( pluginMetadata.getKey(), pluginMetadata );
+                PluginsMetadata pluginMetadata = (PluginsMetadata) metadata;
+                processedPlugins.put(pluginMetadata.getGroupId(), pluginMetadata);
             }
         }
     }
 
     @Override
-    public Collection<? extends Metadata> prepare( Collection<? extends Artifact> artifacts )
-    {
+    public Collection<? extends Metadata> prepare(Collection<? extends Artifact> artifacts) {
         return Collections.emptyList();
     }
 
     @Override
-    public Artifact transformArtifact( Artifact artifact )
-    {
+    public Artifact transformArtifact(Artifact artifact) {
         return artifact;
     }
 
     @Override
-    public Collection<? extends Metadata> finish( Collection<? extends Artifact> artifacts )
-    {
-        for ( Artifact artifact : artifacts )
-        {
-            PluginInfo pluginInfo = pluginsMetadataInfoProvider.getPluginInfo( artifact );
-            if ( pluginInfo != null )
-            {
-                Object key = PluginsMetadata.getKey( artifact );
-                if ( processedPlugins.get( key ) == null )
-                {
-                    PluginsMetadata pluginMetadata = plugins.get( key );
-                    if ( pluginMetadata == null )
-                    {
-                        pluginMetadata = new PluginsMetadata( pluginInfo, timestamp );
-                        plugins.put( key, pluginMetadata );
+    public Collection<? extends Metadata> finish(Collection<? extends Artifact> artifacts) {
+        LinkedHashMap<String, PluginsMetadata> plugins = new LinkedHashMap<>();
+        for (Artifact artifact : artifacts) {
+            PluginInfo pluginInfo = extractPluginInfo(artifact);
+            if (pluginInfo != null) {
+                String key = pluginInfo.groupId;
+                if (processedPlugins.get(key) == null) {
+                    PluginsMetadata pluginMetadata = plugins.get(key);
+                    if (pluginMetadata == null) {
+                        pluginMetadata = new PluginsMetadata(pluginInfo, timestamp);
+                        plugins.put(key, pluginMetadata);
                     }
                 }
             }
         }
-
         return plugins.values();
     }
+
+    private PluginInfo extractPluginInfo(Artifact artifact) {
+        // sanity: jar, no classifier and file exists
+        if (artifact != null
+                && "jar".equals(artifact.getExtension())
+                && "".equals(artifact.getClassifier())
+                && artifact.getFile() != null) {
+            Path artifactPath = artifact.getFile().toPath();
+            if (Files.isRegularFile(artifactPath)) {
+                try (JarFile artifactJar = new JarFile(artifactPath.toFile(), false)) {
+                    ZipEntry pluginDescriptorEntry = artifactJar.getEntry(PLUGIN_DESCRIPTOR_LOCATION);
+
+                    if (pluginDescriptorEntry != null) {
+                        try (InputStream is = artifactJar.getInputStream(pluginDescriptorEntry)) {
+                            // Note: using DOM instead of use of
+                            // org.apache.maven.plugin.descriptor.PluginDescriptor
+                            // as it would pull in dependency on:
+                            // - maven-plugin-api (for model)
+                            // - Plexus Container (for model supporting classes and exceptions)
+                            XmlNode root = XmlNodeBuilder.build(is, null);
+                            String groupId = root.getChild("groupId").getValue();
+                            String artifactId = root.getChild("artifactId").getValue();
+                            String goalPrefix = root.getChild("goalPrefix").getValue();
+                            String name = root.getChild("name").getValue();
+                            return new PluginInfo(groupId, artifactId, goalPrefix, name);
+                        }
+                    }
+                } catch (Exception e) {
+                    // here we can have: IO. ZIP or Plexus Conf Ex: but we should not interfere with user intent
+                }
+            }
+        }
+        return null;
+    }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory.java
index 19d499b..d6ccce5 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataGeneratorFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,8 +16,8 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
-import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
@@ -29,39 +27,27 @@
 import org.eclipse.aether.impl.MetadataGeneratorFactory;
 import org.eclipse.aether.installation.InstallRequest;
 
-import static java.util.Objects.requireNonNull;
-
 /**
- * Plugin G level metadata.
+ * Maven G level metadata generator factory.
  */
-@Named( "plugins" )
+@Named(PluginsMetadataGeneratorFactory.NAME)
 @Singleton
-public class PluginsMetadataGeneratorFactory
-    implements MetadataGeneratorFactory
-{
-    private final PluginsMetadataInfoProvider pluginsMetadataInfoProvider;
+public class PluginsMetadataGeneratorFactory implements MetadataGeneratorFactory {
+    public static final String NAME = "plugins";
 
-    @Inject
-    public PluginsMetadataGeneratorFactory( PluginsMetadataInfoProvider pluginsMetadataInfoProvider )
-    {
-        this.pluginsMetadataInfoProvider = requireNonNull( pluginsMetadataInfoProvider );
+    @Override
+    public MetadataGenerator newInstance(RepositorySystemSession session, InstallRequest request) {
+        return new PluginsMetadataGenerator(session, request);
     }
 
     @Override
-    public MetadataGenerator newInstance( RepositorySystemSession session, InstallRequest request )
-    {
-        return new PluginsMetadataGenerator( pluginsMetadataInfoProvider, session, request );
+    public MetadataGenerator newInstance(RepositorySystemSession session, DeployRequest request) {
+        return new PluginsMetadataGenerator(session, request);
     }
 
+    @SuppressWarnings("checkstyle:magicnumber")
     @Override
-    public MetadataGenerator newInstance( RepositorySystemSession session, DeployRequest request )
-    {
-        return new PluginsMetadataGenerator( pluginsMetadataInfoProvider, session, request );
-    }
-
-    @Override
-    public float getPriority()
-    {
-        return 5;
+    public float getPriority() {
+        return 10; // G level MD should be deployed as 3rd MD
     }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataInfoProvider.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataInfoProvider.java
deleted file mode 100644
index 629a23f..0000000
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/PluginsMetadataInfoProvider.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package org.apache.maven.repository.internal;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.eclipse.aether.artifact.Artifact;
-
-/**
- * Plugin G level metadata provider.
- */
-public interface PluginsMetadataInfoProvider
-{
-    interface PluginInfo
-    {
-        String getPluginGroupId();
-
-        String getPluginArtifactId();
-
-        String getPluginPrefix();
-
-        String getPluginName();
-    }
-
-    /**
-     * Returns {@link PluginInfo} corresponding for passed in {@link Artifact}, or {@code null}.
-     */
-    PluginInfo getPluginInfo( Artifact artifact );
-}
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java
index a0a21e9..4f78f1a 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RelocatedArtifact.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.io.File;
 import java.util.Map;
@@ -27,11 +26,8 @@
 import org.eclipse.aether.artifact.Artifact;
 
 /**
- * @author Benjamin Bentmann
  */
-public final class RelocatedArtifact
-    extends AbstractArtifact
-{
+public final class RelocatedArtifact extends AbstractArtifact {
 
     private final Artifact artifact;
 
@@ -43,113 +39,95 @@
 
     private final String message;
 
-    RelocatedArtifact( Artifact artifact, String groupId, String artifactId, String version, String message )
-    {
-        this.artifact = Objects.requireNonNull( artifact, "artifact cannot be null" );
-        // TODO Use StringUtils here
-        this.groupId = ( groupId != null && groupId.length() > 0 ) ? groupId : null;
-        this.artifactId = ( artifactId != null && artifactId.length() > 0 ) ? artifactId : null;
-        this.version = ( version != null && version.length() > 0 ) ? version : null;
-        this.message = ( message != null && message.length() > 0 ) ? message : null;
+    RelocatedArtifact(Artifact artifact, String groupId, String artifactId, String version, String message) {
+        this.artifact = Objects.requireNonNull(artifact, "artifact cannot be null");
+        this.groupId = (groupId != null && groupId.length() > 0) ? groupId : null;
+        this.artifactId = (artifactId != null && artifactId.length() > 0) ? artifactId : null;
+        this.version = (version != null && version.length() > 0) ? version : null;
+        this.message = (message != null && message.length() > 0) ? message : null;
     }
 
-    public String getGroupId()
-    {
-        if ( groupId != null )
-        {
+    @Override
+    public String getGroupId() {
+        if (groupId != null) {
             return groupId;
-        }
-        else
-        {
+        } else {
             return artifact.getGroupId();
         }
     }
 
-    public String getArtifactId()
-    {
-        if ( artifactId != null )
-        {
+    @Override
+    public String getArtifactId() {
+        if (artifactId != null) {
             return artifactId;
-        }
-        else
-        {
+        } else {
             return artifact.getArtifactId();
         }
     }
 
-    public String getVersion()
-    {
-        if ( version != null )
-        {
+    @Override
+    public String getVersion() {
+        if (version != null) {
             return version;
-        }
-        else
-        {
+        } else {
             return artifact.getVersion();
         }
     }
 
     // Revise these three methods when MRESOLVER-233 is delivered
     @Override
-    public Artifact setVersion( String version )
-    {
-         String current = getVersion();
-         if ( current.equals( version ) || ( version == null && current.length() <= 0 ) )
-         {
-             return this;
-         }
-        return new RelocatedArtifact( artifact, groupId, artifactId, version, message );
+    public Artifact setVersion(String version) {
+        String current = getVersion();
+        if (current.equals(version) || (version == null && current.length() <= 0)) {
+            return this;
+        }
+        return new RelocatedArtifact(artifact, groupId, artifactId, version, message);
     }
 
     @Override
-    public Artifact setFile( File file )
-    {
+    public Artifact setFile(File file) {
         File current = getFile();
-        if ( Objects.equals( current, file ) )
-        {
-             return this;
+        if (Objects.equals(current, file)) {
+            return this;
         }
-        return new RelocatedArtifact( artifact.setFile( file ), groupId, artifactId, version, message );
+        return new RelocatedArtifact(artifact.setFile(file), groupId, artifactId, version, message);
     }
 
     @Override
-    public Artifact setProperties( Map<String, String> properties )
-    {
+    public Artifact setProperties(Map<String, String> properties) {
         Map<String, String> current = getProperties();
-        if ( current.equals( properties ) || ( properties == null && current.isEmpty() ) )
-        {
-             return this;
+        if (current.equals(properties) || (properties == null && current.isEmpty())) {
+            return this;
         }
-        return new RelocatedArtifact( artifact.setProperties( properties ), groupId, artifactId, version, message );
+        return new RelocatedArtifact(artifact.setProperties(properties), groupId, artifactId, version, message);
     }
 
-    public String getClassifier()
-    {
+    @Override
+    public String getClassifier() {
         return artifact.getClassifier();
     }
 
-    public String getExtension()
-    {
+    @Override
+    public String getExtension() {
         return artifact.getExtension();
     }
 
-    public File getFile()
-    {
+    @Override
+    public File getFile() {
         return artifact.getFile();
     }
 
-    public String getProperty( String key, String defaultValue )
-    {
-        return artifact.getProperty( key, defaultValue );
+    @Override
+    public String getProperty(String key, String defaultValue) {
+        return artifact.getProperty(key, defaultValue);
     }
 
-    public Map<String, String> getProperties()
-    {
+    @Override
+    public Map<String, String> getProperties() {
         return artifact.getProperties();
     }
 
-    public String getMessage()
-    {
+    public String getMessage() {
         return message;
     }
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java
index d9b5616..5781057 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.io.File;
 import java.text.DateFormat;
@@ -36,122 +35,101 @@
 import org.eclipse.aether.artifact.Artifact;
 
 /**
- * @author Benjamin Bentmann
+ * Maven remote GAV level metadata.
  */
-final class RemoteSnapshotMetadata
-    extends MavenSnapshotMetadata
-{
+final class RemoteSnapshotMetadata extends MavenSnapshotMetadata {
     public static final String DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT = "yyyyMMdd.HHmmss";
 
-    public static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone( "Etc/UTC" );
+    public static final TimeZone DEFAULT_SNAPSHOT_TIME_ZONE = TimeZone.getTimeZone("Etc/UTC");
 
     private final Map<String, SnapshotVersion> versions = new LinkedHashMap<>();
 
-    RemoteSnapshotMetadata( Artifact artifact, boolean legacyFormat, Date timestamp )
-    {
-        super( createRepositoryMetadata( artifact, legacyFormat ), null, legacyFormat, timestamp );
+    RemoteSnapshotMetadata(Artifact artifact, Date timestamp) {
+        super(createRepositoryMetadata(artifact), null, timestamp);
     }
 
-    private RemoteSnapshotMetadata( Metadata metadata, File file, boolean legacyFormat, Date timestamp )
-    {
-        super( metadata, file, legacyFormat, timestamp );
-    }
-
-    public MavenMetadata setFile( File file )
-    {
-        return new RemoteSnapshotMetadata( metadata, file, legacyFormat, timestamp );
-    }
-
-    public String getExpandedVersion( Artifact artifact )
-    {
-        String key = getKey( artifact.getClassifier(), artifact.getExtension() );
-        return versions.get( key ).getVersion();
+    private RemoteSnapshotMetadata(Metadata metadata, File file, Date timestamp) {
+        super(metadata, file, timestamp);
     }
 
     @Override
-    protected void merge( Metadata recessive )
-    {
+    public MavenMetadata setFile(File file) {
+        return new RemoteSnapshotMetadata(metadata, file, timestamp);
+    }
+
+    public String getExpandedVersion(Artifact artifact) {
+        String key = getKey(artifact.getClassifier(), artifact.getExtension());
+        return versions.get(key).getVersion();
+    }
+
+    @Override
+    protected void merge(Metadata recessive) {
         Snapshot snapshot;
         String lastUpdated;
 
-        if ( metadata.getVersioning() == null )
-        {
-            DateFormat utcDateFormatter = new SimpleDateFormat( DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT );
-            utcDateFormatter.setCalendar( new GregorianCalendar() );
-            utcDateFormatter.setTimeZone( DEFAULT_SNAPSHOT_TIME_ZONE );
+        if (metadata.getVersioning() == null) {
+            DateFormat utcDateFormatter = new SimpleDateFormat(DEFAULT_SNAPSHOT_TIMESTAMP_FORMAT);
+            utcDateFormatter.setCalendar(new GregorianCalendar());
+            utcDateFormatter.setTimeZone(DEFAULT_SNAPSHOT_TIME_ZONE);
 
             snapshot = new Snapshot();
-            snapshot.setBuildNumber( getBuildNumber( recessive ) + 1 );
-            snapshot.setTimestamp( utcDateFormatter.format( timestamp ) );
+            snapshot.setBuildNumber(getBuildNumber(recessive) + 1);
+            snapshot.setTimestamp(utcDateFormatter.format(timestamp));
 
             Versioning versioning = new Versioning();
-            versioning.setSnapshot( snapshot );
-            versioning.setLastUpdatedTimestamp( timestamp );
+            versioning.setSnapshot(snapshot);
+            versioning.setLastUpdatedTimestamp(timestamp);
             lastUpdated = versioning.getLastUpdated();
 
-            metadata.setVersioning( versioning );
-        }
-        else
-        {
+            metadata.setVersioning(versioning);
+        } else {
             snapshot = metadata.getVersioning().getSnapshot();
             lastUpdated = metadata.getVersioning().getLastUpdated();
         }
 
-        for ( Artifact artifact : artifacts )
-        {
+        for (Artifact artifact : artifacts) {
             String version = artifact.getVersion();
 
-            if ( version.endsWith( SNAPSHOT ) )
-            {
+            if (version.endsWith(SNAPSHOT)) {
                 String qualifier = snapshot.getTimestamp() + '-' + snapshot.getBuildNumber();
-                version = version.substring( 0, version.length() - SNAPSHOT.length() ) + qualifier;
+                version = version.substring(0, version.length() - SNAPSHOT.length()) + qualifier;
             }
 
             SnapshotVersion sv = new SnapshotVersion();
-            sv.setClassifier( artifact.getClassifier() );
-            sv.setExtension( artifact.getExtension() );
-            sv.setVersion( version );
-            sv.setUpdated( lastUpdated );
+            sv.setClassifier(artifact.getClassifier());
+            sv.setExtension(artifact.getExtension());
+            sv.setVersion(version);
+            sv.setUpdated(lastUpdated);
 
-            versions.put( getKey( sv.getClassifier(), sv.getExtension() ), sv );
+            versions.put(getKey(sv.getClassifier(), sv.getExtension()), sv);
         }
 
         artifacts.clear();
 
         Versioning versioning = recessive.getVersioning();
-        if ( versioning != null )
-        {
-            for ( SnapshotVersion sv : versioning.getSnapshotVersions() )
-            {
-                String key = getKey( sv.getClassifier(), sv.getExtension() );
-                if ( !versions.containsKey( key ) )
-                {
-                    versions.put( key, sv );
+        if (versioning != null) {
+            for (SnapshotVersion sv : versioning.getSnapshotVersions()) {
+                String key = getKey(sv.getClassifier(), sv.getExtension());
+                if (!versions.containsKey(key)) {
+                    versions.put(key, sv);
                 }
             }
         }
 
-        if ( !legacyFormat )
-        {
-            metadata.getVersioning().setSnapshotVersions( new ArrayList<>( versions.values() ) );
-        }
+        metadata.getVersioning().setSnapshotVersions(new ArrayList<>(versions.values()));
     }
 
-    private static int getBuildNumber( Metadata metadata )
-    {
+    private static int getBuildNumber(Metadata metadata) {
         int number = 0;
 
         Versioning versioning = metadata.getVersioning();
-        if ( versioning != null )
-        {
+        if (versioning != null) {
             Snapshot snapshot = versioning.getSnapshot();
-            if ( snapshot != null && snapshot.getBuildNumber() > 0 )
-            {
+            if (snapshot != null && snapshot.getBuildNumber() > 0) {
                 number = snapshot.getBuildNumber();
             }
         }
 
         return number;
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java
index 2e42bee..2fcef26 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataGenerator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -33,23 +32,18 @@
 import org.eclipse.aether.util.ConfigUtils;
 
 /**
- * @author Benjamin Bentmann
+ * Maven remote GAV level metadata generator.
+ * <p>
+ * Remote snapshot metadata converts artifact on-the-fly to use timestamped snapshot version, and enlist it accordingly.
  */
-class RemoteSnapshotMetadataGenerator
-    implements MetadataGenerator
-{
+class RemoteSnapshotMetadataGenerator implements MetadataGenerator {
 
     private final Map<Object, RemoteSnapshotMetadata> snapshots;
 
-    private final boolean legacyFormat;
-
     private final Date timestamp;
 
-    RemoteSnapshotMetadataGenerator( RepositorySystemSession session, DeployRequest request )
-    {
-        legacyFormat = ConfigUtils.getBoolean( session, false, "maven.metadata.legacy" );
-
-        timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" );
+    RemoteSnapshotMetadataGenerator(RepositorySystemSession session, DeployRequest request) {
+        timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
 
         snapshots = new LinkedHashMap<>();
 
@@ -59,54 +53,46 @@
          * same timestamp+buildno for the snapshot versions. Allowing the caller to pass in metadata from a previous
          * deployment allows to re-establish the association between the artifacts of the same project.
          */
-        for ( Metadata metadata : request.getMetadata() )
-        {
-            if ( metadata instanceof RemoteSnapshotMetadata )
-            {
+        for (Metadata metadata : request.getMetadata()) {
+            if (metadata instanceof RemoteSnapshotMetadata) {
                 RemoteSnapshotMetadata snapshotMetadata = (RemoteSnapshotMetadata) metadata;
-                snapshots.put( snapshotMetadata.getKey(), snapshotMetadata );
+                snapshots.put(snapshotMetadata.getKey(), snapshotMetadata);
             }
         }
     }
 
-    public Collection<? extends Metadata> prepare( Collection<? extends Artifact> artifacts )
-    {
-        for ( Artifact artifact : artifacts )
-        {
-            if ( artifact.isSnapshot() )
-            {
-                Object key = RemoteSnapshotMetadata.getKey( artifact );
-                RemoteSnapshotMetadata snapshotMetadata = snapshots.get( key );
-                if ( snapshotMetadata == null )
-                {
-                    snapshotMetadata = new RemoteSnapshotMetadata( artifact, legacyFormat, timestamp );
-                    snapshots.put( key, snapshotMetadata );
+    @Override
+    public Collection<? extends Metadata> prepare(Collection<? extends Artifact> artifacts) {
+        for (Artifact artifact : artifacts) {
+            if (artifact.isSnapshot()) {
+                Object key = RemoteSnapshotMetadata.getKey(artifact);
+                RemoteSnapshotMetadata snapshotMetadata = snapshots.get(key);
+                if (snapshotMetadata == null) {
+                    snapshotMetadata = new RemoteSnapshotMetadata(artifact, timestamp);
+                    snapshots.put(key, snapshotMetadata);
                 }
-                snapshotMetadata.bind( artifact );
+                snapshotMetadata.bind(artifact);
             }
         }
 
         return snapshots.values();
     }
 
-    public Artifact transformArtifact( Artifact artifact )
-    {
-        if ( artifact.isSnapshot() && artifact.getVersion().equals( artifact.getBaseVersion() ) )
-        {
-            Object key = RemoteSnapshotMetadata.getKey( artifact );
-            RemoteSnapshotMetadata snapshotMetadata = snapshots.get( key );
-            if ( snapshotMetadata != null )
-            {
-                artifact = artifact.setVersion( snapshotMetadata.getExpandedVersion( artifact ) );
+    @Override
+    public Artifact transformArtifact(Artifact artifact) {
+        if (artifact.isSnapshot() && artifact.getVersion().equals(artifact.getBaseVersion())) {
+            Object key = RemoteSnapshotMetadata.getKey(artifact);
+            RemoteSnapshotMetadata snapshotMetadata = snapshots.get(key);
+            if (snapshotMetadata != null) {
+                artifact = artifact.setVersion(snapshotMetadata.getExpandedVersion(artifact));
             }
         }
 
         return artifact;
     }
 
-    public Collection<? extends Metadata> finish( Collection<? extends Artifact> artifacts )
-    {
+    @Override
+    public Collection<? extends Metadata> finish(Collection<? extends Artifact> artifacts) {
         return Collections.emptyList();
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java
index ba6dadf..d25fc2d 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/SnapshotMetadataGeneratorFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -29,27 +28,26 @@
 import org.eclipse.aether.installation.InstallRequest;
 
 /**
- * @author Benjamin Bentmann
+ * Maven GAV level metadata generator factory.
  */
-@Named( "snapshot" )
+@Named(SnapshotMetadataGeneratorFactory.NAME)
 @Singleton
-public class SnapshotMetadataGeneratorFactory
-    implements MetadataGeneratorFactory
-{
+public class SnapshotMetadataGeneratorFactory implements MetadataGeneratorFactory {
+    public static final String NAME = "snapshot";
 
-    public MetadataGenerator newInstance( RepositorySystemSession session, InstallRequest request )
-    {
-        return new LocalSnapshotMetadataGenerator( session, request );
+    @Override
+    public MetadataGenerator newInstance(RepositorySystemSession session, InstallRequest request) {
+        return new LocalSnapshotMetadataGenerator(session, request);
     }
 
-    public MetadataGenerator newInstance( RepositorySystemSession session, DeployRequest request )
-    {
-        return new RemoteSnapshotMetadataGenerator( session, request );
+    @Override
+    public MetadataGenerator newInstance(RepositorySystemSession session, DeployRequest request) {
+        return new RemoteSnapshotMetadataGenerator(session, request);
     }
 
-    public float getPriority()
-    {
-        return 10;
+    @SuppressWarnings("checkstyle:magicnumber")
+    @Override
+    public float getPriority() {
+        return 30; // GAV level metadata should be deployed 1st MD
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java
index 5103e5c..12e1ce0 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadata.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.io.File;
 import java.util.ArrayList;
@@ -31,104 +30,91 @@
 import org.eclipse.aether.artifact.ArtifactProperties;
 
 /**
- * @author Benjamin Bentmann
+ * Maven GA level metadata.
  */
-final class VersionsMetadata
-    extends MavenMetadata
-{
+final class VersionsMetadata extends MavenMetadata {
 
     private final Artifact artifact;
 
-    VersionsMetadata( Artifact artifact, Date timestamp )
-    {
-        super( createRepositoryMetadata( artifact ), null, timestamp );
+    VersionsMetadata(Artifact artifact, Date timestamp) {
+        super(createRepositoryMetadata(artifact), null, timestamp);
         this.artifact = artifact;
     }
 
-    VersionsMetadata( Artifact artifact, File file, Date timestamp )
-    {
-        super( createRepositoryMetadata( artifact ), file, timestamp );
+    VersionsMetadata(Artifact artifact, File file, Date timestamp) {
+        super(createRepositoryMetadata(artifact), file, timestamp);
         this.artifact = artifact;
     }
 
-    private static Metadata createRepositoryMetadata( Artifact artifact )
-    {
+    private static Metadata createRepositoryMetadata(Artifact artifact) {
         Metadata metadata = new Metadata();
-        metadata.setGroupId( artifact.getGroupId() );
-        metadata.setArtifactId( artifact.getArtifactId() );
+        metadata.setGroupId(artifact.getGroupId());
+        metadata.setArtifactId(artifact.getArtifactId());
 
         Versioning versioning = new Versioning();
-        versioning.addVersion( artifact.getBaseVersion() );
-        if ( !artifact.isSnapshot() )
-        {
-            versioning.setRelease( artifact.getBaseVersion() );
+        versioning.addVersion(artifact.getBaseVersion());
+        if (!artifact.isSnapshot()) {
+            versioning.setRelease(artifact.getBaseVersion());
         }
-        if ( "maven-plugin".equals( artifact.getProperty( ArtifactProperties.TYPE, "" ) ) )
-        {
-            versioning.setLatest( artifact.getBaseVersion() );
+        if ("maven-plugin".equals(artifact.getProperty(ArtifactProperties.TYPE, ""))) {
+            versioning.setLatest(artifact.getBaseVersion());
         }
 
-        metadata.setVersioning( versioning );
+        metadata.setVersioning(versioning);
 
         return metadata;
     }
 
     @Override
-    protected void merge( Metadata recessive )
-    {
+    protected void merge(Metadata recessive) {
         Versioning versioning = metadata.getVersioning();
-        versioning.setLastUpdatedTimestamp( timestamp );
+        versioning.setLastUpdatedTimestamp(timestamp);
 
-        if ( recessive.getVersioning() != null )
-        {
-            if ( versioning.getLatest() == null )
-            {
-                versioning.setLatest( recessive.getVersioning().getLatest() );
+        if (recessive.getVersioning() != null) {
+            if (versioning.getLatest() == null) {
+                versioning.setLatest(recessive.getVersioning().getLatest());
             }
-            if ( versioning.getRelease() == null )
-            {
-                versioning.setRelease( recessive.getVersioning().getRelease() );
+            if (versioning.getRelease() == null) {
+                versioning.setRelease(recessive.getVersioning().getRelease());
             }
 
-            Collection<String> versions = new LinkedHashSet<>( recessive.getVersioning().getVersions() );
-            versions.addAll( versioning.getVersions() );
-            versioning.setVersions( new ArrayList<>( versions ) );
+            Collection<String> versions =
+                    new LinkedHashSet<>(recessive.getVersioning().getVersions());
+            versions.addAll(versioning.getVersions());
+            versioning.setVersions(new ArrayList<>(versions));
         }
     }
 
-    public Object getKey()
-    {
+    public Object getKey() {
         return getGroupId() + ':' + getArtifactId();
     }
 
-    public static Object getKey( Artifact artifact )
-    {
+    public static Object getKey(Artifact artifact) {
         return artifact.getGroupId() + ':' + artifact.getArtifactId();
     }
 
-    public MavenMetadata setFile( File file )
-    {
-        return new VersionsMetadata( artifact, file, timestamp );
+    @Override
+    public MavenMetadata setFile(File file) {
+        return new VersionsMetadata(artifact, file, timestamp);
     }
 
-    public String getGroupId()
-    {
+    @Override
+    public String getGroupId() {
         return artifact.getGroupId();
     }
 
-    public String getArtifactId()
-    {
+    @Override
+    public String getArtifactId() {
         return artifact.getArtifactId();
     }
 
-    public String getVersion()
-    {
+    @Override
+    public String getVersion() {
         return "";
     }
 
-    public Nature getNature()
-    {
+    @Override
+    public Nature getNature() {
         return artifact.isSnapshot() ? Nature.RELEASE_OR_SNAPSHOT : Nature.RELEASE;
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java
index 409eec4..f9d98cd 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGenerator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -35,33 +34,30 @@
 import org.eclipse.aether.util.ConfigUtils;
 
 /**
- * @author Benjamin Bentmann
+ * Maven GA level metadata generator.
+ *
+ * Version metadata contains list of existing baseVersions within this GA.
  */
-class VersionsMetadataGenerator
-    implements MetadataGenerator
-{
+class VersionsMetadataGenerator implements MetadataGenerator {
 
-    private Map<Object, VersionsMetadata> versions;
+    private final Map<Object, VersionsMetadata> versions;
 
-    private Map<Object, VersionsMetadata> processedVersions;
+    private final Map<Object, VersionsMetadata> processedVersions;
 
     private final Date timestamp;
 
-    VersionsMetadataGenerator( RepositorySystemSession session, InstallRequest request )
-    {
-        this( session, request.getMetadata() );
+    VersionsMetadataGenerator(RepositorySystemSession session, InstallRequest request) {
+        this(session, request.getMetadata());
     }
 
-    VersionsMetadataGenerator( RepositorySystemSession session, DeployRequest request )
-    {
-        this( session, request.getMetadata() );
+    VersionsMetadataGenerator(RepositorySystemSession session, DeployRequest request) {
+        this(session, request.getMetadata());
     }
 
-    private VersionsMetadataGenerator( RepositorySystemSession session, Collection<? extends Metadata> metadatas )
-    {
+    private VersionsMetadataGenerator(RepositorySystemSession session, Collection<? extends Metadata> metadatas) {
         versions = new LinkedHashMap<>();
         processedVersions = new LinkedHashMap<>();
-        timestamp = (Date) ConfigUtils.getObject( session, new Date(), "maven.startTime" );
+        timestamp = (Date) ConfigUtils.getObject(session, new Date(), "maven.startTime");
 
         /*
          * NOTE: This should be considered a quirk to support interop with Maven's legacy ArtifactDeployer which
@@ -69,45 +65,39 @@
          * same version index. Allowing the caller to pass in metadata from a previous deployment allows to re-establish
          * the association between the artifacts of the same project.
          */
-        for ( Iterator<? extends Metadata> it = metadatas.iterator(); it.hasNext(); )
-        {
+        for (Iterator<? extends Metadata> it = metadatas.iterator(); it.hasNext(); ) {
             Metadata metadata = it.next();
-            if ( metadata instanceof VersionsMetadata )
-            {
+            if (metadata instanceof VersionsMetadata) {
                 it.remove();
                 VersionsMetadata versionsMetadata = (VersionsMetadata) metadata;
-                processedVersions.put( versionsMetadata.getKey(), versionsMetadata );
+                processedVersions.put(versionsMetadata.getKey(), versionsMetadata);
             }
         }
     }
 
-    public Collection<? extends Metadata> prepare( Collection<? extends Artifact> artifacts )
-    {
+    @Override
+    public Collection<? extends Metadata> prepare(Collection<? extends Artifact> artifacts) {
         return Collections.emptyList();
     }
 
-    public Artifact transformArtifact( Artifact artifact )
-    {
+    @Override
+    public Artifact transformArtifact(Artifact artifact) {
         return artifact;
     }
 
-    public Collection<? extends Metadata> finish( Collection<? extends Artifact> artifacts )
-    {
-        for ( Artifact artifact : artifacts )
-        {
-            Object key = VersionsMetadata.getKey( artifact );
-            if ( processedVersions.get( key ) == null )
-            {
-                VersionsMetadata versionsMetadata = versions.get( key );
-                if ( versionsMetadata == null )
-                {
-                    versionsMetadata = new VersionsMetadata( artifact, timestamp );
-                    versions.put( key, versionsMetadata );
+    @Override
+    public Collection<? extends Metadata> finish(Collection<? extends Artifact> artifacts) {
+        for (Artifact artifact : artifacts) {
+            Object key = VersionsMetadata.getKey(artifact);
+            if (processedVersions.get(key) == null) {
+                VersionsMetadata versionsMetadata = versions.get(key);
+                if (versionsMetadata == null) {
+                    versionsMetadata = new VersionsMetadata(artifact, timestamp);
+                    versions.put(key, versionsMetadata);
                 }
             }
         }
 
         return versions.values();
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java
index eae836a..77baab2 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/VersionsMetadataGeneratorFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
@@ -29,27 +28,26 @@
 import org.eclipse.aether.installation.InstallRequest;
 
 /**
- * @author Benjamin Bentmann
+ * Maven GA level metadata generator factory.
  */
-@Named( "versions" )
+@Named(VersionsMetadataGeneratorFactory.NAME)
 @Singleton
-public class VersionsMetadataGeneratorFactory
-    implements MetadataGeneratorFactory
-{
+public class VersionsMetadataGeneratorFactory implements MetadataGeneratorFactory {
+    public static final String NAME = "versions";
 
-    public MetadataGenerator newInstance( RepositorySystemSession session, InstallRequest request )
-    {
-        return new VersionsMetadataGenerator( session, request );
+    @Override
+    public MetadataGenerator newInstance(RepositorySystemSession session, InstallRequest request) {
+        return new VersionsMetadataGenerator(session, request);
     }
 
-    public MetadataGenerator newInstance( RepositorySystemSession session, DeployRequest request )
-    {
-        return new VersionsMetadataGenerator( session, request );
+    @Override
+    public MetadataGenerator newInstance(RepositorySystemSession session, DeployRequest request) {
+        return new VersionsMetadataGenerator(session, request);
     }
 
-    public float getPriority()
-    {
-        return 5;
+    @SuppressWarnings("checkstyle:magicnumber")
+    @Override
+    public float getPriority() {
+        return 20; // GA level metadata should be deployed 2nd MD
     }
-
 }
diff --git a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/package-info.java b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/package-info.java
index 7309c2b..e745bf7 100644
--- a/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/package-info.java
+++ b/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/package-info.java
@@ -4,22 +4,3 @@
  * repository metadata.
  */
 package org.apache.maven.repository.internal;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
diff --git a/maven-resolver-provider/src/site/site.xml b/maven-resolver-provider/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-resolver-provider/src/site/site.xml
+++ b/maven-resolver-provider/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/AbstractRepositoryTestCase.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/AbstractRepositoryTestCase.java
index 7660616..c0ea5b5 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/AbstractRepositoryTestCase.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/AbstractRepositoryTestCase.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.net.MalformedURLException;
+package org.apache.maven.repository.internal;
 
 import javax.inject.Inject;
 
+import java.net.MalformedURLException;
+
 import org.apache.maven.repository.internal.util.ConsoleRepositoryListener;
 import org.apache.maven.repository.internal.util.ConsoleTransferListener;
 import org.codehaus.plexus.PlexusContainer;
 import org.codehaus.plexus.testing.PlexusTest;
-import org.eclipse.aether.DefaultRepositorySystemSession;
 import org.eclipse.aether.RepositorySystem;
 import org.eclipse.aether.RepositorySystemSession;
+import org.eclipse.aether.RepositorySystemSession.SessionBuilder;
 import org.eclipse.aether.repository.LocalRepository;
 import org.eclipse.aether.repository.RemoteRepository;
 import org.junit.jupiter.api.BeforeEach;
@@ -37,8 +36,7 @@
 import static org.codehaus.plexus.testing.PlexusExtension.getTestFile;
 
 @PlexusTest
-public abstract class AbstractRepositoryTestCase
-{
+public abstract class AbstractRepositoryTestCase {
     @Inject
     protected RepositorySystem system;
 
@@ -48,33 +46,30 @@
     protected RepositorySystemSession session;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
-        session = newMavenRepositorySystemSession( system );
+    public void setUp() throws Exception {
+        session = newMavenRepositorySystemSession(system);
     }
 
     protected PlexusContainer getContainer() {
         return container;
     }
 
-    public static RepositorySystemSession newMavenRepositorySystemSession(RepositorySystem system )
-    {
-        DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
+    public static RepositorySystemSession newMavenRepositorySystemSession(RepositorySystem system) {
+        SessionBuilder session = MavenRepositorySystemUtils.newSession(
+                system.createSessionBuilder(), MavenRepositorySystemUtils.newArtifactTypeRegistry());
 
-        LocalRepository localRepo = new LocalRepository( "target/local-repo" );
-        session.setLocalRepositoryManager( system.newLocalRepositoryManager( session, localRepo ) );
+        session.withLocalRepositories(new LocalRepository("target/local-repo"));
+        session.setTransferListener(new ConsoleTransferListener());
+        session.setRepositoryListener(new ConsoleRepositoryListener());
 
-        session.setTransferListener( new ConsoleTransferListener() );
-        session.setRepositoryListener( new ConsoleRepositoryListener() );
-
-        return session;
+        return session.build();
     }
 
-    public static RemoteRepository newTestRepository()
-        throws MalformedURLException
-    {
-        return new RemoteRepository.Builder( "repo", "default",
-                                             getTestFile( "target/test-classes/repo" ).toURI().toURL().toString() ).build();
+    public static RemoteRepository newTestRepository() throws MalformedURLException {
+        return new RemoteRepository.Builder(
+                        "repo",
+                        "default",
+                        getTestFile("target/test-classes/repo").toURI().toURL().toString())
+                .build();
     }
 }
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReaderTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReaderTest.java
index 733fa59..3aa7ba3 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReaderTest.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultArtifactDescriptorReaderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.lang.reflect.Field;
 
@@ -35,48 +34,48 @@
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 
-public class DefaultArtifactDescriptorReaderTest
-    extends AbstractRepositoryTestCase
-{
+class DefaultArtifactDescriptorReaderTest extends AbstractRepositoryTestCase {
 
     @Test
-    public void testMng5459()
-        throws Exception
-    {
+    void testMng5459() throws Exception {
         // prepare
-        DefaultArtifactDescriptorReader reader = (DefaultArtifactDescriptorReader) getContainer().lookup( ArtifactDescriptorReader.class );
+        DefaultArtifactDescriptorReader reader =
+                (DefaultArtifactDescriptorReader) getContainer().lookup(ArtifactDescriptorReader.class);
 
-        RepositoryEventDispatcher eventDispatcher = mock( RepositoryEventDispatcher.class );
+        RepositoryEventDispatcher eventDispatcher = mock(RepositoryEventDispatcher.class);
 
-        ArgumentCaptor<RepositoryEvent> event = ArgumentCaptor.forClass( RepositoryEvent.class );
+        ArgumentCaptor<RepositoryEvent> event = ArgumentCaptor.forClass(RepositoryEvent.class);
 
-        Field field = DefaultArtifactDescriptorReader.class.getDeclaredField( "repositoryEventDispatcher" );
-        field.setAccessible( true );
-        field.set( reader, eventDispatcher );
+        Field field = DefaultArtifactDescriptorReader.class.getDeclaredField("repositoryEventDispatcher");
+        field.setAccessible(true);
+        field.set(reader, eventDispatcher);
 
         ArtifactDescriptorRequest request = new ArtifactDescriptorRequest();
 
-        request.addRepository( newTestRepository() );
+        request.addRepository(newTestRepository());
 
-        request.setArtifact( new DefaultArtifact( "org.apache.maven.its", "dep-mng5459", "jar", "0.4.0-SNAPSHOT" ) );
+        request.setArtifact(new DefaultArtifact("org.apache.maven.its", "dep-mng5459", "jar", "0.4.0-SNAPSHOT"));
 
         // execute
-        reader.readArtifactDescriptor( session, request );
+        reader.readArtifactDescriptor(session, request);
 
         // verify
-        verify( eventDispatcher ).dispatch( event.capture() );
+        verify(eventDispatcher).dispatch(event.capture());
 
         boolean missingArtifactDescriptor = false;
 
-        for( RepositoryEvent evt : event.getAllValues() )
-        {
-            if ( EventType.ARTIFACT_DESCRIPTOR_MISSING.equals( evt.getType() ) )
-            {
-                assertEquals( "Could not find artifact org.apache.maven.its:dep-mng5459:pom:0.4.0-20130404.090532-2 in repo (" + newTestRepository().getUrl() + ")", evt.getException().getMessage() );
+        for (RepositoryEvent evt : event.getAllValues()) {
+            if (EventType.ARTIFACT_DESCRIPTOR_MISSING.equals(evt.getType())) {
+                assertEquals(
+                        "Could not find artifact org.apache.maven.its:dep-mng5459:pom:0.4.0-20130404.090532-2 in repo ("
+                                + newTestRepository().getUrl() + ")",
+                        evt.getException().getMessage());
                 missingArtifactDescriptor = true;
             }
         }
 
-        assertTrue( missingArtifactDescriptor, "Expected missing artifact descriptor for org.apache.maven.its:dep-mng5459:pom:0.4.0-20130404.090532-2" );
+        assertTrue(
+                missingArtifactDescriptor,
+                "Expected missing artifact descriptor for org.apache.maven.its:dep-mng5459:pom:0.4.0-20130404.090532-2");
     }
 }
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultModelResolverTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultModelResolverTest.java
index 1a4d444..1fd832a 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultModelResolverTest.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultModelResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,12 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.net.MalformedURLException;
 import java.util.Arrays;
+import java.util.concurrent.atomic.AtomicReference;
 
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Parent;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.Parent;
 import org.apache.maven.model.resolution.ModelResolver;
 import org.apache.maven.model.resolution.UnresolvableModelException;
 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
@@ -40,172 +40,170 @@
 /**
  * Test cases for the default {@code ModelResolver} implementation.
  *
- * @author Christian Schulte
  * @since 3.5.0
  */
-public final class DefaultModelResolverTest extends AbstractRepositoryTestCase
-{
+final class DefaultModelResolverTest extends AbstractRepositoryTestCase {
 
     /**
      * Creates a new {@code DefaultModelResolverTest} instance.
      */
-    public DefaultModelResolverTest()
-    {
+    public DefaultModelResolverTest() {
         super();
     }
 
     @Test
-    public void testResolveParentThrowsUnresolvableModelExceptionWhenNotFound() throws Exception
-    {
-        final Parent parent = new Parent();
-        parent.setGroupId( "ut.simple" );
-        parent.setArtifactId( "artifact" );
-        parent.setVersion( "0" );
+    void testResolveParentThrowsUnresolvableModelExceptionWhenNotFound() throws Exception {
+        final Parent parent = Parent.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("0")
+                .build();
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( parent ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertNotNull( e.getMessage() );
-        assertTrue( e.getMessage().startsWith( "Could not find artifact ut.simple:artifact:pom:0 in repo" ) );
+                () -> newModelResolver().resolveModel(parent, new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertNotNull(e.getMessage());
+        assertTrue(e.getMessage().contains("Could not find artifact ut.simple:artifact:pom:0 in repo"));
     }
 
     @Test
-    public void testResolveParentThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception
-    {
-        final Parent parent = new Parent();
-        parent.setGroupId( "ut.simple" );
-        parent.setArtifactId( "artifact" );
-        parent.setVersion( "[2.0,2.1)" );
+    void testResolveParentThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception {
+        final Parent parent = Parent.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("[2.0,2.1)")
+                .build();
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( parent ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertNotNull( e.getMessage() );
-        assertEquals( "No versions matched the requested parent version range '[2.0,2.1)'",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(parent, new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertNotNull(e.getMessage());
+        assertEquals("No versions matched the requested parent version range '[2.0,2.1)'", e.getMessage());
     }
 
     @Test
-    public void testResolveParentThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception
-    {
-        final Parent parent = new Parent();
-        parent.setGroupId( "ut.simple" );
-        parent.setArtifactId( "artifact" );
-        parent.setVersion( "[1.0,)" );
+    void testResolveParentThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception {
+        final Parent parent = Parent.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("[1.0,)")
+                .build();
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( parent ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertEquals( "The requested parent version range '[1.0,)' does not specify an upper bound",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(parent, new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertEquals("The requested parent version range '[1.0,)' does not specify an upper bound", e.getMessage());
     }
 
     @Test
-    public void testResolveParentSuccessfullyResolvesExistingParentWithoutRange() throws Exception
-    {
-        final Parent parent = new Parent();
-        parent.setGroupId( "ut.simple" );
-        parent.setArtifactId( "artifact" );
-        parent.setVersion( "1.0" );
+    void testResolveParentSuccessfullyResolvesExistingParentWithoutRange() throws Exception {
+        final Parent parent = Parent.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("1.0")
+                .build();
 
-        assertNotNull( this.newModelResolver().resolveModel( parent ) );
-        assertEquals( "1.0", parent.getVersion() );
+        assertNotNull(this.newModelResolver().resolveModel(parent, new AtomicReference<>()));
+        assertEquals("1.0", parent.getVersion());
     }
 
     @Test
-    public void testResolveParentSuccessfullyResolvesExistingParentUsingHighestVersion() throws Exception
-    {
-        final Parent parent = new Parent();
-        parent.setGroupId( "ut.simple" );
-        parent.setArtifactId( "artifact" );
-        parent.setVersion( "(,2.0)" );
+    void testResolveParentSuccessfullyResolvesExistingParentUsingHighestVersion() throws Exception {
+        final Parent parent = Parent.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("(,2.0)")
+                .build();
 
-        assertNotNull( this.newModelResolver().resolveModel( parent ) );
-        assertEquals( "1.0", parent.getVersion() );
+        AtomicReference<Parent> modified = new AtomicReference<>();
+        assertNotNull(this.newModelResolver().resolveModel(parent, modified));
+        assertNotNull(modified.get());
+        assertEquals("1.0", modified.get().getVersion());
     }
 
     @Test
-    public void testResolveDependencyThrowsUnresolvableModelExceptionWhenNotFound() throws Exception
-    {
-        final Dependency dependency = new Dependency();
-        dependency.setGroupId( "ut.simple" );
-        dependency.setArtifactId( "artifact" );
-        dependency.setVersion( "0" );
+    void testResolveDependencyThrowsUnresolvableModelExceptionWhenNotFound() throws Exception {
+        final Dependency dependency = Dependency.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("0")
+                .build();
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( dependency ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertNotNull( e.getMessage() );
-        assertTrue( e.getMessage().startsWith( "Could not find artifact ut.simple:artifact:pom:0 in repo" ) );
+                () -> newModelResolver().resolveModel(dependency, new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertNotNull(e.getMessage());
+        assertTrue(e.getMessage().contains("Could not find artifact ut.simple:artifact:pom:0 in repo"));
     }
 
     @Test
-    public void testResolveDependencyThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception
-    {
-        final Dependency dependency = new Dependency();
-        dependency.setGroupId( "ut.simple" );
-        dependency.setArtifactId( "artifact" );
-        dependency.setVersion( "[2.0,2.1)" );
+    void testResolveDependencyThrowsUnresolvableModelExceptionWhenNoMatchingVersionFound() throws Exception {
+        final Dependency dependency = Dependency.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("[2.0,2.1)")
+                .build();
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( dependency ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertEquals( "No versions matched the requested dependency version range '[2.0,2.1)'",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(dependency, new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertEquals("No versions matched the requested dependency version range '[2.0,2.1)'", e.getMessage());
     }
 
     @Test
-    public void testResolveDependencyThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception
-    {
-        final Dependency dependency = new Dependency();
-        dependency.setGroupId( "ut.simple" );
-        dependency.setArtifactId( "artifact" );
-        dependency.setVersion( "[1.0,)" );
+    void testResolveDependencyThrowsUnresolvableModelExceptionWhenUsingRangesWithoutUpperBound() throws Exception {
+        final Dependency dependency = Dependency.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("[1.0,)")
+                .build();
 
         UnresolvableModelException e = assertThrows(
                 UnresolvableModelException.class,
-                () -> newModelResolver().resolveModel( dependency ),
-                "Expected 'UnresolvableModelException' not thrown." );
-        assertEquals( "The requested dependency version range '[1.0,)' does not specify an upper bound",
-                      e.getMessage() );
+                () -> newModelResolver().resolveModel(dependency, new AtomicReference<>()),
+                "Expected 'UnresolvableModelException' not thrown.");
+        assertEquals("The requested dependency version range '[1.0,)' does not specify an upper bound", e.getMessage());
     }
 
     @Test
-    public void testResolveDependencySuccessfullyResolvesExistingDependencyWithoutRange() throws Exception
-    {
-        final Dependency dependency = new Dependency();
-        dependency.setGroupId( "ut.simple" );
-        dependency.setArtifactId( "artifact" );
-        dependency.setVersion( "1.0" );
+    void testResolveDependencySuccessfullyResolvesExistingDependencyWithoutRange() throws Exception {
+        final Dependency dependency = Dependency.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("1.0")
+                .build();
 
-        assertNotNull( this.newModelResolver().resolveModel( dependency ) );
-        assertEquals( "1.0", dependency.getVersion() );
+        assertNotNull(this.newModelResolver().resolveModel(dependency, new AtomicReference<>()));
+        assertEquals("1.0", dependency.getVersion());
     }
 
     @Test
-    public void testResolveDependencySuccessfullyResolvesExistingDependencyUsingHighestVersion() throws Exception
-    {
-        final Dependency dependency = new Dependency();
-        dependency.setGroupId( "ut.simple" );
-        dependency.setArtifactId( "artifact" );
-        dependency.setVersion( "(,2.0)" );
+    void testResolveDependencySuccessfullyResolvesExistingDependencyUsingHighestVersion() throws Exception {
+        final Dependency dependency = Dependency.newBuilder()
+                .groupId("ut.simple")
+                .artifactId("artifact")
+                .version("(,2.0)")
+                .build();
 
-        assertNotNull( this.newModelResolver().resolveModel( dependency ) );
-        assertEquals( "1.0", dependency.getVersion() );
+        AtomicReference<Dependency> modified = new AtomicReference<>();
+        assertNotNull(this.newModelResolver().resolveModel(dependency, modified));
+        assertNotNull(modified.get());
+        assertEquals("1.0", modified.get().getVersion());
     }
 
-    private ModelResolver newModelResolver() throws ComponentLookupException, MalformedURLException
-    {
-        return new DefaultModelResolver( this.session, null, this.getClass().getName(),
-                                         getContainer().lookup( ArtifactResolver.class ), getContainer().lookup( VersionRangeResolver.class ),
-                                         getContainer().lookup( RemoteRepositoryManager.class ),
-                                         Arrays.asList( newTestRepository() ) );
-
+    private ModelResolver newModelResolver() throws ComponentLookupException, MalformedURLException {
+        return new DefaultModelResolver(
+                this.session,
+                null,
+                this.getClass().getName(),
+                getContainer().lookup(ArtifactResolver.class),
+                getContainer().lookup(VersionRangeResolver.class),
+                getContainer().lookup(RemoteRepositoryManager.class),
+                Arrays.asList(newTestRepository()));
     }
-
 }
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultVersionResolverTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultVersionResolverTest.java
index d934033..8231324 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultVersionResolverTest.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/DefaultVersionResolverTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import javax.inject.Inject;
 
@@ -29,58 +28,50 @@
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class DefaultVersionResolverTest
-    extends AbstractRepositoryTestCase
-{
+class DefaultVersionResolverTest extends AbstractRepositoryTestCase {
     @Inject
     private DefaultVersionResolver versionResolver;
 
     @Test
-    public void testResolveSeparateInstalledClassifiedNonUniqueVersionedArtifacts()
-        throws Exception
-    {
+    void testResolveSeparateInstalledClassifiedNonUniqueVersionedArtifacts() throws Exception {
         VersionRequest requestB = new VersionRequest();
-        requestB.addRepository( newTestRepository() );
+        requestB.addRepository(newTestRepository());
         Artifact artifactB =
-            new DefaultArtifact( "org.apache.maven.its", "dep-mng5324", "classifierB", "jar", "07.20.3-SNAPSHOT" );
-        requestB.setArtifact( artifactB );
+                new DefaultArtifact("org.apache.maven.its", "dep-mng5324", "classifierB", "jar", "07.20.3-SNAPSHOT");
+        requestB.setArtifact(artifactB);
 
-        VersionResult resultB = versionResolver.resolveVersion( session, requestB );
-        assertEquals( "07.20.3-20120809.112920-97", resultB.getVersion() );
+        VersionResult resultB = versionResolver.resolveVersion(session, requestB);
+        assertEquals("07.20.3-20120809.112920-97", resultB.getVersion());
 
         VersionRequest requestA = new VersionRequest();
-        requestA.addRepository( newTestRepository() );
+        requestA.addRepository(newTestRepository());
 
         Artifact artifactA =
-            new DefaultArtifact( "org.apache.maven.its", "dep-mng5324", "classifierA", "jar", "07.20.3-SNAPSHOT" );
-        requestA.setArtifact( artifactA );
+                new DefaultArtifact("org.apache.maven.its", "dep-mng5324", "classifierA", "jar", "07.20.3-SNAPSHOT");
+        requestA.setArtifact(artifactA);
 
-        VersionResult resultA = versionResolver.resolveVersion( session, requestA );
-        assertEquals( "07.20.3-20120809.112124-88", resultA.getVersion() );
+        VersionResult resultA = versionResolver.resolveVersion(session, requestA);
+        assertEquals("07.20.3-20120809.112124-88", resultA.getVersion());
     }
 
     @Test
-    public void testResolveSeparateInstalledClassifiedNonVersionedArtifacts()
-        throws Exception
-    {
+    void testResolveSeparateInstalledClassifiedNonVersionedArtifacts() throws Exception {
         VersionRequest requestA = new VersionRequest();
-        requestA.addRepository( newTestRepository() );
+        requestA.addRepository(newTestRepository());
         String versionA = "07.20.3-20120809.112124-88";
-        Artifact artifactA =
-            new DefaultArtifact( "org.apache.maven.its", "dep-mng5324", "classifierA", "jar", versionA );
-        requestA.setArtifact( artifactA );
+        Artifact artifactA = new DefaultArtifact("org.apache.maven.its", "dep-mng5324", "classifierA", "jar", versionA);
+        requestA.setArtifact(artifactA);
 
-        VersionResult resultA = versionResolver.resolveVersion( session, requestA );
-        assertEquals( versionA, resultA.getVersion() );
+        VersionResult resultA = versionResolver.resolveVersion(session, requestA);
+        assertEquals(versionA, resultA.getVersion());
 
         VersionRequest requestB = new VersionRequest();
-        requestB.addRepository( newTestRepository() );
+        requestB.addRepository(newTestRepository());
         String versionB = "07.20.3-20120809.112920-97";
-        Artifact artifactB =
-            new DefaultArtifact( "org.apache.maven.its", "dep-mng5324", "classifierB", "jar", versionB );
-        requestB.setArtifact( artifactB );
+        Artifact artifactB = new DefaultArtifact("org.apache.maven.its", "dep-mng5324", "classifierB", "jar", versionB);
+        requestB.setArtifact(artifactB);
 
-        VersionResult resultB = versionResolver.resolveVersion( session, requestB );
-        assertEquals( versionB, resultB.getVersion() );
+        VersionResult resultB = versionResolver.resolveVersion(session, requestB);
+        assertEquals(versionB, resultB.getVersion());
     }
 }
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/MavenRepositorySystemUtilsTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/MavenRepositorySystemUtilsTest.java
deleted file mode 100644
index d06269f..0000000
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/MavenRepositorySystemUtilsTest.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package org.apache.maven.repository.internal;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import org.eclipse.aether.RepositorySystemSession;
-import org.junit.jupiter.api.Test;
-
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-
-public class MavenRepositorySystemUtilsTest
-{
-
-    @Test
-    public void testNewSession()
-    {
-        RepositorySystemSession session = MavenRepositorySystemUtils.newSession();
-        assertNotNull( session );
-    }
-
-}
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java
index 86c7269..6d19de8 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RemoteSnapshotMetadataTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
@@ -26,6 +25,7 @@
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import org.apache.maven.artifact.repository.metadata.Metadata;
 import org.eclipse.aether.artifact.DefaultArtifact;
@@ -35,47 +35,43 @@
 
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class RemoteSnapshotMetadataTest
-{
+class RemoteSnapshotMetadataTest {
     private Locale defaultLocale;
 
+    private static final Pattern DATE_FILTER = Pattern.compile("\\..*");
+
     @BeforeEach
-    public void setLocaleToUseBuddhistCalendar()
-    {
+    void setLocaleToUseBuddhistCalendar() {
         defaultLocale = Locale.getDefault();
-        Locale.setDefault( new Locale( "th", "TH" ) );
+        Locale.setDefault(new Locale("th", "TH"));
     }
 
     @AfterEach
-    public void restoreLocale()
-    {
-        Locale.setDefault( defaultLocale );
+    void restoreLocale() {
+        Locale.setDefault(defaultLocale);
     }
 
-    static String gregorianDate()
-    {
-        SimpleDateFormat df = new SimpleDateFormat( "yyyyMMdd" );
-        df.setCalendar( new GregorianCalendar() );
-        df.setTimeZone( RemoteSnapshotMetadata.DEFAULT_SNAPSHOT_TIME_ZONE );
-        return df.format( new Date() );
+    static String gregorianDate() {
+        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
+        df.setCalendar(new GregorianCalendar());
+        df.setTimeZone(RemoteSnapshotMetadata.DEFAULT_SNAPSHOT_TIME_ZONE);
+        return df.format(new Date());
     }
 
     @Test
-    public void gregorianCalendarIsUsed()
-    {
+    void gregorianCalendarIsUsed() {
         String dateBefore = gregorianDate();
 
-        RemoteSnapshotMetadata metadata = new RemoteSnapshotMetadata(
-                new DefaultArtifact( "a:b:1-SNAPSHOT" ), false, new Date() );
-        metadata.merge( new Metadata() );
+        RemoteSnapshotMetadata metadata = new RemoteSnapshotMetadata(new DefaultArtifact("a:b:1-SNAPSHOT"), new Date());
+        metadata.merge(new Metadata());
 
         String dateAfter = gregorianDate();
 
         String ts = metadata.metadata.getVersioning().getSnapshot().getTimestamp();
-        String datePart = ts.replaceAll( "\\..*", "" );
+        String datePart = DATE_FILTER.matcher(ts).replaceAll("");
 
         /* Allow for this test running across midnight */
-        Set<String> expected = new HashSet<>( Arrays.asList( dateBefore, dateAfter ) );
-        assertTrue( expected.contains( datePart ), "Expected " + datePart + " to be in " + expected );
+        Set<String> expected = new HashSet<>(Arrays.asList(dateBefore, dateAfter));
+        assertTrue(expected.contains(datePart), "Expected " + datePart + " to be in " + expected);
     }
 }
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RepositorySystemTest.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RepositorySystemTest.java
index 77b2781..ce33186 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RepositorySystemTest.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/RepositorySystemTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal;
 
 import java.util.Arrays;
 import java.util.List;
@@ -40,199 +39,176 @@
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class RepositorySystemTest
-    extends AbstractRepositoryTestCase
-{
+class RepositorySystemTest extends AbstractRepositoryTestCase {
     @Test
-    public void testResolveVersionRange()
-        throws Exception
-    {
-        //VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request )
+    void testResolveVersionRange() throws Exception {
+        // VersionRangeResult resolveVersionRange( RepositorySystemSession session, VersionRangeRequest request )
         //                throws VersionRangeResolutionException;
 
     }
 
     @Test
-    public void testResolveVersion()
-        throws Exception
-    {
-        //VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request )
+    void testResolveVersion() throws Exception {
+        // VersionResult resolveVersion( RepositorySystemSession session, VersionRequest request )
         //                throws VersionResolutionException;
     }
 
     @Test
-    public void testReadArtifactDescriptor()
-        throws Exception
-    {
-        Artifact artifact = new DefaultArtifact( "ut.simple:artifact:extension:classifier:1.0" );
+    void testReadArtifactDescriptor() throws Exception {
+        Artifact artifact = new DefaultArtifact("ut.simple:artifact:extension:classifier:1.0");
 
         ArtifactDescriptorRequest request = new ArtifactDescriptorRequest();
-        request.setArtifact( artifact );
-        request.addRepository( newTestRepository() );
+        request.setArtifact(artifact);
+        request.addRepository(newTestRepository());
 
-        ArtifactDescriptorResult result = system.readArtifactDescriptor( session, request );
+        ArtifactDescriptorResult result = system.readArtifactDescriptor(session, request);
 
         List<Dependency> deps = result.getDependencies();
-        assertEquals( 2, deps.size() );
-        checkUtSimpleArtifactDependencies( deps.get( 0 ), deps.get( 1 ) );
+        assertEquals(2, deps.size());
+        checkUtSimpleArtifactDependencies(deps.get(0), deps.get(1));
     }
 
     /**
      * check ut.simple:artifact:1.0 dependencies
      */
-    private void checkUtSimpleArtifactDependencies( Dependency dep1, Dependency dep2 )
-    {
-        assertEquals( "compile", dep1.getScope() );
-        assertFalse( dep1.isOptional() );
-        assertEquals( 0, dep1.getExclusions().size() );
+    private void checkUtSimpleArtifactDependencies(Dependency dep1, Dependency dep2) {
+        assertEquals("compile", dep1.getScope());
+        assertFalse(dep1.isOptional());
+        assertEquals(0, dep1.getExclusions().size());
         Artifact depArtifact = dep1.getArtifact();
-        assertEquals( "ut.simple", depArtifact.getGroupId() );
-        assertEquals( "dependency", depArtifact.getArtifactId() );
-        assertEquals( "1.0", depArtifact.getVersion() );
-        assertEquals( "1.0", depArtifact.getBaseVersion() );
-        assertNull( depArtifact.getFile() );
-        assertFalse( depArtifact.isSnapshot() );
-        assertEquals( "", depArtifact.getClassifier() );
-        assertEquals( "jar", depArtifact.getExtension() );
-        assertEquals( "java", depArtifact.getProperty( "language", null ) );
-        assertEquals( "jar", depArtifact.getProperty( "type", null ) );
-        assertEquals( "true", depArtifact.getProperty( "constitutesBuildPath", null ) );
-        assertEquals( "false", depArtifact.getProperty( "includesDependencies", null ) );
-        assertEquals( 4, depArtifact.getProperties().size() );
+        assertEquals("ut.simple", depArtifact.getGroupId());
+        assertEquals("dependency", depArtifact.getArtifactId());
+        assertEquals("1.0", depArtifact.getVersion());
+        assertEquals("1.0", depArtifact.getBaseVersion());
+        assertNull(depArtifact.getFile());
+        assertFalse(depArtifact.isSnapshot());
+        assertEquals("", depArtifact.getClassifier());
+        assertEquals("jar", depArtifact.getExtension());
+        assertEquals("java", depArtifact.getProperty("language", null));
+        assertEquals("jar", depArtifact.getProperty("type", null));
+        assertEquals("true", depArtifact.getProperty("constitutesBuildPath", null));
+        assertEquals("false", depArtifact.getProperty("includesDependencies", null));
+        assertEquals(4, depArtifact.getProperties().size());
 
-        assertEquals( "compile", dep2.getScope() );
-        assertFalse( dep2.isOptional() );
-        assertEquals( 0, dep2.getExclusions().size() );
+        assertEquals("compile", dep2.getScope());
+        assertFalse(dep2.isOptional());
+        assertEquals(0, dep2.getExclusions().size());
         depArtifact = dep2.getArtifact();
-        assertEquals( "ut.simple", depArtifact.getGroupId() );
-        assertEquals( "dependency", depArtifact.getArtifactId() );
-        assertEquals( "1.0", depArtifact.getVersion() );
-        assertEquals( "1.0", depArtifact.getBaseVersion() );
-        assertNull( depArtifact.getFile() );
-        assertFalse( depArtifact.isSnapshot() );
-        assertEquals( "sources", depArtifact.getClassifier() );
-        assertEquals( "jar", depArtifact.getExtension() );
-        assertEquals( "java", depArtifact.getProperty( "language", null ) );
-        assertEquals( "jar", depArtifact.getProperty( "type", null ) ); // shouldn't it be java-sources given the classifier?
-        assertEquals( "true", depArtifact.getProperty( "constitutesBuildPath", null ) ); // shouldn't it be false given the classifier?
-        assertEquals( "false", depArtifact.getProperty( "includesDependencies", null ) );
-        assertEquals( 4, depArtifact.getProperties().size() );
+        assertEquals("ut.simple", depArtifact.getGroupId());
+        assertEquals("dependency", depArtifact.getArtifactId());
+        assertEquals("1.0", depArtifact.getVersion());
+        assertEquals("1.0", depArtifact.getBaseVersion());
+        assertNull(depArtifact.getFile());
+        assertFalse(depArtifact.isSnapshot());
+        assertEquals("sources", depArtifact.getClassifier());
+        assertEquals("jar", depArtifact.getExtension());
+        assertEquals("java", depArtifact.getProperty("language", null));
+        assertEquals(
+                "jar", depArtifact.getProperty("type", null)); // shouldn't it be java-sources given the classifier?
+        assertEquals(
+                "true",
+                depArtifact.getProperty("constitutesBuildPath", null)); // shouldn't it be false given the classifier?
+        assertEquals("false", depArtifact.getProperty("includesDependencies", null));
+        assertEquals(4, depArtifact.getProperties().size());
     }
 
     @Test
-    public void testCollectDependencies()
-        throws Exception
-    {
-        Artifact artifact = new DefaultArtifact( "ut.simple:artifact:extension:classifier:1.0" );
+    void testCollectDependencies() throws Exception {
+        Artifact artifact = new DefaultArtifact("ut.simple:artifact:extension:classifier:1.0");
         // notice: extension and classifier not really used in this test...
 
         CollectRequest collectRequest = new CollectRequest();
-        collectRequest.setRoot( new Dependency( artifact, null ) );
-        collectRequest.addRepository( newTestRepository() );
+        collectRequest.setRoot(new Dependency(artifact, null));
+        collectRequest.addRepository(newTestRepository());
 
-        CollectResult collectResult = system.collectDependencies( session, collectRequest );
+        CollectResult collectResult = system.collectDependencies(session, collectRequest);
 
         List<DependencyNode> nodes = collectResult.getRoot().getChildren();
-        assertEquals( 2, nodes.size() );
-        checkUtSimpleArtifactDependencies( nodes.get( 0 ).getDependency(), nodes.get( 1 ).getDependency() );
+        assertEquals(2, nodes.size());
+        checkUtSimpleArtifactDependencies(
+                nodes.get(0).getDependency(), nodes.get(1).getDependency());
     }
 
     @Test
-    public void testResolveArtifact()
-        throws Exception
-    {
-        Artifact artifact = new DefaultArtifact( "ut.simple:artifact:1.0" );
+    void testResolveArtifact() throws Exception {
+        Artifact artifact = new DefaultArtifact("ut.simple:artifact:1.0");
 
         ArtifactRequest artifactRequest = new ArtifactRequest();
-        artifactRequest.setArtifact( artifact );
-        artifactRequest.addRepository( newTestRepository() );
+        artifactRequest.setArtifact(artifact);
+        artifactRequest.addRepository(newTestRepository());
 
-        ArtifactResult artifactResult = system.resolveArtifact( session, artifactRequest );
-        checkArtifactResult( artifactResult, "artifact-1.0.jar" );
+        ArtifactResult artifactResult = system.resolveArtifact(session, artifactRequest);
+        checkArtifactResult(artifactResult, "artifact-1.0.jar");
 
-        artifact = new DefaultArtifact( "ut.simple:artifact:zip:1.0" );
-        artifactRequest.setArtifact( artifact );
-        artifactResult = system.resolveArtifact( session, artifactRequest );
-        checkArtifactResult( artifactResult, "artifact-1.0.zip" );
+        artifact = new DefaultArtifact("ut.simple:artifact:zip:1.0");
+        artifactRequest.setArtifact(artifact);
+        artifactResult = system.resolveArtifact(session, artifactRequest);
+        checkArtifactResult(artifactResult, "artifact-1.0.zip");
 
-        artifact = new DefaultArtifact( "ut.simple:artifact:zip:classifier:1.0" );
-        artifactRequest.setArtifact( artifact );
-        artifactResult = system.resolveArtifact( session, artifactRequest );
-        checkArtifactResult( artifactResult, "artifact-1.0-classifier.zip" );
+        artifact = new DefaultArtifact("ut.simple:artifact:zip:classifier:1.0");
+        artifactRequest.setArtifact(artifact);
+        artifactResult = system.resolveArtifact(session, artifactRequest);
+        checkArtifactResult(artifactResult, "artifact-1.0-classifier.zip");
     }
 
-    private void checkArtifactResult( ArtifactResult result, String filename )
-    {
-        assertFalse( result.isMissing() );
-        assertTrue( result.isResolved() );
+    private void checkArtifactResult(ArtifactResult result, String filename) {
+        assertFalse(result.isMissing());
+        assertTrue(result.isResolved());
         Artifact artifact = result.getArtifact();
-        assertNotNull( artifact.getFile() );
-        assertEquals( filename, artifact.getFile().getName() );
+        assertNotNull(artifact.getFile());
+        assertEquals(filename, artifact.getFile().getName());
     }
 
     @Test
-    public void testResolveArtifacts()
-        throws Exception
-    {
+    void testResolveArtifacts() throws Exception {
         ArtifactRequest req1 = new ArtifactRequest();
-        req1.setArtifact( new DefaultArtifact( "ut.simple:artifact:1.0" ) );
-        req1.addRepository( newTestRepository() );
+        req1.setArtifact(new DefaultArtifact("ut.simple:artifact:1.0"));
+        req1.addRepository(newTestRepository());
 
         ArtifactRequest req2 = new ArtifactRequest();
-        req2.setArtifact( new DefaultArtifact( "ut.simple:artifact:zip:1.0" ) );
-        req2.addRepository( newTestRepository() );
+        req2.setArtifact(new DefaultArtifact("ut.simple:artifact:zip:1.0"));
+        req2.addRepository(newTestRepository());
 
         ArtifactRequest req3 = new ArtifactRequest();
-        req3.setArtifact( new DefaultArtifact( "ut.simple:artifact:zip:classifier:1.0" ) );
-        req3.addRepository( newTestRepository() );
+        req3.setArtifact(new DefaultArtifact("ut.simple:artifact:zip:classifier:1.0"));
+        req3.addRepository(newTestRepository());
 
-        List<ArtifactRequest> requests = Arrays.asList( req1, req2, req3 );
+        List<ArtifactRequest> requests = Arrays.asList(req1, req2, req3);
 
-        List<ArtifactResult> results = system.resolveArtifacts( session, requests );
+        List<ArtifactResult> results = system.resolveArtifacts(session, requests);
 
-        assertEquals( 3, results.size() );
-        checkArtifactResult( results.get( 0 ), "artifact-1.0.jar" );
-        checkArtifactResult( results.get( 1 ), "artifact-1.0.zip" );
-        checkArtifactResult( results.get( 2 ), "artifact-1.0-classifier.zip" );
+        assertEquals(3, results.size());
+        checkArtifactResult(results.get(0), "artifact-1.0.jar");
+        checkArtifactResult(results.get(1), "artifact-1.0.zip");
+        checkArtifactResult(results.get(2), "artifact-1.0-classifier.zip");
     }
 
     @Test
-    public void testResolveMetadata()
-        throws Exception
-    {
-        //List<MetadataResult> resolveMetadata( RepositorySystemSession session,
+    void testResolveMetadata() throws Exception {
+        // List<MetadataResult> resolveMetadata( RepositorySystemSession session,
         //                                      Collection<? extends MetadataRequest> requests );
     }
 
     @Test
-    public void testInstall()
-        throws Exception
-    {
-        //InstallResult install( RepositorySystemSession session, InstallRequest request )
+    void testInstall() throws Exception {
+        // InstallResult install( RepositorySystemSession session, InstallRequest request )
         //                throws InstallationException;
         // release, snapshot unique ou non unique, attachment
     }
 
     @Test
-    public void testDeploy()
-        throws Exception
-    {
-        //DeployResult deploy( RepositorySystemSession session, DeployRequest request )
+    void testDeploy() throws Exception {
+        // DeployResult deploy( RepositorySystemSession session, DeployRequest request )
         //                throws DeploymentException;
     }
 
     @Test
-    public void testNewLocalRepositoryManager()
-        throws Exception
-    {
-        //LocalRepositoryManager newLocalRepositoryManager( LocalRepository localRepository );
+    void testNewLocalRepositoryManager() throws Exception {
+        // LocalRepositoryManager newLocalRepositoryManager( LocalRepository localRepository );
     }
 
     @Test
-    public void testNewSyncContext()
-        throws Exception
-    {
-        //SyncContext newSyncContext( RepositorySystemSession session, boolean shared );
+    void testNewSyncContext() throws Exception {
+        // SyncContext newSyncContext( RepositorySystemSession session, boolean shared );
     }
-
 }
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleRepositoryListener.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleRepositoryListener.java
index 2879a9f..603f993 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleRepositoryListener.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleRepositoryListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal.util;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,115 +16,96 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal.util;
 
 import java.io.PrintStream;
 
 import org.eclipse.aether.AbstractRepositoryListener;
 import org.eclipse.aether.RepositoryEvent;
 
-public class ConsoleRepositoryListener
-    extends AbstractRepositoryListener
-{
+public class ConsoleRepositoryListener extends AbstractRepositoryListener {
 
     private PrintStream out;
 
-    public ConsoleRepositoryListener()
-    {
-        this( null );
+    public ConsoleRepositoryListener() {
+        this(null);
     }
 
-    public ConsoleRepositoryListener( PrintStream out )
-    {
-        this.out = ( out != null ) ? out : System.out;
+    public ConsoleRepositoryListener(PrintStream out) {
+        this.out = (out != null) ? out : System.out;
     }
 
-    public void artifactDeployed( RepositoryEvent event )
-    {
-        println( "artifactDeployed", event.getArtifact() + " to " + event.getRepository() );
+    public void artifactDeployed(RepositoryEvent event) {
+        println("artifactDeployed", event.getArtifact() + " to " + event.getRepository());
     }
 
-    public void artifactDeploying( RepositoryEvent event )
-    {
-        println( "artifactDeploying", event.getArtifact() + " to " + event.getRepository() );
+    public void artifactDeploying(RepositoryEvent event) {
+        println("artifactDeploying", event.getArtifact() + " to " + event.getRepository());
     }
 
-    public void artifactDescriptorInvalid( RepositoryEvent event )
-    {
-        println( "artifactDescriptorInvalid", "for " + event.getArtifact() + ": " + event.getException().getMessage() );
+    public void artifactDescriptorInvalid(RepositoryEvent event) {
+        println(
+                "artifactDescriptorInvalid",
+                "for " + event.getArtifact() + ": " + event.getException().getMessage());
     }
 
-    public void artifactDescriptorMissing( RepositoryEvent event )
-    {
-        println( "artifactDescriptorMissing", "for " + event.getArtifact() );
+    public void artifactDescriptorMissing(RepositoryEvent event) {
+        println("artifactDescriptorMissing", "for " + event.getArtifact());
     }
 
-    public void artifactInstalled( RepositoryEvent event )
-    {
-        println( "artifactInstalled", event.getArtifact() + " to " + event.getFile() );
+    public void artifactInstalled(RepositoryEvent event) {
+        println("artifactInstalled", event.getArtifact() + " to " + event.getFile());
     }
 
-    public void artifactInstalling( RepositoryEvent event )
-    {
-        println( "artifactInstalling", event.getArtifact() + " to " + event.getFile() );
+    public void artifactInstalling(RepositoryEvent event) {
+        println("artifactInstalling", event.getArtifact() + " to " + event.getFile());
     }
 
-    public void artifactResolved( RepositoryEvent event )
-    {
-        println( "artifactResolved", event.getArtifact() + " from " + event.getRepository() );
+    public void artifactResolved(RepositoryEvent event) {
+        println("artifactResolved", event.getArtifact() + " from " + event.getRepository());
     }
 
-    public void artifactDownloading( RepositoryEvent event )
-    {
-        println( "artifactDownloading", event.getArtifact() + " from " + event.getRepository() );
+    public void artifactDownloading(RepositoryEvent event) {
+        println("artifactDownloading", event.getArtifact() + " from " + event.getRepository());
     }
 
-    public void artifactDownloaded( RepositoryEvent event )
-    {
-        println( "artifactDownloaded", event.getArtifact() + " from " + event.getRepository() );
+    public void artifactDownloaded(RepositoryEvent event) {
+        println("artifactDownloaded", event.getArtifact() + " from " + event.getRepository());
     }
 
-    public void artifactResolving( RepositoryEvent event )
-    {
-        println( "artifactResolving", event.getArtifact().toString() );
+    public void artifactResolving(RepositoryEvent event) {
+        println("artifactResolving", event.getArtifact().toString());
     }
 
-    public void metadataDeployed( RepositoryEvent event )
-    {
-        println( "metadataDeployed", event.getMetadata() + " to " + event.getRepository() );
+    public void metadataDeployed(RepositoryEvent event) {
+        println("metadataDeployed", event.getMetadata() + " to " + event.getRepository());
     }
 
-    public void metadataDeploying( RepositoryEvent event )
-    {
-        println( "metadataDeploying", event.getMetadata() + " to " + event.getRepository() );
+    public void metadataDeploying(RepositoryEvent event) {
+        println("metadataDeploying", event.getMetadata() + " to " + event.getRepository());
     }
 
-    public void metadataInstalled( RepositoryEvent event )
-    {
-        println( "metadataInstalled", event.getMetadata() + " to " + event.getFile() );
+    public void metadataInstalled(RepositoryEvent event) {
+        println("metadataInstalled", event.getMetadata() + " to " + event.getFile());
     }
 
-    public void metadataInstalling( RepositoryEvent event )
-    {
-        println( "metadataInstalling", event.getMetadata() + " to " + event.getFile() );
+    public void metadataInstalling(RepositoryEvent event) {
+        println("metadataInstalling", event.getMetadata() + " to " + event.getFile());
     }
 
-    public void metadataInvalid( RepositoryEvent event )
-    {
-        println( "metadataInvalid", event.getMetadata().toString() );
+    public void metadataInvalid(RepositoryEvent event) {
+        println("metadataInvalid", event.getMetadata().toString());
     }
 
-    public void metadataResolved( RepositoryEvent event )
-    {
-        println( "metadataResolved", event.getMetadata() + " from " + event.getRepository() );
+    public void metadataResolved(RepositoryEvent event) {
+        println("metadataResolved", event.getMetadata() + " from " + event.getRepository());
     }
 
-    public void metadataResolving( RepositoryEvent event )
-    {
-        println( "metadataResolving", event.getMetadata() + " from " + event.getRepository() );
+    public void metadataResolving(RepositoryEvent event) {
+        println("metadataResolving", event.getMetadata() + " from " + event.getRepository());
     }
 
-    private void println( String event, String message )
-    {
-        out.println( "Aether Repository - " + event + ": " + message );
+    private void println(String event, String message) {
+        out.println("Aether Repository - " + event + ": " + message);
     }
 }
diff --git a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleTransferListener.java b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleTransferListener.java
index cf587d8..aaf648a 100644
--- a/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleTransferListener.java
+++ b/maven-resolver-provider/src/test/java/org/apache/maven/repository/internal/util/ConsoleTransferListener.java
@@ -1,5 +1,3 @@
-package org.apache.maven.repository.internal.util;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.repository.internal.util;
 
 import java.io.PrintStream;
 import java.text.DecimalFormat;
@@ -30,9 +29,7 @@
 import org.eclipse.aether.transfer.TransferEvent;
 import org.eclipse.aether.transfer.TransferResource;
 
-public class ConsoleTransferListener
-    extends AbstractTransferListener
-{
+public class ConsoleTransferListener extends AbstractTransferListener {
 
     private PrintStream out;
 
@@ -40,147 +37,131 @@
 
     private int lastLength;
 
-    public ConsoleTransferListener()
-    {
-        this( null );
+    public ConsoleTransferListener() {
+        this(null);
     }
 
-    public ConsoleTransferListener( PrintStream out )
-    {
-        this.out = ( out != null ) ? out : System.out;
+    public ConsoleTransferListener(PrintStream out) {
+        this.out = (out != null) ? out : System.out;
     }
 
     @Override
-    public void transferInitiated( TransferEvent event )
-    {
+    public void transferInitiated(TransferEvent event) {
         String message = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
 
-        println( "transferInitiated", message + ": " + event.getResource().getRepositoryUrl() + event.getResource().getResourceName() );
+        println(
+                "transferInitiated",
+                message + ": " + event.getResource().getRepositoryUrl()
+                        + event.getResource().getResourceName());
     }
 
     @Override
-    public void transferProgressed( TransferEvent event )
-    {
+    public void transferProgressed(TransferEvent event) {
         TransferResource resource = event.getResource();
-        downloads.put( resource, event.getTransferredBytes() );
+        downloads.put(resource, event.getTransferredBytes());
 
-        StringBuilder buffer = new StringBuilder( 64 );
+        StringBuilder buffer = new StringBuilder(64);
 
-        for ( Map.Entry<TransferResource, Long> entry : downloads.entrySet() )
-        {
+        for (Map.Entry<TransferResource, Long> entry : downloads.entrySet()) {
             long total = entry.getKey().getContentLength();
             long complete = entry.getValue();
 
-            buffer.append( getStatus( complete, total ) ).append( "  " );
+            buffer.append(getStatus(complete, total)).append("  ");
         }
 
         int pad = lastLength - buffer.length();
         lastLength = buffer.length();
-        pad( buffer, pad );
-        buffer.append( '\r' );
+        pad(buffer, pad);
+        buffer.append('\r');
 
-        print( "transferProgressed", buffer.toString() );
+        print("transferProgressed", buffer.toString());
     }
 
-    private String getStatus( long complete, long total )
-    {
-        if ( total >= 1024 )
-        {
-            return toKB( complete ) + "/" + toKB( total ) + " KB ";
-        }
-        else if ( total >= 0 )
-        {
+    private String getStatus(long complete, long total) {
+        if (total >= 1024) {
+            return toKB(complete) + "/" + toKB(total) + " KB ";
+        } else if (total >= 0) {
             return complete + "/" + total + " B ";
-        }
-        else if ( complete >= 1024 )
-        {
-            return toKB( complete ) + " KB ";
-        }
-        else
-        {
+        } else if (complete >= 1024) {
+            return toKB(complete) + " KB ";
+        } else {
             return complete + " B ";
         }
     }
 
-    private void pad( StringBuilder buffer, int spaces )
-    {
+    private void pad(StringBuilder buffer, int spaces) {
         String block = "                                        ";
-        while ( spaces > 0 )
-        {
-            int n = Math.min( spaces, block.length() );
-            buffer.append( block, 0, n );
+        while (spaces > 0) {
+            int n = Math.min(spaces, block.length());
+            buffer.append(block, 0, n);
             spaces -= n;
         }
     }
 
     @Override
-    public void transferSucceeded( TransferEvent event )
-    {
-        transferCompleted( event );
+    public void transferSucceeded(TransferEvent event) {
+        transferCompleted(event);
 
         TransferResource resource = event.getResource();
         long contentLength = event.getTransferredBytes();
-        if ( contentLength >= 0 )
-        {
-            String type = ( event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded" );
-            String len = contentLength >= 1024 ? toKB( contentLength ) + " KB" : contentLength + " B";
+        if (contentLength >= 0) {
+            String type = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded");
+            String len = contentLength >= 1024 ? toKB(contentLength) + " KB" : contentLength + " B";
 
             String throughput = "";
             long duration = System.currentTimeMillis() - resource.getTransferStartTime();
-            if ( duration > 0 )
-            {
-                DecimalFormat format = new DecimalFormat( "0.0", new DecimalFormatSymbols( Locale.ENGLISH ) );
-                double kbPerSec = ( contentLength / 1024.0 ) / ( duration / 1000.0 );
-                throughput = " at " + format.format( kbPerSec ) + " KB/sec";
+            if (duration > 0) {
+                DecimalFormat format = new DecimalFormat("0.0", new DecimalFormatSymbols(Locale.ENGLISH));
+                double kbPerSec = (contentLength / 1024.0) / (duration / 1000.0);
+                throughput = " at " + format.format(kbPerSec) + " KB/sec";
             }
 
-            println( "transferSucceeded", type + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " ("
-                + len + throughput + ")" );
+            println(
+                    "transferSucceeded",
+                    type + ": " + resource.getRepositoryUrl() + resource.getResourceName() + " (" + len + throughput
+                            + ")");
         }
     }
 
     @Override
-    public void transferFailed( TransferEvent event )
-    {
-        transferCompleted( event );
+    public void transferFailed(TransferEvent event) {
+        transferCompleted(event);
 
-        println( "transferFailed", event.getException().getClass() + ": " + event.getException().getMessage()  );
+        println(
+                "transferFailed",
+                event.getException().getClass() + ": " + event.getException().getMessage());
     }
 
-    private void transferCompleted( TransferEvent event )
-    {
-        downloads.remove( event.getResource() );
+    private void transferCompleted(TransferEvent event) {
+        downloads.remove(event.getResource());
 
-        StringBuilder buffer = new StringBuilder( 64 );
-        pad( buffer, lastLength );
-        buffer.append( '\r' );
-        out.println( buffer );
+        StringBuilder buffer = new StringBuilder(64);
+        pad(buffer, lastLength);
+        buffer.append('\r');
+        out.println(buffer);
     }
 
     @Override
-    public void transferCorrupted( TransferEvent event )
-    {
-        println( "transferCorrupted", event.getException().getClass() + ": " + event.getException().getMessage() );
+    public void transferCorrupted(TransferEvent event) {
+        println(
+                "transferCorrupted",
+                event.getException().getClass() + ": " + event.getException().getMessage());
     }
 
-    protected long toKB( long bytes )
-    {
-        return ( bytes + 1023 ) / 1024;
+    protected long toKB(long bytes) {
+        return (bytes + 1023) / 1024;
     }
 
-    private void println( String event, String message )
-    {
-        print( event, message );
+    private void println(String event, String message) {
+        print(event, message);
         out.println();
     }
 
-    private void print( String event, String message )
-    {
-        out.print( "Aether Transfer - " + event );
-        if ( message != null )
-        {
-            out.print( ": " );
-            out.print( message );
+    private void print(String event, String message) {
+        out.print("Aether Transfer - " + event);
+        if (message != null) {
+            out.print(": ");
+            out.print(message);
         }
     }
 }
diff --git a/maven-settings-builder/pom.xml b/maven-settings-builder/pom.xml
index 669c3a9..4030e42 100644
--- a/maven-settings-builder/pom.xml
+++ b/maven-settings-builder/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-settings-builder</artifactId>
@@ -54,10 +52,6 @@
       <artifactId>plexus-interpolation</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
       <groupId>org.apache.maven</groupId>
       <artifactId>maven-settings</artifactId>
     </dependency>
@@ -77,6 +71,17 @@
         <groupId>org.eclipse.sisu</groupId>
         <artifactId>sisu-maven-plugin</artifactId>
       </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <parameter>
+            <excludes>
+              <exclude>org.apache.maven.settings.validation.SettingsValidator#validate(org.apache.maven.settings.Settings,boolean,org.apache.maven.settings.building.SettingsProblemCollector):METHOD_NEW_DEFAULT</exclude>
+            </excludes>
+          </parameter>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java
index 0d1a1b6..b81de62 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,27 +16,32 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+package org.apache.maven.settings.building;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.api.settings.InputSource;
 import org.apache.maven.building.FileSource;
 import org.apache.maven.building.Source;
+import org.apache.maven.settings.Repository;
+import org.apache.maven.settings.RepositoryPolicy;
+import org.apache.maven.settings.Server;
 import org.apache.maven.settings.Settings;
 import org.apache.maven.settings.TrackableBase;
 import org.apache.maven.settings.io.SettingsParseException;
 import org.apache.maven.settings.io.SettingsReader;
 import org.apache.maven.settings.io.SettingsWriter;
 import org.apache.maven.settings.merge.MavenSettingsMerger;
+import org.apache.maven.settings.v4.SettingsTransformer;
 import org.apache.maven.settings.validation.SettingsValidator;
 import org.codehaus.plexus.interpolation.EnvarBasedValueSource;
 import org.codehaus.plexus.interpolation.InterpolationException;
@@ -48,13 +51,10 @@
 /**
  * Builds the effective settings from a user settings file and/or a global settings file.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultSettingsBuilder
-    implements SettingsBuilder
-{
+public class DefaultSettingsBuilder implements SettingsBuilder {
 
     private SettingsReader settingsReader;
 
@@ -65,80 +65,88 @@
     private final MavenSettingsMerger settingsMerger = new MavenSettingsMerger();
 
     @Inject
-    public DefaultSettingsBuilder( SettingsReader settingsReader,
-                                   SettingsWriter settingsWriter,
-                                   SettingsValidator settingsValidator )
-    {
+    public DefaultSettingsBuilder(
+            SettingsReader settingsReader, SettingsWriter settingsWriter, SettingsValidator settingsValidator) {
         this.settingsReader = settingsReader;
         this.settingsWriter = settingsWriter;
         this.settingsValidator = settingsValidator;
     }
 
-    public DefaultSettingsBuilder setSettingsReader( SettingsReader settingsReader )
-    {
+    public DefaultSettingsBuilder setSettingsReader(SettingsReader settingsReader) {
         this.settingsReader = settingsReader;
         return this;
     }
 
-    public DefaultSettingsBuilder setSettingsWriter( SettingsWriter settingsWriter )
-    {
+    public DefaultSettingsBuilder setSettingsWriter(SettingsWriter settingsWriter) {
         this.settingsWriter = settingsWriter;
         return this;
     }
 
-    public DefaultSettingsBuilder setSettingsValidator( SettingsValidator settingsValidator )
-    {
+    public DefaultSettingsBuilder setSettingsValidator(SettingsValidator settingsValidator) {
         this.settingsValidator = settingsValidator;
         return this;
     }
 
     @Override
-    public SettingsBuildingResult build( SettingsBuildingRequest request )
-        throws SettingsBuildingException
-    {
-        DefaultSettingsProblemCollector problems = new DefaultSettingsProblemCollector( null );
+    public SettingsBuildingResult build(SettingsBuildingRequest request) throws SettingsBuildingException {
+        DefaultSettingsProblemCollector problems = new DefaultSettingsProblemCollector(null);
 
         Source globalSettingsSource =
-            getSettingsSource( request.getGlobalSettingsFile(), request.getGlobalSettingsSource() );
-        Settings globalSettings = readSettings( globalSettingsSource, request, problems );
+                getSettingsSource(request.getGlobalSettingsFile(), request.getGlobalSettingsSource());
+        Settings globalSettings = readSettings(globalSettingsSource, false, request, problems);
 
-        Source userSettingsSource =
-            getSettingsSource( request.getUserSettingsFile(), request.getUserSettingsSource() );
-        Settings userSettings = readSettings( userSettingsSource, request, problems );
+        Source projectSettingsSource =
+                getSettingsSource(request.getProjectSettingsFile(), request.getProjectSettingsSource());
+        Settings projectSettings = readSettings(projectSettingsSource, true, request, problems);
 
-        settingsMerger.merge( userSettings, globalSettings, TrackableBase.GLOBAL_LEVEL );
+        Source userSettingsSource = getSettingsSource(request.getUserSettingsFile(), request.getUserSettingsSource());
+        Settings userSettings = readSettings(userSettingsSource, false, request, problems);
 
-        problems.setSource( "" );
+        settingsMerger.merge(projectSettings, globalSettings, TrackableBase.GLOBAL_LEVEL);
+        settingsMerger.merge(userSettings, projectSettings, TrackableBase.PROJECT_LEVEL);
 
-        userSettings = interpolate( userSettings, request, problems );
+        // If no repository is defined in the user/global settings,
+        // it means that we have "old" settings (as those are new in 4.0)
+        // so add central to the computed settings for backward compatibility.
+        if (userSettings.getRepositories().isEmpty()
+                && userSettings.getPluginRepositories().isEmpty()) {
+            Repository central = new Repository();
+            central.setId("central");
+            central.setName("Central Repository");
+            central.setUrl("https://repo.maven.apache.org/maven2");
+            RepositoryPolicy disabledPolicy = new RepositoryPolicy();
+            disabledPolicy.setEnabled(false);
+            central.setSnapshots(disabledPolicy);
+            userSettings.getRepositories().add(central);
+            central = central.clone();
+            RepositoryPolicy updateNeverPolicy = new RepositoryPolicy();
+            disabledPolicy.setUpdatePolicy("never");
+            central.setReleases(updateNeverPolicy);
+            userSettings.getPluginRepositories().add(central);
+        }
+
+        problems.setSource("");
 
         // for the special case of a drive-relative Windows path, make sure it's absolute to save plugins from trouble
         String localRepository = userSettings.getLocalRepository();
-        if ( localRepository != null && localRepository.length() > 0 )
-        {
-            File file = new File( localRepository );
-            if ( !file.isAbsolute() && file.getPath().startsWith( File.separator ) )
-            {
-                userSettings.setLocalRepository( file.getAbsolutePath() );
+        if (localRepository != null && localRepository.length() > 0) {
+            File file = new File(localRepository);
+            if (!file.isAbsolute() && file.getPath().startsWith(File.separator)) {
+                userSettings.setLocalRepository(file.getAbsolutePath());
             }
         }
 
-        if ( hasErrors( problems.getProblems() ) )
-        {
-            throw new SettingsBuildingException( problems.getProblems() );
+        if (hasErrors(problems.getProblems())) {
+            throw new SettingsBuildingException(problems.getProblems());
         }
 
-        return new DefaultSettingsBuildingResult( userSettings, problems.getProblems() );
+        return new DefaultSettingsBuildingResult(userSettings, problems.getProblems());
     }
 
-    private boolean hasErrors( List<SettingsProblem> problems )
-    {
-        if ( problems != null )
-        {
-            for ( SettingsProblem problem : problems )
-            {
-                if ( SettingsProblem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
-                {
+    private boolean hasErrors(List<SettingsProblem> problems) {
+        if (problems != null) {
+            for (SettingsProblem problem : problems) {
+                if (SettingsProblem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
                     return true;
                 }
             }
@@ -147,136 +155,116 @@
         return false;
     }
 
-    private Source getSettingsSource( File settingsFile, Source settingsSource )
-    {
-        if ( settingsSource != null )
-        {
+    private Source getSettingsSource(File settingsFile, Source settingsSource) {
+        if (settingsSource != null) {
             return settingsSource;
-        }
-        else if ( settingsFile != null && settingsFile.exists() )
-        {
-            return new FileSource( settingsFile );
+        } else if (settingsFile != null && settingsFile.exists()) {
+            return new FileSource(settingsFile);
         }
         return null;
     }
 
-    private Settings readSettings( Source settingsSource, SettingsBuildingRequest request,
-                                   DefaultSettingsProblemCollector problems )
-    {
-        if ( settingsSource == null )
-        {
+    private Settings readSettings(
+            Source settingsSource,
+            boolean isProjectSettings,
+            SettingsBuildingRequest request,
+            DefaultSettingsProblemCollector problems) {
+        if (settingsSource == null) {
             return new Settings();
         }
 
-        problems.setSource( settingsSource.getLocation() );
+        problems.setSource(settingsSource.getLocation());
 
         Settings settings;
 
-        try
-        {
-            Map<String, ?> options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.TRUE );
+        try {
+            Map<String, Object> options = new HashMap<>();
+            options.put(SettingsReader.IS_STRICT, Boolean.TRUE);
+            options.put(InputSource.class.getName(), new InputSource(settingsSource.getLocation()));
+            try {
+                settings = settingsReader.read(settingsSource.getInputStream(), options);
+            } catch (SettingsParseException e) {
+                options = Collections.singletonMap(SettingsReader.IS_STRICT, Boolean.FALSE);
 
-            try
-            {
-                settings = settingsReader.read( settingsSource.getInputStream(), options );
+                settings = settingsReader.read(settingsSource.getInputStream(), options);
+
+                problems.add(
+                        SettingsProblem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e);
             }
-            catch ( SettingsParseException e )
-            {
-                options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.FALSE );
-
-                settings = settingsReader.read( settingsSource.getInputStream(), options );
-
-                problems.add( SettingsProblem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(),
-                              e );
-            }
-        }
-        catch ( SettingsParseException e )
-        {
-            problems.add( SettingsProblem.Severity.FATAL, "Non-parseable settings " + settingsSource.getLocation()
-                + ": " + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        } catch (SettingsParseException e) {
+            problems.add(
+                    SettingsProblem.Severity.FATAL,
+                    "Non-parseable settings " + settingsSource.getLocation() + ": " + e.getMessage(),
+                    e.getLineNumber(),
+                    e.getColumnNumber(),
+                    e);
             return new Settings();
-        }
-        catch ( IOException e )
-        {
-            problems.add( SettingsProblem.Severity.FATAL, "Non-readable settings " + settingsSource.getLocation()
-                + ": " + e.getMessage(), -1, -1, e );
+        } catch (IOException e) {
+            problems.add(
+                    SettingsProblem.Severity.FATAL,
+                    "Non-readable settings " + settingsSource.getLocation() + ": " + e.getMessage(),
+                    -1,
+                    -1,
+                    e);
             return new Settings();
         }
 
-        settingsValidator.validate( settings, problems );
+        settings = interpolate(settings, request, problems);
+
+        settingsValidator.validate(settings, isProjectSettings, problems);
+
+        if (isProjectSettings) {
+            settings.setLocalRepository(null);
+            settings.setInteractiveMode(true);
+            settings.setOffline(false);
+            settings.setProxies(Collections.emptyList());
+            settings.setUsePluginRegistry(false);
+            for (Server server : settings.getServers()) {
+                server.setUsername(null);
+                server.setPassword(null);
+                server.setPrivateKey(null);
+                server.setPassword(null);
+                server.setFilePermissions(null);
+                server.setDirectoryPermissions(null);
+            }
+        }
 
         return settings;
     }
 
-    private Settings interpolate( Settings settings, SettingsBuildingRequest request,
-                                  SettingsProblemCollector problems )
-    {
-        StringWriter writer = new StringWriter( 1024 * 4 );
-
-        try
-        {
-            settingsWriter.write( writer, null, settings );
-        }
-        catch ( IOException e )
-        {
-            throw new IllegalStateException( "Failed to serialize settings to memory", e );
-        }
-
-        String serializedSettings = writer.toString();
+    private Settings interpolate(
+            Settings settings, SettingsBuildingRequest request, SettingsProblemCollector problems) {
 
         RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
 
-        interpolator.addValueSource( new PropertiesBasedValueSource( request.getUserProperties() ) );
+        interpolator.addValueSource(new PropertiesBasedValueSource(request.getUserProperties()));
 
-        interpolator.addValueSource( new PropertiesBasedValueSource( request.getSystemProperties() ) );
+        interpolator.addValueSource(new PropertiesBasedValueSource(request.getSystemProperties()));
 
-        try
-        {
-            interpolator.addValueSource( new EnvarBasedValueSource() );
-        }
-        catch ( IOException e )
-        {
-            problems.add( SettingsProblem.Severity.WARNING, "Failed to use environment variables for interpolation: "
-                + e.getMessage(), -1, -1, e );
+        try {
+            interpolator.addValueSource(new EnvarBasedValueSource());
+        } catch (IOException e) {
+            problems.add(
+                    SettingsProblem.Severity.WARNING,
+                    "Failed to use environment variables for interpolation: " + e.getMessage(),
+                    -1,
+                    -1,
+                    e);
         }
 
-        interpolator.addPostProcessor( ( expression, value ) ->
-        {
-            if ( value != null )
-            {
-                // we're going to parse this back in as XML so we need to escape XML markup
-                value = value.toString().replace( "&", "&amp;" ).replace( "<", "&lt;" ).replace( ">", "&gt;" );
-                return value;
-            }
-            return null;
-        } );
-
-        try
-        {
-            serializedSettings = interpolator.interpolate( serializedSettings, "settings" );
-        }
-        catch ( InterpolationException e )
-        {
-            problems.add( SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1,
-                          e );
-
-            return settings;
-        }
-
-        Settings result;
-        try
-        {
-            Map<String, ?> options = Collections.singletonMap( SettingsReader.IS_STRICT, Boolean.FALSE );
-            result = settingsReader.read( new StringReader( serializedSettings ), options );
-        }
-        catch ( IOException e )
-        {
-            problems.add( SettingsProblem.Severity.ERROR, "Failed to interpolate settings: " + e.getMessage(), -1, -1,
-                          e );
-            return settings;
-        }
-
-        return result;
+        return new Settings(new SettingsTransformer(value -> {
+                    try {
+                        return value != null ? interpolator.interpolate(value) : null;
+                    } catch (InterpolationException e) {
+                        problems.add(
+                                SettingsProblem.Severity.WARNING,
+                                "Failed to interpolate settings: " + e.getMessage(),
+                                -1,
+                                -1,
+                                e);
+                        return value;
+                    }
+                })
+                .visit(settings.getDelegate()));
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java
index 805a4c8..c94cd90 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import org.apache.maven.settings.io.DefaultSettingsReader;
 import org.apache.maven.settings.io.DefaultSettingsWriter;
@@ -32,23 +31,18 @@
  * Maven plugins should always acquire settings builder instances via dependency injection. Developers might want to
  * subclass this factory to provide custom implementations for some of the components used by the settings builder.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultSettingsBuilderFactory
-{
+public class DefaultSettingsBuilderFactory {
 
-    protected SettingsReader newSettingsReader()
-    {
+    protected SettingsReader newSettingsReader() {
         return new DefaultSettingsReader();
     }
 
-    protected SettingsWriter newSettingsWriter()
-    {
+    protected SettingsWriter newSettingsWriter() {
         return new DefaultSettingsWriter();
     }
 
-    protected SettingsValidator newSettingsValidator()
-    {
+    protected SettingsValidator newSettingsValidator() {
         return new DefaultSettingsValidator();
     }
 
@@ -57,11 +51,7 @@
      *
      * @return The new settings builder instance, never {@code null}.
      */
-    public DefaultSettingsBuilder newInstance()
-    {
-        return new DefaultSettingsBuilder( newSettingsReader(),
-                                           newSettingsWriter(),
-                                           newSettingsValidator() );
+    public DefaultSettingsBuilder newInstance() {
+        return new DefaultSettingsBuilder(newSettingsReader(), newSettingsWriter(), newSettingsValidator());
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingRequest.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingRequest.java
index f39f579..cf82db7 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingRequest.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.io.File;
 import java.util.Properties;
@@ -25,18 +24,19 @@
 /**
  * Collects settings that control building of effective settings.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultSettingsBuildingRequest
-    implements SettingsBuildingRequest
-{
+public class DefaultSettingsBuildingRequest implements SettingsBuildingRequest {
 
     private File globalSettingsFile;
 
+    private File projectSettingsFile;
+
     private File userSettingsFile;
 
     private SettingsSource globalSettingsSource;
 
+    private SettingsSource projectSettingsSource;
+
     private SettingsSource userSettingsSource;
 
     private Properties systemProperties;
@@ -44,66 +44,80 @@
     private Properties userProperties;
 
     @Override
-    public File getGlobalSettingsFile()
-    {
+    public File getGlobalSettingsFile() {
         return globalSettingsFile;
     }
 
     @Override
-    public DefaultSettingsBuildingRequest setGlobalSettingsFile( File globalSettingsFile )
-    {
+    public DefaultSettingsBuildingRequest setGlobalSettingsFile(File globalSettingsFile) {
         this.globalSettingsFile = globalSettingsFile;
 
         return this;
     }
 
     @Override
-    public SettingsSource getGlobalSettingsSource()
-    {
+    public SettingsSource getGlobalSettingsSource() {
         return globalSettingsSource;
     }
 
     @Override
-    public DefaultSettingsBuildingRequest setGlobalSettingsSource( SettingsSource globalSettingsSource )
-    {
+    public DefaultSettingsBuildingRequest setGlobalSettingsSource(SettingsSource globalSettingsSource) {
         this.globalSettingsSource = globalSettingsSource;
 
         return this;
     }
 
     @Override
-    public File getUserSettingsFile()
-    {
+    public File getProjectSettingsFile() {
+        return projectSettingsFile;
+    }
+
+    @Override
+    public DefaultSettingsBuildingRequest setProjectSettingsFile(File projectSettingsFile) {
+        this.projectSettingsFile = projectSettingsFile;
+
+        return this;
+    }
+
+    @Override
+    public SettingsSource getProjectSettingsSource() {
+        return projectSettingsSource;
+    }
+
+    @Override
+    public DefaultSettingsBuildingRequest setProjectSettingsSource(SettingsSource projectSettingsSource) {
+        this.projectSettingsSource = projectSettingsSource;
+
+        return this;
+    }
+
+    @Override
+    public File getUserSettingsFile() {
         return userSettingsFile;
     }
 
     @Override
-    public DefaultSettingsBuildingRequest setUserSettingsFile( File userSettingsFile )
-    {
+    public DefaultSettingsBuildingRequest setUserSettingsFile(File userSettingsFile) {
         this.userSettingsFile = userSettingsFile;
 
         return this;
     }
 
     @Override
-    public SettingsSource getUserSettingsSource()
-    {
+    public SettingsSource getUserSettingsSource() {
         return userSettingsSource;
     }
 
     @Override
-    public DefaultSettingsBuildingRequest setUserSettingsSource( SettingsSource userSettingsSource )
-    {
+    public DefaultSettingsBuildingRequest setUserSettingsSource(SettingsSource userSettingsSource) {
         this.userSettingsSource = userSettingsSource;
 
         return this;
     }
 
     @Override
-    public Properties getSystemProperties()
-    {
-        if ( systemProperties == null )
-        {
+    public Properties getSystemProperties() {
+        if (systemProperties == null) {
             systemProperties = new Properties();
         }
 
@@ -111,18 +125,14 @@
     }
 
     @Override
-    public DefaultSettingsBuildingRequest setSystemProperties( Properties systemProperties )
-    {
-        if ( systemProperties != null )
-        {
+    public DefaultSettingsBuildingRequest setSystemProperties(Properties systemProperties) {
+        if (systemProperties != null) {
             this.systemProperties = new Properties();
-            synchronized ( systemProperties )
-            { // avoid concurrent modification if someone else sets/removes an unrelated system property
-                this.systemProperties.putAll( systemProperties );
+            synchronized (systemProperties) { // avoid concurrent modification if someone else sets/removes an unrelated
+                // system property
+                this.systemProperties.putAll(systemProperties);
             }
-        }
-        else
-        {
+        } else {
             this.systemProperties = null;
         }
 
@@ -130,10 +140,8 @@
     }
 
     @Override
-    public Properties getUserProperties()
-    {
-        if ( userProperties == null )
-        {
+    public Properties getUserProperties() {
+        if (userProperties == null) {
             userProperties = new Properties();
         }
 
@@ -141,19 +149,14 @@
     }
 
     @Override
-    public DefaultSettingsBuildingRequest setUserProperties( Properties userProperties )
-    {
-        if ( userProperties != null )
-        {
+    public DefaultSettingsBuildingRequest setUserProperties(Properties userProperties) {
+        if (userProperties != null) {
             this.userProperties = new Properties();
-            this.userProperties.putAll( userProperties );
-        }
-        else
-        {
+            this.userProperties.putAll(userProperties);
+        } else {
             this.userProperties = null;
         }
 
         return this;
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingResult.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingResult.java
index 48456e5..ab631b4 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingResult.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,32 +26,25 @@
 /**
  * Collects the output of the settings builder.
  *
- * @author Benjamin Bentmann
  */
-class DefaultSettingsBuildingResult
-    implements SettingsBuildingResult
-{
+class DefaultSettingsBuildingResult implements SettingsBuildingResult {
 
     private Settings effectiveSettings;
 
     private List<SettingsProblem> problems;
 
-    DefaultSettingsBuildingResult( Settings effectiveSettings, List<SettingsProblem> problems )
-    {
+    DefaultSettingsBuildingResult(Settings effectiveSettings, List<SettingsProblem> problems) {
         this.effectiveSettings = effectiveSettings;
-        this.problems = ( problems != null ) ? problems : new ArrayList<>();
+        this.problems = (problems != null) ? problems : new ArrayList<>();
     }
 
     @Override
-    public Settings getEffectiveSettings()
-    {
+    public Settings getEffectiveSettings() {
         return effectiveSettings;
     }
 
     @Override
-    public List<SettingsProblem> getProblems()
-    {
+    public List<SettingsProblem> getProblems() {
         return problems;
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblem.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblem.java
index ac06109..b00422e 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblem.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 /**
  * Describes a problem that was encountered during settings building. A problem can either be an exception that was
  * thrown or a simple string message. In addition, a problem carries a hint about its source, e.g. the settings file
  * that exhibits the problem.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultSettingsProblem
-    implements SettingsProblem
-{
+public class DefaultSettingsProblem implements SettingsProblem {
 
     private final String source;
 
@@ -53,91 +49,74 @@
      * @param columnNumber The one-based index of the column containing the problem or {@code -1} if unknown.
      * @param exception The exception that caused this problem, may be {@code null}.
      */
-    public DefaultSettingsProblem( String message, Severity severity, String source, int lineNumber, int columnNumber,
-                                   Exception exception )
-    {
+    public DefaultSettingsProblem(
+            String message, Severity severity, String source, int lineNumber, int columnNumber, Exception exception) {
         this.message = message;
-        this.severity = ( severity != null ) ? severity : Severity.ERROR;
-        this.source = ( source != null ) ? source : "";
+        this.severity = (severity != null) ? severity : Severity.ERROR;
+        this.source = (source != null) ? source : "";
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
         this.exception = exception;
     }
 
     @Override
-    public String getSource()
-    {
+    public String getSource() {
         return source;
     }
 
     @Override
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
 
     @Override
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
 
     @Override
-    public String getLocation()
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
+    public String getLocation() {
+        StringBuilder buffer = new StringBuilder(256);
 
-        if ( getSource().length() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (getSource().length() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( getSource() );
+            buffer.append(getSource());
         }
 
-        if ( getLineNumber() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (getLineNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( "line " ).append( getLineNumber() );
+            buffer.append("line ").append(getLineNumber());
         }
 
-        if ( getColumnNumber() > 0 )
-        {
-            if ( buffer.length() > 0 )
-            {
-                buffer.append( ", " );
+        if (getColumnNumber() > 0) {
+            if (buffer.length() > 0) {
+                buffer.append(", ");
             }
-            buffer.append( "column " ).append( getColumnNumber() );
+            buffer.append("column ").append(getColumnNumber());
         }
 
         return buffer.toString();
     }
 
     @Override
-    public Exception getException()
-    {
+    public Exception getException() {
         return exception;
     }
 
     @Override
-    public String getMessage()
-    {
+    public String getMessage() {
         String msg;
 
-        if ( message != null && message.length() > 0 )
-        {
+        if (message != null && message.length() > 0) {
             msg = message;
-        }
-        else
-        {
+        } else {
             msg = exception.getMessage();
 
-            if ( msg == null )
-            {
+            if (msg == null) {
                 msg = "";
             }
         }
@@ -146,26 +125,22 @@
     }
 
     @Override
-    public Severity getSeverity()
-    {
+    public Severity getSeverity() {
         return severity;
     }
 
     @Override
-    public String toString()
-    {
-        StringBuilder buffer = new StringBuilder( 128 );
+    public String toString() {
+        StringBuilder buffer = new StringBuilder(128);
 
-        buffer.append( '[' ).append( getSeverity() ).append( "] " );
-        buffer.append( getMessage() );
+        buffer.append('[').append(getSeverity()).append("] ");
+        buffer.append(getMessage());
         String location = getLocation();
-        if ( !location.isEmpty() )
-        {
-             buffer.append( " @ " );
-             buffer.append( location );
+        if (!location.isEmpty()) {
+            buffer.append(" @ ");
+            buffer.append(location);
         }
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblemCollector.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblemCollector.java
index 024f5a7..ee6e791 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblemCollector.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/DefaultSettingsProblemCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -27,44 +26,35 @@
 /**
  * Collects problems that are encountered during settings building.
  *
- * @author Benjamin Bentmann
  */
-class DefaultSettingsProblemCollector
-    implements SettingsProblemCollector
-{
+class DefaultSettingsProblemCollector implements SettingsProblemCollector {
 
     private List<SettingsProblem> problems;
 
     private String source;
 
-    DefaultSettingsProblemCollector( List<SettingsProblem> problems )
-    {
-        this.problems = ( problems != null ) ? problems : new ArrayList<>();
+    DefaultSettingsProblemCollector(List<SettingsProblem> problems) {
+        this.problems = (problems != null) ? problems : new ArrayList<>();
     }
 
-    public List<SettingsProblem> getProblems()
-    {
+    public List<SettingsProblem> getProblems() {
         return problems;
     }
 
-    public void setSource( String source )
-    {
+    public void setSource(String source) {
         this.source = source;
     }
 
     @Override
-    public void add( SettingsProblem.Severity severity, String message, int line, int column, Exception cause )
-    {
-        if ( line <= 0 && column <= 0 && ( cause instanceof SettingsParseException ) )
-        {
+    public void add(SettingsProblem.Severity severity, String message, int line, int column, Exception cause) {
+        if (line <= 0 && column <= 0 && (cause instanceof SettingsParseException)) {
             SettingsParseException e = (SettingsParseException) cause;
             line = e.getLineNumber();
             column = e.getColumnNumber();
         }
 
-        SettingsProblem problem = new DefaultSettingsProblem( message, severity, source, line, column, cause );
+        SettingsProblem problem = new DefaultSettingsProblem(message, severity, source, line, column, cause);
 
-        problems.add( problem );
+        problems.add(problem);
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/FileSettingsSource.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/FileSettingsSource.java
index 711261d..40a90d5 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/FileSettingsSource.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/FileSettingsSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.io.File;
 
@@ -26,23 +25,19 @@
 /**
  * Wraps an ordinary {@link File} as a settings source.
  *
- * @author Benjamin Bentmann
  *
  * @deprecated instead use {@link FileSource}
  */
 @Deprecated
-public class FileSettingsSource extends FileSource
-    implements SettingsSource
-{
+public class FileSettingsSource extends FileSource implements SettingsSource {
 
     /**
      * Creates a new settings source backed by the specified file.
      *
      * @param settingsFile The settings file, must not be {@code null}.
      */
-    public FileSettingsSource( File settingsFile )
-    {
-        super( settingsFile );
+    public FileSettingsSource(File settingsFile) {
+        super(settingsFile);
     }
 
     /**
@@ -52,8 +47,7 @@
      * @deprecated instead use {@link #getFile()}
      */
     @Deprecated
-    public File getSettingsFile()
-    {
+    public File getSettingsFile() {
         return getFile();
     }
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuilder.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuilder.java
index 61e34e9..b50a274 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuilder.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 /**
- * Builds the effective settings from a user settings file and/or a global settings file.
+ * Builds the effective settings from a user settings file, a project settings file
+ * and/or a global settings file.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsBuilder
-{
+public interface SettingsBuilder {
 
     /**
      * Builds the effective settings of the specified settings files.
@@ -34,7 +32,5 @@
      * @return The result of the settings building, never {@code null}.
      * @throws SettingsBuildingException If the effective settings could not be built.
      */
-    SettingsBuildingResult build( SettingsBuildingRequest request )
-        throws SettingsBuildingException;
-
+    SettingsBuildingResult build(SettingsBuildingRequest request) throws SettingsBuildingException;
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingException.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingException.java
index 89ce8d4..d603f35 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingException.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -29,11 +28,8 @@
  * possible before eventually failing to provide callers with rich error information. Use {@link #getProblems()} to
  * query the details of the failure.
  *
- * @author Benjamin Bentmann
  */
-public class SettingsBuildingException
-    extends Exception
-{
+public class SettingsBuildingException extends Exception {
 
     private final List<SettingsProblem> problems;
 
@@ -42,14 +38,12 @@
      *
      * @param problems The problems that cause this exception, may be {@code null}.
      */
-    public SettingsBuildingException( List<SettingsProblem> problems )
-    {
-        super( toMessage( problems ) );
+    public SettingsBuildingException(List<SettingsProblem> problems) {
+        super(toMessage(problems));
 
         this.problems = new ArrayList<>();
-        if ( problems != null )
-        {
-            this.problems.addAll( problems );
+        if (problems != null) {
+            this.problems.addAll(problems);
         }
     }
 
@@ -58,37 +52,32 @@
      *
      * @return The problems that caused this exception, never {@code null}.
      */
-    public List<SettingsProblem> getProblems()
-    {
+    public List<SettingsProblem> getProblems() {
         return problems;
     }
 
-    private static String toMessage( List<SettingsProblem> problems )
-    {
-        StringWriter buffer = new StringWriter( 1024 );
+    private static String toMessage(List<SettingsProblem> problems) {
+        StringWriter buffer = new StringWriter(1024);
 
-        PrintWriter writer = new PrintWriter( buffer );
+        PrintWriter writer = new PrintWriter(buffer);
 
-        writer.print( problems.size() );
-        writer.print( ( problems.size() == 1 ) ? " problem was " : " problems were " );
-        writer.print( "encountered while building the effective settings" );
+        writer.print(problems.size());
+        writer.print((problems.size() == 1) ? " problem was " : " problems were ");
+        writer.print("encountered while building the effective settings");
         writer.println();
 
-        for ( SettingsProblem problem : problems )
-        {
-            writer.print( "[" );
-            writer.print( problem.getSeverity() );
-            writer.print( "] " );
-            writer.print( problem.getMessage() );
+        for (SettingsProblem problem : problems) {
+            writer.print("[");
+            writer.print(problem.getSeverity());
+            writer.print("] ");
+            writer.print(problem.getMessage());
             String location = problem.getLocation();
-            if ( !location.isEmpty() )
-            {
-                writer.print( " @ " );
-                writer.println( location );
+            if (!location.isEmpty()) {
+                writer.print(" @ ");
+                writer.println(location);
             }
         }
 
         return buffer.toString();
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingRequest.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingRequest.java
index 92d87d8..dea23ff 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingRequest.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.io.File;
 import java.util.Properties;
@@ -25,10 +24,8 @@
 /**
  * Collects settings that control the building of effective settings.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsBuildingRequest
-{
+public interface SettingsBuildingRequest {
 
     /**
      * Gets the global settings file.
@@ -44,7 +41,7 @@
      * @param globalSettingsFile The global settings file, may be {@code null} to disable global settings.
      * @return This request, never {@code null}.
      */
-    SettingsBuildingRequest setGlobalSettingsFile( File globalSettingsFile );
+    SettingsBuildingRequest setGlobalSettingsFile(File globalSettingsFile);
 
     /**
      * Gets the global settings source.
@@ -60,7 +57,41 @@
      * @param globalSettingsSource The global settings source, may be {@code null} to disable global settings.
      * @return This request, never {@code null}.
      */
-    SettingsBuildingRequest setGlobalSettingsSource( SettingsSource globalSettingsSource );
+    SettingsBuildingRequest setGlobalSettingsSource(SettingsSource globalSettingsSource);
+
+    /**
+     * Gets the project settings file.
+     *
+     * @return The project settings file or {@code null} if none.
+     * @since 4.0.0
+     */
+    File getProjectSettingsFile();
+
+    /**
+     * Sets the project settings file. A non-existent settings file is equivalent to empty settings.
+     *
+     * @param projectSettingsFile The project settings file, may be {@code null} to disable project settings.
+     * @return This request, never {@code null}.
+     * @since 4.0.0
+     */
+    DefaultSettingsBuildingRequest setProjectSettingsFile(File projectSettingsFile);
+
+    /**
+     * Gets the project settings source.
+     *
+     * @return The project settings source or {@code null} if none.
+     * @since 4.0.0
+     */
+    SettingsSource getProjectSettingsSource();
+
+    /**
+     * Sets the project settings source.
+     *
+     * @param projectSettingsSource The project settings source, may be {@code null} to disable global settings.
+     * @return This request, never {@code null}.
+     * @since 4.0.0
+     */
+    SettingsBuildingRequest setProjectSettingsSource(SettingsSource projectSettingsSource);
 
     /**
      * Gets the user settings file.
@@ -76,7 +107,7 @@
      * @param userSettingsFile The user settings file, may be {@code null} to disable user settings.
      * @return This request, never {@code null}.
      */
-    SettingsBuildingRequest setUserSettingsFile( File userSettingsFile );
+    SettingsBuildingRequest setUserSettingsFile(File userSettingsFile);
 
     /**
      * Gets the user settings source.
@@ -92,7 +123,7 @@
      * @param userSettingsSource The user settings source, may be {@code null} to disable user settings.
      * @return This request, never {@code null}.
      */
-    SettingsBuildingRequest setUserSettingsSource( SettingsSource userSettingsSource );
+    SettingsBuildingRequest setUserSettingsSource(SettingsSource userSettingsSource);
 
     /**
      * Gets the system properties to use for interpolation. The system properties are collected from the runtime
@@ -109,7 +140,7 @@
      * @param systemProperties The system properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    SettingsBuildingRequest setSystemProperties( Properties systemProperties );
+    SettingsBuildingRequest setSystemProperties(Properties systemProperties);
 
     /**
      * Gets the user properties to use for interpolation. The user properties have been configured directly by the user
@@ -126,6 +157,5 @@
      * @param userProperties The user properties, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    SettingsBuildingRequest setUserProperties( Properties userProperties );
-
+    SettingsBuildingRequest setUserProperties(Properties userProperties);
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingResult.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingResult.java
index 43b2359..b2e28ca 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingResult.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.util.List;
 
@@ -26,10 +25,8 @@
 /**
  * Collects the output of the settings builder.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsBuildingResult
-{
+public interface SettingsBuildingResult {
 
     /**
      * Gets the assembled settings.
@@ -46,5 +43,4 @@
      * @return The problems that were encountered during the settings building, can be empty but never {@code null}.
      */
     List<SettingsProblem> getProblems();
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblem.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblem.java
index e9e563d..ed8b295 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblem.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblem.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,27 +16,23 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 /**
  * Describes a problem that was encountered during settings building. A problem can either be an exception that was
  * thrown or a simple string message. In addition, a problem carries a hint about its source, e.g. the settings file
  * that exhibits the problem.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsProblem
-{
+public interface SettingsProblem {
 
     /**
      * The different severity levels for a problem, in decreasing order.
      */
-    enum Severity
-    {
-
+    enum Severity {
         FATAL, //
         ERROR, //
         WARNING //
-
     }
 
     /**
@@ -96,5 +90,4 @@
      * @return The severity level of this problem, never {@code null}.
      */
     Severity getSeverity();
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblemCollector.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblemCollector.java
index 63869c0..6ec7d55 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblemCollector.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsProblemCollector.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 /**
  * Collects problems that are encountered during settings building.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsProblemCollector
-{
+public interface SettingsProblemCollector {
 
     /**
      * Adds the specified problem.
@@ -36,6 +33,5 @@
      * @param column The one-based index of the column containing the problem or {@code -1} if unknown.
      * @param cause The cause of the problem, may be {@code null}.
      */
-    void add( SettingsProblem.Severity severity, String message, int line, int column, Exception cause );
-
+    void add(SettingsProblem.Severity severity, String message, int line, int column, Exception cause);
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsSource.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsSource.java
index a933b09..093e64d 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsSource.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/SettingsSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import org.apache.maven.building.Source;
 
 /**
  * Provides access to the contents of settings independently of the backing store (e.g. file system, database, memory).
  *
- * @author Benjamin Bentmann
  *
  * @deprecated instead use {@link Source}
  */
 @Deprecated
-public interface SettingsSource extends Source
-{
-
-}
+public interface SettingsSource extends Source {}
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/StringSettingsSource.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/StringSettingsSource.java
index 989fc0e..380a5e3 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/StringSettingsSource.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/StringSettingsSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,29 +16,26 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import org.apache.maven.building.StringSource;
 
 /**
  * Wraps an ordinary {@link CharSequence} as a settings source.
  *
- * @author Benjamin Bentmann
  *
  * @deprecated instead use {@link StringSource}
  */
 @Deprecated
-public class StringSettingsSource extends StringSource
-    implements SettingsSource
-{
+public class StringSettingsSource extends StringSource implements SettingsSource {
 
     /**
      * Creates a new settings source backed by the specified string.
      *
      * @param settings The settings' string representation, may be empty or {@code null}.
      */
-    public StringSettingsSource( CharSequence settings )
-    {
-        this( settings, null );
+    public StringSettingsSource(CharSequence settings) {
+        this(settings, null);
     }
 
     /**
@@ -49,9 +44,8 @@
      * @param settings The settings' string representation, may be empty or {@code null}.
      * @param location The location to report for this use, may be {@code null}.
      */
-    public StringSettingsSource( CharSequence settings, String location )
-    {
-        super( settings, location );
+    public StringSettingsSource(CharSequence settings, String location) {
+        super(settings, location);
     }
 
     /**
@@ -61,9 +55,7 @@
      * @deprecated instead use {@link #getContent()}
      */
     @Deprecated
-    public String getSettings()
-    {
+    public String getSettings() {
         return getContent();
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/UrlSettingsSource.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/UrlSettingsSource.java
index 1adc4bf..755cdd9 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/building/UrlSettingsSource.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/building/UrlSettingsSource.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.net.URL;
 
@@ -26,23 +25,19 @@
 /**
  * Wraps an ordinary {@link URL} as a settings source.
  *
- * @author Benjamin Bentmann
  *
  * @deprecated instead use {@link UrlSource}
  */
 @Deprecated
-public class UrlSettingsSource extends UrlSource
-    implements SettingsSource
-{
+public class UrlSettingsSource extends UrlSource implements SettingsSource {
 
     /**
      * Creates a new model source backed by the specified URL.
      *
      * @param settingsUrl The settings URL, must not be {@code null}.
      */
-    public UrlSettingsSource( URL settingsUrl )
-    {
-        super( settingsUrl );
+    public UrlSettingsSource(URL settingsUrl) {
+        super(settingsUrl);
     }
 
     /**
@@ -52,9 +47,7 @@
      * @deprecated instead use {@link #getUrl()}
      */
     @Deprecated
-    public URL getSettingsUrl()
-    {
+    public URL getSettingsUrl() {
         return getUrl();
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecrypter.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecrypter.java
index 7d6c8b9..34997a5 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecrypter.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecrypter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.crypto;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.ArrayList;
-import java.util.List;
+package org.apache.maven.settings.crypto;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import org.apache.maven.settings.Proxy;
 import org.apache.maven.settings.Server;
 import org.apache.maven.settings.building.DefaultSettingsProblem;
@@ -37,81 +36,75 @@
 /**
  * Decrypts passwords in the settings.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultSettingsDecrypter
-    implements SettingsDecrypter
-{
+public class DefaultSettingsDecrypter implements SettingsDecrypter {
     private final SecDispatcher securityDispatcher;
 
     @Inject
-    public DefaultSettingsDecrypter( @Named( "maven" ) SecDispatcher securityDispatcher )
-    {
+    public DefaultSettingsDecrypter(@Named("maven") SecDispatcher securityDispatcher) {
         this.securityDispatcher = securityDispatcher;
     }
 
     @Override
-    public SettingsDecryptionResult decrypt( SettingsDecryptionRequest request )
-    {
+    public SettingsDecryptionResult decrypt(SettingsDecryptionRequest request) {
         List<SettingsProblem> problems = new ArrayList<>();
 
         List<Server> servers = new ArrayList<>();
 
-        for ( Server server : request.getServers() )
-        {
+        for (Server server : request.getServers()) {
             server = server.clone();
 
-            servers.add( server );
-
-            try
-            {
-                server.setPassword( decrypt( server.getPassword() ) );
-            }
-            catch ( SecDispatcherException e )
-            {
-                problems.add( new DefaultSettingsProblem( "Failed to decrypt password for server " + server.getId()
-                    + ": " + e.getMessage(), Severity.ERROR, "server: " + server.getId(), -1, -1, e ) );
+            try {
+                server.setPassword(decrypt(server.getPassword()));
+            } catch (SecDispatcherException e) {
+                problems.add(new DefaultSettingsProblem(
+                        "Failed to decrypt password for server " + server.getId() + ": " + e.getMessage(),
+                        Severity.ERROR,
+                        "server: " + server.getId(),
+                        -1,
+                        -1,
+                        e));
             }
 
-            try
-            {
-                server.setPassphrase( decrypt( server.getPassphrase() ) );
+            try {
+                server.setPassphrase(decrypt(server.getPassphrase()));
+            } catch (SecDispatcherException e) {
+                problems.add(new DefaultSettingsProblem(
+                        "Failed to decrypt passphrase for server " + server.getId() + ": " + e.getMessage(),
+                        Severity.ERROR,
+                        "server: " + server.getId(),
+                        -1,
+                        -1,
+                        e));
             }
-            catch ( SecDispatcherException e )
-            {
-                problems.add( new DefaultSettingsProblem( "Failed to decrypt passphrase for server " + server.getId()
-                    + ": " + e.getMessage(), Severity.ERROR, "server: " + server.getId(), -1, -1, e ) );
-            }
+
+            servers.add(server);
         }
 
         List<Proxy> proxies = new ArrayList<>();
 
-        for ( Proxy proxy : request.getProxies() )
-        {
-            proxy = proxy.clone();
-
-            proxies.add( proxy );
-
-            try
-            {
-                proxy.setPassword( decrypt( proxy.getPassword() ) );
+        for (Proxy proxy : request.getProxies()) {
+            try {
+                proxy.setPassword(decrypt(proxy.getPassword()));
+            } catch (SecDispatcherException e) {
+                problems.add(new DefaultSettingsProblem(
+                        "Failed to decrypt password for proxy " + proxy.getId() + ": " + e.getMessage(),
+                        Severity.ERROR,
+                        "proxy: " + proxy.getId(),
+                        -1,
+                        -1,
+                        e));
             }
-            catch ( SecDispatcherException e )
-            {
-                problems.add( new DefaultSettingsProblem( "Failed to decrypt password for proxy " + proxy.getId()
-                    + ": " + e.getMessage(), Severity.ERROR, "proxy: " + proxy.getId(), -1, -1, e ) );
-            }
+
+            proxies.add(proxy);
         }
 
-        return new DefaultSettingsDecryptionResult( servers, proxies, problems );
+        return new DefaultSettingsDecryptionResult(servers, proxies, problems);
     }
 
-    private String decrypt( String str )
-        throws SecDispatcherException
-    {
-        return ( str == null ) ? null : securityDispatcher.decrypt( str );
+    private String decrypt(String str) throws SecDispatcherException {
+        return (str == null) ? null : securityDispatcher.decrypt(str);
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionRequest.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionRequest.java
index 9cb49ac..37b93d9 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionRequest.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.crypto;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.crypto;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -30,11 +29,8 @@
 /**
  * Collects parameters that control the decryption of settings.
  *
- * @author Benjamin Bentmann
  */
-public class DefaultSettingsDecryptionRequest
-    implements SettingsDecryptionRequest
-{
+public class DefaultSettingsDecryptionRequest implements SettingsDecryptionRequest {
 
     private List<Server> servers;
 
@@ -43,8 +39,7 @@
     /**
      * Creates an empty request.
      */
-    public DefaultSettingsDecryptionRequest()
-    {
+    public DefaultSettingsDecryptionRequest() {
         // does nothing
     }
 
@@ -53,10 +48,9 @@
      *
      * @param settings The settings to decrypt, must not be {@code null}.
      */
-    public DefaultSettingsDecryptionRequest( Settings settings )
-    {
-        setServers( settings.getServers() );
-        setProxies( settings.getProxies() );
+    public DefaultSettingsDecryptionRequest(Settings settings) {
+        setServers(settings.getServers());
+        setProxies(settings.getProxies());
     }
 
     /**
@@ -64,9 +58,8 @@
      *
      * @param server The server to decrypt, must not be {@code null}.
      */
-    public DefaultSettingsDecryptionRequest( Server server )
-    {
-        this.servers = new ArrayList<>( Arrays.asList( server ) );
+    public DefaultSettingsDecryptionRequest(Server server) {
+        this.servers = new ArrayList<>(Arrays.asList(server));
     }
 
     /**
@@ -74,16 +67,13 @@
      *
      * @param proxy The proxy to decrypt, must not be {@code null}.
      */
-    public DefaultSettingsDecryptionRequest( Proxy proxy )
-    {
-        this.proxies = new ArrayList<>( Arrays.asList( proxy ) );
+    public DefaultSettingsDecryptionRequest(Proxy proxy) {
+        this.proxies = new ArrayList<>(Arrays.asList(proxy));
     }
 
     @Override
-    public List<Server> getServers()
-    {
-        if ( servers == null )
-        {
+    public List<Server> getServers() {
+        if (servers == null) {
             servers = new ArrayList<>();
         }
 
@@ -91,18 +81,15 @@
     }
 
     @Override
-    public DefaultSettingsDecryptionRequest setServers( List<Server> servers )
-    {
+    public DefaultSettingsDecryptionRequest setServers(List<Server> servers) {
         this.servers = servers;
 
         return this;
     }
 
     @Override
-    public List<Proxy> getProxies()
-    {
-        if ( proxies == null )
-        {
+    public List<Proxy> getProxies() {
+        if (proxies == null) {
             proxies = new ArrayList<>();
         }
 
@@ -110,11 +97,9 @@
     }
 
     @Override
-    public DefaultSettingsDecryptionRequest setProxies( List<Proxy> proxies )
-    {
+    public DefaultSettingsDecryptionRequest setProxies(List<Proxy> proxies) {
         this.proxies = proxies;
 
         return this;
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionResult.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionResult.java
index ccdad19..d36d77d 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionResult.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/DefaultSettingsDecryptionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.crypto;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.crypto;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -29,11 +28,8 @@
 /**
  * Collects the output of the settings decrypter.
  *
- * @author Benjamin Bentmann
  */
-class DefaultSettingsDecryptionResult
-    implements SettingsDecryptionResult
-{
+class DefaultSettingsDecryptionResult implements SettingsDecryptionResult {
 
     private List<Server> servers;
 
@@ -41,41 +37,34 @@
 
     private List<SettingsProblem> problems;
 
-    DefaultSettingsDecryptionResult( List<Server> servers, List<Proxy> proxies, List<SettingsProblem> problems )
-    {
-        this.servers = ( servers != null ) ? servers : new ArrayList<>();
-        this.proxies = ( proxies != null ) ? proxies : new ArrayList<>();
-        this.problems = ( problems != null ) ? problems : new ArrayList<>();
+    DefaultSettingsDecryptionResult(List<Server> servers, List<Proxy> proxies, List<SettingsProblem> problems) {
+        this.servers = (servers != null) ? servers : new ArrayList<>();
+        this.proxies = (proxies != null) ? proxies : new ArrayList<>();
+        this.problems = (problems != null) ? problems : new ArrayList<>();
     }
 
     @Override
-    public Server getServer()
-    {
-        return servers.isEmpty() ? null : servers.get( 0 );
+    public Server getServer() {
+        return servers.isEmpty() ? null : servers.get(0);
     }
 
     @Override
-    public List<Server> getServers()
-    {
+    public List<Server> getServers() {
         return servers;
     }
 
     @Override
-    public Proxy getProxy()
-    {
-        return proxies.isEmpty() ? null : proxies.get( 0 );
+    public Proxy getProxy() {
+        return proxies.isEmpty() ? null : proxies.get(0);
     }
 
     @Override
-    public List<Proxy> getProxies()
-    {
+    public List<Proxy> getProxies() {
         return proxies;
     }
 
     @Override
-    public List<SettingsProblem> getProblems()
-    {
+    public List<SettingsProblem> getProblems() {
         return problems;
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/MavenSecDispatcherProvider.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/MavenSecDispatcherProvider.java
index a23d20c..d912c7d 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/MavenSecDispatcherProvider.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/MavenSecDispatcherProvider.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.crypto;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,40 +16,33 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.Map;
+package org.apache.maven.settings.crypto;
 
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Provider;
 import javax.inject.Singleton;
 
+import java.util.Map;
+
 import org.sonatype.plexus.components.cipher.PlexusCipher;
 import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
 import org.sonatype.plexus.components.sec.dispatcher.PasswordDecryptor;
 import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
 
-@Named( "maven" )
+@Named("maven")
 @Singleton
-public final class MavenSecDispatcherProvider
-    implements Provider<SecDispatcher>
-{
+public final class MavenSecDispatcherProvider implements Provider<SecDispatcher> {
     private final SecDispatcher secDispatcher;
 
     @Inject
-    public MavenSecDispatcherProvider( final PlexusCipher plexusCipher,
-                                       final Map<String, PasswordDecryptor> decryptors )
-    {
-        this.secDispatcher = new DefaultSecDispatcher(
-            plexusCipher,
-            decryptors,
-            "~/.m2/settings-security.xml"
-        );
+    public MavenSecDispatcherProvider(
+            final PlexusCipher plexusCipher, final Map<String, PasswordDecryptor> decryptors) {
+        this.secDispatcher = new DefaultSecDispatcher(plexusCipher, decryptors, "~/.m2/settings-security.xml");
     }
 
     @Override
-    public SecDispatcher get()
-    {
+    public SecDispatcher get() {
         return secDispatcher;
     }
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecrypter.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecrypter.java
index b34c394..f339a39 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecrypter.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecrypter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.crypto;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,14 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.crypto;
 
 /**
  * Decrypts passwords in the settings.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsDecrypter
-{
+public interface SettingsDecrypter {
 
     /**
      * Decrypts passwords in the settings.
@@ -33,6 +30,5 @@
      * @param request The settings decryption request that holds the parameters, must not be {@code null}.
      * @return The result of the settings decryption, never {@code null}.
      */
-    SettingsDecryptionResult decrypt( SettingsDecryptionRequest request );
-
+    SettingsDecryptionResult decrypt(SettingsDecryptionRequest request);
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionRequest.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionRequest.java
index b344a99..044eb2b 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionRequest.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.crypto;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.crypto;
 
 import java.util.List;
 
@@ -27,10 +26,8 @@
 /**
  * Collects parameters that control the decryption of settings.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsDecryptionRequest
-{
+public interface SettingsDecryptionRequest {
 
     /**
      * Gets the servers whose passwords should be decrypted.
@@ -45,7 +42,7 @@
      * @param servers The servers to decrypt, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    SettingsDecryptionRequest setServers( List<Server> servers );
+    SettingsDecryptionRequest setServers(List<Server> servers);
 
     /**
      * Gets the proxies whose passwords should be decrypted.
@@ -60,6 +57,5 @@
      * @param proxies The proxies to decrypt, may be {@code null}.
      * @return This request, never {@code null}.
      */
-    SettingsDecryptionRequest setProxies( List<Proxy> proxies );
-
+    SettingsDecryptionRequest setProxies(List<Proxy> proxies);
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionResult.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionResult.java
index 5b7b1f4..c76ee01 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionResult.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/crypto/SettingsDecryptionResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.crypto;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.crypto;
 
 import java.util.List;
 
@@ -28,10 +27,8 @@
 /**
  * Collects the output of the settings decrypter.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsDecryptionResult
-{
+public interface SettingsDecryptionResult {
 
     /**
      * Gets the decrypted server. This is a convenience method to retrieve the first element from {@link #getServers()}.
@@ -67,5 +64,4 @@
      * @return The problems that were encountered during the decryption, can be empty but never {@code null}.
      */
     List<SettingsProblem> getProblems();
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java
index 4ce48dd..f7cd5ca 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,78 +16,82 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.io;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.nio.file.Files;
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
+import org.apache.maven.api.settings.InputSource;
 import org.apache.maven.settings.Settings;
-import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.apache.maven.settings.v4.SettingsStaxReader;
 
 /**
  * Handles deserialization of settings from the default textual format.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultSettingsReader
-    implements SettingsReader
-{
+public class DefaultSettingsReader implements SettingsReader {
 
     @Override
-    public Settings read( File input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Settings read(File input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        return read( ReaderFactory.newXmlReader( input ), options );
-    }
-
-    @Override
-    public Settings read( Reader input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
-
-        try ( Reader in = input )
-        {
-            return new SettingsXpp3Reader().read( in, isStrict( options ) );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new SettingsParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        try (InputStream in = Files.newInputStream(input.toPath())) {
+            InputSource source = new InputSource(input.toString());
+            return new Settings(new SettingsStaxReader().read(in, isStrict(options), source));
+        } catch (XMLStreamException e) {
+            throw new SettingsParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
         }
     }
 
     @Override
-    public Settings read( InputStream input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public Settings read(Reader input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        try ( InputStream in = input )
-        {
-            return new SettingsXpp3Reader().read( in, isStrict( options ) );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new SettingsParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        try (Reader in = input) {
+            InputSource source = (InputSource) options.get(InputSource.class.getName());
+            return new Settings(new SettingsStaxReader().read(in, isStrict(options), source));
+        } catch (XMLStreamException e) {
+            throw new SettingsParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
         }
     }
 
-    private boolean isStrict( Map<String, ?> options )
-    {
-        Object value = ( options != null ) ? options.get( IS_STRICT ) : null;
-        return value == null || Boolean.parseBoolean( value.toString() );
+    @Override
+    public Settings read(InputStream input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
+
+        try (InputStream in = input) {
+            InputSource source = (InputSource) options.get(InputSource.class.getName());
+            return new Settings(new SettingsStaxReader().read(in, isStrict(options), source));
+        } catch (XMLStreamException e) {
+            throw new SettingsParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
+        }
     }
 
+    private boolean isStrict(Map<String, ?> options) {
+        Object value = (options != null) ? options.get(IS_STRICT) : null;
+        return value == null || Boolean.parseBoolean(value.toString());
+    }
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsWriter.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsWriter.java
index 54f626a..dda40a3 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsWriter.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/DefaultSettingsWriter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,76 +16,62 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.io;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.OutputStreamWriter;
 import java.io.Writer;
+import java.nio.file.Files;
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.settings.Settings;
-import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
-import org.codehaus.plexus.util.WriterFactory;
+import org.apache.maven.settings.v4.SettingsStaxWriter;
 
 /**
  * Handles serialization of settings into the default textual format.
  *
- * @author Benjamin Bentmann
  */
 @Named
 @Singleton
-public class DefaultSettingsWriter
-    implements SettingsWriter
-{
+public class DefaultSettingsWriter implements SettingsWriter {
 
     @Override
-    public void write( File output, Map<String, Object> options, Settings settings )
-        throws IOException
-    {
-        Objects.requireNonNull( output, "output cannot be null" );
-        Objects.requireNonNull( settings, "settings cannot be null" );
+    public void write(File output, Map<String, Object> options, Settings settings) throws IOException {
+        Objects.requireNonNull(output, "output cannot be null");
+        Objects.requireNonNull(settings, "settings cannot be null");
 
         output.getParentFile().mkdirs();
 
-        write( WriterFactory.newXmlWriter( output ), options, settings );
+        write(Files.newOutputStream(output.toPath()), options, settings);
     }
 
     @Override
-    public void write( Writer output, Map<String, Object> options, Settings settings )
-        throws IOException
-    {
-        Objects.requireNonNull( output, "output cannot be null" );
-        Objects.requireNonNull( settings, "settings cannot be null" );
+    public void write(Writer output, Map<String, Object> options, Settings settings) throws IOException {
+        Objects.requireNonNull(output, "output cannot be null");
+        Objects.requireNonNull(settings, "settings cannot be null");
 
-        try ( Writer out = output )
-        {
-            new SettingsXpp3Writer().write( out, settings );
+        try (Writer out = output) {
+            new SettingsStaxWriter().write(out, settings.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException("Error writing settings", e);
         }
     }
 
     @Override
-    public void write( OutputStream output, Map<String, Object> options, Settings settings )
-        throws IOException
-    {
-        Objects.requireNonNull( output, "output cannot be null" );
-        Objects.requireNonNull( settings, "settings cannot be null" );
+    public void write(OutputStream output, Map<String, Object> options, Settings settings) throws IOException {
+        Objects.requireNonNull(output, "output cannot be null");
+        Objects.requireNonNull(settings, "settings cannot be null");
 
-        String encoding = settings.getModelEncoding();
-        // TODO Use StringUtils here
-        if ( encoding == null || encoding.length() <= 0 )
-        {
-            encoding = "UTF-8";
-        }
-
-        try ( Writer out = new OutputStreamWriter( output, encoding ) )
-        {
-            write( out, options, settings );
+        try (OutputStream out = output) {
+            new SettingsStaxWriter().write(out, settings.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException("Error writing settings", e);
         }
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsParseException.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsParseException.java
index b8772a9..493eab8 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsParseException.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsParseException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,15 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.io;
 
 import java.io.IOException;
 
 /**
  * Signals a failure to parse the settings due to invalid syntax (e.g. non well formed XML or unknown elements).
  *
- * @author Benjamin Bentmann
  */
-public class SettingsParseException
-    extends IOException
-{
+public class SettingsParseException extends IOException {
 
     /**
      * The one-based index of the line containing the error.
@@ -47,9 +43,8 @@
      * @param lineNumber The one-based index of the line containing the error or {@code -1} if unknown.
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      */
-    public SettingsParseException( String message, int lineNumber, int columnNumber )
-    {
-        super( message );
+    public SettingsParseException(String message, int lineNumber, int columnNumber) {
+        super(message);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -62,10 +57,9 @@
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      * @param cause The nested cause of this error, may be {@code null}.
      */
-    public SettingsParseException( String message, int lineNumber, int columnNumber, Throwable cause )
-    {
-        super( message );
-        initCause( cause );
+    public SettingsParseException(String message, int lineNumber, int columnNumber, Throwable cause) {
+        super(message);
+        initCause(cause);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -75,8 +69,7 @@
      *
      * @return The one-based index of the line containing the error or a non-positive value if unknown.
      */
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
 
@@ -85,9 +78,7 @@
      *
      * @return The one-based index of the column containing the error or non-positive value if unknown.
      */
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsReader.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsReader.java
index 7817df6..197b060 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsReader.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.io;
 
 import java.io.File;
 import java.io.IOException;
@@ -30,10 +29,8 @@
 /**
  * Handles deserialization of settings from some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsReader
-{
+public interface SettingsReader {
 
     /**
      * The key for the option to enable strict parsing. This option is of type {@link Boolean} and defaults to {@code
@@ -50,8 +47,7 @@
      * @throws IOException If the settings could not be deserialized.
      * @throws SettingsParseException If the input format could not be parsed.
      */
-    Settings read( File input, Map<String, ?> options )
-        throws IOException, SettingsParseException;
+    Settings read(File input, Map<String, ?> options) throws IOException, SettingsParseException;
 
     /**
      * Reads the settings from the specified character reader. The reader will be automatically closed before the method
@@ -63,8 +59,7 @@
      * @throws IOException If the settings could not be deserialized.
      * @throws SettingsParseException If the input format could not be parsed.
      */
-    Settings read( Reader input, Map<String, ?> options )
-        throws IOException, SettingsParseException;
+    Settings read(Reader input, Map<String, ?> options) throws IOException, SettingsParseException;
 
     /**
      * Reads the settings from the specified byte stream. The stream will be automatically closed before the method
@@ -76,7 +71,5 @@
      * @throws IOException If the settings could not be deserialized.
      * @throws SettingsParseException If the input format could not be parsed.
      */
-    Settings read( InputStream input, Map<String, ?> options )
-        throws IOException, SettingsParseException;
-
+    Settings read(InputStream input, Map<String, ?> options) throws IOException, SettingsParseException;
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsWriter.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsWriter.java
index 54bfcf0..3e7ea37 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsWriter.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/io/SettingsWriter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.io;
 
 import java.io.File;
 import java.io.IOException;
@@ -30,10 +29,8 @@
 /**
  * Handles serialization of settings into some kind of textual format like XML.
  *
- * @author Benjamin Bentmann
  */
-public interface SettingsWriter
-{
+public interface SettingsWriter {
 
     /**
      * Writes the supplied settings to the specified file. Any non-existing parent directories of the output file will
@@ -44,8 +41,7 @@
      * @param settings The settings to serialize, must not be {@code null}.
      * @throws IOException If the settings could not be serialized.
      */
-    void write( File output, Map<String, Object> options, Settings settings )
-        throws IOException;
+    void write(File output, Map<String, Object> options, Settings settings) throws IOException;
 
     /**
      * Writes the supplied settings to the specified character writer. The writer will be automatically closed before
@@ -56,8 +52,7 @@
      * @param settings The settings to serialize, must not be {@code null}.
      * @throws IOException If the settings could not be serialized.
      */
-    void write( Writer output, Map<String, Object> options, Settings settings )
-        throws IOException;
+    void write(Writer output, Map<String, Object> options, Settings settings) throws IOException;
 
     /**
      * Writes the supplied settings to the specified byte stream. The stream will be automatically closed before the
@@ -68,7 +63,5 @@
      * @param settings The settings to serialize, must not be {@code null}.
      * @throws IOException If the settings could not be serialized.
      */
-    void write( OutputStream output, Map<String, Object> options, Settings settings )
-        throws IOException;
-
+    void write(OutputStream output, Map<String, Object> options, Settings settings) throws IOException;
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java
index cb5f6c1..b3da63e 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/merge/MavenSettingsMerger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.merge;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.merge;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -26,45 +25,37 @@
 
 import org.apache.maven.settings.IdentifiableBase;
 import org.apache.maven.settings.Settings;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
- * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
- * @author Benjamin Bentmann
+ * @deprecated use {@link org.apache.maven.settings.v4.SettingsMerger}
  */
-public class MavenSettingsMerger
-{
+@Deprecated
+public class MavenSettingsMerger {
 
     /**
      * @param dominant
      * @param recessive
      * @param recessiveSourceLevel
      */
-    public void merge( Settings dominant, Settings recessive, String recessiveSourceLevel )
-    {
-        if ( dominant == null || recessive == null )
-        {
+    public void merge(Settings dominant, Settings recessive, String recessiveSourceLevel) {
+        if (dominant == null || recessive == null) {
             return;
         }
 
-        recessive.setSourceLevel( recessiveSourceLevel );
+        recessive.setSourceLevel(recessiveSourceLevel);
 
         List<String> dominantActiveProfiles = dominant.getActiveProfiles();
         List<String> recessiveActiveProfiles = recessive.getActiveProfiles();
 
-        if ( recessiveActiveProfiles != null )
-        {
-            if ( dominantActiveProfiles == null )
-            {
+        if (recessiveActiveProfiles != null) {
+            if (dominantActiveProfiles == null) {
                 dominantActiveProfiles = new ArrayList<>();
-                dominant.setActiveProfiles( dominantActiveProfiles );
+                dominant.setActiveProfiles(dominantActiveProfiles);
             }
 
-            for ( String profileId : recessiveActiveProfiles )
-            {
-                if ( !dominantActiveProfiles.contains( profileId ) )
-                {
-                    dominantActiveProfiles.add( profileId );
+            for (String profileId : recessiveActiveProfiles) {
+                if (!dominantActiveProfiles.contains(profileId)) {
+                    dominantActiveProfiles.add(profileId);
                 }
             }
         }
@@ -73,33 +64,30 @@
 
         List<String> recessivePluginGroupIds = recessive.getPluginGroups();
 
-        if ( recessivePluginGroupIds != null )
-        {
-            if ( dominantPluginGroupIds == null )
-            {
+        if (recessivePluginGroupIds != null) {
+            if (dominantPluginGroupIds == null) {
                 dominantPluginGroupIds = new ArrayList<>();
-                dominant.setPluginGroups( dominantPluginGroupIds );
+                dominant.setPluginGroups(dominantPluginGroupIds);
             }
 
-            for ( String pluginGroupId : recessivePluginGroupIds )
-            {
-                if ( !dominantPluginGroupIds.contains( pluginGroupId ) )
-                {
-                    dominantPluginGroupIds.add( pluginGroupId );
+            for (String pluginGroupId : recessivePluginGroupIds) {
+                if (!dominantPluginGroupIds.contains(pluginGroupId)) {
+                    dominantPluginGroupIds.add(pluginGroupId);
                 }
             }
         }
 
-        if ( StringUtils.isEmpty( dominant.getLocalRepository() ) )
-        {
-            dominant.setLocalRepository( recessive.getLocalRepository() );
+        if (dominant.getLocalRepository() == null
+                || dominant.getLocalRepository().isEmpty()) {
+            dominant.setLocalRepository(recessive.getLocalRepository());
         }
 
-        shallowMergeById( dominant.getMirrors(), recessive.getMirrors(), recessiveSourceLevel );
-        shallowMergeById( dominant.getServers(), recessive.getServers(), recessiveSourceLevel );
-        shallowMergeById( dominant.getProxies(), recessive.getProxies(), recessiveSourceLevel );
-        shallowMergeById( dominant.getProfiles(), recessive.getProfiles(), recessiveSourceLevel );
-
+        shallowMergeById(dominant.getMirrors(), recessive.getMirrors(), recessiveSourceLevel);
+        shallowMergeById(dominant.getServers(), recessive.getServers(), recessiveSourceLevel);
+        shallowMergeById(dominant.getProxies(), recessive.getProxies(), recessiveSourceLevel);
+        shallowMergeById(dominant.getProfiles(), recessive.getProfiles(), recessiveSourceLevel);
+        shallowMergeById(dominant.getRepositories(), recessive.getRepositories(), recessiveSourceLevel);
+        shallowMergeById(dominant.getPluginRepositories(), recessive.getPluginRepositories(), recessiveSourceLevel);
     }
 
     /**
@@ -107,39 +95,33 @@
      * @param recessive
      * @param recessiveSourceLevel
      */
-    private static <T extends IdentifiableBase> void shallowMergeById( List<T> dominant, List<T> recessive,
-                                                                       String recessiveSourceLevel )
-    {
-        Map<String, T> dominantById = mapById( dominant );
-        final List<T> identifiables = new ArrayList<>( recessive.size() );
+    private static <T extends IdentifiableBase> void shallowMergeById(
+            List<T> dominant, List<T> recessive, String recessiveSourceLevel) {
+        Map<String, T> dominantById = mapById(dominant);
+        final List<T> identifiables = new ArrayList<>(recessive.size());
 
-        for ( T identifiable : recessive )
-        {
-            if ( !dominantById.containsKey( identifiable.getId() ) )
-            {
-                identifiable.setSourceLevel( recessiveSourceLevel );
+        for (T identifiable : recessive) {
+            if (!dominantById.containsKey(identifiable.getId())) {
+                identifiable.setSourceLevel(recessiveSourceLevel);
 
-                identifiables.add( identifiable );
+                identifiables.add(identifiable);
             }
         }
 
-        dominant.addAll( 0, identifiables );
+        dominant.addAll(0, identifiables);
     }
 
     /**
      * @param identifiables
      * @return a map
      */
-    private static <T extends IdentifiableBase> Map<String, T> mapById( List<T> identifiables )
-    {
+    private static <T extends IdentifiableBase> Map<String, T> mapById(List<T> identifiables) {
         Map<String, T> byId = new HashMap<>();
 
-        for ( T identifiable : identifiables )
-        {
-            byId.put( identifiable.getId(), identifiable );
+        for (T identifiable : identifiables) {
+            byId.put(identifiable.getId(), identifiable);
         }
 
         return byId;
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
index f088642..143ff8a 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/DefaultSettingsValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,182 +16,237 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+package org.apache.maven.settings.validation;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Pattern;
+
 import org.apache.maven.settings.Mirror;
 import org.apache.maven.settings.Profile;
-import org.apache.maven.settings.Repository;
 import org.apache.maven.settings.Proxy;
+import org.apache.maven.settings.Repository;
 import org.apache.maven.settings.Server;
 import org.apache.maven.settings.Settings;
 import org.apache.maven.settings.building.SettingsProblem.Severity;
 import org.apache.maven.settings.building.SettingsProblemCollector;
-import org.codehaus.plexus.util.StringUtils;
 
 /**
- * @author Milos Kleint
  */
 @Named
 @Singleton
-public class DefaultSettingsValidator
-    implements SettingsValidator
-{
+public class DefaultSettingsValidator implements SettingsValidator {
 
-    private static final String ID_REGEX = "[A-Za-z0-9_\\-.]+";
+    private static final String ID = "[\\w.-]+";
+    private static final Pattern ID_REGEX = Pattern.compile(ID);
 
-    private static final String ILLEGAL_FS_CHARS = "\\/:\"<>|?*";
-
-    private static final String ILLEGAL_REPO_ID_CHARS = ILLEGAL_FS_CHARS;
+    private static final String ILLEGAL_REPO_ID_CHARS = "\\/:\"<>|?*"; // ILLEGAL_FS_CHARS
 
     @Override
-    public void validate( Settings settings, SettingsProblemCollector problems )
-    {
-        if ( settings.isUsePluginRegistry() )
-        {
-            addViolation( problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect." );
+    public void validate(Settings settings, SettingsProblemCollector problems) {
+        validate(settings, false, problems);
+    }
+
+    @Override
+    public void validate(Settings settings, boolean isProjectSettings, SettingsProblemCollector problems) {
+        if (isProjectSettings) {
+            String msgS = "is not supported on project settings.";
+            String msgP = "are not supported on project settings.";
+            if (settings.getLocalRepository() != null
+                    && !settings.getLocalRepository().isEmpty()) {
+                addViolation(problems, Severity.WARNING, "localRepository", null, msgS);
+            }
+            if (settings.getInteractiveMode() != null && !settings.getInteractiveMode()) {
+                addViolation(problems, Severity.WARNING, "interactiveMode", null, msgS);
+            }
+            if (settings.isOffline()) {
+                addViolation(problems, Severity.WARNING, "offline", null, msgS);
+            }
+            if (!settings.getProxies().isEmpty()) {
+                addViolation(problems, Severity.WARNING, "proxies", null, msgP);
+            }
+            if (settings.isUsePluginRegistry()) {
+                addViolation(problems, Severity.WARNING, "usePluginRegistry", null, msgS);
+            }
+            List<Server> servers = settings.getServers();
+            for (int i = 0; i < servers.size(); i++) {
+                Server server = servers.get(i);
+                String serverField = "servers.server[" + i + "]";
+                validateStringEmpty(problems, serverField + ".username", server.getUsername(), msgS);
+                validateStringEmpty(problems, serverField + ".password", server.getPassword(), msgS);
+                validateStringEmpty(problems, serverField + ".privateKey", server.getPrivateKey(), msgS);
+                validateStringEmpty(problems, serverField + ".passphrase", server.getPassphrase(), msgS);
+                validateStringEmpty(problems, serverField + ".filePermissions", server.getFilePermissions(), msgS);
+                validateStringEmpty(
+                        problems, serverField + ".directoryPermissions", server.getDirectoryPermissions(), msgS);
+            }
+        }
+
+        if (settings.isUsePluginRegistry()) {
+            addViolation(problems, Severity.WARNING, "usePluginRegistry", null, "is deprecated and has no effect.");
         }
 
         List<String> pluginGroups = settings.getPluginGroups();
 
-        if ( pluginGroups != null )
-        {
-            for ( int i = 0; i < pluginGroups.size(); i++ )
-            {
-                String pluginGroup = pluginGroups.get( i ).trim();
+        if (pluginGroups != null) {
+            for (int i = 0; i < pluginGroups.size(); i++) {
+                String pluginGroup = pluginGroups.get(i);
 
-                if ( StringUtils.isBlank( pluginGroup ) )
-                {
-                    addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null,
-                                  "must not be empty" );
-                }
-                else if ( !pluginGroup.matches( ID_REGEX ) )
-                {
-                    addViolation( problems, Severity.ERROR, "pluginGroups.pluginGroup[" + i + "]", null,
-                                  "must denote a valid group id and match the pattern " + ID_REGEX );
+                validateStringNotEmpty(problems, "pluginGroups.pluginGroup[" + i + "]", pluginGroup, null);
+
+                if (!ID_REGEX.matcher(pluginGroup).matches()) {
+                    addViolation(
+                            problems,
+                            Severity.ERROR,
+                            "pluginGroups.pluginGroup[" + i + "]",
+                            null,
+                            "must denote a valid group id and match the pattern " + ID);
                 }
             }
         }
 
         List<Server> servers = settings.getServers();
 
-        if ( servers != null )
-        {
+        if (servers != null) {
             Set<String> serverIds = new HashSet<>();
 
-            for ( int i = 0; i < servers.size(); i++ )
-            {
-                Server server = servers.get( i );
+            for (int i = 0; i < servers.size(); i++) {
+                Server server = servers.get(i);
 
-                validateStringNotEmpty( problems, "servers.server[" + i + "].id", server.getId(), null );
+                validateStringNotEmpty(problems, "servers.server[" + i + "].id", server.getId(), null);
 
-                if ( !serverIds.add( server.getId() ) )
-                {
-                    addViolation( problems, Severity.WARNING, "servers.server.id", null,
-                                  "must be unique but found duplicate server with id " + server.getId() );
+                if (!serverIds.add(server.getId())) {
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            "servers.server.id",
+                            null,
+                            "must be unique but found duplicate server with id " + server.getId());
                 }
             }
         }
 
         List<Mirror> mirrors = settings.getMirrors();
 
-        if ( mirrors != null )
-        {
-            for ( Mirror mirror : mirrors )
-            {
-                validateStringNotEmpty( problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl() );
+        if (mirrors != null) {
+            for (Mirror mirror : mirrors) {
+                validateStringNotEmpty(problems, "mirrors.mirror.id", mirror.getId(), mirror.getUrl());
 
-                validateBannedCharacters( problems, "mirrors.mirror.id", Severity.WARNING, mirror.getId(), null,
-                                          ILLEGAL_REPO_ID_CHARS );
+                validateBannedCharacters(
+                        problems, "mirrors.mirror.id", Severity.WARNING, mirror.getId(), null, ILLEGAL_REPO_ID_CHARS);
 
-                if ( "local".equals( mirror.getId() ) )
-                {
-                    addViolation( problems, Severity.WARNING, "mirrors.mirror.id", null, "must not be 'local'"
-                        + ", this identifier is reserved for the local repository"
-                        + ", using it for other repositories will corrupt your repository metadata." );
+                if ("local".equals(mirror.getId())) {
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            "mirrors.mirror.id",
+                            null,
+                            "must not be 'local'"
+                                    + ", this identifier is reserved for the local repository"
+                                    + ", using it for other repositories will corrupt your repository metadata.");
                 }
 
-                validateStringNotEmpty( problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId() );
+                validateStringNotEmpty(problems, "mirrors.mirror.url", mirror.getUrl(), mirror.getId());
 
-                validateStringNotEmpty( problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId() );
+                validateStringNotEmpty(problems, "mirrors.mirror.mirrorOf", mirror.getMirrorOf(), mirror.getId());
             }
         }
 
         List<Profile> profiles = settings.getProfiles();
 
-        if ( profiles != null )
-        {
+        if (profiles != null) {
             Set<String> profileIds = new HashSet<>();
 
-            for ( Profile profile : profiles )
-            {
-                if ( !profileIds.add( profile.getId() ) )
-                {
-                    addViolation( problems, Severity.WARNING, "profiles.profile.id", null,
-                                  "must be unique but found duplicate profile with id " + profile.getId() );
+            for (Profile profile : profiles) {
+                if (!profileIds.add(profile.getId())) {
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            "profiles.profile.id",
+                            null,
+                            "must be unique but found duplicate profile with id " + profile.getId());
                 }
 
                 String prefix = "profiles.profile[" + profile.getId() + "].";
 
-                validateRepositories( problems, profile.getRepositories(), prefix + "repositories.repository" );
-                validateRepositories( problems, profile.getPluginRepositories(), prefix
-                    + "pluginRepositories.pluginRepository" );
+                validateRepositories(problems, profile.getRepositories(), prefix + "repositories.repository");
+                validateRepositories(
+                        problems, profile.getPluginRepositories(), prefix + "pluginRepositories.pluginRepository");
             }
         }
 
         List<Proxy> proxies = settings.getProxies();
 
-        if ( proxies != null )
-        {
+        if (proxies != null) {
             Set<String> proxyIds = new HashSet<>();
 
-            for ( Proxy proxy : proxies )
-            {
-                if ( !proxyIds.add( proxy.getId() ) )
-                {
-                    addViolation( problems, Severity.WARNING, "proxies.proxy.id", null,
-                                  "must be unique but found duplicate proxy with id " + proxy.getId() );
+            for (Proxy proxy : proxies) {
+                if (!proxyIds.add(proxy.getId())) {
+                    addViolation(
+                            problems,
+                            Severity.WARNING,
+                            "proxies.proxy.id",
+                            null,
+                            "must be unique but found duplicate proxy with id " + proxy.getId());
                 }
-                validateStringNotEmpty( problems, "proxies.proxy.host", proxy.getHost(), proxy.getId() );
+                validateStringNotEmpty(problems, "proxies.proxy.host", proxy.getHost(), proxy.getId());
+
+                try {
+                    Integer.parseInt(proxy.getPortString());
+                } catch (NumberFormatException e) {
+                    addViolation(
+                            problems,
+                            Severity.ERROR,
+                            "proxies.proxy[" + proxy.getId() + "].port",
+                            null,
+                            "must be a valid integer but found '" + proxy.getPortString() + "'");
+                }
             }
         }
     }
 
-    private void validateRepositories( SettingsProblemCollector problems, List<Repository> repositories, String prefix )
-    {
+    private void validateRepositories(SettingsProblemCollector problems, List<Repository> repositories, String prefix) {
         Set<String> repoIds = new HashSet<>();
 
-        for ( Repository repository : repositories )
-        {
-            validateStringNotEmpty( problems, prefix + ".id", repository.getId(), repository.getUrl() );
+        for (Repository repository : repositories) {
+            validateStringNotEmpty(problems, prefix + ".id", repository.getId(), repository.getUrl());
 
-            validateBannedCharacters( problems, prefix + ".id", Severity.WARNING, repository.getId(), null,
-                                      ILLEGAL_REPO_ID_CHARS );
+            validateBannedCharacters(
+                    problems, prefix + ".id", Severity.WARNING, repository.getId(), null, ILLEGAL_REPO_ID_CHARS);
 
-            if ( "local".equals( repository.getId() ) )
-            {
-                addViolation( problems, Severity.WARNING, prefix + ".id", null, "must not be 'local'"
-                    + ", this identifier is reserved for the local repository"
-                    + ", using it for other repositories will corrupt your repository metadata." );
+            if ("local".equals(repository.getId())) {
+                addViolation(
+                        problems,
+                        Severity.WARNING,
+                        prefix + ".id",
+                        null,
+                        "must not be 'local'"
+                                + ", this identifier is reserved for the local repository"
+                                + ", using it for other repositories will corrupt your repository metadata.");
             }
 
-            if ( !repoIds.add( repository.getId() ) )
-            {
-                addViolation( problems, Severity.WARNING, prefix + ".id", null,
-                              "must be unique but found duplicate repository with id " + repository.getId() );
+            if (!repoIds.add(repository.getId())) {
+                addViolation(
+                        problems,
+                        Severity.WARNING,
+                        prefix + ".id",
+                        null,
+                        "must be unique but found duplicate repository with id " + repository.getId());
             }
 
-            validateStringNotEmpty( problems, prefix + ".url", repository.getUrl(), repository.getId() );
+            validateStringNotEmpty(problems, prefix + ".url", repository.getUrl(), repository.getId());
 
-            if ( "legacy".equals( repository.getLayout() ) )
-            {
-                addViolation( problems, Severity.WARNING, prefix + ".layout", repository.getId(),
-                              "uses the unsupported value 'legacy', artifact resolution might fail." );
+            if ("legacy".equals(repository.getLayout())) {
+                addViolation(
+                        problems,
+                        Severity.WARNING,
+                        prefix + ".layout",
+                        repository.getId(),
+                        "uses the unsupported value 'legacy', artifact resolution might fail.");
             }
         }
     }
@@ -206,24 +259,40 @@
      * Asserts:
      * <p/>
      * <ul>
+     * <li><code>string.length == null</code>
+     * <li><code>string.length == 0</code>
+     * </ul>
+     */
+    private static boolean validateStringEmpty(
+            SettingsProblemCollector problems, String fieldName, String string, String message) {
+        if (string == null || string.length() == 0) {
+            return true;
+        }
+
+        addViolation(problems, Severity.WARNING, fieldName, null, message);
+
+        return false;
+    }
+
+    /**
+     * Asserts:
+     * <p/>
+     * <ul>
      * <li><code>string.length != null</code>
      * <li><code>string.length > 0</code>
      * </ul>
      */
-    private static boolean validateStringNotEmpty( SettingsProblemCollector problems, String fieldName, String string,
-                                            String sourceHint )
-    {
-        if ( !validateNotNull( problems, fieldName, string, sourceHint ) )
-        {
+    private static boolean validateStringNotEmpty(
+            SettingsProblemCollector problems, String fieldName, String string, String sourceHint) {
+        if (!validateNotNull(problems, fieldName, string, sourceHint)) {
             return false;
         }
 
-        if ( string.length() > 0 )
-        {
+        if (string.length() > 0) {
             return true;
         }
 
-        addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" );
+        addViolation(problems, Severity.ERROR, fieldName, sourceHint, "is missing");
 
         return false;
     }
@@ -235,32 +304,33 @@
      * <li><code>string != null</code>
      * </ul>
      */
-    private static boolean validateNotNull( SettingsProblemCollector problems, String fieldName, Object object,
-                                            String sourceHint )
-    {
-        if ( object != null )
-        {
+    private static boolean validateNotNull(
+            SettingsProblemCollector problems, String fieldName, Object object, String sourceHint) {
+        if (object != null) {
             return true;
         }
 
-        addViolation( problems, Severity.ERROR, fieldName, sourceHint, "is missing" );
+        addViolation(problems, Severity.ERROR, fieldName, sourceHint, "is missing");
 
         return false;
     }
 
-    private static boolean validateBannedCharacters( SettingsProblemCollector problems, String fieldName,
-                                                     Severity severity, String string, String sourceHint,
-                                                     String banned )
-    {
-        if ( string != null )
-        {
-            for ( int i = string.length() - 1; i >= 0; i-- )
-            {
-                if ( banned.indexOf( string.charAt( i ) ) >= 0 )
-                {
-                    addViolation( problems, severity, fieldName, sourceHint,
-                                  "must not contain any of these characters " + banned + " but found "
-                                      + string.charAt( i ) );
+    private static boolean validateBannedCharacters(
+            SettingsProblemCollector problems,
+            String fieldName,
+            Severity severity,
+            String string,
+            String sourceHint,
+            String banned) {
+        if (string != null) {
+            for (int i = string.length() - 1; i >= 0; i--) {
+                if (banned.indexOf(string.charAt(i)) >= 0) {
+                    addViolation(
+                            problems,
+                            severity,
+                            fieldName,
+                            sourceHint,
+                            "must not contain any of these characters " + banned + " but found " + string.charAt(i));
                     return false;
                 }
             }
@@ -269,20 +339,17 @@
         return true;
     }
 
-    private static void addViolation( SettingsProblemCollector problems, Severity severity, String fieldName,
-                               String sourceHint, String message )
-    {
-        StringBuilder buffer = new StringBuilder( 256 );
-        buffer.append( '\'' ).append( fieldName ).append( '\'' );
+    private static void addViolation(
+            SettingsProblemCollector problems, Severity severity, String fieldName, String sourceHint, String message) {
+        StringBuilder buffer = new StringBuilder(256);
+        buffer.append('\'').append(fieldName).append('\'');
 
-        if ( sourceHint != null )
-        {
-            buffer.append( " for " ).append( sourceHint );
+        if (sourceHint != null) {
+            buffer.append(" for ").append(sourceHint);
         }
 
-        buffer.append( ' ' ).append( message );
+        buffer.append(' ').append(message);
 
-        problems.add( severity, buffer.toString(), -1, -1, null );
+        problems.add(severity, buffer.toString(), -1, -1, null);
     }
-
 }
diff --git a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/SettingsValidator.java b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/SettingsValidator.java
index 79745ec..8f1668a 100644
--- a/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/SettingsValidator.java
+++ b/maven-settings-builder/src/main/java/org/apache/maven/settings/validation/SettingsValidator.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.validation;
 
 import org.apache.maven.settings.Settings;
 import org.apache.maven.settings.building.SettingsProblemCollector;
@@ -25,10 +24,8 @@
 /**
  * Validate a model settings
  *
- * @author Milos Kleint
  */
-public interface SettingsValidator
-{
+public interface SettingsValidator {
 
     /**
      * Validate the specified settings.
@@ -36,6 +33,16 @@
      * @param settings The settings to validate, must not be {@code null}.
      * @param problems The container used to collect problems that were encountered, must not be {@code null}.
      */
-    void validate( Settings settings, SettingsProblemCollector problems );
+    void validate(Settings settings, SettingsProblemCollector problems);
 
+    /**
+     * Validate the specified settings.
+     *
+     * @param settings The settings to validate, must not be {@code null}.
+     * @param isProjectSettings Boolean indicating if the validation is for project settings or user / global settings.
+     * @param problems The container used to collect problems that were encountered, must not be {@code null}.
+     */
+    default void validate(Settings settings, boolean isProjectSettings, SettingsProblemCollector problems) {
+        validate(settings, problems);
+    }
 }
diff --git a/maven-settings-builder/src/site/site.xml b/maven-settings-builder/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-settings-builder/src/site/site.xml
+++ b/maven-settings-builder/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java b/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java
index 63d62be..2959e4f 100644
--- a/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java
+++ b/maven-settings-builder/src/test/java/org/apache/maven/settings/building/DefaultSettingsBuilderFactoryTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.building;
 
 import java.io.File;
 
@@ -26,30 +25,24 @@
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
 /**
- * @author Benjamin Bentmann
  */
-public class DefaultSettingsBuilderFactoryTest
-{
+class DefaultSettingsBuilderFactoryTest {
 
-    private File getSettings( String name )
-    {
-        return new File( "src/test/resources/settings/factory/" + name + ".xml" ).getAbsoluteFile();
+    private File getSettings(String name) {
+        return new File("src/test/resources/settings/factory/" + name + ".xml").getAbsoluteFile();
     }
 
     @Test
-    public void testCompleteWiring()
-        throws Exception
-    {
+    void testCompleteWiring() throws Exception {
         SettingsBuilder builder = new DefaultSettingsBuilderFactory().newInstance();
-        assertNotNull( builder );
+        assertNotNull(builder);
 
         DefaultSettingsBuildingRequest request = new DefaultSettingsBuildingRequest();
-        request.setSystemProperties( System.getProperties() );
-        request.setUserSettingsFile( getSettings( "simple" ) );
+        request.setSystemProperties(System.getProperties());
+        request.setUserSettingsFile(getSettings("simple"));
 
-        SettingsBuildingResult result = builder.build( request );
-        assertNotNull( result );
-        assertNotNull( result.getEffectiveSettings() );
+        SettingsBuildingResult result = builder.build(request);
+        assertNotNull(result);
+        assertNotNull(result.getEffectiveSettings());
     }
-
 }
diff --git a/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java b/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java
index c23ebd2..c92b4af 100644
--- a/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java
+++ b/maven-settings-builder/src/test/java/org/apache/maven/settings/validation/DefaultSettingsValidatorTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.settings.validation;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.settings.validation;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -38,216 +37,194 @@
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
- * @author mkleint
  */
-public class DefaultSettingsValidatorTest
-{
+class DefaultSettingsValidatorTest {
 
     private DefaultSettingsValidator validator;
 
     @BeforeEach
-    public void setUp()
-        throws Exception
-    {
+    void setUp() throws Exception {
         validator = new DefaultSettingsValidator();
     }
 
     @AfterEach
-    public void tearDown()
-        throws Exception
-    {
+    void tearDown() throws Exception {
         validator = null;
     }
 
-    private void assertContains( String msg, String substring )
-    {
-        assertTrue( msg.contains( substring ), "\"" + substring + "\" was not found in: " + msg );
+    private void assertContains(String msg, String substring) {
+        assertTrue(msg.contains(substring), "\"" + substring + "\" was not found in: " + msg);
     }
 
     @Test
-    public void testValidate()
-    {
+    void testValidate() {
         Settings model = new Settings();
         Profile prof = new Profile();
-        prof.setId( "xxx" );
-        model.addProfile( prof );
+        prof.setId("xxx");
+        model.addProfile(prof);
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( model, problems );
-        assertEquals( 0, problems.messages.size() );
+        validator.validate(model, problems);
+        assertEquals(0, problems.messages.size());
 
-        Repository repo = new Repository();
-        prof.addRepository( repo );
+        Repository repo = new Repository(org.apache.maven.api.settings.Repository.newInstance(false));
+        prof.addRepository(repo);
         problems = new SimpleProblemCollector();
-        validator.validate( model, problems );
-        assertEquals( 2, problems.messages.size() );
+        validator.validate(model, problems);
+        assertEquals(2, problems.messages.size());
 
-        repo.setUrl( "http://xxx.xxx.com" );
+        repo.setUrl("http://xxx.xxx.com");
         problems = new SimpleProblemCollector();
-        validator.validate( model, problems );
-        assertEquals( 1, problems.messages.size() );
+        validator.validate(model, problems);
+        assertEquals(1, problems.messages.size());
 
-        repo.setId( "xxx" );
+        repo.setId("xxx");
         problems = new SimpleProblemCollector();
-        validator.validate( model, problems );
-        assertEquals( 0, problems.messages.size() );
+        validator.validate(model, problems);
+        assertEquals(0, problems.messages.size());
     }
 
     @Test
-    public void testValidateMirror()
-        throws Exception
-    {
+    void testValidateMirror() throws Exception {
         Settings settings = new Settings();
         Mirror mirror = new Mirror();
-        mirror.setId( "local" );
-        settings.addMirror( mirror );
+        mirror.setId("local");
+        settings.addMirror(mirror);
         mirror = new Mirror();
-        mirror.setId( "illegal\\:/chars" );
-        mirror.setUrl( "http://void" );
-        mirror.setMirrorOf( "void" );
-        settings.addMirror( mirror );
+        mirror.setId("illegal\\:/chars");
+        mirror.setUrl("http://void");
+        mirror.setMirrorOf("void");
+        settings.addMirror(mirror);
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( settings, problems );
-        assertEquals( 4, problems.messages.size() );
-        assertContains( problems.messages.get( 0 ), "'mirrors.mirror.id' must not be 'local'" );
-        assertContains( problems.messages.get( 1 ), "'mirrors.mirror.url' for local is missing" );
-        assertContains( problems.messages.get( 2 ), "'mirrors.mirror.mirrorOf' for local is missing" );
-        assertContains( problems.messages.get( 3 ), "'mirrors.mirror.id' must not contain any of these characters" );
+        validator.validate(settings, problems);
+        assertEquals(4, problems.messages.size());
+        assertContains(problems.messages.get(0), "'mirrors.mirror.id' must not be 'local'");
+        assertContains(problems.messages.get(1), "'mirrors.mirror.url' for local is missing");
+        assertContains(problems.messages.get(2), "'mirrors.mirror.mirrorOf' for local is missing");
+        assertContains(problems.messages.get(3), "'mirrors.mirror.id' must not contain any of these characters");
     }
 
     @Test
-    public void testValidateRepository()
-        throws Exception
-    {
+    void testValidateRepository() throws Exception {
         Profile profile = new Profile();
         Repository repo = new Repository();
-        repo.setId( "local" );
-        profile.addRepository( repo );
+        repo.setId("local");
+        profile.addRepository(repo);
         repo = new Repository();
-        repo.setId( "illegal\\:/chars" );
-        repo.setUrl( "http://void" );
-        profile.addRepository( repo );
+        repo.setId("illegal\\:/chars");
+        repo.setUrl("http://void");
+        profile.addRepository(repo);
         Settings settings = new Settings();
-        settings.addProfile( profile );
+        settings.addProfile(profile);
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( settings, problems );
-        assertEquals( 3, problems.messages.size() );
-        assertContains( problems.messages.get( 0 ),
-                        "'profiles.profile[default].repositories.repository.id' must not be 'local'" );
-        assertContains( problems.messages.get( 1 ),
-                        "'profiles.profile[default].repositories.repository.url' for local is missing" );
-        assertContains( problems.messages.get( 2 ),
-                        "'profiles.profile[default].repositories.repository.id' must not contain any of these characters" );
+        validator.validate(settings, problems);
+        assertEquals(3, problems.messages.size());
+        assertContains(
+                problems.messages.get(0), "'profiles.profile[default].repositories.repository.id' must not be 'local'");
+        assertContains(
+                problems.messages.get(1),
+                "'profiles.profile[default].repositories.repository.url' for local is missing");
+        assertContains(
+                problems.messages.get(2),
+                "'profiles.profile[default].repositories.repository.id' must not contain any of these characters");
     }
 
     @Test
-    public void testValidateUniqueServerId()
-        throws Exception
-    {
+    void testValidateUniqueServerId() throws Exception {
         Settings settings = new Settings();
         Server server1 = new Server();
-        server1.setId( "test" );
-        settings.addServer( server1 );
+        server1.setId("test");
+        settings.addServer(server1);
         Server server2 = new Server();
-        server2.setId( "test" );
-        settings.addServer( server2 );
+        server2.setId("test");
+        settings.addServer(server2);
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( settings, problems );
-        assertEquals( 1, problems.messages.size() );
-        assertContains( problems.messages.get( 0 ),
-                        "'servers.server.id' must be unique but found duplicate server with id test" );
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(
+                problems.messages.get(0), "'servers.server.id' must be unique but found duplicate server with id test");
     }
 
     @Test
-    public void testValidateUniqueProfileId()
-        throws Exception
-    {
+    void testValidateUniqueProfileId() throws Exception {
         Settings settings = new Settings();
         Profile profile1 = new Profile();
-        profile1.setId( "test" );
-        settings.addProfile( profile1 );
+        profile1.setId("test");
+        settings.addProfile(profile1);
         Profile profile2 = new Profile();
-        profile2.setId( "test" );
-        settings.addProfile( profile2 );
+        profile2.setId("test");
+        settings.addProfile(profile2);
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( settings, problems );
-        assertEquals( 1, problems.messages.size() );
-        assertContains( problems.messages.get( 0 ),
-                        "'profiles.profile.id' must be unique but found duplicate profile with id test" );
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(
+                problems.messages.get(0),
+                "'profiles.profile.id' must be unique but found duplicate profile with id test");
     }
 
     @Test
-    public void testValidateUniqueRepositoryId()
-        throws Exception
-    {
+    void testValidateUniqueRepositoryId() throws Exception {
         Settings settings = new Settings();
         Profile profile = new Profile();
-        profile.setId( "pro" );
-        settings.addProfile( profile );
+        profile.setId("pro");
+        settings.addProfile(profile);
         Repository repo1 = new Repository();
-        repo1.setUrl( "http://apache.org/" );
-        repo1.setId( "test" );
-        profile.addRepository( repo1 );
+        repo1.setUrl("http://apache.org/");
+        repo1.setId("test");
+        profile.addRepository(repo1);
         Repository repo2 = new Repository();
-        repo2.setUrl( "http://apache.org/" );
-        repo2.setId( "test" );
-        profile.addRepository( repo2 );
+        repo2.setUrl("http://apache.org/");
+        repo2.setId("test");
+        profile.addRepository(repo2);
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( settings, problems );
-        assertEquals( 1, problems.messages.size() );
-        assertContains( problems.messages.get( 0 ), "'profiles.profile[pro].repositories.repository.id' must be unique"
-            + " but found duplicate repository with id test" );
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(
+                problems.messages.get(0),
+                "'profiles.profile[pro].repositories.repository.id' must be unique"
+                        + " but found duplicate repository with id test");
     }
 
     @Test
-    public void testValidateUniqueProxyId()
-        throws Exception
-    {
+    void testValidateUniqueProxyId() throws Exception {
         Settings settings = new Settings();
         Proxy proxy = new Proxy();
-        String id = null;
-        proxy.setId( id );
+        String id = "foo";
+        proxy.setId(id);
         proxy.setHost("www.example.com");
-        settings.addProxy( proxy );
-        settings.addProxy( proxy );
+        settings.addProxy(proxy);
+        settings.addProxy(proxy);
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( settings, problems );
-        assertEquals( 1, problems.messages.size() );
-        assertContains( problems.messages.get( 0 ), "'proxies.proxy.id' must be unique"
-            + " but found duplicate proxy with id " + id );
-
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(
+                problems.messages.get(0),
+                "'proxies.proxy.id' must be unique" + " but found duplicate proxy with id " + id);
     }
 
     @Test
-    public void testValidateProxy()
-        throws Exception
-    {
+    void testValidateProxy() throws Exception {
         Settings settings = new Settings();
         Proxy proxy1 = new Proxy();
-        settings.addProxy( proxy1 );
+        settings.addProxy(proxy1);
 
         SimpleProblemCollector problems = new SimpleProblemCollector();
-        validator.validate( settings, problems );
-        assertEquals( 1, problems.messages.size() );
-        assertContains( problems.messages.get( 0 ), "'proxies.proxy.host' for default is missing" );
+        validator.validate(settings, problems);
+        assertEquals(1, problems.messages.size());
+        assertContains(problems.messages.get(0), "'proxies.proxy.host' for default is missing");
     }
 
-    private static class SimpleProblemCollector
-        implements SettingsProblemCollector
-    {
+    private static class SimpleProblemCollector implements SettingsProblemCollector {
 
         public List<String> messages = new ArrayList<>();
 
-        public void add( Severity severity, String message, int line, int column, Exception cause )
-        {
-            messages.add( message );
+        public void add(Severity severity, String message, int line, int column, Exception cause) {
+            messages.add(message);
         }
-
     }
-
 }
diff --git a/maven-settings/pom.xml b/maven-settings/pom.xml
index 4405e5c..c8481dc 100644
--- a/maven-settings/pom.xml
+++ b/maven-settings/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,14 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-settings</artifactId>
@@ -35,8 +33,22 @@
 
   <dependencies>
     <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-settings</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-xml-impl</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
       <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
+      <artifactId>plexus-xml</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.woodstox</groupId>
+      <artifactId>woodstox-core</artifactId>
     </dependency>
   </dependencies>
 
@@ -46,10 +58,64 @@
         <groupId>org.codehaus.modello</groupId>
         <artifactId>modello-maven-plugin</artifactId>
         <configuration>
-          <version>1.2.0</version>
+          <version>2.0.0</version>
+          <basedir>${project.basedir}/../api/maven-api-settings</basedir>
+          <velocityBasedir>${project.basedir}/../src/mdo</velocityBasedir>
           <models>
             <model>src/main/mdo/settings.mdo</model>
           </models>
+          <params>
+            <param>forcedIOModelVersion=1.2.0</param>
+            <param>packageModelV3=org.apache.maven.settings</param>
+            <param>packageModelV4=org.apache.maven.api.settings</param>
+            <param>packageToolV4=org.apache.maven.settings.v4</param>
+          </params>
+        </configuration>
+        <executions>
+          <execution>
+            <id>velocity</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <templates>
+                <template>merger.vm</template>
+                <template>transformer.vm</template>
+                <template>reader-stax.vm</template>
+                <template>writer-stax.vm</template>
+              </templates>
+              <params combine.children="append">
+                <param>locationTracking=true</param>
+              </params>
+            </configuration>
+          </execution>
+          <execution>
+            <id>v3</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <version>1.3.0</version>
+              <templates>
+                <template>model-v3.vm</template>
+              </templates>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <parameter>
+            <excludes>
+              <exclude>org.apache.maven.settings.io.xpp3.SettingsXpp3Reader#contentTransformer</exclude>
+              <exclude>org.apache.maven.settings.RuntimeInfo</exclude>
+              <exclude>org.apache.maven.settings.Settings#setModelEncoding(java.lang.String):METHOD_REMOVED</exclude>
+            </excludes>
+          </parameter>
         </configuration>
       </plugin>
     </plugins>
diff --git a/maven-settings/src/main/java/org/apache/maven/settings/BaseObject.java b/maven-settings/src/main/java/org/apache/maven/settings/BaseObject.java
new file mode 100644
index 0000000..7b66110
--- /dev/null
+++ b/maven-settings/src/main/java/org/apache/maven/settings/BaseObject.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.settings;
+
+import java.io.Serializable;
+
+public abstract class BaseObject implements Serializable, Cloneable {
+    protected transient ChildrenTracking childrenTracking;
+
+    protected Object delegate;
+
+    public BaseObject() {}
+
+    public BaseObject(Object delegate, BaseObject parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent != null ? parent::replace : null;
+    }
+
+    public BaseObject(Object delegate, ChildrenTracking parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent;
+    }
+
+    public Object getDelegate() {
+        return delegate;
+    }
+
+    public void update(Object newDelegate) {
+        if (delegate != newDelegate) {
+            if (childrenTracking != null) {
+                childrenTracking.replace(delegate, newDelegate);
+            }
+            delegate = newDelegate;
+        }
+    }
+
+    protected boolean replace(Object oldDelegate, Object newDelegate) {
+        return false;
+    }
+
+    @FunctionalInterface
+    protected interface ChildrenTracking {
+        boolean replace(Object oldDelegate, Object newDelegate);
+    }
+}
diff --git a/maven-settings/src/main/java/org/apache/maven/settings/RuntimeInfo.java b/maven-settings/src/main/java/org/apache/maven/settings/RuntimeInfo.java
deleted file mode 100644
index 39ffb7e..0000000
--- a/maven-settings/src/main/java/org/apache/maven/settings/RuntimeInfo.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.apache.maven.settings;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import java.io.File;
-
-/**
- * To handle runtime information like local repository or profiles.
- *
- */
-@Deprecated
-public class RuntimeInfo
-{
-    @SuppressWarnings( "checkstyle:constantname" )
-    public static final String userHome = System.getProperty( "user.home" );
-
-    @SuppressWarnings( "checkstyle:constantname" )
-    public static final File userMavenConfigurationHome = new File( userHome, ".m2" );
-
-    public static final File DEFAULT_USER_SETTINGS_FILE = new File( userMavenConfigurationHome, "settings.xml" );
-
-    private File settings;
-
-    public RuntimeInfo()
-    {
-        this.settings = DEFAULT_USER_SETTINGS_FILE;
-    }
-
-    public RuntimeInfo( File settings )
-    {
-        this.settings = settings;
-    }
-
-    public File getFile()
-    {
-        return settings;
-    }
-}
diff --git a/maven-settings/src/main/java/org/apache/maven/settings/io/xpp3/SettingsXpp3Reader.java b/maven-settings/src/main/java/org/apache/maven/settings/io/xpp3/SettingsXpp3Reader.java
new file mode 100644
index 0000000..14f0674
--- /dev/null
+++ b/maven-settings/src/main/java/org/apache/maven/settings/io/xpp3/SettingsXpp3Reader.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.settings.io.xpp3;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.v4.SettingsStaxReader;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * @deprecated Maven 3 compatibility - please use {@code org.apache.maven.api.services.xml.SettingsXmlFactory} from {@code maven-api-core}
+ * or {@link SettingsStaxReader}
+ */
+@Deprecated
+public class SettingsXpp3Reader {
+
+    private final SettingsStaxReader delegate;
+
+    public SettingsXpp3Reader() {
+        delegate = new SettingsStaxReader();
+    }
+
+    public SettingsXpp3Reader(ContentTransformer contentTransformer) {
+        delegate = new SettingsStaxReader(contentTransformer::transform);
+    }
+
+    /**
+     * Returns the state of the "add default entities" flag.
+     *
+     * @return boolean
+     */
+    public boolean getAddDefaultEntities() {
+        return delegate.getAddDefaultEntities();
+    }
+
+    /**
+     * Sets the state of the "add default entities" flag.
+     *
+     * @param addDefaultEntities a addDefaultEntities object.
+     */
+    public void setAddDefaultEntities(boolean addDefaultEntities) {
+        delegate.setAddDefaultEntities(addDefaultEntities);
+    }
+
+    /**
+     * @param reader a reader object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Settings
+     */
+    public Settings read(Reader reader, boolean strict) throws IOException, XmlPullParserException {
+        try {
+            return new Settings(delegate.read(reader, strict, null));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * @param reader a reader object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Model
+     */
+    public Settings read(Reader reader) throws IOException, XmlPullParserException {
+        try {
+            return new Settings(delegate.read(reader));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Settings
+     */
+    public Settings read(InputStream in, boolean strict) throws IOException, XmlPullParserException {
+        try {
+            return new Settings(delegate.read(in, strict, null));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Settings
+     */
+    public Settings read(InputStream in) throws IOException, XmlPullParserException {
+        try {
+            return new Settings(delegate.read(in));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    /**
+     * Method read.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XmlPullParserException XmlPullParserException if
+     * any.
+     * @return Settings
+     */
+    public Settings read(XMLStreamReader parser, boolean strict) throws IOException, XmlPullParserException {
+        try {
+            return new Settings(delegate.read(parser, strict, null));
+        } catch (XMLStreamException e) {
+            throw new XmlPullParserException(e.getMessage(), null, e);
+        }
+    }
+
+    public interface ContentTransformer {
+        /**
+         * Interpolate the value read from the xpp3 document
+         * @param source The source value
+         * @param fieldName A description of the field being interpolated. The implementation may use this to
+         *                           log stuff.
+         * @return The interpolated value.
+         */
+        String transform(String source, String fieldName);
+    }
+}
diff --git a/maven-settings/src/main/java/org/apache/maven/settings/io/xpp3/SettingsXpp3Writer.java b/maven-settings/src/main/java/org/apache/maven/settings/io/xpp3/SettingsXpp3Writer.java
new file mode 100644
index 0000000..890c7ec
--- /dev/null
+++ b/maven-settings/src/main/java/org/apache/maven/settings/io/xpp3/SettingsXpp3Writer.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.settings.io.xpp3;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+
+import org.apache.maven.settings.Settings;
+import org.apache.maven.settings.v4.SettingsStaxWriter;
+
+/**
+ * @deprecated Maven 3 compatibility - please use {@code org.apache.maven.api.services.xml.SettingsXmlFactory} from {@code maven-api-core}
+ * or {@link SettingsStaxWriter}
+ */
+@Deprecated
+public class SettingsXpp3Writer {
+
+    private final SettingsStaxWriter delegate;
+
+    public SettingsXpp3Writer() {
+        delegate = new SettingsStaxWriter();
+        delegate.setAddLocationInformation(false);
+    }
+    /**
+     * Method setFileComment.
+     *
+     * @param fileComment a fileComment object.
+     */
+    public void setFileComment(String fileComment) {
+        delegate.setFileComment(fileComment);
+    }
+
+    /**
+     * Method write.
+     *
+     * @param writer a writer object.
+     * @param settings a settings object.
+     * @throws IOException java.io.IOException if any.
+     */
+    public void write(Writer writer, Settings settings) throws IOException {
+        try {
+            delegate.write(writer, settings.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+
+    /**
+     * Method write.
+     *
+     * @param stream a stream object.
+     * @param settings a settings object.
+     * @throws IOException java.io.IOException if any.
+     */
+    public void write(OutputStream stream, Settings settings) throws IOException {
+        try {
+            delegate.write(stream, settings.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException(e);
+        }
+    }
+}
diff --git a/maven-settings/src/main/mdo/settings.mdo b/maven-settings/src/main/mdo/settings.mdo
deleted file mode 100644
index 4500560..0000000
--- a/maven-settings/src/main/mdo/settings.mdo
+++ /dev/null
@@ -1,1086 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
--->
-
-<model xmlns="http://codehaus-plexus.github.io/MODELLO/1.4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/1.4.0 http://codehaus-plexus.github.io/modello/xsd/modello-1.4.0.xsd"
-  xml.namespace="http://maven.apache.org/SETTINGS/${version}"
-  xml.schemaLocation="http://maven.apache.org/xsd/settings-${version}.xsd">
-  <id>settings</id>
-  <name>Settings</name>
-  <description>
-    <![CDATA[
-    <p>This is a reference for the user-specific configuration for Maven.</p>
-    <p>Includes things that should not be distributed with the pom.xml file, such as developer identity, along with
-    local settings, like proxy information.</p>
-    <p>The default location for the settings file is <i>~/.m2/settings.xml</i></p>
-    ]]>
-  </description>
-  <defaults>
-    <default>
-      <key>package</key>
-      <value>org.apache.maven.settings</value>
-    </default>
-  </defaults>
-  <classes>
-    <class java.clone="deep">
-      <name>TrackableBase</name>
-      <version>1.0.0+</version>
-      <description>
-        common base class that contains code to track the source for
-        this instance (USER|GLOBAL)
-      </description>
-      <codeSegments>
-        <codeSegment>
-          <version>1.0.0+</version>
-          <code>
-            <![CDATA[
-    public static final String USER_LEVEL = "user-level";
-    public static final String GLOBAL_LEVEL = "global-level";
-
-    private String sourceLevel = USER_LEVEL;
-    private boolean sourceLevelSet = false;
-
-    public void setSourceLevel( String sourceLevel )
-    {
-        if ( sourceLevelSet )
-        {
-            throw new IllegalStateException( "Cannot reset sourceLevel attribute; it is already set to: " + sourceLevel );
-        }
-        else if ( !( USER_LEVEL.equals( sourceLevel ) || GLOBAL_LEVEL.equals( sourceLevel ) ) )
-        {
-            throw new IllegalArgumentException( "sourceLevel must be one of: {" + USER_LEVEL + "," + GLOBAL_LEVEL + "}" );
-        }
-        else
-        {
-            this.sourceLevel = sourceLevel;
-            this.sourceLevelSet = true;
-        }
-    }
-
-    public String getSourceLevel()
-    {
-        return sourceLevel;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <class>
-      <name>IdentifiableBase</name>
-      <superClass>TrackableBase</superClass>
-      <version>1.0.0+</version>
-      <description>
-        <![CDATA[
-        Base class for <code>Mirror</code>, <code>Profile</code>, <code>Proxy</code> and <code>Server</code>.
-        ]]></description>
-      <fields>
-        <field>
-          <name>id</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <defaultValue>default</defaultValue>
-          <required>true</required>
-        </field>
-      </fields>
-    </class>
-    <class rootElement="true" xml.tagName="settings">
-      <name>Settings</name>
-      <version>1.0.0+</version>
-      <superClass>TrackableBase</superClass>
-      <description>
-        Root element of the user configuration file.
-      </description>
-      <fields>
-        <field>
-          <name>localRepository</name>
-          <version>1.0.0+</version>
-          <required>true</required>
-          <description>
-            <![CDATA[
-            The local repository.<br><b>Default value is:</b> <code>${user.home}/.m2/repository</code>
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>interactiveMode</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Whether Maven should attempt to interact with the user for input.
-            ]]>
-          </description>
-          <type>boolean</type>
-          <defaultValue>true</defaultValue>
-        </field>
-        <field>
-          <name>usePluginRegistry</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Whether Maven should use the plugin-registry.xml file to manage plugin versions.
-            ]]>
-          </description>
-          <type>boolean</type>
-          <defaultValue>false</defaultValue>
-        </field>
-        <!-- [JC] Not ready to use yet, so I'm making if unavailable for now. -->
-        <!-- field>
-          <name>passwordStore</name>
-          <version>1.0.0+</version>
-          <required>false</required>
-          <description><![CDATA[The keystore used to store passwords.]]></description>
-          <type>String</type>
-          </field -->
-        <field>
-          <name>offline</name>
-          <version>1.0.0+</version>
-          <required>false</required>
-          <description>
-            <![CDATA[
-            Indicate whether maven should operate in offline mode full-time.
-            ]]>
-          </description>
-          <type>boolean</type>
-          <defaultValue>false</defaultValue>
-        </field>
-        <!-- [JC] Not ready to use yet, so I'm making if unavailable for now. -->
-        <!-- field>
-          <name>jdks</name>
-          <version>1.0.0+</version>
-          <description><![CDATA[
-          Configuration for different java environment profiles. One good use
-          for this might be to configure both JDK 1.4 and JDK 1.5 to work with
-          maven. Profiles will allow switching of entire java environments
-          based on the profile id, either in the defaults section below, or on
-          the command line.
-          ]]></description>
-          <association>
-          <type>Jdk</type>
-          <multiplicity>*</multiplicity>
-          </association>
-          </field -->
-        <field xdoc.separator="blank">
-          <name>proxies</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Configuration for different proxy profiles. Multiple proxy profiles
-            might come in handy for anyone working from a notebook or other
-            mobile platform, to enable easy switching of entire proxy
-            configurations by simply specifying the profile id, again either from
-            the command line or from the defaults section below.
-            ]]>
-          </description>
-          <association>
-            <type>Proxy</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>servers</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Configuration of server-specific settings, mainly authentication
-            method. This allows configuration of authentication on a per-server
-            basis.
-            ]]>
-          </description>
-          <association>
-            <type>Server</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>mirrors</name>
-          <version>1.0.0+</version>
-          <description>
-            Configuration of download mirrors for repositories.
-          </description>
-          <association>
-            <type>Mirror</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>profiles</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Configuration of build profiles for adjusting the build
-            according to environmental parameters.
-            ]]>
-          </description>
-          <association>
-            <type>Profile</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>activeProfiles</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            List of manually-activated build profiles, specified in the order in which
-            they should be applied.
-            ]]>
-          </description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>pluginGroups</name>
-          <version>1.0.0+</version>
-          <description>
-            List of groupIds to search for a plugin when that plugin
-            groupId is not explicitly provided.
-          </description>
-          <association>
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>1.0.0+</version>
-          <code>
-            <![CDATA[
-    public Boolean getInteractiveMode()
-    {
-        return Boolean.valueOf( isInteractiveMode() );
-    }
-
-    private Proxy activeProxy;
-
-    /**
-     * Reset the <code>activeProxy</code> field to <code>null</code>
-     */
-    public void flushActiveProxy()
-    {
-        this.activeProxy = null;
-    }
-
-    /**
-     * @return the first active proxy
-     */
-    public synchronized Proxy getActiveProxy()
-    {
-        if ( activeProxy == null )
-        {
-            java.util.List<Proxy> proxies = getProxies();
-            if ( proxies != null && !proxies.isEmpty() )
-            {
-                for ( Proxy proxy : proxies )
-                {
-                    if ( proxy.isActive() )
-                    {
-                        activeProxy = proxy;
-                        break;
-                    }
-                }
-            }
-        }
-
-        return activeProxy;
-    }
-
-    public Server getServer( String serverId )
-    {
-        Server match = null;
-
-        java.util.List<Server> servers = getServers();
-        if ( servers != null && serverId != null )
-        {
-            for ( Server server : servers )
-            {
-                if ( serverId.equals( server.getId() ) )
-                {
-                    match = server;
-                    break;
-                }
-            }
-        }
-
-        return match;
-    }
-
-    @Deprecated
-    public Mirror getMirrorOf( String repositoryId )
-    {
-        Mirror match = null;
-
-        java.util.List<Mirror> mirrors = getMirrors();
-        if ( mirrors != null && repositoryId != null )
-        {
-            for ( Mirror mirror : mirrors )
-            {
-                if ( repositoryId.equals( mirror.getMirrorOf() ) )
-                {
-                    match = mirror;
-                    break;
-                }
-            }
-        }
-
-        return match;
-    }
-
-    private java.util.Map<String, Profile> profileMap;
-
-    /**
-     * Reset the <code>profileMap</code> field to <code>null</code>
-     */
-    public void flushProfileMap()
-    {
-        this.profileMap = null;
-    }
-
-    /**
-     * @return a Map of profiles field with <code>Profile#getId()</code> as key
-     * @see org.apache.maven.settings.Profile#getId()
-     */
-    public java.util.Map<String, Profile> getProfilesAsMap()
-    {
-        if ( profileMap == null )
-        {
-            profileMap = new java.util.LinkedHashMap<String, Profile>();
-
-            if ( getProfiles() != null )
-            {
-                for ( Profile profile : getProfiles() )
-                {
-                    profileMap.put( profile.getId(), profile );
-                }
-            }
-        }
-
-        return profileMap;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <!-- @todo: is any of this too CVS specific? Investigate other SCMs -->
-    <!-- [JC] Commenting out until we're ready to use it... -->
-    <!-- class>
-      <name>Jdk</name>
-      <version>1.0.0+</version>
-      <superClass>TrackableBase</superClass>
-      <description><![CDATA[Describes one Java environment]]></description>
-      <fields>
-      <field>
-      <name>active</name>
-      <version>1.0.0+</version>
-      <required>false</required>
-      <defaultValue>false</defaultValue>
-      <description><![CDATA[Whether this JDK is the active one.]]></description>
-      <type>boolean</type>
-      </field>
-      <field>
-      <name>version</name>
-      <version>1.0.0+</version>
-      <required>true</required>
-      <description><![CDATA[The JDK major version (eg. '1.4').]]></description>
-      <type>String</type>
-      </field>
-      <field>
-      <name>javaHome</name>
-      <version>1.0.0+</version>
-      <required>true</required>
-      <description><![CDATA[The JDK home.]]></description>
-      <type>String</type>
-      </field>
-      </fields>
-      </class -->
-    <class>
-      <name>Proxy</name>
-      <version>1.0.0+</version>
-      <superClass>IdentifiableBase</superClass>
-      <description>
-        <![CDATA[
-        The <code>&lt;proxy&gt;</code> element contains informations required to a proxy settings.
-        ]]></description>
-      <fields>
-        <field>
-          <name>active</name>
-          <version>1.0.0+</version>
-          <required>false</required>
-          <defaultValue>true</defaultValue>
-          <description>
-            <![CDATA[
-            Whether this proxy configuration is the active one.
-            ]]>
-          </description>
-          <type>boolean</type>
-        </field>
-        <field>
-          <name>protocol</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The proxy protocol.
-            ]]>
-          </description>
-          <type>String</type>
-          <defaultValue>http</defaultValue>
-        </field>
-        <field>
-          <name>username</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The proxy user.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>password</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The proxy password.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>port</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The proxy port.
-            ]]>
-          </description>
-          <type>int</type>
-          <defaultValue>8080</defaultValue>
-        </field>
-        <field>
-          <name>host</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The proxy host.
-            ]]>
-          </description>
-          <type>String</type>
-          <required>true</required>
-        </field>
-        <field>
-          <name>nonProxyHosts</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The list of non-proxied hosts (delimited by |).
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-    <class>
-      <name>Server</name>
-      <version>1.0.0+</version>
-      <superClass>IdentifiableBase</superClass>
-      <description>
-        <![CDATA[
-        The <code>&lt;server&gt;</code> element contains informations required to a server settings.
-        ]]></description>
-      <fields>
-        <field>
-          <name>username</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The username used to authenticate.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>password</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The password used in conjunction with the username to authenticate.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>privateKey</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The private key location used to authenticate.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>passphrase</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The passphrase used in conjunction with the privateKey to authenticate.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>filePermissions</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The permissions for files when they are created.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>directoryPermissions</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The permissions for directories when they are created.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>configuration</name>
-          <type>DOM</type>
-          <description>
-            <![CDATA[
-            Extra configuration for the transport layer.
-            ]]>
-          </description>
-        </field>
-      </fields>
-    </class>
-    <class>
-      <name>Mirror</name>
-      <version>1.0.0+</version>
-      <superClass>IdentifiableBase</superClass>
-      <description>
-        A download mirror for a given repository.
-      </description>
-      <fields>
-        <field>
-          <name>mirrorOf</name>
-          <required>true</required>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The server ID of the repository being mirrored, e.g.,
-            "central". This MUST NOT match the mirror id.
-          </description>
-        </field>
-        <field>
-          <name>name</name>
-          <required>false</required>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The optional name that describes the mirror.
-          </description>
-        </field>
-        <field>
-          <name>url</name>
-          <required>true</required>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>The URL of the mirror repository.</description>
-        </field>
-        <field>
-          <name>layout</name>
-          <version>1.1.0+</version>
-          <type>String</type>
-          <defaultValue>default</defaultValue>
-          <description>The layout of the mirror repository. Since Maven 3.</description>
-        </field>
-        <field>
-          <name>mirrorOfLayouts</name>
-          <version>1.1.0+</version>
-          <type>String</type>
-          <defaultValue>default,legacy</defaultValue>
-          <description>
-            The layouts of repositories being mirrored. This value can be used to restrict the usage
-            of the mirror to repositories with a matching layout (apart from a matching id). Since Maven 3.
-          </description>
-        </field>
-        <field>
-          <name>blocked</name>
-          <version>1.2.0+</version>
-          <type>boolean</type>
-          <defaultValue>false</defaultValue>
-          <description>
-            Whether this mirror should be blocked from any download request but fail the download process, explaining why.
-          </description>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>1.0.0+</version>
-          <code>
-            <![CDATA[
-
-    public String toString()
-    {
-        StringBuilder sb = new StringBuilder( 128 );
-        sb.append( "Mirror[" );
-        sb.append( "id=" ).append( this.getId() );
-        sb.append( ",mirrorOf=" ).append( mirrorOf );
-        sb.append( ",url=" ).append( this.url );
-        sb.append( ",name=" ).append( this.name );
-        if ( isBlocked() )
-        {
-            sb.append( ",blocked" );
-        }
-        sb.append( "]" );
-        return sb.toString();
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-    <!-- Profile support -->
-    <class>
-      <name>Profile</name>
-      <version>1.0.0+</version>
-      <superClass>IdentifiableBase</superClass>
-      <description>
-        <![CDATA[
-        Modifications to the build process which is keyed on some
-        sort of environmental parameter.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>activation</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The conditional logic which will automatically
-            trigger the inclusion of this profile.
-            ]]>
-          </description>
-          <association>
-            <type>Activation</type>
-          </association>
-        </field>
-        <field>
-          <name>properties</name>
-          <description>
-            <![CDATA[
-            Extended configuration specific to this profile goes here.
-            Contents take the form of
-            <code>&lt;property.name&gt;property.value&lt;/property.name&gt;</code>
-            ]]>
-          </description>
-          <type>Properties</type>
-          <association xml.mapStyle="inline">
-            <type>String</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field xdoc.separator="blank">
-          <name>repositories</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The lists of the remote repositories.
-            ]]>
-          </description>
-          <association>
-            <type>Repository</type>
-            <multiplicity>*</multiplicity>
-          </association>
-        </field>
-        <field>
-          <name>pluginRepositories</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The lists of the remote repositories for discovering plugins.
-            ]]>
-          </description>
-          <association>
-            <type>Repository</type>
-            <multiplicity>*</multiplicity>
-          </association>
-          <comment>
-            <![CDATA[
-            This may be removed or relocated in the near
-            future. It is undecided whether plugins really need a remote
-            repository set of their own.
-            ]]>
-          </comment>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>Activation</name>
-      <version>1.0.0+</version>
-      <description>
-        <![CDATA[
-        The conditions within the build runtime environment which will trigger
-        the automatic inclusion of the parent build profile.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>activeByDefault</name>
-          <version>1.0.0+</version>
-          <type>boolean</type>
-          <description>
-            Flag specifying whether this profile is active as a default.
-          </description>
-        </field>
-        <field>
-          <name>jdk</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            <![CDATA[
-            Specifies that this profile will be activated when a matching JDK is detected.
-            ]]>
-          </description>
-        </field>
-        <field>
-          <name>os</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Specifies that this profile will be activated when matching OS attributes are detected.
-            ]]>
-          </description>
-          <association>
-            <type>ActivationOS</type>
-          </association>
-        </field>
-        <field>
-          <name>property</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Specifies that this profile will be activated when this System property is specified.
-            ]]>
-          </description>
-          <association>
-            <type>ActivationProperty</type>
-          </association>
-        </field>
-        <field>
-          <name>file</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Specifies that this profile will be activated based on existence of a file.
-            ]]>
-          </description>
-          <association>
-            <type>ActivationFile</type>
-          </association>
-        </field>
-      </fields>
-    </class>
-
-    <!-- TODO: reproduced from maven-model/maven.mdo, instead should inherit code and link to external docs -->
-    <class java.clone="deep">
-      <name>RepositoryBase</name>
-      <version>1.0.0+</version>
-      <description>
-        <![CDATA[
-        Repository contains the information needed
-        for establishing connections with remote repository
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>id</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            A unique identifier for a repository.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>name</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            Human readable name of the repository.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>url</name>
-          <version>1.0.0+</version>
-          <description>
-            <![CDATA[
-            The url of the repository.
-            ]]>
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>layout</name>
-          <version>1.0.0+</version>
-          <description>
-            The type of layout this repository uses for locating and
-            storing artifacts - can be "legacy" or "default".
-          </description>
-          <type>String</type>
-          <defaultValue>default</defaultValue>
-        </field>
-      </fields>
-      <codeSegments>
-        <codeSegment>
-          <version>1.0.0+</version>
-          <code>
-            <![CDATA[
-    /**
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
-    public boolean equals( Object obj )
-    {
-        RepositoryBase other =  (RepositoryBase) obj;
-
-        boolean retValue = false;
-
-        if ( id != null )
-        {
-            retValue = id.equals( other.id );
-        }
-
-        return retValue;
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-
-    <class>
-      <name>Repository</name>
-      <superClass>RepositoryBase</superClass>
-      <version>1.0.0+</version>
-      <description>
-        Repository contains the information needed for establishing
-        connections with remote repository
-      </description>
-      <fields>
-        <field>
-          <name>releases</name>
-          <version>1.0.0+</version>
-          <description>
-            How to handle downloading of releases from this repository
-          </description>
-          <association>
-            <type>RepositoryPolicy</type>
-          </association>
-        </field>
-        <field>
-          <name>snapshots</name>
-          <version>1.0.0+</version>
-          <description>
-            How to handle downloading of snapshots from this repository
-          </description>
-          <association>
-            <type>RepositoryPolicy</type>
-          </association>
-        </field>
-      </fields>
-      <!-- prevent Modello generation of an incorrect equals method. Could be avoided by using <identity/> tags to mark ID as the only identity field -->
-      <codeSegments>
-        <codeSegment>
-          <version>1.0.0+</version>
-          <code>
-            <![CDATA[
-    /**
-     * @see org.apache.maven.settings.RepositoryBase#equals(java.lang.Object)
-     */
-    public boolean equals( Object obj )
-    {
-        return super.equals( obj );
-    }
-            ]]>
-          </code>
-        </codeSegment>
-      </codeSegments>
-    </class>
-
-    <class java.clone="deep">
-      <name>RepositoryPolicy</name>
-      <version>1.0.0+</version>
-      <description>Download policy</description>
-      <fields>
-        <field>
-          <name>enabled</name>
-          <version>1.0.0+</version>
-          <description>
-            Whether to use this repository for downloading this type of
-            artifact.
-          </description>
-          <type>boolean</type>
-          <defaultValue>true</defaultValue>
-        </field>
-        <field>
-          <name>updatePolicy</name>
-          <version>1.0.0+</version>
-          <description>
-            The frequency for downloading updates - can be "always",
-            "daily" (default), "interval:XXX" (in minutes) or "never"
-            (only if it doesn't exist locally).
-          </description>
-          <type>String</type>
-        </field>
-        <field>
-          <name>checksumPolicy</name>
-          <version>1.0.0+</version>
-          <description>
-            What to do when verification of an artifact checksum fails. Valid values are "fail" (default for Maven 4 and
-            above), "warn" (default for Maven 2 and 3) or "ignore".
-          </description>
-          <type>String</type>
-        </field>
-      </fields>
-    </class>
-
-    <class java.clone="deep">
-      <name>ActivationProperty</name>
-      <version>1.0.0+</version>
-      <description>
-        <![CDATA[
-        This is the property specification used to activate a profile. If the value field is empty,
-        then the existence of the named property will activate the profile, otherwise it does a case-sensitive
-        match against the property value as well.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <required>true</required>
-          <description>
-            The name of the property to be used to activate a profile.
-          </description>
-        </field>
-        <field>
-          <name>value</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The value of the property to be used to activate a profile.
-          </description>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>ActivationOS</name>
-      <version>1.0.0+</version>
-      <description>
-        <![CDATA[
-        This is an activator which will detect an operating system's attributes in order to activate
-        its profile.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>name</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The name of the OS to be used to activate a profile.
-          </description>
-        </field>
-        <field>
-          <name>family</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The general family of the OS to be used to activate a
-            profile (e.g. 'windows')
-          </description>
-        </field>
-        <field>
-          <name>arch</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The architecture of the OS to be used to activate a profile.
-          </description>
-        </field>
-        <field>
-          <name>version</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The version of the OS to be used to activate a profile.
-          </description>
-        </field>
-      </fields>
-    </class>
-    <class java.clone="deep">
-      <name>ActivationFile</name>
-      <version>1.0.0+</version>
-      <description>
-        <![CDATA[
-        This is the file specification used to activate a profile. The missing value will be a the location
-        of a file that needs to exist, and if it doesn't the profile must run.  On the other hand exists will test
-        for the existence of the file and if it is there will run the profile.
-        ]]>
-      </description>
-      <fields>
-        <field>
-          <name>missing</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The name of the file that should be missing to activate a
-            profile.
-          </description>
-        </field>
-        <field>
-          <name>exists</name>
-          <version>1.0.0+</version>
-          <type>String</type>
-          <description>
-            The name of the file that should exist to activate a profile.
-          </description>
-        </field>
-      </fields>
-    </class>
-    <!-- /BuildProfile support -->
-  </classes>
-</model>
diff --git a/maven-settings/src/site/apt/index.apt b/maven-settings/src/site/apt/index.apt
index 2b42ccd..95193e9 100644
--- a/maven-settings/src/site/apt/index.apt
+++ b/maven-settings/src/site/apt/index.apt
@@ -25,11 +25,14 @@
 
 Maven Settings Model
 
- This is strictly the model for Maven settings.
+ This is the model for Maven settings in <<<org.apache.maven.settings>>> package,
+ delegating content to {{{../api/maven-api-settings/index.html}Maven 4 API immutable settings}}. All the effective model
+ building logic from multiple settings files is done in {{{../maven-settings-builder/}Maven Settings Builder}}.
 
  The following are generated from this model:
 
-   * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser
+   * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser, <<<ToAPiV3()>>> and <<<ToApiV4()>>> transformers, and <<<v4>>> package
+     for Merger and v4 Reader and Writers for the Xpp3 XML parser,
 
    * A {{{./settings.html}Descriptor Reference}}
 
diff --git a/maven-settings/src/site/site.xml b/maven-settings/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-settings/src/site/site.xml
+++ b/maven-settings/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml
index b109f9e..25c58a8 100644
--- a/maven-slf4j-provider/pom.xml
+++ b/maven-slf4j-provider/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,23 +17,20 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-slf4j-provider</artifactId>
 
   <name>Maven SLF4J Simple Provider</name>
-  <description>
-    Maven SLF4J provider based on SLF4J's simple provider, extended to support Maven styled colors
-    for levels and stacktraces rendering.
-  </description>
+  <description>Maven SLF4J provider based on SLF4J's simple provider, extended to support Maven styled colors
+    for levels and stacktraces rendering.</description>
 
   <dependencies>
     <dependency>
@@ -42,12 +38,16 @@
       <artifactId>slf4j-api</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.maven.shared</groupId>
-      <artifactId>maven-shared-utils</artifactId>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-slf4j-wrapper</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
-      <artifactId>maven-slf4j-wrapper</artifactId>
+      <artifactId>maven-api-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-embedder</artifactId>
     </dependency>
   </dependencies>
 
@@ -83,14 +83,13 @@
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>build-helper-maven-plugin</artifactId>
-        <version>1.12</version>
         <executions>
           <execution>
             <id>add-slf4j-simple</id>
-            <phase>generate-sources</phase>
             <goals>
               <goal>add-source</goal>
             </goals>
+            <phase>generate-sources</phase>
             <configuration>
               <sources>
                 <source>${project.build.directory}/generated-sources/slf4j-simple</source>
diff --git a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenFailOnSeverityLogger.java b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenFailOnSeverityLogger.java
index 12c6cc2..c277be6 100644
--- a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenFailOnSeverityLogger.java
+++ b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenFailOnSeverityLogger.java
@@ -1,5 +1,3 @@
-package org.slf4j.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.slf4j.impl;
 
 import org.apache.maven.logwrapper.LogLevelRecorder;
 import org.slf4j.event.Level;
@@ -26,13 +25,11 @@
  * A proxy which enhances the MavenSimpleLogger with functionality to track whether a logging threshold is hit.
  * Currently only support WARN and ERROR states, since it's been used for the --fail-on-severity flag.
  */
-public class MavenFailOnSeverityLogger extends MavenSimpleLogger
-{
+public class MavenFailOnSeverityLogger extends MavenSimpleLogger {
     private final LogLevelRecorder logLevelRecorder;
 
-    MavenFailOnSeverityLogger( String name, LogLevelRecorder logLevelRecorder )
-    {
-        super( name );
+    MavenFailOnSeverityLogger(String name, LogLevelRecorder logLevelRecorder) {
+        super(name);
         this.logLevelRecorder = logLevelRecorder;
     }
 
@@ -41,10 +38,9 @@
      * according to the format outlined above.
      */
     @Override
-    public void warn( String msg )
-    {
-        super.warn( msg );
-        logLevelRecorder.record( Level.WARN );
+    public void warn(String msg) {
+        super.warn(msg);
+        logLevelRecorder.record(Level.WARN);
     }
 
     /**
@@ -52,10 +48,9 @@
      * WARN according to the format outlined above.
      */
     @Override
-    public void warn( String format, Object arg )
-    {
-        super.warn( format, arg );
-        logLevelRecorder.record( Level.WARN );
+    public void warn(String format, Object arg) {
+        super.warn(format, arg);
+        logLevelRecorder.record(Level.WARN);
     }
 
     /**
@@ -63,10 +58,9 @@
      * WARN according to the format outlined above.
      */
     @Override
-    public void warn( String format, Object arg1, Object arg2 )
-    {
-        super.warn( format, arg1, arg2 );
-        logLevelRecorder.record( Level.WARN );
+    public void warn(String format, Object arg1, Object arg2) {
+        super.warn(format, arg1, arg2);
+        logLevelRecorder.record(Level.WARN);
     }
 
     /**
@@ -74,18 +68,16 @@
      * WARN according to the format outlined above.
      */
     @Override
-    public void warn( String format, Object... argArray )
-    {
-        super.warn( format, argArray );
-        logLevelRecorder.record( Level.WARN );
+    public void warn(String format, Object... argArray) {
+        super.warn(format, argArray);
+        logLevelRecorder.record(Level.WARN);
     }
 
     /** Log a message of level WARN, including an exception. */
     @Override
-    public void warn( String msg, Throwable t )
-    {
-        super.warn( msg, t );
-        logLevelRecorder.record( Level.WARN );
+    public void warn(String msg, Throwable t) {
+        super.warn(msg, t);
+        logLevelRecorder.record(Level.WARN);
     }
 
     /**
@@ -93,10 +85,9 @@
      * according to the format outlined above.
      */
     @Override
-    public void error( String msg )
-    {
-        super.error( msg );
-        logLevelRecorder.record( Level.ERROR );
+    public void error(String msg) {
+        super.error(msg);
+        logLevelRecorder.record(Level.ERROR);
     }
 
     /**
@@ -104,10 +95,9 @@
      * ERROR according to the format outlined above.
      */
     @Override
-    public void error( String format, Object arg )
-    {
-        super.error( format, arg );
-        logLevelRecorder.record( Level.ERROR );
+    public void error(String format, Object arg) {
+        super.error(format, arg);
+        logLevelRecorder.record(Level.ERROR);
     }
 
     /**
@@ -115,10 +105,9 @@
      * ERROR according to the format outlined above.
      */
     @Override
-    public void error( String format, Object arg1, Object arg2 )
-    {
-        super.error( format, arg1, arg2 );
-        logLevelRecorder.record( Level.ERROR );
+    public void error(String format, Object arg1, Object arg2) {
+        super.error(format, arg1, arg2);
+        logLevelRecorder.record(Level.ERROR);
     }
 
     /**
@@ -126,17 +115,15 @@
      * ERROR according to the format outlined above.
      */
     @Override
-    public void error( String format, Object... argArray )
-    {
-        super.error( format, argArray );
-        logLevelRecorder.record( Level.ERROR );
+    public void error(String format, Object... argArray) {
+        super.error(format, argArray);
+        logLevelRecorder.record(Level.ERROR);
     }
 
     /** Log a message of level ERROR, including an exception. */
     @Override
-    public void error( String msg, Throwable t )
-    {
-        super.error( msg, t );
-        logLevelRecorder.record( Level.ERROR );
+    public void error(String msg, Throwable t) {
+        super.error(msg, t);
+        logLevelRecorder.record(Level.ERROR);
     }
 }
diff --git a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenLoggerFactory.java b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenLoggerFactory.java
index 7ef126d..16cf4d9 100644
--- a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenLoggerFactory.java
+++ b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenLoggerFactory.java
@@ -1,5 +1,3 @@
-package org.slf4j.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,65 +16,47 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.slf4j.impl;
+
+import java.util.Optional;
 
 import org.apache.maven.logwrapper.LogLevelRecorder;
 import org.apache.maven.logwrapper.MavenSlf4jWrapperFactory;
 import org.slf4j.Logger;
 
-import java.util.Optional;
-
 /**
  * LogFactory for Maven which can create a simple logger or one which, if set, fails the build on a severity threshold.
  */
-public class MavenLoggerFactory extends SimpleLoggerFactory implements MavenSlf4jWrapperFactory
-{
+public class MavenLoggerFactory extends SimpleLoggerFactory implements MavenSlf4jWrapperFactory {
     private LogLevelRecorder logLevelRecorder = null;
 
     @Override
-    public void setLogLevelRecorder( LogLevelRecorder logLevelRecorder )
-    {
-        if ( this.logLevelRecorder != null )
-        {
-            throw new IllegalStateException( "LogLevelRecorder has already been set." );
+    public void setLogLevelRecorder(LogLevelRecorder logLevelRecorder) {
+        if (this.logLevelRecorder != null) {
+            throw new IllegalStateException("LogLevelRecorder has already been set.");
         }
 
         this.logLevelRecorder = logLevelRecorder;
     }
 
     @Override
-    public Optional<LogLevelRecorder> getLogLevelRecorder()
-    {
-        return Optional.ofNullable( logLevelRecorder );
+    public Optional<LogLevelRecorder> getLogLevelRecorder() {
+        return Optional.ofNullable(logLevelRecorder);
     }
 
     /**
      * Return an appropriate {@link MavenSimpleLogger} instance by name.
      */
     @Override
-    public Logger getLogger( String name )
-    {
-        Logger simpleLogger = loggerMap.get( name );
-        if ( simpleLogger != null )
-        {
-            return simpleLogger;
-        }
-        else
-        {
-            Logger newInstance = getNewLoggingInstance( name );
-            Logger oldInstance = loggerMap.putIfAbsent( name, newInstance );
-            return oldInstance == null ? newInstance : oldInstance;
-        }
+    public Logger getLogger(String name) {
+        return loggerMap.computeIfAbsent(name, this::getNewLoggingInstance);
     }
 
-    private Logger getNewLoggingInstance( String name )
-    {
-        if ( logLevelRecorder == null )
-        {
-            return new MavenSimpleLogger( name );
-        }
-        else
-        {
-            return new MavenFailOnSeverityLogger( name, logLevelRecorder );
+    private Logger getNewLoggingInstance(String name) {
+        if (logLevelRecorder == null) {
+            return new MavenSimpleLogger(name);
+        } else {
+            return new MavenFailOnSeverityLogger(name, logLevelRecorder);
         }
     }
 }
diff --git a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java
index 2b1637c..12a871c 100644
--- a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java
+++ b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java
@@ -1,5 +1,3 @@
-package org.slf4j.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,11 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.slf4j.impl;
 
 import java.io.PrintStream;
 
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
-import static org.apache.maven.shared.utils.logging.MessageUtils.level;
+import org.apache.maven.api.services.MessageBuilder;
+
+import static org.apache.maven.cli.jansi.MessageUtils.builder;
 
 /**
  * Logger for Maven, that support colorization of levels and stacktraces. This class implements 2 methods introduced in
@@ -30,90 +30,95 @@
  *
  * @since 3.5.0
  */
-public class MavenSimpleLogger extends SimpleLogger
-{
-    MavenSimpleLogger( String name )
-    {
-        super( name );
+public class MavenSimpleLogger extends SimpleLogger {
+
+    private final String traceRenderedLevel = builder().trace("TRACE").build();
+    private final String debugRenderedLevel = builder().debug("DEBUG").build();
+    private final String infoRenderedLevel = builder().info("INFO").build();
+    private final String warnRenderedLevel = builder().warning("WARNING").build();
+    private final String errorRenderedLevel = builder().error("ERROR").build();
+
+    MavenSimpleLogger(String name) {
+        super(name);
     }
 
     @Override
-    protected String renderLevel( int level )
-    {
-        switch ( level )
-        {
+    protected String renderLevel(int level) {
+        switch (level) {
             case LOG_LEVEL_TRACE:
-                return level().debug( "TRACE" );
+                return traceRenderedLevel;
             case LOG_LEVEL_DEBUG:
-                return level().debug( "DEBUG" );
+                return debugRenderedLevel;
             case LOG_LEVEL_INFO:
-                return level().info( "INFO" );
+                return infoRenderedLevel;
             case LOG_LEVEL_WARN:
-                return level().warning( "WARNING" );
+                return warnRenderedLevel;
             case LOG_LEVEL_ERROR:
             default:
-                return level().error( "ERROR" );
+                return errorRenderedLevel;
         }
     }
 
     @Override
-    protected void writeThrowable( Throwable t, PrintStream stream )
-    {
-        if ( t == null )
-        {
+    protected void writeThrowable(Throwable t, PrintStream stream) {
+        if (t == null) {
             return;
         }
-        stream.print( buffer().failure( t.getClass().getName() ) );
-        if ( t.getMessage() != null )
-        {
-            stream.print( ": " );
-            stream.print( buffer().failure( t.getMessage() ) );
+        MessageBuilder builder = builder().failure(t.getClass().getName());
+        if (t.getMessage() != null) {
+            builder.a(": ").failure(t.getMessage());
         }
-        stream.println();
+        stream.println(builder);
 
-        while ( t != null )
-        {
-            for ( StackTraceElement e : t.getStackTrace() )
-            {
-                stream.print( "    " );
-                stream.print( buffer().strong( "at" ) );
-                stream.print( " " + e.getClassName() + "." + e.getMethodName() );
-                stream.print( buffer().a( " (" ).strong( getLocation( e ) ).a( ")" ) );
-                stream.println();
-            }
+        printStackTrace(t, stream, "");
+    }
 
-            t = t.getCause();
-            if ( t != null )
-            {
-                stream.print( buffer().strong( "Caused by" ).a( ": " ).a( t.getClass().getName() ) );
-                if ( t.getMessage() != null )
-                {
-                    stream.print( ": " );
-                    stream.print( buffer().failure( t.getMessage() ) );
-                }
-                stream.println();
-            }
+    private void printStackTrace(Throwable t, PrintStream stream, String prefix) {
+        MessageBuilder builder = builder();
+        for (StackTraceElement e : t.getStackTrace()) {
+            builder.a(prefix);
+            builder.a("    ");
+            builder.strong("at");
+            builder.a(" ");
+            builder.a(e.getClassName());
+            builder.a(".");
+            builder.a(e.getMethodName());
+            builder.a(" (");
+            builder.strong(getLocation(e));
+            builder.a(")");
+            stream.println(builder);
+            builder.setLength(0);
+        }
+        for (Throwable se : t.getSuppressed()) {
+            writeThrowable(se, stream, "Suppressed", prefix + "    ");
+        }
+        Throwable cause = t.getCause();
+        if (cause != null && t != cause) {
+            writeThrowable(cause, stream, "Caused by", prefix);
         }
     }
 
-    protected String getLocation( final StackTraceElement e )
-    {
+    private void writeThrowable(Throwable t, PrintStream stream, String caption, String prefix) {
+        MessageBuilder builder =
+                builder().a(prefix).strong(caption).a(": ").a(t.getClass().getName());
+        if (t.getMessage() != null) {
+            builder.a(": ").failure(t.getMessage());
+        }
+        stream.println(builder);
+
+        printStackTrace(t, stream, prefix);
+    }
+
+    protected String getLocation(final StackTraceElement e) {
         assert e != null;
 
-        if ( e.isNativeMethod() )
-        {
+        if (e.isNativeMethod()) {
             return "Native Method";
-        }
-        else if ( e.getFileName() == null )
-        {
+        } else if (e.getFileName() == null) {
             return "Unknown Source";
-        }
-        else if ( e.getLineNumber() >= 0 )
-        {
-            return String.format( "%s:%s", e.getFileName(), e.getLineNumber() );
-        }
-        else
-        {
+        } else if (e.getLineNumber() >= 0) {
+            return e.getFileName() + ":" + e.getLineNumber();
+        } else {
             return e.getFileName();
         }
     }
diff --git a/maven-slf4j-provider/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/maven-slf4j-provider/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
index ed94c70..b8d2a34 100644
--- a/maven-slf4j-provider/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
+++ b/maven-slf4j-provider/src/main/java/org/slf4j/impl/StaticLoggerBinder.java
@@ -1,5 +1,3 @@
-package org.slf4j.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.slf4j.impl;
 
 import org.slf4j.ILoggerFactory;
 import org.slf4j.spi.LoggerFactoryBinder;
@@ -29,15 +28,13 @@
  *
  * @since 3.5.1
  */
-public final class StaticLoggerBinder
-    implements LoggerFactoryBinder
-{
+public final class StaticLoggerBinder implements LoggerFactoryBinder {
     /**
      * Declare the version of the SLF4J API this implementation is compiled
      * against. The value of this field is usually modified with each release.
      */
     // to avoid constant folding by the compiler, this field must *not* be final
-    @SuppressWarnings( { "checkstyle:staticvariablename", "checkstyle:visibilitymodifier" } )
+    @SuppressWarnings({"checkstyle:staticvariablename", "checkstyle:visibilitymodifier"})
     public static String REQUESTED_API_VERSION = "1.7.25"; // !final
 
     private static final String LOGGER_FACTORY_CLASS_STR = MavenLoggerFactory.class.getName();
@@ -56,16 +53,14 @@
     /**
      * Private constructor to prevent instantiation
      */
-    private StaticLoggerBinder()
-    {
+    private StaticLoggerBinder() {
         loggerFactory = new MavenLoggerFactory();
     }
 
     /**
      * Returns the singleton of this class.
      */
-    public static StaticLoggerBinder getSingleton()
-    {
+    public static StaticLoggerBinder getSingleton() {
         return SINGLETON;
     }
 
@@ -73,8 +68,7 @@
      * Returns the factory.
      */
     @Override
-    public ILoggerFactory getLoggerFactory()
-    {
+    public ILoggerFactory getLoggerFactory() {
         return loggerFactory;
     }
 
@@ -82,8 +76,7 @@
      * Returns the class name.
      */
     @Override
-    public String getLoggerFactoryClassStr()
-    {
+    public String getLoggerFactoryClassStr() {
         return LOGGER_FACTORY_CLASS_STR;
     }
 }
diff --git a/maven-slf4j-provider/src/site/apt/index.apt b/maven-slf4j-provider/src/site/apt/index.apt
new file mode 100644
index 0000000..802632a
--- /dev/null
+++ b/maven-slf4j-provider/src/site/apt/index.apt
@@ -0,0 +1,35 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ -----
+ About
+ -----
+ Hervé Boutemy
+ -----
+ 2023-06-19
+ -----
+
+Maven SLF4J Provider
+
+ An extension to {{{https://www.slf4j.org/api/org/slf4j/simple/SimpleLogger.html}SLF4J Simple}} to add enhanced color support.
+
+ Color is managed by <<<MavenSimpleLogger>>>, created by <<<MavenSimpleLoggerFactory>>>, and injected by <<<StaticLoggerBinder>>>: everything else is
+ copied at build time from {{{https://www.slf4j.org/api/org/slf4j/simple/SimpleLogger.html}SLF4J Simple}}
+
+* See Also
+
+ * {{{../maven-embedder/logging.html}Maven Logging}}
diff --git a/maven-slf4j-provider/src/site/site.xml b/maven-slf4j-provider/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-slf4j-provider/src/site/site.xml
+++ b/maven-slf4j-provider/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenLoggerFactoryTest.java b/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenLoggerFactoryTest.java
index 44ac3d2..9400594 100644
--- a/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenLoggerFactoryTest.java
+++ b/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenLoggerFactoryTest.java
@@ -1,5 +1,3 @@
-package org.slf4j.impl;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,75 +16,73 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.slf4j.impl;
 
 import org.apache.maven.logwrapper.LogLevelRecorder;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 
 import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNotSame;
 import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class MavenLoggerFactoryTest
-{
+class MavenLoggerFactoryTest {
     @Test
-    public void createsSimpleLogger()
-    {
+    void createsSimpleLogger() {
         MavenLoggerFactory mavenLoggerFactory = new MavenLoggerFactory();
 
-        Logger logger = mavenLoggerFactory.getLogger( "Test" );
+        Logger logger = mavenLoggerFactory.getLogger("Test");
 
-        assertThat( logger, instanceOf( MavenSimpleLogger.class ) );
+        assertThat(logger, instanceOf(MavenSimpleLogger.class));
     }
 
     @Test
-    public void loggerCachingWorks()
-    {
+    void loggerCachingWorks() {
         MavenLoggerFactory mavenLoggerFactory = new MavenLoggerFactory();
 
-        Logger logger = mavenLoggerFactory.getLogger( "Test" );
-        Logger logger2 = mavenLoggerFactory.getLogger( "Test" );
-        Logger differentLogger = mavenLoggerFactory.getLogger( "TestWithDifferentName" );
+        Logger logger = mavenLoggerFactory.getLogger("Test");
+        Logger logger2 = mavenLoggerFactory.getLogger("Test");
+        Logger differentLogger = mavenLoggerFactory.getLogger("TestWithDifferentName");
 
-        assertNotNull( logger );
-        assertNotNull( differentLogger );
-        assertSame( logger, logger2 );
-        assertNotSame( logger, differentLogger );
+        assertNotNull(logger);
+        assertNotNull(differentLogger);
+        assertSame(logger, logger2);
+        assertNotSame(logger, differentLogger);
     }
 
     @Test
-    public void reportsWhenFailOnSeverityThresholdHasBeenHit()
-    {
+    void reportsWhenFailOnSeverityThresholdHasBeenHit() {
         MavenLoggerFactory mavenLoggerFactory = new MavenLoggerFactory();
-        mavenLoggerFactory.setLogLevelRecorder( new LogLevelRecorder( "ERROR" ) );
+        mavenLoggerFactory.setLogLevelRecorder(new LogLevelRecorder("ERROR"));
 
-        assertTrue( mavenLoggerFactory.getLogLevelRecorder().isPresent() );
-        LogLevelRecorder logLevelRecorder = mavenLoggerFactory.getLogLevelRecorder().get();
+        assertTrue(mavenLoggerFactory.getLogLevelRecorder().isPresent());
+        LogLevelRecorder logLevelRecorder =
+                mavenLoggerFactory.getLogLevelRecorder().get();
 
-        MavenFailOnSeverityLogger logger = (MavenFailOnSeverityLogger) mavenLoggerFactory.getLogger( "Test" );
-        assertFalse( logLevelRecorder.metThreshold() );
+        MavenFailOnSeverityLogger logger = (MavenFailOnSeverityLogger) mavenLoggerFactory.getLogger("Test");
+        assertFalse(logLevelRecorder.metThreshold());
 
-        logger.warn( "This should not hit the fail threshold" );
-        assertFalse( logLevelRecorder.metThreshold() );
+        logger.warn("This should not hit the fail threshold");
+        assertFalse(logLevelRecorder.metThreshold());
 
-        logger.error( "This should hit the fail threshold" );
-        assertTrue( logLevelRecorder.metThreshold() );
+        logger.error("This should hit the fail threshold");
+        assertTrue(logLevelRecorder.metThreshold());
 
-        logger.warn( "This should not reset the fail threshold" );
-        assertTrue( logLevelRecorder.metThreshold() );
+        logger.warn("This should not reset the fail threshold");
+        assertTrue(logLevelRecorder.metThreshold());
     }
 
     @Test
-    public void failOnSeverityThresholdCanOnlyBeSetOnce()
-    {
+    void failOnSeverityThresholdCanOnlyBeSetOnce() {
         MavenLoggerFactory mavenLoggerFactory = new MavenLoggerFactory();
-        mavenLoggerFactory.setLogLevelRecorder( new LogLevelRecorder( "WARN" ) );
-        assertThrows( IllegalStateException.class,
-                      () -> mavenLoggerFactory.setLogLevelRecorder( new LogLevelRecorder( "ERROR" ) ) );
+        mavenLoggerFactory.setLogLevelRecorder(new LogLevelRecorder("WARN"));
+        assertThrows(
+                IllegalStateException.class,
+                () -> mavenLoggerFactory.setLogLevelRecorder(new LogLevelRecorder("ERROR")));
     }
 }
diff --git a/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenSimpleLoggerTest.java b/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenSimpleLoggerTest.java
new file mode 100644
index 0000000..da2d0b0
--- /dev/null
+++ b/maven-slf4j-provider/src/test/java/org/slf4j/impl/MavenSimpleLoggerTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.slf4j.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.jupiter.api.Assertions.assertLinesMatch;
+
+class MavenSimpleLoggerTest {
+
+    @Test
+    void includesCauseAndSuppressedExceptionsWhenWritingThrowables(TestInfo testInfo) throws Exception {
+        Exception causeOfSuppressed = new NoSuchElementException("cause of suppressed");
+        Exception suppressed = new IllegalStateException("suppressed", causeOfSuppressed);
+        suppressed.addSuppressed(new IllegalArgumentException(
+                "suppressed suppressed", new ArrayIndexOutOfBoundsException("suppressed suppressed cause")));
+        Exception cause = new IllegalArgumentException("cause");
+        cause.addSuppressed(suppressed);
+        Exception throwable = new RuntimeException("top-level", cause);
+
+        ByteArrayOutputStream output = new ByteArrayOutputStream();
+
+        new MavenSimpleLogger("logger").writeThrowable(throwable, new PrintStream(output));
+
+        String actual = output.toString(UTF_8.name());
+        List<String> actualLines = Arrays.asList(actual.split(System.lineSeparator()));
+
+        Class<?> testClass = testInfo.getTestClass().get();
+        String testMethodName = testInfo.getTestMethod().get().getName();
+        String testClassStackTraceLinePattern = "at " + testClass.getName() + "." + testMethodName + " \\("
+                + testClass.getSimpleName() + ".java:\\d+\\)";
+        List<String> expectedLines = Arrays.asList(
+                "java.lang.RuntimeException: top-level",
+                "    " + testClassStackTraceLinePattern,
+                ">> stacktrace >>",
+                "Caused by: java.lang.IllegalArgumentException: cause",
+                "    " + testClassStackTraceLinePattern,
+                ">> stacktrace >>",
+                "    Suppressed: java.lang.IllegalStateException: suppressed",
+                "        " + testClassStackTraceLinePattern,
+                ">> stacktrace >>",
+                "        Suppressed: java.lang.IllegalArgumentException: suppressed suppressed",
+                "            " + testClassStackTraceLinePattern,
+                ">> stacktrace >>",
+                "        Caused by: java.lang.ArrayIndexOutOfBoundsException: suppressed suppressed cause",
+                "            " + testClassStackTraceLinePattern,
+                ">> stacktrace >>",
+                "    Caused by: java.util.NoSuchElementException: cause of suppressed",
+                "        " + testClassStackTraceLinePattern,
+                ">> stacktrace >>");
+
+        assertLinesMatch(expectedLines, actualLines);
+    }
+}
diff --git a/maven-slf4j-wrapper/pom.xml b/maven-slf4j-wrapper/pom.xml
index 2631135..889bfe1 100644
--- a/maven-slf4j-wrapper/pom.xml
+++ b/maven-slf4j-wrapper/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,22 +17,19 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven</artifactId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
   </parent>
 
   <artifactId>maven-slf4j-wrapper</artifactId>
 
   <name>Maven SLF4J Wrapper</name>
-  <description>
-    This modules provides an ILoggerFactory interface which avoids a cyclic dependency between maven-embedder and maven-slf4j-provider.
-  </description>
+  <description>This modules provides an ILoggerFactory interface which avoids a cyclic dependency between maven-embedder and maven-slf4j-provider.</description>
 
   <dependencies>
     <dependency>
@@ -46,4 +42,4 @@
       <scope>test</scope>
     </dependency>
   </dependencies>
-</project>
\ No newline at end of file
+</project>
diff --git a/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/LogLevelRecorder.java b/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/LogLevelRecorder.java
index a7fec83..d77ca4d 100644
--- a/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/LogLevelRecorder.java
+++ b/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/LogLevelRecorder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.logwrapper;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,56 +16,49 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.slf4j.event.Level;
+package org.apache.maven.logwrapper;
 
 import java.util.HashMap;
 import java.util.Map;
 
+import org.slf4j.event.Level;
+
 /**
  * Responsible for keeping state of whether the threshold of the --fail-on-severity flag has been hit.
  */
-public class LogLevelRecorder
-{
+public class LogLevelRecorder {
     private static final Map<String, Level> ACCEPTED_LEVELS = new HashMap<>();
-    static
-    {
-        ACCEPTED_LEVELS.put( "WARN", Level.WARN );
-        ACCEPTED_LEVELS.put( "WARNING", Level.WARN );
-        ACCEPTED_LEVELS.put( "ERROR", Level.ERROR );
+
+    static {
+        ACCEPTED_LEVELS.put("WARN", Level.WARN);
+        ACCEPTED_LEVELS.put("WARNING", Level.WARN);
+        ACCEPTED_LEVELS.put("ERROR", Level.ERROR);
     }
 
     private final Level logThreshold;
     private boolean metThreshold = false;
 
-    public LogLevelRecorder( String threshold )
-    {
-        logThreshold = determineThresholdLevel( threshold );
+    public LogLevelRecorder(String threshold) {
+        logThreshold = determineThresholdLevel(threshold);
     }
 
-    private Level determineThresholdLevel( String input )
-    {
-        final Level result = ACCEPTED_LEVELS.get( input );
-        if ( result == null )
-        {
+    private Level determineThresholdLevel(String input) {
+        final Level result = ACCEPTED_LEVELS.get(input);
+        if (result == null) {
             String message = String.format(
-                    "%s is not a valid log severity threshold. Valid severities are WARN/WARNING and ERROR.",
-                    input );
-            throw new IllegalArgumentException( message );
+                    "%s is not a valid log severity threshold. Valid severities are WARN/WARNING and ERROR.", input);
+            throw new IllegalArgumentException(message);
         }
         return result;
     }
 
-    public void record( Level logLevel )
-    {
-        if ( !metThreshold && logLevel.toInt() >= logThreshold.toInt() )
-        {
+    public void record(Level logLevel) {
+        if (!metThreshold && logLevel.toInt() >= logThreshold.toInt()) {
             metThreshold = true;
         }
     }
 
-    public boolean metThreshold()
-    {
+    public boolean metThreshold() {
         return metThreshold;
     }
 }
diff --git a/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/MavenSlf4jWrapperFactory.java b/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/MavenSlf4jWrapperFactory.java
index e2063b7..afa8bb1 100644
--- a/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/MavenSlf4jWrapperFactory.java
+++ b/maven-slf4j-wrapper/src/main/java/org/apache/maven/logwrapper/MavenSlf4jWrapperFactory.java
@@ -1,5 +1,3 @@
-package org.apache.maven.logwrapper;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,16 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.slf4j.ILoggerFactory;
+package org.apache.maven.logwrapper;
 
 import java.util.Optional;
 
+import org.slf4j.ILoggerFactory;
+
 /**
  * Wrapper for creating loggers which can have a log level threshold.
  */
-public interface MavenSlf4jWrapperFactory extends ILoggerFactory
-{
-    void setLogLevelRecorder( LogLevelRecorder logLevelRecorder );
+public interface MavenSlf4jWrapperFactory extends ILoggerFactory {
+    void setLogLevelRecorder(LogLevelRecorder logLevelRecorder);
+
     Optional<LogLevelRecorder> getLogLevelRecorder();
 }
diff --git a/maven-slf4j-wrapper/src/site/site.xml b/maven-slf4j-wrapper/src/site/site.xml
index e475330..8ffe43d 100644
--- a/maven-slf4j-wrapper/src/site/site.xml
+++ b/maven-slf4j-wrapper/src/site/site.xml
@@ -27,7 +27,7 @@
   <body>
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
     </menu>
diff --git a/maven-slf4j-wrapper/src/test/java/org/apache/maven/logwrapper/LogLevelRecorderTest.java b/maven-slf4j-wrapper/src/test/java/org/apache/maven/logwrapper/LogLevelRecorderTest.java
index 1e521a9..e806fb6 100644
--- a/maven-slf4j-wrapper/src/test/java/org/apache/maven/logwrapper/LogLevelRecorderTest.java
+++ b/maven-slf4j-wrapper/src/test/java/org/apache/maven/logwrapper/LogLevelRecorderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.logwrapper;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.logwrapper;
 
 import org.junit.jupiter.api.Test;
 import org.slf4j.event.Level;
@@ -27,40 +26,35 @@
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-public class LogLevelRecorderTest
-{
+class LogLevelRecorderTest {
     @Test
-    public void createsLogLevelRecorder()
-    {
-        LogLevelRecorder logLevelRecorder = new LogLevelRecorder( "WARN" );
-        logLevelRecorder.record( Level.ERROR );
+    void createsLogLevelRecorder() {
+        LogLevelRecorder logLevelRecorder = new LogLevelRecorder("WARN");
+        logLevelRecorder.record(Level.ERROR);
 
-        assertTrue( logLevelRecorder.metThreshold() );
+        assertTrue(logLevelRecorder.metThreshold());
     }
 
     @Test
-    public void failsOnLowerThanWarn ()
-    {
-        assertThrows( IllegalArgumentException.class, () -> new LogLevelRecorder( "INFO" ) );
+    void failsOnLowerThanWarn() {
+        assertThrows(IllegalArgumentException.class, () -> new LogLevelRecorder("INFO"));
     }
 
     @Test
-    public void createsLogLevelRecorderWithWarning()
-    {
-        LogLevelRecorder logLevelRecorder = new LogLevelRecorder( "WARNING" );
-        logLevelRecorder.record( Level.ERROR );
+    void createsLogLevelRecorderWithWarning() {
+        LogLevelRecorder logLevelRecorder = new LogLevelRecorder("WARNING");
+        logLevelRecorder.record(Level.ERROR);
 
-        assertTrue( logLevelRecorder.metThreshold() );
+        assertTrue(logLevelRecorder.metThreshold());
     }
 
     @Test
-    public void failsOnUnknownLogLevel ()
-    {
-        Throwable thrown = assertThrows( IllegalArgumentException.class, () -> new LogLevelRecorder( "SEVERE" ) );
+    void failsOnUnknownLogLevel() {
+        Throwable thrown = assertThrows(IllegalArgumentException.class, () -> new LogLevelRecorder("SEVERE"));
         String message = thrown.getMessage();
-        assertThat( message, containsString( "SEVERE is not a valid log severity threshold" ) );
-        assertThat( message, containsString( "WARN" ) );
-        assertThat( message, containsString( "WARNING" ) );
-        assertThat( message, containsString( "ERROR" ) );
+        assertThat(message, containsString("SEVERE is not a valid log severity threshold"));
+        assertThat(message, containsString("WARN"));
+        assertThat(message, containsString("WARNING"));
+        assertThat(message, containsString("ERROR"));
     }
-}
\ No newline at end of file
+}
diff --git a/maven-toolchain-builder/pom.xml b/maven-toolchain-builder/pom.xml
index df19e6d..2233838 100644
--- a/maven-toolchain-builder/pom.xml
+++ b/maven-toolchain-builder/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,16 +17,13 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
-<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">
-  <parent>
-    <artifactId>maven</artifactId>
-    <groupId>org.apache.maven</groupId>
-    <version>4.0.0-alpha-1-SNAPSHOT</version>
-  </parent>
+<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>org.apache.maven</groupId>
+    <artifactId>maven</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
 
   <artifactId>maven-toolchain-builder</artifactId>
 
@@ -49,10 +45,6 @@
     </dependency>
     <dependency>
       <groupId>org.codehaus.plexus</groupId>
-      <artifactId>plexus-utils</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.codehaus.plexus</groupId>
       <artifactId>plexus-interpolation</artifactId>
     </dependency>
     <dependency>
@@ -68,6 +60,32 @@
         <groupId>org.eclipse.sisu</groupId>
         <artifactId>sisu-maven-plugin</artifactId>
       </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <parameter>
+            <includes>
+              <include>org.apache.maven.toolchain.building</include>
+              <include>org.apache.maven.toolchain.io</include>
+              <include>org.apache.maven.toolchain.io.xpp3</include>
+              <include>org.apache.maven.toolchain.merge</include>
+            </includes>
+            <excludes>
+              <exclude>org.apache.maven.toolchain.building.DefaultToolchainsBuilder#DefaultToolchainsBuilder():CONSTRUCTOR_REMOVED</exclude>
+              <exclude>org.apache.maven.toolchain.merge.MavenToolchainMerger#getToolchainModelKey(org.apache.maven.toolchain.model.ToolchainModel):METHOD_REMOVED</exclude>
+              <exclude>org.apache.maven.toolchain.merge.MavenToolchainMerger#mergeToolchainModelConfiguration(org.apache.maven.toolchain.model.ToolchainModel,org.apache.maven.toolchain.model.ToolchainModel):METHOD_REMOVED</exclude>
+            </excludes>
+          </parameter>
+          <oldVersion>
+            <dependency>
+              <groupId>org.apache.maven</groupId>
+              <artifactId>maven-core</artifactId>
+              <version>${maven.baseline}</version>
+            </dependency>
+          </oldVersion>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java
index d119987..ebd8303 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
 
 import org.apache.maven.building.Problem;
 import org.apache.maven.building.ProblemCollector;
@@ -33,180 +43,145 @@
 import org.codehaus.plexus.interpolation.InterpolationException;
 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
 
-import javax.inject.Inject;
-import javax.inject.Named;
-import javax.inject.Singleton;
-import java.io.IOException;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-
 /**
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
 @Named
 @Singleton
-public class DefaultToolchainsBuilder
-    implements ToolchainsBuilder
-{
+public class DefaultToolchainsBuilder implements ToolchainsBuilder {
     private final MavenToolchainMerger toolchainsMerger = new MavenToolchainMerger();
     private final ToolchainsWriter toolchainsWriter;
     private final ToolchainsReader toolchainsReader;
 
     @Inject
-    public DefaultToolchainsBuilder(
-            ToolchainsWriter toolchainsWriter,
-            ToolchainsReader toolchainsReader )
-    {
+    public DefaultToolchainsBuilder(ToolchainsWriter toolchainsWriter, ToolchainsReader toolchainsReader) {
         this.toolchainsWriter = toolchainsWriter;
         this.toolchainsReader = toolchainsReader;
     }
 
     @Override
-    public ToolchainsBuildingResult build( ToolchainsBuildingRequest request )
-        throws ToolchainsBuildingException
-    {
-        ProblemCollector problems = ProblemCollectorFactory.newInstance( null );
+    public ToolchainsBuildingResult build(ToolchainsBuildingRequest request) throws ToolchainsBuildingException {
+        ProblemCollector problems = ProblemCollectorFactory.newInstance(null);
 
-        PersistedToolchains globalToolchains = readToolchains( request.getGlobalToolchainsSource(), request, problems );
+        PersistedToolchains globalToolchains = readToolchains(request.getGlobalToolchainsSource(), request, problems);
 
-        PersistedToolchains userToolchains = readToolchains( request.getUserToolchainsSource(), request, problems );
+        PersistedToolchains userToolchains = readToolchains(request.getUserToolchainsSource(), request, problems);
 
-        toolchainsMerger.merge( userToolchains, globalToolchains, TrackableBase.GLOBAL_LEVEL );
+        toolchainsMerger.merge(userToolchains, globalToolchains, TrackableBase.GLOBAL_LEVEL);
 
-        problems.setSource( "" );
+        problems.setSource("");
 
-        userToolchains = interpolate( userToolchains, problems );
+        userToolchains = interpolate(userToolchains, problems);
 
-        if ( hasErrors( problems.getProblems() ) )
-        {
-            throw new ToolchainsBuildingException( problems.getProblems() );
+        if (hasErrors(problems.getProblems())) {
+            throw new ToolchainsBuildingException(problems.getProblems());
         }
 
-
-        return new DefaultToolchainsBuildingResult( userToolchains, problems.getProblems() );
+        return new DefaultToolchainsBuildingResult(userToolchains, problems.getProblems());
     }
 
-    private PersistedToolchains interpolate( PersistedToolchains toolchains, ProblemCollector problems )
-    {
+    private PersistedToolchains interpolate(PersistedToolchains toolchains, ProblemCollector problems) {
 
-        StringWriter stringWriter = new StringWriter( 1024 * 4 );
-        try
-        {
-            toolchainsWriter.write( stringWriter, null, toolchains );
-        }
-        catch ( IOException e )
-        {
-            throw new IllegalStateException( "Failed to serialize toolchains to memory", e );
+        StringWriter stringWriter = new StringWriter(1024 * 4);
+        try {
+            toolchainsWriter.write(stringWriter, null, toolchains);
+        } catch (IOException e) {
+            throw new IllegalStateException("Failed to serialize toolchains to memory", e);
         }
 
         String serializedToolchains = stringWriter.toString();
 
         RegexBasedInterpolator interpolator = new RegexBasedInterpolator();
 
-        try
-        {
-            interpolator.addValueSource( new EnvarBasedValueSource() );
-        }
-        catch ( IOException e )
-        {
-            problems.add( Problem.Severity.WARNING, "Failed to use environment variables for interpolation: "
-                    + e.getMessage(), -1, -1, e );
+        try {
+            interpolator.addValueSource(new EnvarBasedValueSource());
+        } catch (IOException e) {
+            problems.add(
+                    Problem.Severity.WARNING,
+                    "Failed to use environment variables for interpolation: " + e.getMessage(),
+                    -1,
+                    -1,
+                    e);
         }
 
-        interpolator.addPostProcessor( ( expression, value ) ->
-        {
-            if ( value != null )
-            {
+        interpolator.addPostProcessor((expression, value) -> {
+            if (value != null) {
                 // we're going to parse this back in as XML so we need to escape XML markup
-                value = value.toString().replace( "&", "&amp;" ).replace( "<", "&lt;" ).replace( ">", "&gt;" );
+                value = value.toString()
+                        .replace("&", "&amp;")
+                        .replace("<", "&lt;")
+                        .replace(">", "&gt;");
                 return value;
             }
             return null;
-        } );
+        });
 
-        try
-        {
-            serializedToolchains = interpolator.interpolate( serializedToolchains );
-        }
-        catch ( InterpolationException e )
-        {
-            problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e );
+        try {
+            serializedToolchains = interpolator.interpolate(serializedToolchains);
+        } catch (InterpolationException e) {
+            problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e);
             return toolchains;
         }
 
         PersistedToolchains result;
-        try
-        {
-            Map<String, ?> options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE );
+        try {
+            Map<String, ?> options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE);
 
-            result = toolchainsReader.read( new StringReader( serializedToolchains ), options );
-        }
-        catch ( IOException e )
-        {
-            problems.add( Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e );
+            result = toolchainsReader.read(new StringReader(serializedToolchains), options);
+        } catch (IOException e) {
+            problems.add(Problem.Severity.ERROR, "Failed to interpolate toolchains: " + e.getMessage(), -1, -1, e);
             return toolchains;
         }
 
         return result;
     }
 
-    private PersistedToolchains readToolchains( Source toolchainsSource, ToolchainsBuildingRequest request,
-                                                ProblemCollector problems )
-    {
-        if ( toolchainsSource == null )
-        {
+    private PersistedToolchains readToolchains(
+            Source toolchainsSource, ToolchainsBuildingRequest request, ProblemCollector problems) {
+        if (toolchainsSource == null) {
             return new PersistedToolchains();
         }
 
         PersistedToolchains toolchains;
 
-        try
-        {
-            Map<String, ?> options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.TRUE );
+        try {
+            Map<String, ?> options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.TRUE);
 
-            try
-            {
-                toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options );
+            try {
+                toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options);
+            } catch (ToolchainsParseException e) {
+                options = Collections.singletonMap(ToolchainsReader.IS_STRICT, Boolean.FALSE);
+
+                toolchains = toolchainsReader.read(toolchainsSource.getInputStream(), options);
+
+                problems.add(Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e);
             }
-            catch ( ToolchainsParseException e )
-            {
-                options = Collections.singletonMap( ToolchainsReader.IS_STRICT, Boolean.FALSE );
-
-                toolchains = toolchainsReader.read( toolchainsSource.getInputStream(), options );
-
-                problems.add( Problem.Severity.WARNING, e.getMessage(), e.getLineNumber(), e.getColumnNumber(),
-                              e );
-            }
-        }
-        catch ( ToolchainsParseException e )
-        {
-            problems.add( Problem.Severity.FATAL, "Non-parseable toolchains " + toolchainsSource.getLocation()
-                + ": " + e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        } catch (ToolchainsParseException e) {
+            problems.add(
+                    Problem.Severity.FATAL,
+                    "Non-parseable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
+                    e.getLineNumber(),
+                    e.getColumnNumber(),
+                    e);
             return new PersistedToolchains();
-        }
-        catch ( IOException e )
-        {
-            problems.add( Problem.Severity.FATAL, "Non-readable toolchains " + toolchainsSource.getLocation()
-                + ": " + e.getMessage(), -1, -1, e );
+        } catch (IOException e) {
+            problems.add(
+                    Problem.Severity.FATAL,
+                    "Non-readable toolchains " + toolchainsSource.getLocation() + ": " + e.getMessage(),
+                    -1,
+                    -1,
+                    e);
             return new PersistedToolchains();
         }
 
         return toolchains;
     }
 
-    private boolean hasErrors( List<Problem> problems )
-    {
-        if ( problems != null )
-        {
-            for ( Problem problem : problems )
-            {
-                if ( Problem.Severity.ERROR.compareTo( problem.getSeverity() ) >= 0 )
-                {
+    private boolean hasErrors(List<Problem> problems) {
+        if (problems != null) {
+            for (Problem problem : problems) {
+                if (Problem.Severity.ERROR.compareTo(problem.getSeverity()) >= 0) {
                     return true;
                 }
             }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java
index 3c0e65d..2d0e887 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,46 +16,39 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
 
 import org.apache.maven.building.Source;
 
 /**
  * Collects toolchains that control building of effective toolchains.
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public class DefaultToolchainsBuildingRequest
-    implements ToolchainsBuildingRequest
-{
+public class DefaultToolchainsBuildingRequest implements ToolchainsBuildingRequest {
     private Source globalToolchainsSource;
 
     private Source userToolchainsSource;
 
     @Override
-    public Source getGlobalToolchainsSource()
-    {
+    public Source getGlobalToolchainsSource() {
         return globalToolchainsSource;
     }
 
     @Override
-    public ToolchainsBuildingRequest setGlobalToolchainsSource( Source globalToolchainsSource )
-    {
+    public ToolchainsBuildingRequest setGlobalToolchainsSource(Source globalToolchainsSource) {
         this.globalToolchainsSource = globalToolchainsSource;
         return this;
     }
 
     @Override
-    public Source getUserToolchainsSource()
-    {
+    public Source getUserToolchainsSource() {
         return userToolchainsSource;
     }
 
     @Override
-    public ToolchainsBuildingRequest setUserToolchainsSource( Source userToolchainsSource )
-    {
+    public ToolchainsBuildingRequest setUserToolchainsSource(Source userToolchainsSource) {
         this.userToolchainsSource = userToolchainsSource;
         return this;
     }
-
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
index 2d07a4a..f4df2b4 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/DefaultToolchainsBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -28,12 +27,9 @@
 /**
  * Holds the result of the merged toolchains and holds the problems during this build, if any.
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public class DefaultToolchainsBuildingResult
-    implements ToolchainsBuildingResult
-{
+public class DefaultToolchainsBuildingResult implements ToolchainsBuildingResult {
 
     private PersistedToolchains effectiveToolchains;
 
@@ -45,22 +41,18 @@
      * @param effectiveToolchains the merged toolchains, may not be {@code null}
      * @param problems the problems while building the effectiveToolchains, if any.
      */
-    public DefaultToolchainsBuildingResult( PersistedToolchains effectiveToolchains, List<Problem> problems )
-    {
+    public DefaultToolchainsBuildingResult(PersistedToolchains effectiveToolchains, List<Problem> problems) {
         this.effectiveToolchains = effectiveToolchains;
-        this.problems = ( problems != null ) ? problems : new ArrayList<>();
+        this.problems = (problems != null) ? problems : new ArrayList<>();
     }
 
     @Override
-    public PersistedToolchains getEffectiveToolchains()
-    {
+    public PersistedToolchains getEffectiveToolchains() {
         return effectiveToolchains;
     }
 
     @Override
-    public List<Problem> getProblems()
-    {
+    public List<Problem> getProblems() {
         return problems;
     }
-
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java
index b2ef0d1..7451b79 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuilder.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,15 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
 
 /**
  * Builds the effective toolchains from a user toolchains file and/or a global toolchains file.
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public interface ToolchainsBuilder
-{
+public interface ToolchainsBuilder {
 
     /**
      * Builds the effective toolchains of the specified toolchains files.
@@ -35,7 +32,5 @@
      * @return The result of the toolchains building, never {@code null}.
      * @throws ToolchainsBuildingException If the effective toolchains could not be built.
      */
-    ToolchainsBuildingResult build( ToolchainsBuildingRequest request )
-        throws ToolchainsBuildingException;
-
+    ToolchainsBuildingResult build(ToolchainsBuildingRequest request) throws ToolchainsBuildingException;
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
index c598f76..3ddf5a3 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -27,12 +26,9 @@
 import org.apache.maven.building.Problem;
 
 /**
- * @author Robert Scholte
  * @since 3.3.0
  */
-public class ToolchainsBuildingException
-    extends Exception
-{
+public class ToolchainsBuildingException extends Exception {
 
     private final List<Problem> problems;
 
@@ -41,14 +37,12 @@
      *
      * @param problems The problems that cause this exception, must not be {@code null}.
      */
-    public ToolchainsBuildingException( List<Problem> problems )
-    {
-        super( toMessage( problems ) );
+    public ToolchainsBuildingException(List<Problem> problems) {
+        super(toMessage(problems));
 
         this.problems = new ArrayList<>();
-        if ( problems != null )
-        {
-            this.problems.addAll( problems );
+        if (problems != null) {
+            this.problems.addAll(problems);
         }
     }
 
@@ -57,33 +51,29 @@
      *
      * @return The problems that caused this exception, never {@code null}.
      */
-    public List<Problem> getProblems()
-    {
+    public List<Problem> getProblems() {
         return problems;
     }
 
-    private static String toMessage( List<Problem> problems )
-    {
-        StringWriter buffer = new StringWriter( 1024 );
+    private static String toMessage(List<Problem> problems) {
+        StringWriter buffer = new StringWriter(1024);
 
-        PrintWriter writer = new PrintWriter( buffer );
+        PrintWriter writer = new PrintWriter(buffer);
 
-        writer.print( problems.size() );
-        writer.print( ( problems.size() == 1 ) ? " problem was " : " problems were " );
-        writer.print( "encountered while building the effective toolchains" );
+        writer.print(problems.size());
+        writer.print((problems.size() == 1) ? " problem was " : " problems were ");
+        writer.print("encountered while building the effective toolchains");
         writer.println();
 
-        for ( Problem problem : problems )
-        {
-            writer.print( "[" );
-            writer.print( problem.getSeverity() );
-            writer.print( "] " );
-            writer.print( problem.getMessage() );
+        for (Problem problem : problems) {
+            writer.print("[");
+            writer.print(problem.getSeverity());
+            writer.print("] ");
+            writer.print(problem.getMessage());
             String location = problem.getLocation();
-            if ( !location.isEmpty() )
-            {
-                writer.print( " @ " );
-                writer.print( location );
+            if (!location.isEmpty()) {
+                writer.print(" @ ");
+                writer.print(location);
             }
             writer.println();
         }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java
index cf65d4c..b2b8eb2 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingRequest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,17 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
 
 import org.apache.maven.building.Source;
 
 /**
  * Collects toolchains that control the building of effective toolchains.
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public interface ToolchainsBuildingRequest
-{
+public interface ToolchainsBuildingRequest {
 
     /**
      * Gets the global toolchains source.
@@ -44,7 +41,7 @@
      * @param globalToolchainsSource The global toolchains source, may be {@code null} to disable global toolchains.
      * @return This request, never {@code null}.
      */
-    ToolchainsBuildingRequest setGlobalToolchainsSource( Source globalToolchainsSource );
+    ToolchainsBuildingRequest setGlobalToolchainsSource(Source globalToolchainsSource);
 
     /**
      * Gets the user toolchains source.
@@ -60,5 +57,5 @@
      * @param userToolchainsSource The user toolchains source, may be {@code null} to disable user toolchains.
      * @return This request, never {@code null}.
      */
-    ToolchainsBuildingRequest setUserToolchainsSource( Source userToolchainsSource );
+    ToolchainsBuildingRequest setUserToolchainsSource(Source userToolchainsSource);
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
index f7c5f71..b4a5416 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/building/ToolchainsBuildingResult.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
 
 import java.util.List;
 
@@ -27,11 +26,9 @@
 /**
  * Collects the output of the toolchains builder.
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public interface ToolchainsBuildingResult
-{
+public interface ToolchainsBuildingResult {
 
     /**
      * Gets the assembled toolchains.
@@ -46,5 +43,4 @@
      * @return a list of problems, never {@code null}.
      */
     List<Problem> getProblems();
-
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
index 2522551..f474b9c 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,79 +16,79 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.io;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
+import java.nio.file.Files;
 import java.util.Map;
 import java.util.Objects;
 
-import javax.inject.Named;
-import javax.inject.Singleton;
-
 import org.apache.maven.toolchain.model.PersistedToolchains;
-import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader;
-import org.codehaus.plexus.util.ReaderFactory;
-import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.apache.maven.toolchain.v4.MavenToolchainsStaxReader;
 
 /**
  * Handles deserialization of toolchains from the default textual format.
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
 @Named
 @Singleton
-public class DefaultToolchainsReader
-    implements ToolchainsReader
-{
+public class DefaultToolchainsReader implements ToolchainsReader {
 
     @Override
-    public PersistedToolchains read( File input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public PersistedToolchains read(File input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        return read( ReaderFactory.newXmlReader( input ), options );
-    }
-
-    @Override
-    public PersistedToolchains read( Reader input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
-
-        try ( Reader in = input )
-        {
-            return new MavenToolchainsXpp3Reader().read( in, isStrict( options ) );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new ToolchainsParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        try (InputStream in = Files.newInputStream(input.toPath())) {
+            return new PersistedToolchains(new MavenToolchainsStaxReader().read(in, isStrict(options)));
+        } catch (XMLStreamException e) {
+            throw new ToolchainsParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
         }
     }
 
     @Override
-    public PersistedToolchains read( InputStream input, Map<String, ?> options )
-        throws IOException
-    {
-        Objects.requireNonNull( input, "input cannot be null" );
+    public PersistedToolchains read(Reader input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
 
-        try ( InputStream in = input )
-        {
-            return new MavenToolchainsXpp3Reader().read( in, isStrict( options ) );
-        }
-        catch ( XmlPullParserException e )
-        {
-            throw new ToolchainsParseException( e.getMessage(), e.getLineNumber(), e.getColumnNumber(), e );
+        try (Reader in = input) {
+            return new PersistedToolchains(new MavenToolchainsStaxReader().read(in, isStrict(options)));
+        } catch (XMLStreamException e) {
+            throw new ToolchainsParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
         }
     }
 
-    private boolean isStrict( Map<String, ?> options )
-    {
-        Object value = ( options != null ) ? options.get( IS_STRICT ) : null;
-        return value == null || Boolean.parseBoolean( value.toString() );
+    @Override
+    public PersistedToolchains read(InputStream input, Map<String, ?> options) throws IOException {
+        Objects.requireNonNull(input, "input cannot be null");
+
+        try (InputStream in = input) {
+            return new PersistedToolchains(new MavenToolchainsStaxReader().read(in, isStrict(options)));
+        } catch (XMLStreamException e) {
+            throw new ToolchainsParseException(
+                    e.getMessage(),
+                    e.getLocation().getLineNumber(),
+                    e.getLocation().getColumnNumber(),
+                    e);
+        }
     }
 
+    private boolean isStrict(Map<String, ?> options) {
+        Object value = (options != null) ? options.get(IS_STRICT) : null;
+        return value == null || Boolean.parseBoolean(value.toString());
+    }
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java
index 51ebdc7..e10b341 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/DefaultToolchainsWriter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,37 +16,37 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.toolchain.model.PersistedToolchains;
-import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Writer;
+package org.apache.maven.toolchain.io;
 
 import javax.inject.Named;
 import javax.inject.Singleton;
+import javax.xml.stream.XMLStreamException;
+
 import java.io.IOException;
 import java.io.Writer;
 import java.util.Map;
 import java.util.Objects;
 
+import org.apache.maven.toolchain.model.PersistedToolchains;
+import org.apache.maven.toolchain.v4.MavenToolchainsStaxWriter;
+
 /**
  * Handles serialization of toolchains into the default textual format.
  *
- * @author Mike Mol
- * @author Martin Kanters
  */
 @Named
 @Singleton
-public class DefaultToolchainsWriter implements ToolchainsWriter
-{
+public class DefaultToolchainsWriter implements ToolchainsWriter {
 
     @Override
-    public void write( Writer output, Map<String, Object> options, PersistedToolchains toolchains ) throws IOException
-    {
-        Objects.requireNonNull( output, "output cannot be null" );
-        Objects.requireNonNull( toolchains, "toolchains cannot be null" );
+    public void write(Writer output, Map<String, Object> options, PersistedToolchains toolchains) throws IOException {
+        Objects.requireNonNull(output, "output cannot be null");
+        Objects.requireNonNull(toolchains, "toolchains cannot be null");
 
-        try ( Writer out = output )
-        {
-            new MavenToolchainsXpp3Writer().write( out, toolchains );
+        try (Writer out = output) {
+            new MavenToolchainsStaxWriter().write(out, toolchains.getDelegate());
+        } catch (XMLStreamException e) {
+            throw new IOException("Error writing toolchains", e);
         }
     }
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java
index 71608ff..406b2ee 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsParseException.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,18 +16,16 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.io;
 
 import java.io.IOException;
 
 /**
  * Signals a failure to parse the toolchains due to invalid syntax (e.g. non well formed XML or unknown elements).
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public class ToolchainsParseException
-    extends IOException
-{
+public class ToolchainsParseException extends IOException {
 
     /**
      * The one-based index of the line containing the error.
@@ -48,9 +44,8 @@
      * @param lineNumber The one-based index of the line containing the error or {@code -1} if unknown.
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      */
-    public ToolchainsParseException( String message, int lineNumber, int columnNumber )
-    {
-        super( message );
+    public ToolchainsParseException(String message, int lineNumber, int columnNumber) {
+        super(message);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -63,10 +58,9 @@
      * @param columnNumber The one-based index of the column containing the error or {@code -1} if unknown.
      * @param cause The nested cause of this error, may be {@code null}.
      */
-    public ToolchainsParseException( String message, int lineNumber, int columnNumber, Throwable cause )
-    {
-        super( message );
-        initCause( cause );
+    public ToolchainsParseException(String message, int lineNumber, int columnNumber, Throwable cause) {
+        super(message);
+        initCause(cause);
         this.lineNumber = lineNumber;
         this.columnNumber = columnNumber;
     }
@@ -76,8 +70,7 @@
      *
      * @return The one-based index of the line containing the error or a non-positive value if unknown.
      */
-    public int getLineNumber()
-    {
+    public int getLineNumber() {
         return lineNumber;
     }
 
@@ -86,9 +79,7 @@
      *
      * @return The one-based index of the column containing the error or non-positive value if unknown.
      */
-    public int getColumnNumber()
-    {
+    public int getColumnNumber() {
         return columnNumber;
     }
-
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
index 44dc2bd..e5dab7e 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsReader.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -18,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.io;
 
 import java.io.File;
 import java.io.IOException;
@@ -30,11 +29,9 @@
 /**
  * Handles deserialization of toolchains from some kind of textual format like XML.
  *
- * @author Robert Scholte
  * @since 3.3.0
  */
-public interface ToolchainsReader
-{
+public interface ToolchainsReader {
 
     /**
      * The key for the option to enable strict parsing. This option is of type {@link Boolean} and defaults to {@code
@@ -51,8 +48,7 @@
      * @throws IOException If the toolchains could not be deserialized.
      * @throws ToolchainsParseException If the input format could not be parsed.
      */
-    PersistedToolchains read( File input, Map<String, ?> options )
-        throws IOException, ToolchainsParseException;
+    PersistedToolchains read(File input, Map<String, ?> options) throws IOException, ToolchainsParseException;
 
     /**
      * Reads the toolchains from the specified character reader. The reader will be automatically closed before the
@@ -64,8 +60,7 @@
      * @throws IOException If the toolchains could not be deserialized.
      * @throws ToolchainsParseException If the input format could not be parsed.
      */
-    PersistedToolchains read( Reader input, Map<String, ?> options )
-        throws IOException, ToolchainsParseException;
+    PersistedToolchains read(Reader input, Map<String, ?> options) throws IOException, ToolchainsParseException;
 
     /**
      * Reads the toolchains from the specified byte stream. The stream will be automatically closed before the method
@@ -77,7 +72,5 @@
      * @throws IOException If the toolchains could not be deserialized.
      * @throws ToolchainsParseException If the input format could not be parsed.
      */
-    PersistedToolchains read( InputStream input, Map<String, ?> options )
-        throws IOException, ToolchainsParseException;
-
+    PersistedToolchains read(InputStream input, Map<String, ?> options) throws IOException, ToolchainsParseException;
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java
index 0b15f34..9875474 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/io/ToolchainsWriter.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.io;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,21 +16,19 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import org.apache.maven.toolchain.model.PersistedToolchains;
+package org.apache.maven.toolchain.io;
 
 import java.io.IOException;
 import java.io.Writer;
 import java.util.Map;
 
+import org.apache.maven.toolchain.model.PersistedToolchains;
+
 /**
  * Handles serialization of toolchains into some kind of textual format like XML.
  *
- * @author Mike Mol
- * @author Martin Kanters
  */
-public interface ToolchainsWriter
-{
+public interface ToolchainsWriter {
 
     /**
      * Writes the supplied toolchains to the specified character writer. The writer will be automatically closed before
@@ -43,6 +39,5 @@
      * @param toolchains The toolchains to serialize, must not be {@code null}.
      * @throws IOException If the toolchains could not be serialized.
      */
-    void write( Writer output, Map<String, Object> options, PersistedToolchains toolchains )
-            throws IOException;
+    void write(Writer output, Map<String, Object> options, PersistedToolchains toolchains) throws IOException;
 }
diff --git a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
index 9b6596e..96ff052 100644
--- a/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
+++ b/maven-toolchain-builder/src/main/java/org/apache/maven/toolchain/merge/MavenToolchainMerger.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.merge;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,86 +16,24 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
+package org.apache.maven.toolchain.merge;
 
 import org.apache.maven.toolchain.model.PersistedToolchains;
-import org.apache.maven.toolchain.model.ToolchainModel;
-import org.codehaus.plexus.util.xml.Xpp3Dom;
 
 /**
  *
- * @author Robert Scholte
  * @since 3.2.4
  */
-public class MavenToolchainMerger
-{
+public class MavenToolchainMerger {
 
-    public void merge( PersistedToolchains dominant, PersistedToolchains recessive, String recessiveSourceLevel )
-    {
-        if ( dominant == null || recessive == null )
-        {
+    public void merge(PersistedToolchains dominant, PersistedToolchains recessive, String recessiveSourceLevel) {
+        if (dominant == null || recessive == null) {
             return;
         }
 
-        recessive.setSourceLevel( recessiveSourceLevel );
+        recessive.setSourceLevel(recessiveSourceLevel);
 
-        shallowMerge( dominant.getToolchains(), recessive.getToolchains(), recessiveSourceLevel );
+        dominant.update(new org.apache.maven.toolchain.v4.MavenToolchainsMerger()
+                .merge(dominant.getDelegate(), recessive.getDelegate(), true, null));
     }
-
-    private void shallowMerge( List<ToolchainModel> dominant, List<ToolchainModel> recessive,
-                               String recessiveSourceLevel )
-    {
-        Map<Object, ToolchainModel> merged = new LinkedHashMap<>();
-
-        for ( ToolchainModel dominantModel : dominant )
-        {
-            Object key = getToolchainModelKey( dominantModel );
-
-            merged.put( key, dominantModel );
-        }
-
-        for ( ToolchainModel recessiveModel : recessive )
-        {
-            Object key = getToolchainModelKey( recessiveModel );
-
-            ToolchainModel dominantModel = merged.get( key );
-            if ( dominantModel == null )
-            {
-                recessiveModel.setSourceLevel( recessiveSourceLevel );
-                dominant.add( recessiveModel );
-            }
-            else
-            {
-                mergeToolchainModelConfiguration( dominantModel, recessiveModel );
-            }
-        }
-    }
-
-    protected void mergeToolchainModelConfiguration( ToolchainModel target,
-                                                    ToolchainModel source )
-    {
-        Xpp3Dom src = (Xpp3Dom) source.getConfiguration();
-        if ( src != null )
-        {
-            Xpp3Dom tgt = (Xpp3Dom) target.getConfiguration();
-            if ( tgt == null )
-            {
-                tgt = Xpp3Dom.mergeXpp3Dom( new Xpp3Dom( src ), tgt );
-            }
-            else
-            {
-                tgt = Xpp3Dom.mergeXpp3Dom( tgt, src );
-            }
-            target.setConfiguration( tgt );
-        }
-    }
-
-    protected Object getToolchainModelKey( ToolchainModel model )
-    {
-        return model;
-    }
-
-}
\ No newline at end of file
+}
diff --git a/maven-toolchain-builder/src/site/site.xml b/maven-toolchain-builder/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/maven-toolchain-builder/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java
index 6460aaf..80e44ec 100644
--- a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java
+++ b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/DefaultToolchainsBuilderTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,6 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
 
 import org.apache.maven.building.StringSource;
 import org.apache.maven.toolchain.io.DefaultToolchainsReader;
@@ -34,19 +40,13 @@
 import org.mockito.MockitoAnnotations;
 import org.mockito.Spy;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 
-public class DefaultToolchainsBuilderTest
-{
+class DefaultToolchainsBuilderTest {
     private static final String LS = System.lineSeparator();
 
     @Spy
@@ -59,9 +59,8 @@
     private DefaultToolchainsBuilder toolchainBuilder;
 
     @BeforeEach
-    public void onSetup()
-    {
-        MockitoAnnotations.initMocks( this );
+    void onSetup() {
+        MockitoAnnotations.initMocks(this);
 
         Map<String, String> envVarMap = new HashMap<>();
         envVarMap.put("testKey", "testValue");
@@ -70,202 +69,264 @@
     }
 
     @Test
-    public void testBuildEmptyRequest()
-        throws Exception
-    {
+    void testBuildEmptyRequest() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        ToolchainsBuildingResult result = toolchainBuilder.build( request );
-        assertNotNull( result.getEffectiveToolchains() );
-        assertNotNull( result.getProblems() );
-        assertEquals( 0, result.getProblems().size() );
+        ToolchainsBuildingResult result = toolchainBuilder.build(request);
+        assertNotNull(result.getEffectiveToolchains());
+        assertNotNull(result.getProblems());
+        assertEquals(0, result.getProblems().size());
     }
 
     @Test
-    public void testBuildRequestWithUserToolchains()
-        throws Exception
-    {
+    void testBuildRequestWithUserToolchains() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setUserToolchainsSource( new StringSource( "" ) );
+        request.setUserToolchainsSource(new StringSource(""));
 
+        Properties props = new Properties();
+        props.put("key", "user_value");
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType("TYPE");
+        toolchain.setProvides(props);
         PersistedToolchains userResult = new PersistedToolchains();
-        ToolchainModel toolchain = new ToolchainModel();
-        toolchain.setType( "TYPE" );
-        toolchain.addProvide( "key", "user_value" );
-        userResult.addToolchain(  toolchain );
-        doReturn(userResult).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        userResult.setToolchains(Collections.singletonList(toolchain));
+        doReturn(userResult)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
 
-        ToolchainsBuildingResult result = toolchainBuilder.build( request );
-        assertNotNull( result.getEffectiveToolchains() );
-        assertEquals( 1, result.getEffectiveToolchains().getToolchains().size() );
-        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType() );
-        assertEquals( "user_value", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
-        assertNotNull( result.getProblems() );
-        assertEquals( 0, result.getProblems().size() );
+        ToolchainsBuildingResult result = toolchainBuilder.build(request);
+        assertNotNull(result.getEffectiveToolchains());
+        assertEquals(1, result.getEffectiveToolchains().getToolchains().size());
+        assertEquals(
+                "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType());
+        assertEquals(
+                "user_value",
+                result.getEffectiveToolchains()
+                        .getToolchains()
+                        .get(0)
+                        .getProvides()
+                        .get("key"));
+        assertNotNull(result.getProblems());
+        assertEquals(0, result.getProblems().size());
     }
 
     @Test
-    public void testBuildRequestWithGlobalToolchains()
-        throws Exception
-    {
+    void testBuildRequestWithGlobalToolchains() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setGlobalToolchainsSource( new StringSource( "" ) );
+        request.setGlobalToolchainsSource(new StringSource(""));
 
+        Properties props = new Properties();
+        props.put("key", "global_value");
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType("TYPE");
+        toolchain.setProvides(props);
         PersistedToolchains globalResult = new PersistedToolchains();
-        ToolchainModel toolchain = new ToolchainModel();
-        toolchain.setType( "TYPE" );
-        toolchain.addProvide( "key", "global_value" );
-        globalResult.addToolchain(  toolchain );
-        doReturn(globalResult).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        globalResult.setToolchains(Collections.singletonList(toolchain));
+        doReturn(globalResult)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
 
-        ToolchainsBuildingResult result = toolchainBuilder.build( request );
-        assertNotNull( result.getEffectiveToolchains() );
-        assertEquals( 1, result.getEffectiveToolchains().getToolchains().size() );
-        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType() );
-        assertEquals( "global_value", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
-        assertNotNull( result.getProblems() );
-        assertEquals( 0, result.getProblems().size() );
+        ToolchainsBuildingResult result = toolchainBuilder.build(request);
+        assertNotNull(result.getEffectiveToolchains());
+        assertEquals(1, result.getEffectiveToolchains().getToolchains().size());
+        assertEquals(
+                "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType());
+        assertEquals(
+                "global_value",
+                result.getEffectiveToolchains()
+                        .getToolchains()
+                        .get(0)
+                        .getProvides()
+                        .get("key"));
+        assertNotNull(result.getProblems());
+        assertEquals(0, result.getProblems().size());
     }
 
     @Test
-    public void testBuildRequestWithBothToolchains()
-        throws Exception
-    {
+    void testBuildRequestWithBothToolchains() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setGlobalToolchainsSource( new StringSource( "" ) );
-        request.setUserToolchainsSource( new StringSource( "" ) );
+        request.setGlobalToolchainsSource(new StringSource(""));
+        request.setUserToolchainsSource(new StringSource(""));
 
+        Properties props = new Properties();
+        props.put("key", "user_value");
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType("TYPE");
+        toolchain.setProvides(props);
         PersistedToolchains userResult = new PersistedToolchains();
-        ToolchainModel userToolchain = new ToolchainModel();
-        userToolchain.setType( "TYPE" );
-        userToolchain.addProvide( "key", "user_value" );
-        userResult.addToolchain(  userToolchain );
+        userResult.setToolchains(Collections.singletonList(toolchain));
 
+        props = new Properties();
+        props.put("key", "global_value");
+        toolchain = new ToolchainModel();
+        toolchain.setType("TYPE");
+        toolchain.setProvides(props);
         PersistedToolchains globalResult = new PersistedToolchains();
-        ToolchainModel globalToolchain = new ToolchainModel();
-        globalToolchain.setType( "TYPE" );
-        globalToolchain.addProvide( "key", "global_value" );
-        globalResult.addToolchain(  globalToolchain );
-        doReturn(globalResult).doReturn(userResult).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        globalResult.setToolchains(Collections.singletonList(toolchain));
 
-        ToolchainsBuildingResult result = toolchainBuilder.build( request );
-        assertNotNull( result.getEffectiveToolchains() );
-        assertEquals( 2, result.getEffectiveToolchains().getToolchains().size() );
-        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType() );
-        assertEquals( "user_value", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
-        assertEquals( "TYPE", result.getEffectiveToolchains().getToolchains().get(1).getType() );
-        assertEquals( "global_value", result.getEffectiveToolchains().getToolchains().get(1).getProvides().getProperty( "key" ) );
-        assertNotNull( result.getProblems() );
-        assertEquals( 0, result.getProblems().size() );
+        doReturn(globalResult)
+                .doReturn(userResult)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build(request);
+        assertNotNull(result.getEffectiveToolchains());
+        assertEquals(2, result.getEffectiveToolchains().getToolchains().size());
+        assertEquals(
+                "TYPE", result.getEffectiveToolchains().getToolchains().get(0).getType());
+        assertEquals(
+                "user_value",
+                result.getEffectiveToolchains()
+                        .getToolchains()
+                        .get(0)
+                        .getProvides()
+                        .get("key"));
+        assertEquals(
+                "TYPE", result.getEffectiveToolchains().getToolchains().get(1).getType());
+        assertEquals(
+                "global_value",
+                result.getEffectiveToolchains()
+                        .getToolchains()
+                        .get(1)
+                        .getProvides()
+                        .get("key"));
+        assertNotNull(result.getProblems());
+        assertEquals(0, result.getProblems().size());
     }
 
     @Test
-    public void testStrictToolchainsParseException() throws Exception
-    {
+    void testStrictToolchainsParseException() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setGlobalToolchainsSource( new StringSource( "" ) );
-        ToolchainsParseException parseException = new ToolchainsParseException( "MESSAGE", 4, 2 );
-        doThrow(parseException).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        request.setGlobalToolchainsSource(new StringSource(""));
+        ToolchainsParseException parseException = new ToolchainsParseException("MESSAGE", 4, 2);
+        doThrow(parseException)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
 
-        try
-        {
-            toolchainBuilder.build( request );
-        }
-        catch ( ToolchainsBuildingException e )
-        {
-            assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
-                "[FATAL] Non-parseable toolchains (memory): MESSAGE @ line 4, column 2" + LS, e.getMessage() );
+        try {
+            toolchainBuilder.build(request);
+        } catch (ToolchainsBuildingException e) {
+            assertEquals(
+                    "1 problem was encountered while building the effective toolchains" + LS
+                            + "[FATAL] Non-parseable toolchains (memory): MESSAGE @ line 4, column 2" + LS,
+                    e.getMessage());
         }
     }
 
     @Test
-    public void testIOException() throws Exception
-    {
+    void testIOException() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setGlobalToolchainsSource( new StringSource( "", "LOCATION" ) );
-        IOException ioException = new IOException( "MESSAGE" );
-        doThrow(ioException).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        request.setGlobalToolchainsSource(new StringSource("", "LOCATION"));
+        IOException ioException = new IOException("MESSAGE");
+        doThrow(ioException)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
 
-        try
-        {
-            toolchainBuilder.build( request );
-        }
-        catch ( ToolchainsBuildingException e )
-        {
-            assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
-                "[FATAL] Non-readable toolchains LOCATION: MESSAGE" + LS, e.getMessage() );
+        try {
+            toolchainBuilder.build(request);
+        } catch (ToolchainsBuildingException e) {
+            assertEquals(
+                    "1 problem was encountered while building the effective toolchains" + LS
+                            + "[FATAL] Non-readable toolchains LOCATION: MESSAGE" + LS,
+                    e.getMessage());
         }
     }
 
     @Test
-    public void testEnvironmentVariablesAreInterpolated()
-            throws Exception
-    {
+    void testEnvironmentVariablesAreInterpolated() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setUserToolchainsSource( new StringSource( "" ) );
+        request.setUserToolchainsSource(new StringSource(""));
 
-        PersistedToolchains persistedToolchains = new PersistedToolchains();
-        ToolchainModel toolchain = new ToolchainModel();
-        toolchain.setType( "TYPE" );
-        toolchain.addProvide( "key", "${env.testKey}" );
-
+        Properties props = new Properties();
+        props.put("key", "${env.testKey}");
         Xpp3Dom configurationChild = new Xpp3Dom("jdkHome");
         configurationChild.setValue("${env.testKey}");
         Xpp3Dom configuration = new Xpp3Dom("configuration");
         configuration.addChild(configurationChild);
+        ToolchainModel toolchain = new ToolchainModel();
+        toolchain.setType("TYPE");
+        toolchain.setProvides(props);
         toolchain.setConfiguration(configuration);
-        persistedToolchains.addToolchain( toolchain );
-        doReturn(persistedToolchains).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        persistedToolchains.setToolchains(Collections.singletonList(toolchain));
 
-        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        doReturn(persistedToolchains)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
+
+        ToolchainsBuildingResult result = toolchainBuilder.build(request);
         String interpolatedValue = "testValue";
-        assertEquals(interpolatedValue, result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
-        Xpp3Dom toolchainConfiguration = (Xpp3Dom) result.getEffectiveToolchains().getToolchains().get(0).getConfiguration();
-        assertEquals(interpolatedValue, toolchainConfiguration.getChild("jdkHome").getValue());
-        assertNotNull( result.getProblems() );
-        assertEquals( 0, result.getProblems().size() );
+        assertEquals(
+                interpolatedValue,
+                result.getEffectiveToolchains()
+                        .getToolchains()
+                        .get(0)
+                        .getProvides()
+                        .get("key"));
+        org.codehaus.plexus.util.xml.Xpp3Dom toolchainConfiguration = (org.codehaus.plexus.util.xml.Xpp3Dom)
+                result.getEffectiveToolchains().getToolchains().get(0).getConfiguration();
+        assertEquals(
+                interpolatedValue, toolchainConfiguration.getChild("jdkHome").getValue());
+        assertNotNull(result.getProblems());
+        assertEquals(0, result.getProblems().size());
     }
 
     @Test
-    public void testNonExistingEnvironmentVariablesAreNotInterpolated()
-            throws Exception
-    {
+    void testNonExistingEnvironmentVariablesAreNotInterpolated() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setUserToolchainsSource( new StringSource( "" ) );
+        request.setUserToolchainsSource(new StringSource(""));
 
-        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        Properties props = new Properties();
+        props.put("key", "${env.testNonExistingKey}");
         ToolchainModel toolchain = new ToolchainModel();
-        toolchain.setType( "TYPE" );
-        toolchain.addProvide( "key", "${env.testNonExistingKey}" );
+        toolchain.setType("TYPE");
+        toolchain.setProvides(props);
+        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        persistedToolchains.setToolchains(Collections.singletonList(toolchain));
 
-        persistedToolchains.addToolchain( toolchain );
-        doReturn(persistedToolchains).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        doReturn(persistedToolchains)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
 
-        ToolchainsBuildingResult result = toolchainBuilder.build( request );
-        assertEquals("${env.testNonExistingKey}", result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
-        assertNotNull( result.getProblems() );
-        assertEquals( 0, result.getProblems().size() );
+        ToolchainsBuildingResult result = toolchainBuilder.build(request);
+        assertEquals(
+                "${env.testNonExistingKey}",
+                result.getEffectiveToolchains()
+                        .getToolchains()
+                        .get(0)
+                        .getProvides()
+                        .get("key"));
+        assertNotNull(result.getProblems());
+        assertEquals(0, result.getProblems().size());
     }
 
     @Test
-    public void testEnvironmentVariablesWithSpecialCharactersAreInterpolated()
-            throws Exception
-    {
+    void testEnvironmentVariablesWithSpecialCharactersAreInterpolated() throws Exception {
         ToolchainsBuildingRequest request = new DefaultToolchainsBuildingRequest();
-        request.setUserToolchainsSource( new StringSource( "" ) );
+        request.setUserToolchainsSource(new StringSource(""));
 
-        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        Properties props = new Properties();
+        props.put("key", "${env.testSpecialCharactersKey}");
         ToolchainModel toolchain = new ToolchainModel();
-        toolchain.setType( "TYPE" );
-        toolchain.addProvide( "key", "${env.testSpecialCharactersKey}" );
+        toolchain.setType("TYPE");
+        toolchain.setProvides(props);
+        PersistedToolchains persistedToolchains = new PersistedToolchains();
+        persistedToolchains.setToolchains(Collections.singletonList(toolchain));
 
-        persistedToolchains.addToolchain( toolchain );
-        doReturn(persistedToolchains).when( toolchainsReader ).read( any( InputStream.class ), ArgumentMatchers.<String, Object>anyMap());
+        doReturn(persistedToolchains)
+                .when(toolchainsReader)
+                .read(any(InputStream.class), ArgumentMatchers.<String, Object>anyMap());
 
-        ToolchainsBuildingResult result = toolchainBuilder.build( request );
+        ToolchainsBuildingResult result = toolchainBuilder.build(request);
         String interpolatedValue = "<test&Value>";
-        assertEquals(interpolatedValue, result.getEffectiveToolchains().getToolchains().get(0).getProvides().getProperty( "key" ) );
-        assertNotNull( result.getProblems() );
-        assertEquals( 0, result.getProblems().size() );
+        assertEquals(
+                interpolatedValue,
+                result.getEffectiveToolchains()
+                        .getToolchains()
+                        .get(0)
+                        .getProvides()
+                        .get("key"));
+        assertNotNull(result.getProblems());
+        assertEquals(0, result.getProblems().size());
     }
 
     static class TestEnvVarSource implements OperatingSystemUtils.EnvVarSource {
@@ -279,5 +340,4 @@
             return envVarMap;
         }
     }
-
 }
diff --git a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java
index 0ad1087..092492e 100644
--- a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java
+++ b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/building/ToolchainsBuildingExceptionTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.building;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,56 +16,56 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.building;
+
+import java.util.Collections;
 
 import org.apache.maven.building.Problem;
 import org.apache.maven.building.ProblemCollector;
 import org.apache.maven.building.ProblemCollectorFactory;
 import org.junit.jupiter.api.Test;
 
-import java.util.Collections;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class ToolchainsBuildingExceptionTest
-{
+class ToolchainsBuildingExceptionTest {
     private static final String LS = System.lineSeparator();
 
     @Test
-    public void testNoProblems()
-    {
-        ToolchainsBuildingException e = new ToolchainsBuildingException( Collections.<Problem>emptyList() );
-        assertEquals( "0 problems were encountered while building the effective toolchains" + LS, e.getMessage() );
+    void testNoProblems() {
+        ToolchainsBuildingException e = new ToolchainsBuildingException(Collections.<Problem>emptyList());
+        assertEquals("0 problems were encountered while building the effective toolchains" + LS, e.getMessage());
     }
 
     @Test
-    public void testOneProblem()
-    {
-        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance( null );
-        problemCollector.add( Problem.Severity.ERROR, "MESSAGE", 3, 5, new Exception() );
-        ToolchainsBuildingException e = new ToolchainsBuildingException( problemCollector.getProblems() );
-        assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
-                      "[ERROR] MESSAGE @ line 3, column 5" + LS, e.getMessage() );
+    void testOneProblem() {
+        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance(null);
+        problemCollector.add(Problem.Severity.ERROR, "MESSAGE", 3, 5, new Exception());
+        ToolchainsBuildingException e = new ToolchainsBuildingException(problemCollector.getProblems());
+        assertEquals(
+                "1 problem was encountered while building the effective toolchains" + LS
+                        + "[ERROR] MESSAGE @ line 3, column 5" + LS,
+                e.getMessage());
     }
 
     @Test
-    public void testUnknownPositionAndSource()
-    {
-        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance( null );
-        problemCollector.add( Problem.Severity.ERROR, "MESSAGE", -1, -1, new Exception() );
-        ToolchainsBuildingException e = new ToolchainsBuildingException( problemCollector.getProblems() );
-        assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
-                      "[ERROR] MESSAGE" + LS, e.getMessage() );
+    void testUnknownPositionAndSource() {
+        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance(null);
+        problemCollector.add(Problem.Severity.ERROR, "MESSAGE", -1, -1, new Exception());
+        ToolchainsBuildingException e = new ToolchainsBuildingException(problemCollector.getProblems());
+        assertEquals(
+                "1 problem was encountered while building the effective toolchains" + LS + "[ERROR] MESSAGE" + LS,
+                e.getMessage());
     }
 
     @Test
-    public void testUnknownPosition()
-    {
-        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance( null );
-        problemCollector.setSource( "SOURCE" );
-        problemCollector.add( Problem.Severity.ERROR, "MESSAGE", -1, -1, new Exception() );
-        ToolchainsBuildingException e = new ToolchainsBuildingException( problemCollector.getProblems() );
-        assertEquals( "1 problem was encountered while building the effective toolchains" + LS +
-                      "[ERROR] MESSAGE @ SOURCE" + LS, e.getMessage() );
+    void testUnknownPosition() {
+        ProblemCollector problemCollector = ProblemCollectorFactory.newInstance(null);
+        problemCollector.setSource("SOURCE");
+        problemCollector.add(Problem.Severity.ERROR, "MESSAGE", -1, -1, new Exception());
+        ToolchainsBuildingException e = new ToolchainsBuildingException(problemCollector.getProblems());
+        assertEquals(
+                "1 problem was encountered while building the effective toolchains" + LS + "[ERROR] MESSAGE @ SOURCE"
+                        + LS,
+                e.getMessage());
     }
-
 }
diff --git a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/merge/MavenToolchainMergerTest.java b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/merge/MavenToolchainMergerTest.java
index 7bed9a9..3379ef6 100644
--- a/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/merge/MavenToolchainMergerTest.java
+++ b/maven-toolchain-builder/src/test/java/org/apache/maven/toolchain/merge/MavenToolchainMergerTest.java
@@ -1,5 +1,3 @@
-package org.apache.maven.toolchain.merge;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -9,7 +7,7 @@
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
  *
- *  http://www.apache.org/licenses/LICENSE-2.0
+ *   http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
@@ -18,118 +16,114 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.maven.toolchain.merge;
 
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+
+import org.apache.maven.toolchain.io.DefaultToolchainsReader;
 import org.apache.maven.toolchain.model.PersistedToolchains;
-import org.apache.maven.toolchain.model.ToolchainModel;
 import org.apache.maven.toolchain.model.TrackableBase;
-import org.apache.maven.toolchain.model.io.xpp3.MavenToolchainsXpp3Reader;
 import org.codehaus.plexus.util.xml.Xpp3Dom;
 import org.junit.jupiter.api.Test;
 
-import java.io.InputStream;
-
 import static org.junit.jupiter.api.Assertions.assertEquals;
 
-public class MavenToolchainMergerTest
-{
+class MavenToolchainMergerTest {
     private MavenToolchainMerger merger = new MavenToolchainMerger();
 
-    private MavenToolchainsXpp3Reader reader = new MavenToolchainsXpp3Reader();
+    private DefaultToolchainsReader reader = new DefaultToolchainsReader();
 
     @Test
-    public void testMergeNulls()
-    {
-        merger.merge( null, null, null );
+    void testMergeNulls() {
+        merger.merge(null, null, null);
 
         PersistedToolchains pt = new PersistedToolchains();
-        merger.merge( pt, null, null );
-        merger.merge( null, pt, null );
+        merger.merge(pt, null, null);
+        merger.merge(null, pt, null);
     }
 
     @Test
-    public void testMergeJdk()
-        throws Exception
-    {
-        try ( InputStream isDominant = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
-              InputStream isRecessive = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" ) )
-        {
-            PersistedToolchains dominant = reader.read( isDominant );
-            PersistedToolchains recessive = reader.read( isRecessive );
-            assertEquals( 2, dominant.getToolchains().size() );
+    void testMergeJdk() throws Exception {
+        try (InputStream isDominant = MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks.xml");
+                InputStream isRecessive = MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks.xml")) {
+            PersistedToolchains dominant = read(isDominant);
+            PersistedToolchains recessive = read(isRecessive);
+            assertEquals(2, dominant.getToolchains().size());
 
-            merger.merge( dominant, recessive, TrackableBase.USER_LEVEL );
-            assertEquals( 2, dominant.getToolchains().size() );
+            merger.merge(dominant, recessive, TrackableBase.USER_LEVEL);
+            assertEquals(2, dominant.getToolchains().size());
         }
     }
 
     @Test
-    public void testMergeJdkExtra()
-        throws Exception
-    {
-        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
-              InputStream jdksExtraIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extra.xml" ) )
-        {
-            PersistedToolchains jdks = reader.read( jdksIS );
-            PersistedToolchains jdksExtra = reader.read( jdksExtraIS );
-            assertEquals( 2, jdks.getToolchains().size() );
+    void testMergeJdkExtra() throws Exception {
+        try (InputStream jdksIS = MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks.xml");
+                InputStream jdksExtraIS =
+                        MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks-extra.xml")) {
+            PersistedToolchains jdks = read(jdksIS);
+            PersistedToolchains jdksExtra = read(jdksExtraIS);
+            assertEquals(2, jdks.getToolchains().size());
 
-            merger.merge( jdks, jdksExtra, TrackableBase.USER_LEVEL );
-            assertEquals( 4, jdks.getToolchains().size() );
-            assertEquals( 2, jdksExtra.getToolchains().size() );
+            merger.merge(jdks, jdksExtra, TrackableBase.USER_LEVEL);
+            assertEquals(4, jdks.getToolchains().size());
+            assertEquals(2, jdksExtra.getToolchains().size());
         }
-        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
-              InputStream jdksExtraIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extra.xml" ) )
-        {
-            PersistedToolchains jdks = reader.read( jdksIS );
-            PersistedToolchains jdksExtra = reader.read( jdksExtraIS );
-            assertEquals( 2, jdks.getToolchains().size() );
+        try (InputStream jdksIS = MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks.xml");
+                InputStream jdksExtraIS =
+                        MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks-extra.xml")) {
+            PersistedToolchains jdks = read(jdksIS);
+            PersistedToolchains jdksExtra = read(jdksExtraIS);
+            assertEquals(2, jdks.getToolchains().size());
 
             // switch dominant with recessive
-            merger.merge( jdksExtra, jdks, TrackableBase.USER_LEVEL );
-            assertEquals( 4, jdksExtra.getToolchains().size() );
-            assertEquals( 2, jdks.getToolchains().size() );
+            merger.merge(jdksExtra, jdks, TrackableBase.USER_LEVEL);
+            assertEquals(4, jdksExtra.getToolchains().size());
+            assertEquals(2, jdks.getToolchains().size());
         }
     }
 
     @Test
-    public void testMergeJdkExtend()
-        throws Exception
-    {
-        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
-              InputStream jdksExtendIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extend.xml" ) )
-        {
-            PersistedToolchains jdks = reader.read( jdksIS );
-            PersistedToolchains jdksExtend = reader.read( jdksExtendIS );
-            assertEquals( 2, jdks.getToolchains().size() );
+    void testMergeJdkExtend() throws Exception {
+        try (InputStream jdksIS = MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks.xml");
+                InputStream jdksExtendIS =
+                        MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks-extend.xml")) {
+            PersistedToolchains jdks = read(jdksIS);
+            PersistedToolchains jdksExtend = read(jdksExtendIS);
+            assertEquals(2, jdks.getToolchains().size());
 
-            merger.merge( jdks, jdksExtend, TrackableBase.USER_LEVEL );
-            assertEquals( 2, jdks.getToolchains().size() );
-            Xpp3Dom config0 = (Xpp3Dom) jdks.getToolchains().get( 0 ).getConfiguration();
-            assertEquals( "lib/tools.jar", config0.getChild( "toolsJar" ).getValue() );
-            assertEquals( 2, config0.getChildCount() );
-            Xpp3Dom config1 = (Xpp3Dom) jdks.getToolchains().get( 1 ).getConfiguration();
-            assertEquals( 2, config1.getChildCount() );
-            assertEquals( "lib/classes.jar", config1.getChild( "toolsJar" ).getValue() );
-            assertEquals( 2, jdksExtend.getToolchains().size() );
+            merger.merge(jdks, jdksExtend, TrackableBase.USER_LEVEL);
+            assertEquals(2, jdks.getToolchains().size());
+            Xpp3Dom config0 = (Xpp3Dom) jdks.getToolchains().get(0).getConfiguration();
+            assertEquals("lib/tools.jar", config0.getChild("toolsJar").getValue());
+            assertEquals(2, config0.getChildCount());
+            Xpp3Dom config1 = (Xpp3Dom) jdks.getToolchains().get(1).getConfiguration();
+            assertEquals(2, config1.getChildCount());
+            assertEquals("lib/classes.jar", config1.getChild("toolsJar").getValue());
+            assertEquals(2, jdksExtend.getToolchains().size());
         }
-        try ( InputStream jdksIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks.xml" );
-              InputStream jdksExtendIS = ToolchainModel.class.getResourceAsStream( "toolchains-jdks-extend.xml" ) )
-        {
-            PersistedToolchains jdks = reader.read( jdksIS );
-            PersistedToolchains jdksExtend = reader.read( jdksExtendIS );
-            assertEquals( 2, jdks.getToolchains().size() );
+        try (InputStream jdksIS = MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks.xml");
+                InputStream jdksExtendIS =
+                        MavenToolchainMergerTest.class.getResourceAsStream("toolchains-jdks-extend.xml")) {
+            PersistedToolchains jdks = read(jdksIS);
+            PersistedToolchains jdksExtend = read(jdksExtendIS);
+            assertEquals(2, jdks.getToolchains().size());
 
             // switch dominant with recessive
-            merger.merge( jdksExtend, jdks, TrackableBase.USER_LEVEL );
-            assertEquals( 2, jdksExtend.getToolchains().size() );
-            Xpp3Dom config0 = (Xpp3Dom) jdksExtend.getToolchains().get( 0 ).getConfiguration();
-            assertEquals( "lib/tools.jar", config0.getChild( "toolsJar" ).getValue() );
-            assertEquals( 2, config0.getChildCount() );
-            Xpp3Dom config1 = (Xpp3Dom) jdksExtend.getToolchains().get( 1 ).getConfiguration();
-            assertEquals( 2, config1.getChildCount() );
-            assertEquals( "lib/classes.jar", config1.getChild( "toolsJar" ).getValue() );
-            assertEquals( 2, jdks.getToolchains().size() );
+            merger.merge(jdksExtend, jdks, TrackableBase.USER_LEVEL);
+            assertEquals(2, jdksExtend.getToolchains().size());
+            Xpp3Dom config0 = (Xpp3Dom) jdksExtend.getToolchains().get(0).getConfiguration();
+            assertEquals("lib/tools.jar", config0.getChild("toolsJar").getValue());
+            assertEquals(2, config0.getChildCount());
+            Xpp3Dom config1 = (Xpp3Dom) jdksExtend.getToolchains().get(1).getConfiguration();
+            assertEquals(2, config1.getChildCount());
+            assertEquals("lib/classes.jar", config1.getChild("toolsJar").getValue());
+            assertEquals(2, jdks.getToolchains().size());
         }
     }
 
+    private PersistedToolchains read(InputStream is) throws IOException {
+        return reader.read(is, Collections.emptyMap());
+    }
 }
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks-extend.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks-extend.xml
new file mode 100644
index 0000000..637ace9
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks-extend.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.5</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+        <toolsJar>lib/tools.jar</toolsJar>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.6</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+        <toolsJar>lib/classes.jar</toolsJar>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks-extra.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks-extra.xml
new file mode 100644
index 0000000..6ab6c10
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks-extra.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.4</version>
+         <vendor>sun</vendor>
+         <!-- no id, so it's considered 'default' -->
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.7</version>
+         <vendor>ibm</vendor>
+         <id>ibm_17</id>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks.xml
new file mode 100644
index 0000000..8ef961b
--- /dev/null
+++ b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/merge/toolchains-jdks.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<toolchains>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.5</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+  <toolchain>
+     <type>jdk</type>
+     <provides>
+         <version>1.6</version>
+         <vendor>sun</vendor>
+     </provides>
+     <configuration>
+        <jdkHome>${env.JAVA_HOME}</jdkHome>
+     </configuration>
+  </toolchain>
+</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extend.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extend.xml
deleted file mode 100644
index 64de88a..0000000
--- a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extend.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF8"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<toolchains>
-  <toolchain>
-     <type>jdk</type>
-     <provides>
-         <version>1.5</version>
-         <vendor>sun</vendor>
-     </provides>
-     <configuration>
-        <jdkHome>${env.JAVA_HOME}</jdkHome>
-        <toolsJar>lib/tools.jar</toolsJar>
-     </configuration>
-  </toolchain>
-  <toolchain>
-     <type>jdk</type>
-     <provides>
-         <version>1.6</version>
-         <vendor>sun</vendor>
-     </provides>
-     <configuration>
-        <jdkHome>${env.JAVA_HOME}</jdkHome>
-        <toolsJar>lib/classes.jar</toolsJar>
-     </configuration>
-  </toolchain>
-</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extra.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extra.xml
deleted file mode 100644
index 35c3217..0000000
--- a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks-extra.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="UTF8"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<toolchains>
-  <toolchain>
-     <type>jdk</type>
-     <provides>
-         <version>1.4</version>
-         <vendor>sun</vendor>
-         <!-- no id, so it's considered 'default' -->
-     </provides>
-     <configuration>
-        <jdkHome>${env.JAVA_HOME}</jdkHome>
-     </configuration>
-  </toolchain>
-  <toolchain>
-     <type>jdk</type>
-     <provides>
-         <version>1.7</version>
-         <vendor>ibm</vendor>
-         <id>ibm_17</id>
-     </provides>
-     <configuration>
-        <jdkHome>${env.JAVA_HOME}</jdkHome>
-     </configuration>
-  </toolchain>
-</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks.xml b/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks.xml
deleted file mode 100644
index 5233a33..0000000
--- a/maven-toolchain-builder/src/test/resources/org/apache/maven/toolchain/model/toolchains-jdks.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF8"?>
-
-<!--
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-  http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
--->
-
-<toolchains>
-  <toolchain>
-     <type>jdk</type>
-     <provides>
-         <version>1.5</version>
-         <vendor>sun</vendor>
-     </provides>
-     <configuration>
-        <jdkHome>${env.JAVA_HOME}</jdkHome>
-     </configuration>
-  </toolchain>
-  <toolchain>
-     <type>jdk</type>
-     <provides>
-         <version>1.6</version>
-         <vendor>sun</vendor>
-     </provides>
-     <configuration>
-        <jdkHome>${env.JAVA_HOME}</jdkHome>
-     </configuration>
-  </toolchain>
-</toolchains>
\ No newline at end of file
diff --git a/maven-toolchain-model/pom.xml b/maven-toolchain-model/pom.xml
index cf32371..e29e9d7 100644
--- a/maven-toolchain-model/pom.xml
+++ b/maven-toolchain-model/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,42 +17,99 @@
 specific language governing permissions and limitations
 under the License.
 -->
+<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>org.apache.maven</groupId>
+    <artifactId>maven</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
 
-<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">
-    <parent>
-        <artifactId>maven</artifactId>
-        <groupId>org.apache.maven</groupId>
-        <version>4.0.0-alpha-1-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
+  <artifactId>maven-toolchain-model</artifactId>
 
-    <artifactId>maven-toolchain-model</artifactId>
+  <name>Maven Toolchain Model</name>
+  <description>Maven Toolchain model.</description>
 
-    <name>Maven Toolchain Model</name>
-    <description>Maven Toolchain model.</description>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-toolchain</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-xml-impl</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-xml</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.woodstox</groupId>
+      <artifactId>woodstox-core</artifactId>
+    </dependency>
+  </dependencies>
 
-    <dependencies>
-        <dependency>
-            <groupId>org.codehaus.plexus</groupId>
-            <artifactId>plexus-utils</artifactId>
-        </dependency>
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.codehaus.modello</groupId>
-                <artifactId>modello-maven-plugin</artifactId>
-                <configuration>
-                    <version>1.1.0</version>
-                    <models>
-                        <model>src/main/mdo/toolchains.mdo</model>
-                    </models>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.modello</groupId>
+        <artifactId>modello-maven-plugin</artifactId>
+        <configuration>
+          <version>1.1.0</version>
+          <basedir>${project.basedir}/../api/maven-api-toolchain</basedir>
+          <velocityBasedir>${project.basedir}/../src/mdo</velocityBasedir>
+          <models>
+            <model>src/main/mdo/toolchains.mdo</model>
+          </models>
+        </configuration>
+        <executions>
+          <execution>
+            <id>velocity</id>
+            <goals>
+              <goal>velocity</goal>
+            </goals>
+            <phase>generate-sources</phase>
+            <configuration>
+              <templates>
+                <template>model-v3.vm</template>
+                <template>merger.vm</template>
+                <template>reader-stax.vm</template>
+                <template>writer-stax.vm</template>
+              </templates>
+              <params>
+                <param>packageModelV3=org.apache.maven.toolchain.model</param>
+                <param>packageModelV4=org.apache.maven.api.toolchain</param>
+                <param>packageToolV4=org.apache.maven.toolchain.v4</param>
+              </params>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>com.github.siom79.japicmp</groupId>
+        <artifactId>japicmp-maven-plugin</artifactId>
+        <configuration>
+          <parameter>
+            <includes>
+              <include>org.apache.maven.toolchain.model</include>
+            </includes>
+            <excludes>
+              <exclude>org.apache.maven.toolchain.model.PersistedToolchains#setModelEncoding(java.lang.String):METHOD_REMOVED</exclude>
+            </excludes>
+            <includeExclusively>true</includeExclusively>
+          </parameter>
+          <oldVersion>
+            <dependency>
+              <groupId>org.apache.maven</groupId>
+              <artifactId>maven-core</artifactId>
+              <version>${maven.baseline}</version>
+            </dependency>
+          </oldVersion>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
 
 </project>
diff --git a/maven-toolchain-model/src/main/java/org/apache/maven/toolchain/model/BaseObject.java b/maven-toolchain-model/src/main/java/org/apache/maven/toolchain/model/BaseObject.java
new file mode 100644
index 0000000..28bea64
--- /dev/null
+++ b/maven-toolchain-model/src/main/java/org/apache/maven/toolchain/model/BaseObject.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.toolchain.model;
+
+import java.io.Serializable;
+
+public abstract class BaseObject implements Serializable, Cloneable {
+    protected transient ChildrenTracking childrenTracking;
+
+    protected Object delegate;
+
+    public BaseObject() {}
+
+    public BaseObject(Object delegate, BaseObject parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent != null ? parent::replace : null;
+    }
+
+    public BaseObject(Object delegate, ChildrenTracking parent) {
+        this.delegate = delegate;
+        this.childrenTracking = parent;
+    }
+
+    public Object getDelegate() {
+        return delegate;
+    }
+
+    public void update(Object newDelegate) {
+        if (delegate != newDelegate) {
+            if (childrenTracking != null) {
+                childrenTracking.replace(delegate, newDelegate);
+            }
+            delegate = newDelegate;
+        }
+    }
+
+    protected boolean replace(Object oldDelegate, Object newDelegate) {
+        return false;
+    }
+
+    @FunctionalInterface
+    protected interface ChildrenTracking {
+        boolean replace(Object oldDelegate, Object newDelegate);
+    }
+}
diff --git a/maven-toolchain-model/src/main/mdo/toolchains.mdo b/maven-toolchain-model/src/main/mdo/toolchains.mdo
deleted file mode 100644
index 29f742c..0000000
--- a/maven-toolchain-model/src/main/mdo/toolchains.mdo
+++ /dev/null
@@ -1,231 +0,0 @@
-<?xml version="1.0"?>
-
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing,
-  software distributed under the License is distributed on an
-  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-  KIND, either express or implied.  See the License for the
-  specific language governing permissions and limitations
-  under the License.
-
--->
-<model xmlns="http://codehaus-plexus.github.io/MODELLO/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-  xsi:schemaLocation="http://codehaus-plexus.github.io/MODELLO/1.0.0 http://codehaus-plexus.github.io/modello/xsd/modello-1.0.0.xsd"
-  xml.namespace="http://maven.apache.org/TOOLCHAINS/${version}"
-  xml.schemaLocation="http://maven.apache.org/xsd/toolchains-${version}.xsd">
-    <id>toolchains</id>
-    <name>MavenToolchains</name>
-    <description><![CDATA[
-    <p>This is a reference for the Maven Toolchains descriptor.</p>
-    <p>The default location for the toolchains file is <code>~/.m2/toolchains.xml</code></p>
-    <p>A Toolchain is a preconfigured object that Maven plugins can use for tool configuration retrieval (location and other information).</p>
-    <p>The <a href="/plugins/maven-toolchains-plugin/">toolchains-plugin</a> can read available toolchains on the user's computer
-    and match them against the toolchain requirements of the project (as configured in <code>pom.xml</code>):
-    if match is found, the toolchain instance is made available to other Maven plugins.</p>
-    <p>With <code>jdk</code> toolchain, for example, instead of being stuck with the JDK used to run Maven, all plugins can use
-    the same other JDK instance without hardcoding absolute paths into the <code>pom.xml</code>
-    and without configuring every plugin that require path to JDK tools.</p>
-    <p>See the <a href="/guides/mini/guide-using-toolchains.html">Guide to Using Toolchains</a> for
-    more information.</p>
-    ]]></description>
-
-    <defaults>
-        <default>
-            <key>package</key>
-            <value>org.apache.maven.toolchain.model</value>
-        </default>
-    </defaults>
-
-    <classes>
-    <class java.clone="deep">
-          <name>TrackableBase</name>
-          <version>1.1.0+</version>
-          <description>
-            common base class that contains code to track the source for
-            this instance (USER|GLOBAL)
-          </description>
-          <codeSegments>
-            <codeSegment>
-              <version>1.1.0+</version>
-              <code>
-                <![CDATA[
-        public static final String USER_LEVEL = "user-level";
-        public static final String GLOBAL_LEVEL = "global-level";
-
-        private String sourceLevel = USER_LEVEL;
-        private boolean sourceLevelSet = false;
-
-        public void setSourceLevel( String sourceLevel )
-        {
-            if ( sourceLevelSet )
-            {
-                throw new IllegalStateException( "Cannot reset sourceLevel attribute; it is already set to: " + sourceLevel );
-            }
-            else if ( !( USER_LEVEL.equals( sourceLevel ) || GLOBAL_LEVEL.equals( sourceLevel ) ) )
-            {
-                throw new IllegalArgumentException( "sourceLevel must be one of: {" + USER_LEVEL + "," + GLOBAL_LEVEL + "}" );
-            }
-            else
-            {
-                this.sourceLevel = sourceLevel;
-                this.sourceLevelSet = true;
-            }
-        }
-
-        public String getSourceLevel()
-        {
-            return sourceLevel;
-        }
-                ]]>
-              </code>
-            </codeSegment>
-          </codeSegments>
-        </class>
-        <class rootElement="true" xml.tagName="toolchains" xsd.compositor="sequence">
-            <name>PersistedToolchains</name>
-            <superClass>TrackableBase</superClass>
-            <description><![CDATA[
-         The <code>&lt;toolchains&gt;</code> element is the root of the descriptor.
-         The following table lists all of the possible child elements.
-            ]]></description>
-            <version>1.0.0+</version>
-            <fields>
-                <field>
-                    <name>toolchains</name>
-                    <version>1.0.0+</version>
-                    <description><![CDATA[The toolchain instance definition.]]></description>
-                    <association xml.itemsStyle="flat">
-                        <type>ToolchainModel</type>
-                        <multiplicity>*</multiplicity>
-                    </association>
-                </field>
-            </fields>
-        </class>
-        <class>
-            <name>ToolchainModel</name>
-            <superClass>TrackableBase</superClass>
-            <version>1.0.0+</version>
-            <description>Definition of a toolchain instance.</description>
-            <fields>
-                <field>
-                    <name>type</name>
-                    <version>1.0.0+</version>
-                    <!-- <identifier>true</identifier> -->
-                    <description>
-                    <![CDATA[Type of toolchain:<ul>
-                    <li><code>jdk</code> for
-                    <a href="https://maven.apache.org/plugins/maven-toolchains-plugin/toolchains/jdk.html">JDK Standard Toolchain</a>,</li>
-                    <li>other value for
-                    <a href="https://maven.apache.org/plugins/maven-toolchains-plugin/toolchains/custom.html">Custom Toolchain</a></li>
-                    </ul>
-                    ]]></description>
-                    <type>String</type>
-                </field>
-                <field>
-                    <name>provides</name>
-                    <version>1.0.0/1.0.99</version> <!-- fake upperbound, it's inclusive -->
-                    <type>DOM</type> <!-- DOM for Maven 2.0.9/2.3.3 -->
-                    <description>
-                    <![CDATA[
-                    <p>Toolchain identification information, which will be matched against project requirements.</p>
-                    <p>Actual content structure is completely open: each toolchain type will define its own format and semantics.</p>
-                    <p>In general, this is a properties format: <code>&lt;name&gt;value&lt;/name&gt;</code> with
-                    predefined properties names.</p>
-                    ]]></description>
-                </field>
-                <field>
-                    <name>provides</name>
-                    <version>1.1.0+</version>
-                    <type>Properties</type> <!-- Properties for Maven 2.3.4+ -->
-                    <association xml.mapStyle="inline">
-                      <type>String</type>
-                      <multiplicity>*</multiplicity>
-                    </association>
-                    <!-- <identifier>true</identifier> -->
-                    <description>
-                    <![CDATA[
-                    <p>Toolchain identification information, which will be matched against project requirements.</p>
-                    <p>For Maven 2.0.9 to 3.2.3, the actual content structure was completely open: each toolchain type would define its own format and semantics.
-                    In general, this was a properties format.</p>
-                    <p>Since Maven 3.2.4, the type for this field has been changed to Properties to match the de-facto format.</p>
-                    <p>Each toolchain defines its own properties names and semantics.</p>
-                    ]]></description>
-                </field>
-                <field>
-                    <name>configuration</name>
-                    <version>1.0.0+</version>
-                    <type>DOM</type>
-                    <description>
-                    <![CDATA[
-                    <p>Toolchain configuration information, like location or any information that is to be retrieved.</p>
-                    <p>Actual content structure is completely open: each toolchain type will define its own format and semantics.</p>
-                    <p>In general, this is a properties format: <code>&lt;name&gt;value&lt;/name&gt;</code> with
-                    per-toolchain defined properties names.</p>
-                    ]]></description>
-                </field>
-            </fields>
-            <codeSegments>
-            <codeSegment>
-              <version>1.1.0+</version>
-              <comment>Generated hashCode() and equals() based on identifier also calls its super, which breaks comparison</comment>
-              <code>
-                <![CDATA[
-    /**
-     * Method hashCode.
-     *
-     * @return int
-     */
-    public int hashCode()
-    {
-        int result = 17;
-
-        result = 37 * result + ( type != null ? type.hashCode() : 0 );
-        result = 37 * result + ( provides != null ? provides.hashCode() : 0 );
-
-        return result;
-    } //-- int hashCode()
-
-    /**
-     * Method equals.
-     *
-     * @param other
-     * @return boolean
-     */
-    public boolean equals( Object other )
-    {
-        if ( this == other )
-        {
-            return true;
-        }
-
-        if ( !( other instanceof ToolchainModel ) )
-        {
-            return false;
-        }
-
-        ToolchainModel that = (ToolchainModel) other;
-        boolean result = true;
-
-        result = result && ( getType() == null ? that.getType() == null : getType().equals( that.getType() ) );
-        result = result && ( getProvides() == null ? that.getProvides() == null : getProvides().equals( that.getProvides() ) );
-
-        return result;
-    } //-- boolean equals( Object )
-                ]]>
-              </code>
-            </codeSegment>
-          </codeSegments>
-        </class>
-    </classes>
-</model>
-
diff --git a/maven-toolchain-model/src/site/apt/index.apt b/maven-toolchain-model/src/site/apt/index.apt
new file mode 100644
index 0000000..81e22f7
--- /dev/null
+++ b/maven-toolchain-model/src/site/apt/index.apt
@@ -0,0 +1,39 @@
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~ http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+ -----
+ Introduction
+ -----
+ Hervé Boutemy
+ -----
+ 2006-11-04
+ -----
+
+Maven Toolchain Model
+
+ This is the model for Maven toolchain in <<<org.apache.maven.toolchain>>> package,
+ delegating content to {{{../api/maven-api-toolchain/index.html}Maven 4 API immutable toolchain}}. All the effective model
+ building logic from multiple toolchains files is done in {{{../maven-toolchain-builder/}Maven Toolchain Builder}}.
+
+ The following are generated from this model:
+
+   * {{{./apidocs/index.html}Java sources}} with Reader and Writers for the Xpp3 XML parser, <<<ToAPiV3()>>> and <<<ToApiV4()>>> transformers, and <<<v4>>> package
+     for Merger and v4 Reader and Writers for the Xpp3 XML parser,
+
+   * A {{{./toolchains.html}Descriptor Reference}}
+
+   * An {{{https://maven.apache.org/xsd/toolchains-1.1.0.xsd}XSD}}
diff --git a/maven-toolchain-model/src/site/site.xml b/maven-toolchain-model/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/maven-toolchain-model/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/maven-xml-impl/pom.xml b/maven-xml-impl/pom.xml
new file mode 100644
index 0000000..7103f47
--- /dev/null
+++ b/maven-xml-impl/pom.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<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>org.apache.maven</groupId>
+    <artifactId>maven</artifactId>
+    <version>4.0.0-alpha-9-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>maven-xml-impl</artifactId>
+  <name>Implementation of Maven API XML</name>
+  <description>Provides the implementation classes for the Maven API XML</description>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-api-xml</artifactId>
+      <version>4.0.0-alpha-9-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.sisu</groupId>
+      <artifactId>org.eclipse.sisu.plexus</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>org.codehaus.plexus</groupId>
+          <artifactId>plexus-utils</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.woodstox</groupId>
+      <artifactId>woodstox-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.plexus</groupId>
+      <artifactId>plexus-xml</artifactId>
+      <version>${plexusXmlVersion}</version>
+      <scope>provided</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.maven</groupId>
+          <artifactId>maven-xml-impl</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+  </dependencies>
+
+</project>
diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeBuilder.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeBuilder.java
new file mode 100644
index 0000000..91b199e
--- /dev/null
+++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeBuilder.java
@@ -0,0 +1,260 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.ctc.wstx.stax.WstxInputFactory;
+import org.apache.maven.api.xml.XmlNode;
+import org.codehaus.plexus.util.xml.pull.MXParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+
+/**
+ * All methods in this class attempt to fully parse the XML.
+ * The caller is responsible for closing {@code InputStream} and {@code Reader} arguments.
+ */
+public class XmlNodeBuilder {
+    private static final boolean DEFAULT_TRIM = true;
+
+    public static XmlNodeImpl build(Reader reader) throws XmlPullParserException, IOException {
+        return build(reader, (InputLocationBuilder) null);
+    }
+
+    /**
+     * @param reader the reader
+     * @param locationBuilder the builder
+     * @since 3.2.0
+     * @return DOM
+     * @throws XmlPullParserException XML well-formedness error
+     * @throws IOException I/O error reading file or stream
+     */
+    public static XmlNodeImpl build(Reader reader, InputLocationBuilder locationBuilder)
+            throws XmlPullParserException, IOException {
+        return build(reader, DEFAULT_TRIM, locationBuilder);
+    }
+
+    public static XmlNodeImpl build(InputStream is, String encoding) throws XmlPullParserException, IOException {
+        return build(is, encoding, DEFAULT_TRIM);
+    }
+
+    public static XmlNodeImpl build(InputStream is, String encoding, boolean trim)
+            throws XmlPullParserException, IOException {
+        XmlPullParser parser = new MXParser();
+        parser.setInput(is, encoding);
+        return build(parser, trim);
+    }
+
+    public static XmlNodeImpl build(Reader reader, boolean trim) throws XmlPullParserException, IOException {
+        return build(reader, trim, null);
+    }
+
+    /**
+     * @param reader the reader
+     * @param trim to trim
+     * @param locationBuilder the builder
+     * @since 3.2.0
+     * @return DOM
+     * @throws XmlPullParserException XML well-formedness error
+     * @throws IOException I/O error reading file or stream
+     */
+    public static XmlNodeImpl build(Reader reader, boolean trim, InputLocationBuilder locationBuilder)
+            throws XmlPullParserException, IOException {
+        XmlPullParser parser = new MXParser();
+        parser.setInput(reader);
+        return build(parser, trim, locationBuilder);
+    }
+
+    public static XmlNodeImpl build(XmlPullParser parser) throws XmlPullParserException, IOException {
+        return build(parser, DEFAULT_TRIM);
+    }
+
+    public static XmlNodeImpl build(XmlPullParser parser, boolean trim) throws XmlPullParserException, IOException {
+        return build(parser, trim, null);
+    }
+
+    /**
+     * @since 3.2.0
+     * @param locationBuilder builder
+     * @param parser the parser
+     * @param trim do trim
+     * @return DOM
+     * @throws XmlPullParserException XML well-formedness error
+     * @throws IOException I/O error reading file or stream
+     */
+    public static XmlNodeImpl build(XmlPullParser parser, boolean trim, InputLocationBuilder locationBuilder)
+            throws XmlPullParserException, IOException {
+        boolean spacePreserve = false;
+        String name = null;
+        String value = null;
+        Object location = null;
+        Map<String, String> attrs = null;
+        List<XmlNode> children = null;
+        int eventType = parser.getEventType();
+        boolean emptyTag = false;
+        while (eventType != XmlPullParser.END_DOCUMENT) {
+            if (eventType == XmlPullParser.START_TAG) {
+                emptyTag = parser.isEmptyElementTag();
+                if (name == null) {
+                    name = parser.getName();
+                    location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
+                    int attributesSize = parser.getAttributeCount();
+                    if (attributesSize > 0) {
+                        attrs = new HashMap<>();
+                        for (int i = 0; i < attributesSize; i++) {
+                            String aname = parser.getAttributeName(i);
+                            String avalue = parser.getAttributeValue(i);
+                            attrs.put(aname, avalue);
+                            spacePreserve = spacePreserve || ("xml:space".equals(aname) && "preserve".equals(avalue));
+                        }
+                    }
+                } else {
+                    if (children == null) {
+                        children = new ArrayList<>();
+                    }
+                    XmlNode child = build(parser, trim, locationBuilder);
+                    children.add(child);
+                }
+            } else if (eventType == XmlPullParser.TEXT) {
+                String text = parser.getText();
+                if (trim && !spacePreserve) {
+                    text = text.trim();
+                }
+                value = value != null ? value + text : text;
+            } else if (eventType == XmlPullParser.END_TAG) {
+                return new XmlNodeImpl(
+                        name,
+                        children == null ? (value != null ? value : emptyTag ? null : "") : null,
+                        attrs,
+                        children,
+                        location);
+            }
+            eventType = parser.next();
+        }
+        throw new IllegalStateException("End of document found before returning to 0 depth");
+    }
+
+    public static XmlNodeImpl build(Reader reader, InputLocationBuilderStax locationBuilder) throws XMLStreamException {
+        XMLStreamReader parser = WstxInputFactory.newFactory().createXMLStreamReader(reader);
+        return build(parser, DEFAULT_TRIM, locationBuilder);
+    }
+
+    public static XmlNodeImpl build(XMLStreamReader parser) throws XMLStreamException {
+        return build(parser, DEFAULT_TRIM, null);
+    }
+
+    public static XmlNodeImpl build(XMLStreamReader parser, InputLocationBuilderStax locationBuilder)
+            throws XMLStreamException {
+        return build(parser, DEFAULT_TRIM, locationBuilder);
+    }
+
+    public static XmlNodeImpl build(XMLStreamReader parser, boolean trim, InputLocationBuilderStax locationBuilder)
+            throws XMLStreamException {
+        boolean spacePreserve = false;
+        String lPrefix = null;
+        String lNamespaceUri = null;
+        String lName = null;
+        String lValue = null;
+        Object location = null;
+        Map<String, String> attrs = null;
+        List<XmlNode> children = null;
+        int eventType = parser.getEventType();
+        int lastStartTag = -1;
+        while (eventType != XMLStreamReader.END_DOCUMENT) {
+            if (eventType == XMLStreamReader.START_ELEMENT) {
+                lastStartTag = parser.getLocation().getLineNumber() * 1000
+                        + parser.getLocation().getColumnNumber();
+                if (lName == null) {
+                    int namespacesSize = parser.getNamespaceCount();
+                    lPrefix = parser.getPrefix();
+                    lNamespaceUri = parser.getNamespaceURI();
+                    lName = parser.getLocalName();
+                    location = locationBuilder != null ? locationBuilder.toInputLocation(parser) : null;
+                    int attributesSize = parser.getAttributeCount();
+                    if (attributesSize > 0 || namespacesSize > 0) {
+                        attrs = new HashMap<>();
+                        for (int i = 0; i < namespacesSize; i++) {
+                            String nsPrefix = parser.getNamespacePrefix(i);
+                            String nsUri = parser.getNamespaceURI(i);
+                            attrs.put(nsPrefix != null && !nsPrefix.isEmpty() ? "xmlns:" + nsPrefix : "xmlns", nsUri);
+                        }
+                        for (int i = 0; i < attributesSize; i++) {
+                            String aName = parser.getAttributeLocalName(i);
+                            String aValue = parser.getAttributeValue(i);
+                            String aPrefix = parser.getAttributePrefix(i);
+                            if (aPrefix != null && !aPrefix.isEmpty()) {
+                                aName = aPrefix + ":" + aName;
+                            }
+                            attrs.put(aName, aValue);
+                            spacePreserve = spacePreserve || ("xml:space".equals(aName) && "preserve".equals(aValue));
+                        }
+                    }
+                } else {
+                    if (children == null) {
+                        children = new ArrayList<>();
+                    }
+                    XmlNode child = build(parser, trim, locationBuilder);
+                    children.add(child);
+                }
+            } else if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
+                String text = parser.getText();
+                lValue = lValue != null ? lValue + text : text;
+            } else if (eventType == XMLStreamReader.END_ELEMENT) {
+                boolean emptyTag = lastStartTag
+                        == parser.getLocation().getLineNumber() * 1000
+                                + parser.getLocation().getColumnNumber();
+                if (lValue != null && trim && !spacePreserve) {
+                    lValue = lValue.trim();
+                }
+                return new XmlNodeImpl(
+                        lPrefix,
+                        lNamespaceUri,
+                        lName,
+                        children == null ? (lValue != null ? lValue : emptyTag ? null : "") : null,
+                        attrs,
+                        children,
+                        location);
+            }
+            eventType = parser.next();
+        }
+        throw new IllegalStateException("End of document found before returning to 0 depth");
+    }
+
+    /**
+     * Input location builder interface, to be implemented to choose how to store data.
+     *
+     * @since 3.2.0
+     */
+    public interface InputLocationBuilder {
+        Object toInputLocation(XmlPullParser parser);
+    }
+
+    public interface InputLocationBuilderStax {
+        Object toInputLocation(XMLStreamReader parser);
+    }
+}
diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeImpl.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeImpl.java
new file mode 100644
index 0000000..1210b81
--- /dev/null
+++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeImpl.java
@@ -0,0 +1,453 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.xml;
+
+import javax.xml.stream.XMLStreamException;
+
+import java.io.Serializable;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.apache.maven.api.xml.XmlNode;
+
+/**
+ *  NOTE: remove all the util code in here when separated, this class should be pure data.
+ */
+public class XmlNodeImpl implements Serializable, XmlNode {
+    private static final long serialVersionUID = 2567894443061173996L;
+
+    protected final String prefix;
+
+    protected final String namespaceUri;
+
+    protected final String name;
+
+    protected final String value;
+
+    protected final Map<String, String> attributes;
+
+    protected final List<XmlNode> children;
+
+    protected final Object location;
+
+    public XmlNodeImpl(String name) {
+        this(name, null, null, null, null);
+    }
+
+    public XmlNodeImpl(String name, String value) {
+        this(name, value, null, null, null);
+    }
+
+    public XmlNodeImpl(XmlNode from, String name) {
+        this(name, from.getValue(), from.getAttributes(), from.getChildren(), from.getInputLocation());
+    }
+
+    public XmlNodeImpl(
+            String name, String value, Map<String, String> attributes, List<XmlNode> children, Object location) {
+        this("", "", name, value, attributes, children, location);
+    }
+
+    public XmlNodeImpl(
+            String prefix,
+            String namespaceUri,
+            String name,
+            String value,
+            Map<String, String> attributes,
+            List<XmlNode> children,
+            Object location) {
+        this.prefix = prefix == null ? "" : prefix;
+        this.namespaceUri = namespaceUri == null ? "" : namespaceUri;
+        this.name = Objects.requireNonNull(name);
+        this.value = value;
+        this.attributes =
+                attributes != null ? Collections.unmodifiableMap(new HashMap<>(attributes)) : Collections.emptyMap();
+        this.children =
+                children != null ? Collections.unmodifiableList(new ArrayList<>(children)) : Collections.emptyList();
+        this.location = location;
+    }
+
+    @Override
+    public XmlNode merge(XmlNode source, Boolean childMergeOverride) {
+        return merge(this, source, childMergeOverride);
+    }
+
+    // ----------------------------------------------------------------------
+    // Name handling
+    // ----------------------------------------------------------------------
+
+    @Override
+    public String getPrefix() {
+        return prefix;
+    }
+
+    @Override
+    public String getNamespaceUri() {
+        return namespaceUri;
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    // ----------------------------------------------------------------------
+    // Value handling
+    // ----------------------------------------------------------------------
+
+    public String getValue() {
+        return value;
+    }
+
+    // ----------------------------------------------------------------------
+    // Attribute handling
+    // ----------------------------------------------------------------------
+
+    @Override
+    public Map<String, String> getAttributes() {
+        return attributes;
+    }
+
+    public String getAttribute(String name) {
+        return attributes.get(name);
+    }
+
+    // ----------------------------------------------------------------------
+    // Child handling
+    // ----------------------------------------------------------------------
+
+    public XmlNode getChild(String name) {
+        if (name != null) {
+            ListIterator<XmlNode> it = children.listIterator(children.size());
+            while (it.hasPrevious()) {
+                XmlNode child = it.previous();
+                if (name.equals(child.getName())) {
+                    return child;
+                }
+            }
+        }
+        return null;
+    }
+
+    public List<XmlNode> getChildren() {
+        return children;
+    }
+
+    public int getChildCount() {
+        return children.size();
+    }
+
+    // ----------------------------------------------------------------------
+    // Input location handling
+    // ----------------------------------------------------------------------
+
+    /**
+     * @since 3.2.0
+     * @return input location
+     */
+    public Object getInputLocation() {
+        return location;
+    }
+
+    // ----------------------------------------------------------------------
+    // Helpers
+    // ----------------------------------------------------------------------
+
+    /**
+     * Merges one DOM into another, given a specific algorithm and possible override points for that algorithm.<p>
+     * The algorithm is as follows:
+     * <ol>
+     * <li> if the recessive DOM is null, there is nothing to do... return.</li>
+     * <li> Determine whether the dominant node will suppress the recessive one (flag=mergeSelf).
+     *   <ol type="A">
+     *   <li> retrieve the 'combine.self' attribute on the dominant node, and try to match against 'override'...
+     *        if it matches 'override', then set mergeSelf == false...the dominant node suppresses the recessive one
+     *        completely.</li>
+     *   <li> otherwise, use the default value for mergeSelf, which is true...this is the same as specifying
+     *        'combine.self' == 'merge' as an attribute of the dominant root node.</li>
+     *   </ol></li>
+     * <li> If mergeSelf == true
+     *   <ol type="A">
+     *   <li> Determine whether children from the recessive DOM will be merged or appended to the dominant DOM as
+     *        siblings (flag=mergeChildren).
+     *     <ol type="i">
+     *     <li> if childMergeOverride is set (non-null), use that value (true/false)</li>
+     *     <li> retrieve the 'combine.children' attribute on the dominant node, and try to match against
+     *          'append'...</li>
+     *     <li> if it matches 'append', then set mergeChildren == false...the recessive children will be appended as
+     *          siblings of the dominant children.</li>
+     *     <li> otherwise, use the default value for mergeChildren, which is true...this is the same as specifying
+     *         'combine.children' == 'merge' as an attribute on the dominant root node.</li>
+     *     </ol></li>
+     *   <li> Iterate through the recessive children, and:
+     *     <ol type="i">
+     *     <li> if mergeChildren == true and there is a corresponding dominant child (matched by element name),
+     *          merge the two.</li>
+     *     <li> otherwise, add the recessive child as a new child on the dominant root node.</li>
+     *     </ol></li>
+     *   </ol></li>
+     * </ol>
+     */
+    @SuppressWarnings("checkstyle:MethodLength")
+    public static XmlNode merge(XmlNode dominant, XmlNode recessive, Boolean childMergeOverride) {
+        // TODO: share this as some sort of assembler, implement a walk interface?
+        if (recessive == null) {
+            return dominant;
+        }
+        if (dominant == null) {
+            return recessive;
+        }
+
+        boolean mergeSelf = true;
+
+        String selfMergeMode = dominant.getAttribute(SELF_COMBINATION_MODE_ATTRIBUTE);
+
+        if (SELF_COMBINATION_OVERRIDE.equals(selfMergeMode)) {
+            mergeSelf = false;
+        }
+
+        if (mergeSelf) {
+
+            String value = dominant.getValue();
+            Object location = dominant.getInputLocation();
+            Map<String, String> attrs = dominant.getAttributes();
+            List<XmlNode> children = null;
+
+            for (Map.Entry<String, String> attr : recessive.getAttributes().entrySet()) {
+                String key = attr.getKey();
+                if (isEmpty(attrs.get(key))) {
+                    if (attrs == dominant.getAttributes()) {
+                        attrs = new HashMap<>(attrs);
+                    }
+                    attrs.put(key, attr.getValue());
+                }
+            }
+
+            if (!recessive.getChildren().isEmpty()) {
+                boolean mergeChildren = true;
+                if (childMergeOverride != null) {
+                    mergeChildren = childMergeOverride;
+                } else {
+                    String childMergeMode = attrs.get(CHILDREN_COMBINATION_MODE_ATTRIBUTE);
+                    if (CHILDREN_COMBINATION_APPEND.equals(childMergeMode)) {
+                        mergeChildren = false;
+                    }
+                }
+
+                Map<String, Iterator<XmlNode>> commonChildren = new HashMap<>();
+                Set<String> names =
+                        recessive.getChildren().stream().map(XmlNode::getName).collect(Collectors.toSet());
+                for (String name : names) {
+                    List<XmlNode> dominantChildren = dominant.getChildren().stream()
+                            .filter(n -> n.getName().equals(name))
+                            .collect(Collectors.toList());
+                    if (!dominantChildren.isEmpty()) {
+                        commonChildren.put(name, dominantChildren.iterator());
+                    }
+                }
+
+                String keysValue = recessive.getAttribute(KEYS_COMBINATION_MODE_ATTRIBUTE);
+
+                for (XmlNode recessiveChild : recessive.getChildren()) {
+                    String idValue = recessiveChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE);
+
+                    XmlNode childDom = null;
+                    if (!isEmpty(idValue)) {
+                        for (XmlNode dominantChild : dominant.getChildren()) {
+                            if (idValue.equals(dominantChild.getAttribute(ID_COMBINATION_MODE_ATTRIBUTE))) {
+                                childDom = dominantChild;
+                                // we have a match, so don't append but merge
+                                mergeChildren = true;
+                            }
+                        }
+                    } else if (!isEmpty(keysValue)) {
+                        String[] keys = keysValue.split(",");
+                        Map<String, Optional<String>> recessiveKeyValues = Stream.of(keys)
+                                .collect(Collectors.toMap(
+                                        k -> k, k -> Optional.ofNullable(recessiveChild.getAttribute(k))));
+
+                        for (XmlNode dominantChild : dominant.getChildren()) {
+                            Map<String, Optional<String>> dominantKeyValues = Stream.of(keys)
+                                    .collect(Collectors.toMap(
+                                            k -> k, k -> Optional.ofNullable(dominantChild.getAttribute(k))));
+
+                            if (recessiveKeyValues.equals(dominantKeyValues)) {
+                                childDom = dominantChild;
+                                // we have a match, so don't append but merge
+                                mergeChildren = true;
+                            }
+                        }
+                    } else {
+                        childDom = dominant.getChild(recessiveChild.getName());
+                    }
+
+                    if (mergeChildren && childDom != null) {
+                        String name = recessiveChild.getName();
+                        Iterator<XmlNode> it =
+                                commonChildren.computeIfAbsent(name, n1 -> Stream.of(dominant.getChildren().stream()
+                                                .filter(n2 -> n2.getName().equals(n1))
+                                                .collect(Collectors.toList()))
+                                        .filter(l -> !l.isEmpty())
+                                        .map(List::iterator)
+                                        .findFirst()
+                                        .orElse(null));
+                        if (it == null) {
+                            if (children == null) {
+                                children = new ArrayList<>(dominant.getChildren());
+                            }
+                            children.add(recessiveChild);
+                        } else if (it.hasNext()) {
+                            XmlNode dominantChild = it.next();
+
+                            String dominantChildCombinationMode =
+                                    dominantChild.getAttribute(SELF_COMBINATION_MODE_ATTRIBUTE);
+                            if (SELF_COMBINATION_REMOVE.equals(dominantChildCombinationMode)) {
+                                if (children == null) {
+                                    children = new ArrayList<>(dominant.getChildren());
+                                }
+                                children.remove(dominantChild);
+                            } else {
+                                int idx = dominant.getChildren().indexOf(dominantChild);
+                                XmlNode merged = merge(dominantChild, recessiveChild, childMergeOverride);
+                                if (merged != dominantChild) {
+                                    if (children == null) {
+                                        children = new ArrayList<>(dominant.getChildren());
+                                    }
+                                    children.set(idx, merged);
+                                }
+                            }
+                        }
+                    } else {
+                        if (children == null) {
+                            children = new ArrayList<>(dominant.getChildren());
+                        }
+                        int idx = mergeChildren
+                                ? children.size()
+                                : recessive.getChildren().indexOf(recessiveChild);
+                        children.add(idx, recessiveChild);
+                    }
+                }
+            }
+
+            if (value != null || attrs != dominant.getAttributes() || children != null) {
+                if (children == null) {
+                    children = dominant.getChildren();
+                }
+                return new XmlNodeImpl(
+                        dominant.getName(), value != null ? value : dominant.getValue(), attrs, children, location);
+            }
+        }
+        return dominant;
+    }
+
+    /**
+     * Merge two DOMs, with one having dominance in the case of collision. Merge mechanisms (vs. override for nodes, or
+     * vs. append for children) is determined by attributes of the dominant root node.
+     *
+     * @see #CHILDREN_COMBINATION_MODE_ATTRIBUTE
+     * @see #SELF_COMBINATION_MODE_ATTRIBUTE
+     * @param dominant The dominant DOM into which the recessive value/attributes/children will be merged
+     * @param recessive The recessive DOM, which will be merged into the dominant DOM
+     * @return merged DOM
+     */
+    public static XmlNode merge(XmlNode dominant, XmlNode recessive) {
+        return merge(dominant, recessive, null);
+    }
+
+    // ----------------------------------------------------------------------
+    // Standard object handling
+    // ----------------------------------------------------------------------
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        XmlNodeImpl that = (XmlNodeImpl) o;
+        return Objects.equals(this.name, that.name)
+                && Objects.equals(this.value, that.value)
+                && Objects.equals(this.attributes, that.attributes)
+                && Objects.equals(this.children, that.children);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name, value, attributes, children);
+    }
+
+    @Override
+    public String toString() {
+        try {
+            return toStringXml();
+        } catch (XMLStreamException e) {
+            return toStringObject();
+        }
+    }
+
+    public String toStringXml() throws XMLStreamException {
+        StringWriter writer = new StringWriter();
+        XmlNodeWriter.write(writer, this);
+        return writer.toString();
+    }
+
+    public String toStringObject() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("XmlNode[");
+        boolean w = false;
+        w = addToStringField(sb, prefix, o -> !o.isEmpty(), "prefix", w);
+        w = addToStringField(sb, namespaceUri, o -> !o.isEmpty(), "namespaceUri", w);
+        w = addToStringField(sb, name, o -> !o.isEmpty(), "name", w);
+        w = addToStringField(sb, value, o -> !o.isEmpty(), "value", w);
+        w = addToStringField(sb, attributes, o -> !o.isEmpty(), "attributes", w);
+        w = addToStringField(sb, children, o -> !o.isEmpty(), "children", w);
+        w = addToStringField(sb, location, Objects::nonNull, "location", w);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    private static <T> boolean addToStringField(StringBuilder sb, T o, Function<T, Boolean> p, String n, boolean w) {
+        if (!p.apply(o)) {
+            if (w) {
+                sb.append(", ");
+            } else {
+                w = true;
+            }
+            sb.append(n).append("='").append(o).append('\'');
+        }
+        return w;
+    }
+
+    private static boolean isEmpty(String str) {
+        return str == null || str.isEmpty();
+    }
+}
diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeWriter.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeWriter.java
new file mode 100644
index 0000000..ee50fca
--- /dev/null
+++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlNodeWriter.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.xml;
+
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.maven.api.xml.XmlNode;
+import org.codehaus.stax2.util.StreamWriterDelegate;
+
+/**
+ *
+ */
+public class XmlNodeWriter {
+    public static void write(Writer writer, XmlNode dom) throws XMLStreamException {
+        XMLOutputFactory factory = new com.ctc.wstx.stax.WstxOutputFactory();
+        factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
+        factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
+        factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_ADD_SPACE_AFTER_EMPTY_ELEM, true);
+        XMLStreamWriter serializer = new IndentingXMLStreamWriter(factory.createXMLStreamWriter(writer));
+        write(serializer, dom);
+        serializer.close();
+    }
+
+    public static void write(XMLStreamWriter xmlWriter, XmlNode dom) throws XMLStreamException {
+        xmlWriter.writeStartElement(dom.getPrefix(), dom.getName(), dom.getNamespaceUri());
+        for (Map.Entry<String, String> attr : dom.getAttributes().entrySet()) {
+            xmlWriter.writeAttribute(attr.getKey(), attr.getValue());
+        }
+        for (XmlNode aChildren : dom.getChildren()) {
+            write(xmlWriter, aChildren);
+        }
+        String value = dom.getValue();
+        if (value != null) {
+            xmlWriter.writeCharacters(value);
+        }
+        xmlWriter.writeEndElement();
+    }
+
+    static class IndentingXMLStreamWriter extends StreamWriterDelegate {
+
+        int depth = 0;
+        boolean hasChildren = false;
+        boolean anew = true;
+
+        IndentingXMLStreamWriter(XMLStreamWriter parent) {
+            super(parent);
+        }
+
+        @Override
+        public void writeStartDocument() throws XMLStreamException {
+            super.writeStartDocument();
+            anew = false;
+        }
+
+        @Override
+        public void writeStartDocument(String version) throws XMLStreamException {
+            super.writeStartDocument(version);
+            anew = false;
+        }
+
+        @Override
+        public void writeStartDocument(String encoding, String version) throws XMLStreamException {
+            super.writeStartDocument(encoding, version);
+            anew = false;
+        }
+
+        @Override
+        public void writeEmptyElement(String localName) throws XMLStreamException {
+            indent();
+            super.writeEmptyElement(localName);
+            hasChildren = true;
+            anew = false;
+        }
+
+        @Override
+        public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
+            indent();
+            super.writeEmptyElement(namespaceURI, localName);
+            hasChildren = true;
+            anew = false;
+        }
+
+        @Override
+        public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+            indent();
+            super.writeEmptyElement(prefix, localName, namespaceURI);
+            hasChildren = true;
+            anew = false;
+        }
+
+        @Override
+        public void writeStartElement(String localName) throws XMLStreamException {
+            indent();
+            super.writeStartElement(localName);
+            depth++;
+            hasChildren = false;
+            anew = false;
+        }
+
+        @Override
+        public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
+            indent();
+            super.writeStartElement(namespaceURI, localName);
+            depth++;
+            hasChildren = false;
+            anew = false;
+        }
+
+        @Override
+        public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+            indent();
+            super.writeStartElement(prefix, localName, namespaceURI);
+            depth++;
+            hasChildren = false;
+            anew = false;
+        }
+
+        @Override
+        public void writeEndElement() throws XMLStreamException {
+            depth--;
+            if (hasChildren) {
+                indent();
+            }
+            super.writeEndElement();
+            hasChildren = true;
+            anew = false;
+        }
+
+        private void indent() throws XMLStreamException {
+            if (!anew) {
+                super.writeCharacters("\n");
+            }
+            for (int i = 0; i < depth; i++) {
+                super.writeCharacters("  ");
+            }
+        }
+    }
+}
diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlPlexusConfiguration.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlPlexusConfiguration.java
new file mode 100644
index 0000000..bb40e24
--- /dev/null
+++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/XmlPlexusConfiguration.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.xml;
+
+import org.apache.maven.api.xml.XmlNode;
+import org.codehaus.plexus.configuration.DefaultPlexusConfiguration;
+import org.codehaus.plexus.configuration.PlexusConfiguration;
+
+public class XmlPlexusConfiguration extends DefaultPlexusConfiguration {
+    public static PlexusConfiguration toPlexusConfiguration(XmlNode node) {
+        return new XmlPlexusConfiguration(node);
+    }
+
+    public XmlPlexusConfiguration(XmlNode node) {
+        super(node.getName(), node.getValue());
+        node.getAttributes().forEach(this::setAttribute);
+        node.getChildren().forEach(c -> this.addChild(new XmlPlexusConfiguration(c)));
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder buf = new StringBuilder().append('<').append(getName());
+        for (final String a : getAttributeNames()) {
+            buf.append(' ').append(a).append("=\"").append(getAttribute(a)).append('"');
+        }
+        if (getChildCount() > 0) {
+            buf.append('>');
+            for (int i = 0, size = getChildCount(); i < size; i++) {
+                buf.append(getChild(i));
+            }
+            buf.append("</").append(getName()).append('>');
+        } else if (null != getValue()) {
+            buf.append('>').append(getValue()).append("</").append(getName()).append('>');
+        } else {
+            buf.append("/>");
+        }
+        return buf.append('\n').toString();
+    }
+}
diff --git a/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/package-info.java b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/package-info.java
new file mode 100644
index 0000000..2115ad9
--- /dev/null
+++ b/maven-xml-impl/src/main/java/org/apache/maven/internal/xml/package-info.java
@@ -0,0 +1,5 @@
+// CHECKSTYLE_OFF: RegexpHeader
+/**
+ * Contains implementation of the {@link org.apache.maven.api.xml.XmlNode} interface and related classes.
+ */
+package org.apache.maven.internal.xml;
diff --git a/maven-xml-impl/src/site/markdown/index.md b/maven-xml-impl/src/site/markdown/index.md
new file mode 100644
index 0000000..9de640e
--- /dev/null
+++ b/maven-xml-impl/src/site/markdown/index.md
@@ -0,0 +1,22 @@
+<!---
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+Apache Maven XML Impl
+=========================
+
+This module contains the implementation of the `org.apache.maven.api.xml.XmlNode` interface used to convey XML snippets in the object model, and also the modified `org.codehaus.plexus.util.xml` package which wraps the immutable objects from `org.apache.maven.api.xml.XmlNode` in order to provide compatibility and interoperability between the API v3.x and v4.x.
+
+See [Maven Plexus Utils](../plexus-utils/) for more information.
diff --git a/maven-xml-impl/src/site/site.xml b/maven-xml-impl/src/site/site.xml
new file mode 100644
index 0000000..8ffe43d
--- /dev/null
+++ b/maven-xml-impl/src/site/site.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project xmlns="http://maven.apache.org/DECORATION/1.8.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/DECORATION/1.8.0 http://maven.apache.org/xsd/decoration-1.8.0.xsd">
+
+  <edit>${project.scm.url}</edit>
+
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
+      <item name="Source Xref" href="xref/index.html"/>
+      <!--item name="FAQ" href="faq.html"/-->
+    </menu>
+
+    <menu ref="parent"/>
+    <menu ref="reports"/>
+  </body>
+</project>
\ No newline at end of file
diff --git a/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeBuilderTest.java b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeBuilderTest.java
new file mode 100644
index 0000000..abcc2f3
--- /dev/null
+++ b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeBuilderTest.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.xml;
+
+import javax.xml.stream.XMLStreamReader;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import com.ctc.wstx.stax.WstxInputFactory;
+import org.apache.maven.api.xml.XmlNode;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class XmlNodeBuilderTest {
+
+    @Test
+    void testReadMultiDoc() throws Exception {
+        String doc = "<?xml version='1.0'?><doc><child>foo</child></doc>";
+        StringReader r = new StringReader(doc + doc) {
+            @Override
+            public int read(char[] cbuf, int off, int len) throws IOException {
+                return super.read(cbuf, off, 1);
+            }
+        };
+        XmlNode node1 = XmlNodeBuilder.build(r);
+        XmlNode node2 = XmlNodeBuilder.build(r);
+        assertEquals(node1, node2);
+    }
+
+    @Test
+    void testWithNamespace() throws Exception {
+        String doc = "<?xml version='1.0'?><doc xmlns='foo:bar'/>";
+        StringReader r = new StringReader(doc);
+        XMLStreamReader xsr = WstxInputFactory.newFactory().createXMLStreamReader(r);
+        XmlNode node = XmlNodeBuilder.build(xsr);
+        assertEquals("doc", node.getName());
+        assertEquals(1, node.getAttributes().size());
+        assertEquals("foo:bar", node.getAttribute("xmlns"));
+    }
+}
diff --git a/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeImplTest.java b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeImplTest.java
new file mode 100644
index 0000000..973f990
--- /dev/null
+++ b/maven-xml-impl/src/test/java/org/apache/maven/internal/xml/XmlNodeImplTest.java
@@ -0,0 +1,670 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.maven.internal.xml;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.xml.XmlNode;
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+import org.codehaus.plexus.util.xml.Xpp3DomBuilder;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNotSame;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+class XmlNodeImplTest {
+
+    @Test
+    void testCombineChildrenAppend() throws Exception {
+        String lhs = "<configuration>\n"
+                + "    <plugins>\n"
+                + "        <plugin>\n"
+                + "            <groupId>foo.bar</groupId>\n"
+                + "            <artifactId>foo-bar-plugin</artifactId>\n"
+                + "            <configuration>\n"
+                + "                <plugins>\n"
+                + "                    <plugin>\n"
+                + "                        <groupId>org.apache.maven.plugins</groupId>\n"
+                + "                        <artifactId>maven-compiler-plugin</artifactId>\n"
+                + "                    </plugin>\n"
+                + "                    <plugin>\n"
+                + "                        <groupId>org.apache.maven.plugins</groupId>\n"
+                + "                        <artifactId>maven-surefire-plugin</artifactId>\n"
+                + "                        <foo>\n"
+                + "                            <properties combine.children=\"append\">\n"
+                + "                                <property>\n"
+                + "                                    <name>prop2</name>\n"
+                + "                                    <value>value2</value>\n"
+                + "                                </property>\n"
+                + "                            </properties>\n"
+                + "                        </foo>\n"
+                + "                    </plugin>\n"
+                + "                </plugins>\n"
+                + "            </configuration>\n"
+                + "        </plugin>\n"
+                + "    </plugins>\n"
+                + "</configuration>";
+
+        String rhs = "<configuration>\n"
+                + "    <plugins>\n"
+                + "        <plugin>\n"
+                + "            <groupId>foo.bar</groupId>\n"
+                + "            <artifactId>foo-bar-plugin</artifactId>\n"
+                + "            <configuration>\n"
+                + "                <plugins>\n"
+                + "                    <plugin>\n"
+                + "                        <groupId>org.apache.maven.plugins</groupId>\n"
+                + "                        <artifactId>maven-compiler-plugin</artifactId>\n"
+                + "                        <bar>\n"
+                + "                            <value>foo</value>\n"
+                + "                        </bar>\n"
+                + "                    </plugin>\n"
+                + "                    <plugin>\n"
+                + "                        <groupId>org.apache.maven.plugins</groupId>\n"
+                + "                        <artifactId>maven-surefire-plugin</artifactId>\n"
+                + "                        <foo>\n"
+                + "                            <properties>\n"
+                + "                                <property>\n"
+                + "                                    <name>prop1</name>\n"
+                + "                                    <value>value1</value>\n"
+                + "                                </property>\n"
+                + "                            </properties>\n"
+                + "                        </foo>\n"
+                + "                    </plugin>\n"
+                + "                </plugins>\n"
+                + "            </configuration>\n"
+                + "        </plugin>\n"
+                + "    </plugins>\n"
+                + "</configuration>";
+
+        String result = "<configuration>\n"
+                + "    <plugins>\n"
+                + "        <plugin>\n"
+                + "            <groupId>foo.bar</groupId>\n"
+                + "            <artifactId>foo-bar-plugin</artifactId>\n"
+                + "            <configuration>\n"
+                + "                <plugins>\n"
+                + "                    <plugin>\n"
+                + "                        <groupId>org.apache.maven.plugins</groupId>\n"
+                + "                        <artifactId>maven-compiler-plugin</artifactId>\n"
+                + "                        <bar>\n"
+                + "                            <value>foo</value>\n"
+                + "                        </bar>\n"
+                + "                    </plugin>\n"
+                + "                    <plugin>\n"
+                + "                        <groupId>org.apache.maven.plugins</groupId>\n"
+                + "                        <artifactId>maven-surefire-plugin</artifactId>\n"
+                + "                        <foo>\n"
+                + "                            <properties combine.children=\"append\">\n"
+                + "                                <property>\n"
+                + "                                    <name>prop1</name>\n"
+                + "                                    <value>value1</value>\n"
+                + "                                </property>\n"
+                + "                                <property>\n"
+                + "                                    <name>prop2</name>\n"
+                + "                                    <value>value2</value>\n"
+                + "                                </property>\n"
+                + "                            </properties>\n"
+                + "                        </foo>\n"
+                + "                    </plugin>\n"
+                + "                </plugins>\n"
+                + "            </configuration>\n"
+                + "        </plugin>\n"
+                + "    </plugins>\n"
+                + "</configuration>";
+
+        XmlNode leftDom = toXmlNode(lhs);
+        XmlNode rightDom = toXmlNode(rhs);
+
+        XmlNode mergeResult = leftDom.merge(rightDom);
+
+        assertEquals(toXmlNode(result), mergeResult);
+    }
+
+    /**
+     * <p>testCombineId.</p>
+     *
+     * @throws java.lang.Exception if any.
+     */
+    @Test
+    void testCombineId() throws Exception {
+        String lhs = "<props>" + "<property combine.id='LHS-ONLY'><name>LHS-ONLY</name><value>LHS</value></property>"
+                + "<property combine.id='TOOVERWRITE'><name>TOOVERWRITE</name><value>LHS</value></property>"
+                + "</props>";
+
+        String rhs = "<props>" + "<property combine.id='RHS-ONLY'><name>RHS-ONLY</name><value>RHS</value></property>"
+                + "<property combine.id='TOOVERWRITE'><name>TOOVERWRITE</name><value>RHS</value></property>"
+                + "</props>";
+
+        XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+        XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+        XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true);
+        assertEquals(3, getChildren(mergeResult, "property").size());
+
+        XmlNode p0 = getNthChild(mergeResult, "property", 0);
+        assertEquals("LHS-ONLY", p0.getChild("name").getValue());
+        assertEquals("left", p0.getChild("name").getInputLocation());
+        assertEquals("LHS", p0.getChild("value").getValue());
+        assertEquals("left", p0.getChild("value").getInputLocation());
+
+        XmlNode p1 = getNthChild(mergeResult, "property", 1);
+        assertEquals(
+                "TOOVERWRITE",
+                getNthChild(mergeResult, "property", 1).getChild("name").getValue());
+        assertEquals("left", p1.getChild("name").getInputLocation());
+        assertEquals(
+                "LHS", getNthChild(mergeResult, "property", 1).getChild("value").getValue());
+        assertEquals("left", p1.getChild("value").getInputLocation());
+
+        XmlNode p2 = getNthChild(mergeResult, "property", 2);
+        assertEquals(
+                "RHS-ONLY",
+                getNthChild(mergeResult, "property", 2).getChild("name").getValue());
+        assertEquals("right", p2.getChild("name").getInputLocation());
+        assertEquals(
+                "RHS", getNthChild(mergeResult, "property", 2).getChild("value").getValue());
+        assertEquals("right", p2.getChild("value").getInputLocation());
+    }
+
+    /**
+     * <p>testCombineKeys.</p>
+     *
+     * @throws java.lang.Exception if any.
+     */
+    @Test
+    void testCombineKeys() throws Exception {
+        String lhs = "<props combine.keys='key'>"
+                + "<property key=\"LHS-ONLY\"><name>LHS-ONLY</name><value>LHS</value></property>"
+                + "<property combine.keys='name'><name>TOOVERWRITE</name><value>LHS</value></property>" + "</props>";
+
+        String rhs = "<props combine.keys='key'>"
+                + "<property key=\"RHS-ONLY\"><name>RHS-ONLY</name><value>RHS</value></property>"
+                + "<property combine.keys='name'><name>TOOVERWRITE</name><value>RHS</value></property>" + "</props>";
+
+        XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+        XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+        XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true);
+        assertEquals(3, getChildren(mergeResult, "property").size());
+
+        XmlNode p0 = getNthChild(mergeResult, "property", 0);
+        assertEquals("LHS-ONLY", p0.getChild("name").getValue());
+        assertEquals("left", p0.getChild("name").getInputLocation());
+        assertEquals("LHS", p0.getChild("value").getValue());
+        assertEquals("left", p0.getChild("value").getInputLocation());
+
+        XmlNode p1 = getNthChild(mergeResult, "property", 1);
+        assertEquals(
+                "TOOVERWRITE",
+                getNthChild(mergeResult, "property", 1).getChild("name").getValue());
+        assertEquals("left", p1.getChild("name").getInputLocation());
+        assertEquals(
+                "LHS", getNthChild(mergeResult, "property", 1).getChild("value").getValue());
+        assertEquals("left", p1.getChild("value").getInputLocation());
+
+        XmlNode p2 = getNthChild(mergeResult, "property", 2);
+        assertEquals(
+                "RHS-ONLY",
+                getNthChild(mergeResult, "property", 2).getChild("name").getValue());
+        assertEquals("right", p2.getChild("name").getInputLocation());
+        assertEquals(
+                "RHS", getNthChild(mergeResult, "property", 2).getChild("value").getValue());
+        assertEquals("right", p2.getChild("value").getInputLocation());
+    }
+
+    @Test
+    void testPreserveDominantBlankValue() throws XMLStreamException, IOException {
+        String lhs = "<parameter xml:space=\"preserve\"> </parameter>";
+
+        String rhs = "<parameter>recessive</parameter>";
+
+        XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+        XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+        XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true);
+        assertEquals(" ", mergeResult.getValue());
+    }
+
+    @Test
+    void testPreserveDominantEmptyNode() throws XMLStreamException, IOException {
+        String lhs = "<parameter></parameter>";
+
+        String rhs = "<parameter>recessive</parameter>";
+
+        XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+        XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+        XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true);
+        assertEquals("", mergeResult.getValue());
+    }
+
+    @Test
+    void testPreserveDominantEmptyNode2() throws XMLStreamException, IOException {
+        String lhs = "<parameter/>";
+
+        String rhs = "<parameter>recessive</parameter>";
+
+        XmlNodeImpl leftDom = XmlNodeBuilder.build(new StringReader(lhs), new FixedInputLocationBuilder("left"));
+        XmlNodeImpl rightDom = XmlNodeBuilder.build(new StringReader(rhs), new FixedInputLocationBuilder("right"));
+
+        XmlNode mergeResult = XmlNodeImpl.merge(leftDom, rightDom, true);
+        assertNull(mergeResult.getValue());
+    }
+
+    /**
+     * <p>testShouldPerformAppendAtFirstSubElementLevel.</p>
+     */
+    @Test
+    void testShouldPerformAppendAtFirstSubElementLevel() {
+        // create the dominant DOM
+        Xpp3Dom t1 = new Xpp3Dom("top");
+        t1.setAttribute(Xpp3Dom.CHILDREN_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.CHILDREN_COMBINATION_APPEND);
+        t1.setInputLocation("t1top");
+
+        Xpp3Dom t1s1 = new Xpp3Dom("topsub1");
+        t1s1.setValue("t1s1Value");
+        t1s1.setInputLocation("t1s1");
+
+        t1.addChild(t1s1);
+
+        // create the recessive DOM
+        Xpp3Dom t2 = new Xpp3Dom("top");
+        t2.setInputLocation("t2top");
+
+        Xpp3Dom t2s1 = new Xpp3Dom("topsub1");
+        t2s1.setValue("t2s1Value");
+        t2s1.setInputLocation("t2s1");
+
+        t2.addChild(t2s1);
+
+        // merge and check results.
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(t1, t2);
+
+        assertEquals(2, result.getChildren("topsub1").length);
+        assertEquals("t2s1Value", result.getChildren("topsub1")[0].getValue());
+        assertEquals("t1s1Value", result.getChildren("topsub1")[1].getValue());
+
+        assertEquals("t1top", result.getInputLocation());
+        assertEquals("t2s1", result.getChildren("topsub1")[0].getInputLocation());
+        assertEquals("t1s1", result.getChildren("topsub1")[1].getInputLocation());
+    }
+
+    /**
+     * <p>testShouldOverrideAppendAndDeepMerge.</p>
+     */
+    @Test
+    void testShouldOverrideAppendAndDeepMerge() {
+        // create the dominant DOM
+        Xpp3Dom t1 = new Xpp3Dom("top");
+        t1.setAttribute(Xpp3Dom.CHILDREN_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.CHILDREN_COMBINATION_APPEND);
+        t1.setInputLocation("t1top");
+
+        Xpp3Dom t1s1 = new Xpp3Dom("topsub1");
+        t1s1.setValue("t1s1Value");
+        t1s1.setInputLocation("t1s1");
+
+        t1.addChild(t1s1);
+
+        // create the recessive DOM
+        Xpp3Dom t2 = new Xpp3Dom("top");
+        t2.setInputLocation("t2top");
+
+        Xpp3Dom t2s1 = new Xpp3Dom("topsub1");
+        t2s1.setValue("t2s1Value");
+        t2s1.setInputLocation("t2s1");
+
+        t2.addChild(t2s1);
+
+        // merge and check results.
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(t1, t2, Boolean.TRUE);
+
+        assertEquals(1, result.getChildren("topsub1").length);
+        assertEquals("t1s1Value", result.getChildren("topsub1")[0].getValue());
+
+        assertEquals("t1top", result.getInputLocation());
+        assertEquals("t1s1", result.getChildren("topsub1")[0].getInputLocation());
+    }
+
+    /**
+     * <p>testShouldPerformSelfOverrideAtTopLevel.</p>
+     */
+    @Test
+    void testShouldPerformSelfOverrideAtTopLevel() {
+        // create the dominant DOM
+        Xpp3Dom t1 = new Xpp3Dom("top");
+        t1.setAttribute("attr", "value");
+        t1.setInputLocation("t1top");
+
+        t1.setAttribute(Xpp3Dom.SELF_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.SELF_COMBINATION_OVERRIDE);
+
+        // create the recessive DOM
+        Xpp3Dom t2 = new Xpp3Dom("top");
+        t2.setAttribute("attr2", "value2");
+        t2.setValue("t2Value");
+        t2.setInputLocation("t2top");
+
+        // merge and check results.
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(t1, t2);
+
+        assertEquals(2, result.getAttributeNames().length);
+        assertNull(result.getValue());
+        assertEquals("t1top", result.getInputLocation());
+    }
+
+    /**
+     * <p>testShouldMergeValuesAtTopLevelByDefault.</p>
+     */
+    @Test
+    void testShouldNotMergeValuesAtTopLevelByDefault() {
+        // create the dominant DOM
+        Xpp3Dom t1 = new Xpp3Dom("top");
+        t1.setAttribute("attr", "value");
+        t1.setInputLocation("t1top");
+
+        // create the recessive DOM
+        Xpp3Dom t2 = new Xpp3Dom("top");
+        t2.setAttribute("attr2", "value2");
+        t2.setValue("t2Value");
+        t2.setInputLocation("t2top");
+
+        // merge and check results.
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(t1, t2);
+
+        // this is still 2, since we're not using the merge-control attribute.
+        assertEquals(2, result.getAttributeNames().length);
+
+        assertNull(result.getValue());
+        assertEquals("t1top", result.getInputLocation());
+    }
+
+    /**
+     * <p>testShouldMergeValuesAtTopLevel.</p>
+     */
+    @Test
+    void testShouldNotMergeValuesAtTopLevel() {
+        // create the dominant DOM
+        Xpp3Dom t1 = new Xpp3Dom("top");
+        t1.setAttribute("attr", "value");
+
+        t1.setAttribute(Xpp3Dom.SELF_COMBINATION_MODE_ATTRIBUTE, Xpp3Dom.SELF_COMBINATION_MERGE);
+
+        // create the recessive DOM
+        Xpp3Dom t2 = new Xpp3Dom("top");
+        t2.setAttribute("attr2", "value2");
+        t2.setValue("t2Value");
+
+        // merge and check results.
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(t1, t2);
+
+        assertEquals(3, result.getAttributeNames().length);
+        assertNull(result.getValue());
+    }
+
+    /**
+     * <p>testEquals.</p>
+     */
+    @Test
+    void testEquals() {
+        XmlNodeImpl dom = new XmlNodeImpl("top");
+
+        assertEquals(dom, dom);
+        assertNotEquals(dom, null);
+        assertNotEquals(dom, new XmlNodeImpl(""));
+    }
+
+    /**
+     * <p>testEqualsIsNullSafe.</p>
+     */
+    @Test
+    void testEqualsIsNullSafe() throws XMLStreamException, IOException {
+        String testDom = "<configuration><items thing='blah'><item>one</item><item>two</item></items></configuration>";
+        XmlNode dom = toXmlNode(testDom);
+
+        Map<String, String> attributes = new HashMap<>();
+        attributes.put("nullValue", null);
+        attributes.put(null, "nullKey");
+        List<XmlNode> childList = new ArrayList<>();
+        childList.add(null);
+        Xpp3Dom dom2 = new Xpp3Dom(new XmlNodeImpl(dom.getName(), null, attributes, childList, null));
+
+        assertNotEquals(dom, dom2);
+        assertNotEquals(dom2, dom);
+    }
+
+    /**
+     * <p>testShouldOverwritePluginConfigurationSubItemsByDefault.</p>
+     */
+    @Test
+    void testShouldOverwritePluginConfigurationSubItemsByDefault() throws XMLStreamException, IOException {
+        String parentConfigStr = "<configuration><items><item>one</item><item>two</item></items></configuration>";
+        XmlNode parentConfig = toXmlNode(parentConfigStr, new FixedInputLocationBuilder("parent"));
+
+        String childConfigStr = "<configuration><items><item>three</item></items></configuration>";
+        XmlNode childConfig = toXmlNode(childConfigStr, new FixedInputLocationBuilder("child"));
+
+        XmlNode result = XmlNode.merge(childConfig, parentConfig);
+        XmlNode items = result.getChild("items");
+
+        assertEquals(1, items.getChildren().size());
+
+        XmlNode item = items.getChildren().get(0);
+        assertEquals("three", item.getValue());
+        assertEquals("child", item.getInputLocation());
+    }
+
+    /**
+     * <p>testShouldMergePluginConfigurationSubItemsWithMergeAttributeSet.</p>
+     */
+    @Test
+    void testShouldMergePluginConfigurationSubItemsWithMergeAttributeSet() throws XMLStreamException, IOException {
+        String parentConfigStr = "<configuration><items><item>one</item><item>two</item></items></configuration>";
+        XmlNode parentConfig = toXmlNode(parentConfigStr, new FixedInputLocationBuilder("parent"));
+
+        String childConfigStr =
+                "<configuration><items combine.children=\"append\"><item>three</item></items></configuration>";
+        XmlNode childConfig = toXmlNode(childConfigStr, new FixedInputLocationBuilder("child"));
+
+        XmlNode result = XmlNode.merge(childConfig, parentConfig);
+        XmlNode items = result.getChild("items");
+
+        XmlNode[] item = items.getChildren().toArray(new XmlNode[0]);
+        assertEquals(3, item.length);
+        assertEquals("one", item[0].getValue());
+        assertEquals("parent", item[0].getInputLocation());
+        assertEquals("two", item[1].getValue());
+        assertEquals("parent", item[1].getInputLocation());
+        assertEquals("three", item[2].getValue());
+        assertEquals("child", item[2].getInputLocation());
+    }
+
+    /**
+     * <p>testShouldNotChangeUponMergeWithItselfWhenFirstOrLastSubItemIsEmpty.</p>
+     *
+     * @throws java.lang.Exception if any.
+     */
+    @Test
+    void testShouldNotChangeUponMergeWithItselfWhenFirstOrLastSubItemIsEmpty() throws Exception {
+        String configStr = "<configuration><items><item/><item>test</item><item/></items></configuration>";
+        Xpp3Dom dominantConfig = Xpp3DomBuilder.build(new StringReader(configStr));
+        Xpp3Dom recessiveConfig = Xpp3DomBuilder.build(new StringReader(configStr));
+
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(dominantConfig, recessiveConfig);
+        Xpp3Dom items = result.getChild("items");
+
+        assertEquals(3, items.getChildCount());
+
+        assertNull(items.getChild(0).getValue());
+        assertEquals("test", items.getChild(1).getValue());
+        assertNull(items.getChild(2).getValue());
+    }
+
+    /**
+     * <p>testShouldCopyRecessiveChildrenNotPresentInTarget.</p>
+     *
+     * @throws java.lang.Exception if any.
+     */
+    @Test
+    void testShouldCopyRecessiveChildrenNotPresentInTarget() throws Exception {
+        String dominantStr = "<configuration><foo>x</foo></configuration>";
+        String recessiveStr = "<configuration><bar>y</bar></configuration>";
+        Xpp3Dom dominantConfig = Xpp3DomBuilder.build(new StringReader(dominantStr));
+        Xpp3Dom recessiveConfig = Xpp3DomBuilder.build(new StringReader(recessiveStr));
+
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(dominantConfig, recessiveConfig);
+
+        assertEquals(2, result.getChildCount());
+
+        assertEquals("x", result.getChild("foo").getValue());
+        assertEquals("y", result.getChild("bar").getValue());
+        assertNotSame(result.getChild("bar"), recessiveConfig.getChild("bar"));
+    }
+
+    /**
+     * <p>testDupeChildren.</p>
+     */
+    @Test
+    void testDupeChildren() throws IOException, XMLStreamException {
+        String dupes = "<configuration><foo>x</foo><foo>y</foo></configuration>";
+        XmlNode dom = toXmlNode(new StringReader(dupes));
+        assertNotNull(dom);
+        assertEquals("y", dom.getChild("foo").getValue());
+    }
+
+    /**
+     * <p>testShouldRemoveEntireElementWithAttributesAndChildren.</p>
+     *
+     * @throws java.lang.Exception if any.
+     */
+    @Test
+    void testShouldRemoveEntireElementWithAttributesAndChildren() throws Exception {
+        String dominantStr = "<config><service combine.self=\"remove\"/></config>";
+        String recessiveStr = "<config><service><parameter>parameter</parameter></service></config>";
+        Xpp3Dom dominantConfig = Xpp3DomBuilder.build(new StringReader(dominantStr));
+        Xpp3Dom recessiveConfig = Xpp3DomBuilder.build(new StringReader(recessiveStr));
+
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(dominantConfig, recessiveConfig);
+
+        assertEquals(0, result.getChildCount());
+        assertEquals("config", result.getName());
+    }
+
+    /**
+     * <p>testShouldRemoveDoNotRemoveTagWhenSwappedInputDOMs.</p>
+     *
+     * @throws java.lang.Exception if any.
+     */
+    @Test
+    void testShouldRemoveDoNotRemoveTagWhenSwappedInputDOMs() throws Exception {
+        String dominantStr = "<config><service combine.self=\"remove\"/></config>";
+        String recessiveStr = "<config><service><parameter>parameter</parameter></service></config>";
+        Xpp3Dom dominantConfig = Xpp3DomBuilder.build(new StringReader(dominantStr));
+        Xpp3Dom recessiveConfig = Xpp3DomBuilder.build(new StringReader(recessiveStr));
+
+        // same DOMs as testShouldRemoveEntireElementWithAttributesAndChildren(), swapping dominant <--> recessive
+        Xpp3Dom result = Xpp3Dom.mergeXpp3Dom(recessiveConfig, dominantConfig);
+
+        assertEquals(recessiveConfig.toString(), result.toString());
+    }
+
+    @Test
+    void testMergeCombineChildrenAppendOnRecessive() throws XMLStreamException, IOException {
+        String dominant = "<relocations>\n" + "  <relocation>\n"
+                + "    <pattern>org.apache.shiro.crypto.CipherService</pattern>\n"
+                + "    <shadedPattern>org.apache.shiro.crypto.cipher.CipherService</shadedPattern>\n"
+                + "  </relocation>\n"
+                + "</relocations>";
+        String recessive = "<relocations combine.children=\"append\">\n"
+                + "  <relocation>\n"
+                + "    <pattern>javax.faces</pattern>\n"
+                + "    <shadedPattern>jakarta.faces</shadedPattern>\n"
+                + "  </relocation>\n"
+                + "</relocations>";
+        String expected = "<relocations combine.children=\"append\">\n"
+                + "  <relocation>\n"
+                + "    <pattern>javax.faces</pattern>\n"
+                + "    <shadedPattern>jakarta.faces</shadedPattern>\n"
+                + "  </relocation>\n"
+                + "  <relocation>\n"
+                + "    <pattern>org.apache.shiro.crypto.CipherService</pattern>\n"
+                + "    <shadedPattern>org.apache.shiro.crypto.cipher.CipherService</shadedPattern>\n"
+                + "  </relocation>\n"
+                + "</relocations>";
+
+        XmlNode d = toXmlNode(dominant);
+        XmlNode r = toXmlNode(recessive);
+        XmlNode m = d.merge(r);
+        assertEquals(expected, m.toString().replaceAll("\r\n", "\n"));
+    }
+
+    private static List<XmlNode> getChildren(XmlNode node, String name) {
+        return node.getChildren().stream().filter(n -> n.getName().equals(name)).collect(Collectors.toList());
+    }
+
+    private static XmlNode getNthChild(XmlNode node, String name, int nth) {
+        return node.getChildren().stream()
+                .filter(n -> n.getName().equals(name))
+                .skip(nth)
+                .findFirst()
+                .orElse(null);
+    }
+
+    private static XmlNode toXmlNode(String xml) throws XMLStreamException, IOException {
+        return toXmlNode(xml, null);
+    }
+
+    private static XmlNode toXmlNode(String xml, XmlNodeBuilder.InputLocationBuilderStax locationBuilder)
+            throws XMLStreamException, IOException {
+        return toXmlNode(new StringReader(xml), locationBuilder);
+    }
+
+    private static XmlNode toXmlNode(Reader reader) throws XMLStreamException, IOException {
+        return toXmlNode(reader, null);
+    }
+
+    private static XmlNode toXmlNode(Reader reader, XmlNodeBuilder.InputLocationBuilderStax locationBuilder)
+            throws XMLStreamException, IOException {
+        return XmlNodeBuilder.build(reader, locationBuilder);
+    }
+
+    private static class FixedInputLocationBuilder implements XmlNodeBuilder.InputLocationBuilderStax {
+        private final Object location;
+
+        public FixedInputLocationBuilder(Object location) {
+            this.location = location;
+        }
+
+        public Object toInputLocation(XMLStreamReader parser) {
+            return location;
+        }
+    }
+}
diff --git a/pom.xml b/pom.xml
index 345a628..2922a5c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,5 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
 <!--
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
@@ -18,19 +17,19 @@
 specific language governing permissions and limitations
 under the License.
 -->
-
 <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>org.apache.maven</groupId>
     <artifactId>maven-parent</artifactId>
-    <version>36</version>
+    <!-- please also update in maven-bom -->
+    <version>41</version>
     <relativePath />
   </parent>
 
   <artifactId>maven</artifactId>
-  <version>4.0.0-alpha-1-SNAPSHOT</version>
+  <version>4.0.0-alpha-9-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <name>Apache Maven</name>
@@ -40,86 +39,10 @@
     publication, and distribution publication are all controlled from
     the declarative file. Maven can be extended by plugins to utilise a
     number of other development tools for reporting or the build
-    process.
-  </description>
+    process.</description>
   <url>https://maven.apache.org/ref/${project.version}/</url>
   <inceptionYear>2001</inceptionYear>
 
-  <properties>
-    <javaVersion>8</javaVersion>
-    <classWorldsVersion>2.6.0</classWorldsVersion>
-    <commonsCliVersion>1.5.0</commonsCliVersion>
-    <commonsIoVersion>2.11.0</commonsIoVersion>
-    <commonsLangVersion>3.12.0</commonsLangVersion>
-    <junitVersion>5.8.1</junitVersion>
-    <mockitoVersion>3.2.0</mockitoVersion>
-    <plexusVersion>2.1.0</plexusVersion>
-    <plexusInterpolationVersion>1.26</plexusInterpolationVersion>
-    <plexusUtilsVersion>3.4.2</plexusUtilsVersion>
-    <guiceVersion>4.2.3</guiceVersion>
-    <guavaVersion>30.1-jre</guavaVersion>
-    <guavafailureaccessVersion>1.0.1</guavafailureaccessVersion>
-    <wagonVersion>3.5.2</wagonVersion>
-    <securityDispatcherVersion>2.0</securityDispatcherVersion>
-    <cipherVersion>2.0</cipherVersion>
-    <modelloVersion>2.0.0</modelloVersion>
-    <jxpathVersion>1.3</jxpathVersion>
-    <resolverVersion>1.8.2</resolverVersion>
-    <slf4jVersion>1.7.36</slf4jVersion>
-    <xmlunitVersion>2.6.4</xmlunitVersion>
-    <maven.test.redirectTestOutputToFile>true</maven.test.redirectTestOutputToFile>
-    <!-- Control the name of the distribution and information output by mvn -->
-    <distributionId>apache-maven</distributionId>
-    <distributionShortName>Maven</distributionShortName>
-    <distributionName>Apache Maven</distributionName>
-    <maven.site.path>ref/4-LATEST</maven.site.path>
-    <project.build.outputTimestamp>2021-04-05T08:12:18Z</project.build.outputTimestamp>
-  </properties>
-
-  <modules>
-    <module>maven-bom</module>
-    <module>maven-plugin-api</module>
-    <module>maven-builder-support</module>
-    <module>maven-model</module>
-    <module>maven-model-builder</module>
-    <module>maven-model-transform</module>
-    <module>maven-core</module>
-    <module>maven-settings</module>
-    <module>maven-settings-builder</module>
-    <module>maven-artifact</module>
-    <module>maven-resolver-provider</module>
-    <module>maven-repository-metadata</module>
-    <module>maven-slf4j-provider</module>
-    <module>maven-slf4j-wrapper</module>
-    <module>maven-embedder</module>
-    <module>maven-compat</module>
-    <module>apache-maven</module> <!-- rename to apache-maven/maven.pom after RAT-268 -->
-    <module>maven-toolchain-model</module>
-    <module>maven-toolchain-builder</module>
-  </modules>
-
-  <scm>
-    <connection>scm:git:https://gitbox.apache.org/repos/asf/maven.git</connection>
-    <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/maven.git</developerConnection>
-    <url>https://github.com/apache/maven/tree/${project.scm.tag}</url>
-    <tag>master</tag>
-  </scm>
-  <issueManagement>
-    <system>jira</system>
-    <url>https://issues.apache.org/jira/browse/MNG</url>
-  </issueManagement>
-  <ciManagement>
-    <system>Jenkins</system>
-    <url>https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven/</url>
-  </ciManagement>
-  <distributionManagement>
-    <downloadUrl>https://maven.apache.org/download.html</downloadUrl>
-    <site>
-      <id>apache.website</id>
-      <url>scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path}</url>
-    </site>
-  </distributionManagement>
-
   <contributors>
     <contributor>
       <name>Stuart McCulloch</name>
@@ -176,6 +99,93 @@
     </contributor>
   </contributors>
 
+  <modules>
+    <module>maven-bom</module>
+    <module>maven-plugin-api</module>
+    <module>maven-builder-support</module>
+    <module>maven-model</module>
+    <module>maven-model-builder</module>
+    <module>api</module>
+    <module>maven-xml-impl</module>
+    <module>maven-core</module>
+    <module>maven-settings</module>
+    <module>maven-settings-builder</module>
+    <module>maven-artifact</module>
+    <module>maven-resolver-provider</module>
+    <module>maven-repository-metadata</module>
+    <module>maven-slf4j-provider</module>
+    <module>maven-slf4j-wrapper</module>
+    <module>maven-embedder</module>
+    <module>maven-compat</module>
+    <module>apache-maven</module>
+    <!-- rename to apache-maven/maven.pom after RAT-268 -->
+    <module>maven-toolchain-model</module>
+    <module>maven-toolchain-builder</module>
+  </modules>
+
+  <scm>
+    <connection>scm:git:https://gitbox.apache.org/repos/asf/maven.git</connection>
+    <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/maven.git</developerConnection>
+    <tag>maven-4.0.0-alpha-3</tag>
+    <url>https://github.com/apache/maven/tree/${project.scm.tag}</url>
+  </scm>
+  <issueManagement>
+    <system>jira</system>
+    <url>https://issues.apache.org/jira/browse/MNG</url>
+  </issueManagement>
+  <ciManagement>
+    <system>Jenkins</system>
+    <url>https://ci-maven.apache.org/job/Maven/job/maven-box/job/maven/</url>
+  </ciManagement>
+  <distributionManagement>
+    <site>
+      <id>apache.website</id>
+      <url>scm:svn:https://svn.apache.org/repos/asf/maven/website/components/${maven.site.path}</url>
+    </site>
+    <downloadUrl>https://maven.apache.org/download.html</downloadUrl>
+  </distributionManagement>
+
+  <properties>
+    <javaVersion>8</javaVersion>
+    <maven.test.redirectTestOutputToFile>true</maven.test.redirectTestOutputToFile>
+    <maven.baseline>3.8.7</maven.baseline>
+    <!-- Control the name of the distribution and information output by mvn -->
+    <distributionId>apache-maven</distributionId>
+    <distributionShortName>Maven</distributionShortName>
+    <distributionName>Apache Maven</distributionName>
+    <maven.site.path>ref/4-LATEST</maven.site.path>
+    <project.build.outputTimestamp>2023-10-20T19:20:23Z</project.build.outputTimestamp>
+    <!-- various versions -->
+    <asmVersion>9.6</asmVersion>
+    <byteBuddyVersion>1.14.9</byteBuddyVersion>
+    <cipherVersion>2.0</cipherVersion>
+    <classWorldsVersion>2.6.0</classWorldsVersion>
+    <commonsCliVersion>1.5.0</commonsCliVersion>
+    <commonsIoVersion>2.11.0</commonsIoVersion>
+    <guiceVersion>6.0.0</guiceVersion>
+    <guavaVersion>32.0.1-jre</guavaVersion>
+    <guavafailureaccessVersion>1.0.1</guavafailureaccessVersion>
+    <hamcrestVersion>2.2</hamcrestVersion>
+    <jakartaInjectApiVersion>2.0.1</jakartaInjectApiVersion>
+    <jansiVersion>2.4.1</jansiVersion>
+    <javaxAnnotationApiVersion>1.3.2</javaxAnnotationApiVersion>
+    <junitVersion>5.10.1</junitVersion>
+    <jxpathVersion>1.3</jxpathVersion>
+    <logbackClassicVersion>1.2.11</logbackClassicVersion>
+    <mockitoVersion>5.7.0</mockitoVersion>
+    <plexusInterpolationVersion>1.26</plexusInterpolationVersion>
+    <plexusTestingVersion>1.0.0</plexusTestingVersion>
+    <plexusXmlVersion>4.0.1</plexusXmlVersion>
+    <resolverVersion>2.0.0-alpha-2</resolverVersion>
+    <securityDispatcherVersion>2.0</securityDispatcherVersion>
+    <sisuVersion>0.9.0.M2</sisuVersion>
+    <slf4jVersion>1.7.36</slf4jVersion>
+    <stax2ApiVersion>4.2.1</stax2ApiVersion>
+    <wagonVersion>3.5.3</wagonVersion>
+    <woodstoxVersion>6.5.1</woodstoxVersion>
+    <xmlunitVersion>2.6.4</xmlunitVersion>
+  </properties>
+
   <!--bootstrap-start-comment-->
   <dependencyManagement>
     <!--bootstrap-end-comment-->
@@ -200,17 +210,16 @@
         <version>${project.version}</version>
       </dependency>
       <!--bootstrap-end-comment-->
-      <!--  Plexus -->
       <dependency>
         <groupId>org.codehaus.plexus</groupId>
-        <artifactId>plexus-utils</artifactId>
-        <version>${plexusUtilsVersion}</version>
+        <artifactId>plexus-xml</artifactId>
+        <version>${plexusXmlVersion}</version>
       </dependency>
       <dependency>
         <groupId>com.google.inject</groupId>
         <artifactId>guice</artifactId>
         <version>${guiceVersion}</version>
-        <classifier>no_aop</classifier>
+        <classifier>classes</classifier>
         <exclusions>
           <exclusion>
             <groupId>com.google.guava</groupId>
@@ -261,16 +270,33 @@
         <artifactId>org.eclipse.sisu.plexus</artifactId>
         <version>${sisuVersion}</version>
         <exclusions>
-          <exclusion> <!-- Way too easy to conflict with plugins to be in Maven and leak in plugins -->
+          <exclusion>
+            <!-- Way too easy to conflict with plugins to be in Maven and leak in plugins -->
             <groupId>javax.enterprise</groupId>
             <artifactId>cdi-api</artifactId>
           </exclusion>
+          <!-- we use the no_asm classifier for sisu.inject -->
+          <exclusion>
+            <groupId>org.eclipse.sisu</groupId>
+            <artifactId>org.eclipse.sisu.inject</artifactId>
+          </exclusion>
         </exclusions>
       </dependency>
       <dependency>
         <groupId>org.eclipse.sisu</groupId>
         <artifactId>org.eclipse.sisu.inject</artifactId>
         <version>${sisuVersion}</version>
+        <classifier>no_asm</classifier>
+      </dependency>
+      <dependency>
+        <groupId>jakarta.inject</groupId>
+        <artifactId>jakarta.inject-api</artifactId>
+        <version>${jakartaInjectApiVersion}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.ow2.asm</groupId>
+        <artifactId>asm</artifactId>
+        <version>${asmVersion}</version>
       </dependency>
       <dependency>
         <groupId>javax.inject</groupId>
@@ -280,12 +306,7 @@
       <dependency>
         <groupId>javax.annotation</groupId>
         <artifactId>javax.annotation-api</artifactId>
-        <version>1.3.2</version>
-      </dependency>
-      <dependency>
-        <groupId>org.codehaus.plexus</groupId>
-        <artifactId>plexus-component-annotations</artifactId>
-        <version>${plexusVersion}</version>
+        <version>${javaxAnnotationApiVersion}</version>
       </dependency>
       <dependency>
         <groupId>org.codehaus.plexus</groupId>
@@ -298,21 +319,9 @@
         <version>${plexusInterpolationVersion}</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.maven.shared</groupId>
-        <artifactId>maven-shared-utils</artifactId>
-        <version>3.3.4</version>
-        <exclusions>
-          <!-- We use org.apache.maven.shared.utils.logging only in Maven Core -->
-          <exclusion>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-          </exclusion>
-        </exclusions>
-      </dependency>
-      <dependency>
         <groupId>org.fusesource.jansi</groupId>
         <artifactId>jansi</artifactId>
-        <version>2.4.0</version>
+        <version>${jansiVersion}</version>
       </dependency>
       <dependency>
         <groupId>org.slf4j</groupId>
@@ -328,7 +337,7 @@
       <dependency>
         <groupId>ch.qos.logback</groupId>
         <artifactId>logback-classic</artifactId>
-        <version>1.2.11</version>
+        <version>${logbackClassicVersion}</version>
         <optional>true</optional>
       </dependency>
       <!--  Wagon -->
@@ -346,13 +355,6 @@
         <groupId>org.apache.maven.wagon</groupId>
         <artifactId>wagon-http</artifactId>
         <version>${wagonVersion}</version>
-        <exclusions>
-          <!-- Not used at all -->
-          <exclusion>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-          </exclusion>
-        </exclusions>
       </dependency>
       <!--  Repository -->
       <dependency>
@@ -392,6 +394,11 @@
       </dependency>
       <dependency>
         <groupId>org.apache.maven.resolver</groupId>
+        <artifactId>maven-resolver-transport-jdk</artifactId>
+        <version>${resolverVersion}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.apache.maven.resolver</groupId>
         <artifactId>maven-resolver-transport-wagon</artifactId>
         <version>${resolverVersion}</version>
       </dependency>
@@ -412,11 +419,6 @@
         <version>${jxpathVersion}</version>
       </dependency>
       <dependency>
-        <groupId>org.apache.commons</groupId>
-        <artifactId>commons-lang3</artifactId>
-        <version>${commonsLangVersion}</version>
-      </dependency>
-      <dependency>
         <groupId>org.codehaus.plexus</groupId>
         <artifactId>plexus-sec-dispatcher</artifactId>
         <version>${securityDispatcherVersion}</version>
@@ -427,10 +429,14 @@
         <version>${cipherVersion}</version>
       </dependency>
       <dependency>
-        <groupId>org.mockito</groupId>
-        <artifactId>mockito-core</artifactId>
-        <version>${mockitoVersion}</version>
-        <scope>test</scope>
+        <groupId>com.fasterxml.woodstox</groupId>
+        <artifactId>woodstox-core</artifactId>
+        <version>${woodstoxVersion}</version>
+      </dependency>
+      <dependency>
+        <groupId>org.codehaus.woodstox</groupId>
+        <artifactId>stax2-api</artifactId>
+        <version>${stax2ApiVersion}</version>
       </dependency>
       <dependency>
         <groupId>org.xmlunit</groupId>
@@ -453,28 +459,40 @@
       <dependency>
         <groupId>org.hamcrest</groupId>
         <artifactId>hamcrest-core</artifactId>
-        <version>2.2</version>
+        <version>${hamcrestVersion}</version>
         <scope>test</scope>
       </dependency>
       <dependency>
         <groupId>org.hamcrest</groupId>
         <artifactId>hamcrest-library</artifactId>
-        <version>2.2</version>
+        <version>${hamcrestVersion}</version>
         <scope>test</scope>
       </dependency>
       <dependency>
         <groupId>org.codehaus.plexus</groupId>
         <artifactId>plexus-testing</artifactId>
-        <version>1.0.0</version>
+        <version>${plexusTestingVersion}</version>
         <scope>test</scope>
       </dependency>
       <dependency>
         <groupId>org.junit</groupId>
         <artifactId>junit-bom</artifactId>
-        <type>pom</type>
         <version>${junitVersion}</version>
+        <type>pom</type>
         <scope>import</scope>
       </dependency>
+      <dependency>
+        <groupId>org.mockito</groupId>
+        <artifactId>mockito-bom</artifactId>
+        <version>${mockitoVersion}</version>
+        <type>pom</type>
+        <scope>import</scope>
+      </dependency>
+      <dependency>
+        <groupId>net.bytebuddy</groupId>
+        <artifactId>byte-buddy</artifactId>
+        <version>${byteBuddyVersion}</version>
+      </dependency>
     </dependencies>
     <!--bootstrap-start-comment-->
   </dependencyManagement>
@@ -483,7 +501,7 @@
   <dependencies>
     <dependency>
       <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
+      <artifactId>junit-jupiter-api</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
@@ -497,35 +515,37 @@
   <build>
     <pluginManagement>
       <plugins>
+        <!-- Remove when Parent 41 used -->
         <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-checkstyle-plugin</artifactId>
-          <version>3.1.2</version>
-          <dependencies>
-            <dependency>
-              <groupId>com.puppycrawl.tools</groupId>
-              <artifactId>checkstyle</artifactId>
-              <version>8.41.1</version>
-            </dependency>
-            <dependency>
-              <groupId>org.apache.maven.shared</groupId>
-              <artifactId>maven-shared-resources</artifactId>
-              <version>3</version>
-            </dependency>
-          </dependencies>
-        </plugin>
-        <plugin>
-          <groupId>org.codehaus.plexus</groupId>
-          <artifactId>plexus-component-metadata</artifactId>
-          <version>${plexusVersion}</version>
-          <executions>
-            <execution>
-              <goals>
-                <goal>generate-metadata</goal>
-                <goal>generate-test-metadata</goal>
-              </goals>
-            </execution>
-          </executions>
+          <groupId>com.diffplug.spotless</groupId>
+          <artifactId>spotless-maven-plugin</artifactId>
+          <version>2.40.0</version>
+          <configuration>
+            <java>
+              <!-- orders of used formatters are important MPOM-376 -->
+              <!-- eg. palantir override importOrder, so should be first -->
+              <palantirJavaFormat>
+                <version>2.38.0</version>
+              </palantirJavaFormat>
+              <removeUnusedImports />
+              <importOrder>
+                <file>config/maven-eclipse-importorder.txt</file>
+              </importOrder>
+              <licenseHeader>
+                <file>config/maven-header-plain.txt</file>
+              </licenseHeader>
+            </java>
+            <pom>
+              <sortPom>
+                <expandEmptyElements>false</expandEmptyElements>
+                <!-- https://issues.apache.org/jira/browse/MRELEASE-1111 -->
+                <spaceBeforeCloseEmptyElement>true</spaceBeforeCloseEmptyElement>
+              </sortPom>
+            </pom>
+            <upToDateChecking>
+              <enabled>true</enabled>
+            </upToDateChecking>
+          </configuration>
         </plugin>
         <plugin>
           <groupId>org.apache.maven.plugins</groupId>
@@ -547,75 +567,55 @@
         <plugin>
           <groupId>org.codehaus.modello</groupId>
           <artifactId>modello-maven-plugin</artifactId>
-          <version>${modelloVersion}</version>
           <executions>
             <execution>
               <id>modello-site-docs</id>
-              <phase>pre-site</phase>
               <goals>
                 <goal>xdoc</goal>
                 <goal>xsd</goal>
               </goals>
+              <phase>pre-site</phase>
             </execution>
+          </executions>
+        </plugin>
+        <!-- enforce backwards compatibility -->
+        <plugin>
+          <groupId>com.github.siom79.japicmp</groupId>
+          <artifactId>japicmp-maven-plugin</artifactId>
+          <version>0.17.2</version>
+          <executions>
             <execution>
-              <id>modello</id>
               <goals>
-                <goal>java</goal>
-                <goal>xpp3-reader</goal>
-                <goal>xpp3-writer</goal>
+                <goal>cmp</goal>
               </goals>
+              <phase>verify</phase>
+              <configuration>
+                <parameter>
+                  <!-- baseline is 3.8.6 for Maven 4 -->
+                  <oldVersionPattern>${maven.baseline}</oldVersionPattern>
+                  <breakBuildOnBinaryIncompatibleModifications>true</breakBuildOnBinaryIncompatibleModifications>
+                  <onlyBinaryIncompatible>true</onlyBinaryIncompatible>
+                  <!-- don't include subpackages -->
+                  <includeExclusively>true</includeExclusively>
+                </parameter>
+              </configuration>
             </execution>
           </executions>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
-          <artifactId>buildnumber-maven-plugin</artifactId>
-          <version>1.4</version>
+          <artifactId>build-helper-maven-plugin</artifactId>
+          <version>3.4.0</version>
         </plugin>
         <plugin>
-          <groupId>org.apache.rat</groupId>
-          <artifactId>apache-rat-plugin</artifactId>
-          <configuration>
-            <excludes>
-              <exclude>.asf.yaml</exclude>
-              <exclude>src/test/resources*/**</exclude>
-              <exclude>src/test/projects/**</exclude>
-              <exclude>src/test/remote-repo/**</exclude>
-              <exclude>**/*.odg</exclude>
-              <!--
-                ! Excluded the license files itself cause they do not have have a license of themselves.
-              -->
-              <exclude>src/main/appended-resources/licenses/MIT-slf4j-api-1.7.30.txt</exclude>
-              <exclude>src/main/appended-resources/licenses/EPL-1.0.txt</exclude>
-              <exclude>src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.3.2.txt</exclude>
-            </excludes>
-          </configuration>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>buildnumber-maven-plugin</artifactId>
+          <version>3.2.0</version>
         </plugin>
       </plugins>
     </pluginManagement>
     <plugins>
       <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>animal-sniffer-maven-plugin</artifactId>
-        <version>1.21</version>
-        <configuration>
-          <signature>
-            <groupId>org.codehaus.mojo.signature</groupId>
-            <artifactId>java18</artifactId>
-            <version>1.0</version>
-          </signature>
-        </configuration>
-        <executions>
-          <execution>
-            <id>check-java-compat</id>
-            <phase>process-classes</phase>
-            <goals>
-              <goal>check</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-doap-plugin</artifactId>
         <version>1.2</version>
@@ -632,25 +632,39 @@
       <plugin>
         <groupId>org.apache.rat</groupId>
         <artifactId>apache-rat-plugin</artifactId>
-        <configuration>
-          <excludes combine.children="append">
-            <exclude>bootstrap/**</exclude>
-            <exclude>README.bootstrap.txt</exclude>
-            <exclude>README.md</exclude>
-            <exclude>**/.factorypath</exclude>
-          </excludes>
-        </configuration>
+        <executions>
+          <execution>
+            <id>rat-check</id>
+            <inherited>false</inherited>
+            <configuration>
+              <excludes>
+                <exclude>**/.gitattributes</exclude>
+                <exclude>src/test/resources*/**</exclude>
+                <exclude>src/test/projects/**</exclude>
+                <exclude>src/test/remote-repo/**</exclude>
+                <exclude>**/*.odg</exclude>
+                <exclude>.asf.yaml</exclude>
+                <!--
+                  ! Excluded the license files itself cause they do not have have a license of themselves.
+                -->
+                <exclude>src/main/appended-resources/licenses/EPL-1.0.txt</exclude>
+                <exclude>src/main/appended-resources/licenses/unrecognized-aopalliance-1.0.txt</exclude>
+                <exclude>src/main/appended-resources/licenses/unrecognized-javax.annotation-api-1.3.2.txt</exclude>
+              </excludes>
+            </configuration>
+          </execution>
+        </executions>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-enforcer-plugin</artifactId>
         <executions>
           <execution>
+            <id>ensure-no-sonatype-cipher-and-sec-dispatcher</id>
             <goals>
               <goal>enforce</goal>
             </goals>
             <phase>validate</phase>
-            <id>ensure-no-sonatype-cipher-and-sec-dispatcher</id>
             <configuration>
               <rules>
                 <bannedDependencies>
@@ -658,37 +672,34 @@
                     <exclude>org.sonatype.plexus:plexus-sec-dispatcher</exclude>
                     <exclude>org.sonatype.plexus:plexus-cipher</exclude>
                   </excludes>
-                  <message>
-                    ensure no more org.sonatype.plexus:plexus-cipher and org.sonatype.plexus:plexus-sec-dispatcher.
-                  </message>
+                  <message>ensure no more org.sonatype.plexus:plexus-cipher and org.sonatype.plexus:plexus-sec-dispatcher.</message>
                 </bannedDependencies>
               </rules>
               <fail>true</fail>
             </configuration>
           </execution>
+          <execution>
+            <id>enforce-bytecode-version</id>
+            <goals>
+              <goal>enforce</goal>
+            </goals>
+            <configuration>
+              <rules>
+                <requireJavaVersion>
+                  <version>[11,)</version>
+                </requireJavaVersion>
+                <enforceBytecodeVersion>
+                  <maxJdkVersion>${maven.compiler.target}</maxJdkVersion>
+                  <ignoredScopes>
+                    <ignoredScope>test</ignoredScope>
+                  </ignoredScopes>
+                </enforceBytecodeVersion>
+              </rules>
+              <fail>true</fail>
+            </configuration>
+          </execution>
         </executions>
       </plugin>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-checkstyle-plugin</artifactId>
-        <version>3.1.2</version>
-        <configuration>
-          <violationSeverity>info</violationSeverity>
-          <suppressionsLocation>${maven.multiModuleProjectDirectory}/build/checkstyle-suppressions.xml</suppressionsLocation>
-        </configuration>
-        <dependencies>
-          <dependency>
-            <groupId>com.puppycrawl.tools</groupId>
-            <artifactId>checkstyle</artifactId>
-            <version>8.41.1</version>
-          </dependency>
-          <dependency>
-            <groupId>org.apache.maven.shared</groupId>
-            <artifactId>maven-shared-resources</artifactId>
-            <version>3</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
 
@@ -732,10 +743,10 @@
             <reportSets>
               <reportSet>
                 <id>aggregate</id>
-                <inherited>false</inherited>
                 <reports>
                   <report>aggregate</report>
                 </reports>
+                <inherited>false</inherited>
               </reportSet>
             </reportSets>
           </plugin>
@@ -745,10 +756,10 @@
             <reportSets>
               <reportSet>
                 <id>aggregate</id>
-                <inherited>false</inherited>
                 <reports>
                   <report>aggregate</report>
                 </reports>
+                <inherited>false</inherited>
               </reportSet>
             </reportSets>
           </plugin>
@@ -768,13 +779,13 @@
             <groupId>org.apache.maven.plugins</groupId>
             <artifactId>maven-surefire-plugin</artifactId>
             <configuration>
-              <systemProperties combine.children="append">
+              <systemPropertyVariables combine.children="append">
                 <property>
                   <!-- Pass this through to the tests (if set!) to have them pick the right repository -->
                   <name>maven.repo.local</name>
                   <value>${maven.repo.local}</value>
                 </property>
-              </systemProperties>
+              </systemPropertyVariables>
             </configuration>
           </plugin>
         </plugins>
diff --git a/src/mdo/common.vm b/src/mdo/common.vm
new file mode 100644
index 0000000..b8ae209
--- /dev/null
+++ b/src/mdo/common.vm
@@ -0,0 +1,33 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#
+#if ( "${isMavenModel}" == "true" )
+##
+## The following loop code is required in order to change the type of the
+## pomFile attribute to a java.nio.file.Path.  Modello does not support this
+## type and loading a model with such a type would fail the Modello validation.
+##
+#foreach ( $field in $model.getClass("Model", $version).allFields )
+  #if ( $field.name == "pomFile" )
+    #set ( $dummy = $field.setType("java.nio.file.Path") )
+  #end
+#end
+#set ( $locationTracking = true )
+#end
+#
\ No newline at end of file
diff --git a/src/mdo/java/ImmutableCollections.java b/src/mdo/java/ImmutableCollections.java
new file mode 100644
index 0000000..fe4faef
--- /dev/null
+++ b/src/mdo/java/ImmutableCollections.java
@@ -0,0 +1,609 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package ${package};
+
+import java.io.Serializable;
+import java.util.AbstractList;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Properties;
+import java.util.RandomAccess;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
+
+class ImmutableCollections {
+
+    private static final List<?> EMPTY_LIST = new AbstractImmutableList<Object>() {
+        @Override
+        public Object get(int index) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+    };
+
+    private static final Map<?, ?> EMPTY_MAP = new AbstractImmutableMap<Object, Object>() {
+        @Override
+        public Set<Entry<Object, Object>> entrySet() {
+            return new AbstractImmutableSet<Entry<Object, Object>>() {
+                @Override
+                public Iterator<Entry<Object, Object>> iterator() {
+                    return new Iterator<Entry<Object, Object>>() {
+                        @Override
+                        public boolean hasNext() {
+                            return false;
+                        }
+
+                        @Override
+                        public Entry<Object, Object> next() {
+                            throw new NoSuchElementException();
+                        }
+                    };
+                }
+
+                @Override
+                public int size() {
+                    return 0;
+                }
+            };
+        }
+    };
+
+    static <E> List<E> copy(Collection<E> collection) {
+        if (collection == null) {
+            return emptyList();
+        } else if (collection instanceof AbstractImmutableList) {
+            return (List<E>) collection;
+        } else {
+            switch (collection.size()) {
+                case 0:
+                    return emptyList();
+                case 1:
+                    return singletonList(collection.iterator().next());
+                case 2:
+                    Iterator<E> it = collection.iterator();
+                    return new List2<>(it.next(), it.next());
+                default:
+                    return new ListN<>(collection);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    static <E> List<E> emptyList() {
+        return (List<E>) EMPTY_LIST;
+    }
+
+    static <E> List<E> singletonList(E element) {
+        return new List1<>(element);
+    }
+
+    static <K, V> Map<K, V> copy(Map<K, V> map) {
+        if (map == null) {
+            return emptyMap();
+        } else if (map instanceof AbstractImmutableMap) {
+            return map;
+        } else {
+            switch (map.size()) {
+                case 0:
+                    return emptyMap();
+                case 1:
+                    Map.Entry<K, V> entry = map.entrySet().iterator().next();
+                    return singletonMap(entry.getKey(), entry.getValue());
+                default:
+                    return new MapN<>(map);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    static <K, V> Map<K, V> emptyMap() {
+        return (Map<K, V>) EMPTY_MAP;
+    }
+
+    static <K, V> Map<K, V> singletonMap(K key, V value) {
+        return new Map1<>(key, value);
+    }
+
+    static Properties copy(Properties properties) {
+        if (properties instanceof ROProperties) {
+            return properties;
+        }
+        return new ROProperties(properties);
+    }
+
+    private static class List1<E> extends AbstractImmutableList<E> {
+        private final E element;
+
+        private List1(E element) {
+            this.element = element;
+        }
+
+        @Override
+        public E get(int index) {
+            if (index == 0) {
+                return element;
+            }
+            throw outOfBounds(index);
+        }
+
+        @Override
+        public int size() {
+            return 1;
+        }
+    }
+
+    private static class List2<E> extends AbstractImmutableList<E> {
+        private final E element1;
+        private final E element2;
+
+        private List2(E element1, E element2) {
+            this.element1 = element1;
+            this.element2 = element2;
+        }
+
+        @Override
+        public E get(int index) {
+            if (index == 0) {
+                return element1;
+            } else if (index == 1) {
+                return element2;
+            }
+            throw outOfBounds(index);
+        }
+
+        @Override
+        public int size() {
+            return 2;
+        }
+    }
+
+    private static class ListN<E> extends AbstractImmutableList<E> {
+        private final Object[] elements;
+
+        private ListN(Collection<E> elements) {
+            this.elements = elements.toArray();
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public E get(int index) {
+            return (E) elements[index];
+        }
+
+        @Override
+        public int size() {
+            return elements.length;
+        }
+    }
+
+    private abstract static class AbstractImmutableList<E> extends AbstractList<E>
+            implements RandomAccess, Serializable {
+        @Override
+        public boolean add(E e) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean addAll(Collection<? extends E> c) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean removeAll(Collection<?> c) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> c) {
+            throw uoe();
+        }
+
+        @Override
+        public void clear() {
+            throw uoe();
+        }
+
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw uoe();
+        }
+
+        @Override
+        public void replaceAll(UnaryOperator<E> operator) {
+            throw uoe();
+        }
+
+        @Override
+        public void sort(Comparator<? super E> c) {
+            throw uoe();
+        }
+
+        @Override
+        public Iterator<E> iterator() {
+            return new Itr(0);
+        }
+
+        @Override
+        public ListIterator<E> listIterator() {
+            return new Itr(0);
+        }
+
+        @Override
+        public ListIterator<E> listIterator(int index) {
+            if (index < 0 || index > size()) {
+                throw outOfBounds(index);
+            }
+            return new Itr(index);
+        }
+
+        @Override
+        public List<E> subList(int fromIndex, int toIndex) {
+            if (fromIndex < 0) {
+                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
+            }
+            if (toIndex > size()) {
+                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
+            }
+            if (fromIndex > toIndex) {
+                throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+            }
+            return new SubList(fromIndex, toIndex);
+        }
+
+        protected IndexOutOfBoundsException outOfBounds(int index) {
+            return new IndexOutOfBoundsException("Index: " + index + ", Size: " + size());
+        }
+
+        private class SubList extends AbstractImmutableList<E> {
+            private final int fromIndex;
+            private final int toIndex;
+
+            private SubList(int fromIndex, int toIndex) {
+                this.fromIndex = fromIndex;
+                this.toIndex = toIndex;
+            }
+
+            @Override
+            public E get(int index) {
+                if (index < 0 || index > size()) {
+                    throw outOfBounds(index);
+                }
+                return AbstractImmutableList.this.get(fromIndex + index);
+            }
+
+            @Override
+            public int size() {
+                return toIndex - fromIndex;
+            }
+        }
+
+        private class Itr implements ListIterator<E> {
+            int index;
+
+            private Itr(int index) {
+                this.index = index;
+            }
+
+            @Override
+            public boolean hasNext() {
+                return index < size();
+            }
+
+            @Override
+            public E next() {
+                return get(index++);
+            }
+
+            @Override
+            public boolean hasPrevious() {
+                return index > 0;
+            }
+
+            @Override
+            public E previous() {
+                return get(--index);
+            }
+
+            @Override
+            public int nextIndex() {
+                return index;
+            }
+
+            @Override
+            public int previousIndex() {
+                return index - 1;
+            }
+
+            @Override
+            public void remove() {
+                throw uoe();
+            }
+
+            @Override
+            public void set(E e) {
+                throw uoe();
+            }
+
+            @Override
+            public void add(E e) {
+                throw uoe();
+            }
+        }
+    }
+
+    private static class ROProperties extends Properties {
+        private ROProperties(Properties props) {
+            super();
+            if (props != null) {
+                // Do not use super.putAll, as it may delegate to put which throws an UnsupportedOperationException
+                for (Map.Entry<Object, Object> e : props.entrySet()) {
+                    super.put(e.getKey(), e.getValue());
+                }
+            }
+        }
+
+        @Override
+        public Object put(Object key, Object value) {
+            throw uoe();
+        }
+
+        @Override
+        public Object remove(Object key) {
+            throw uoe();
+        }
+
+        @Override
+        public void putAll(Map<?, ?> t) {
+            throw uoe();
+        }
+
+        @Override
+        public void clear() {
+            throw uoe();
+        }
+
+        @Override
+        public void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
+            throw uoe();
+        }
+
+        @Override
+        public Object putIfAbsent(Object key, Object value) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean replace(Object key, Object oldValue, Object newValue) {
+            throw uoe();
+        }
+
+        @Override
+        public Object replace(Object key, Object value) {
+            throw uoe();
+        }
+
+        @Override
+        public Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction) {
+            throw uoe();
+        }
+
+        @Override
+        public Object computeIfPresent(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+            throw uoe();
+        }
+
+        @Override
+        public Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+            throw uoe();
+        }
+
+        @Override
+        public Object merge(Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+            throw uoe();
+        }
+    }
+
+    private static class Map1<K, V> extends AbstractImmutableMap<K, V> {
+        private final Entry<K, V> entry;
+
+        private Map1(K key, V value) {
+            this.entry = new SimpleImmutableEntry<>(key, value);
+        }
+
+        @Override
+        public Set<Entry<K, V>> entrySet() {
+            return new AbstractImmutableSet<Entry<K, V>>() {
+                @Override
+                public Iterator<Entry<K, V>> iterator() {
+                    return new Iterator<Entry<K, V>>() {
+                        int index = 0;
+
+                        @Override
+                        public boolean hasNext() {
+                            return index == 0;
+                        }
+
+                        @Override
+                        public Entry<K, V> next() {
+                            if (index++ == 0) {
+                                return entry;
+                            }
+                            throw new NoSuchElementException();
+                        }
+                    };
+                }
+
+                @Override
+                public int size() {
+                    return 1;
+                }
+            };
+        }
+    }
+
+    private static class MapN<K, V> extends AbstractImmutableMap<K, V> {
+        private final Object[] entries;
+
+        private MapN(Map<K, V> map) {
+            entries = map != null
+                    ? map.entrySet().stream()
+                            .map(e -> new SimpleImmutableEntry<>(e.getKey(), e.getValue()))
+                            .toArray()
+                    : new Object[0];
+        }
+
+        @Override
+        public Set<Entry<K, V>> entrySet() {
+            return new AbstractImmutableSet<Entry<K, V>>() {
+                @Override
+                public Iterator<Entry<K, V>> iterator() {
+                    return new Iterator<Entry<K, V>>() {
+                        int index = 0;
+
+                        @Override
+                        public boolean hasNext() {
+                            return index < entries.length;
+                        }
+
+                        @SuppressWarnings("unchecked")
+                        @Override
+                        public Entry<K, V> next() {
+                            if (index < entries.length) {
+                                return (Entry<K, V>) entries[index++];
+                            }
+                            throw new NoSuchElementException();
+                        }
+                    };
+                }
+
+                @Override
+                public int size() {
+                    return entries.length;
+                }
+            };
+        }
+    }
+
+    private abstract static class AbstractImmutableMap<K, V> extends AbstractMap<K, V> implements Serializable {
+        @Override
+        public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+            throw uoe();
+        }
+
+        @Override
+        public V putIfAbsent(K key, V value) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean remove(Object key, Object value) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean replace(K key, V oldValue, V newValue) {
+            throw uoe();
+        }
+
+        @Override
+        public V replace(K key, V value) {
+            throw uoe();
+        }
+
+        @Override
+        public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
+            throw uoe();
+        }
+
+        @Override
+        public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw uoe();
+        }
+
+        @Override
+        public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+            throw uoe();
+        }
+
+        @Override
+        public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+            throw uoe();
+        }
+    }
+
+    private abstract static class AbstractImmutableSet<E> extends AbstractSet<E> implements Serializable {
+        @Override
+        public boolean removeAll(Collection<?> c) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean add(E e) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            throw uoe();
+        }
+
+        @Override
+        public boolean retainAll(Collection<?> c) {
+            throw uoe();
+        }
+
+        @Override
+        public void clear() {
+            throw uoe();
+        }
+
+        @Override
+        public boolean removeIf(Predicate<? super E> filter) {
+            throw uoe();
+        }
+    }
+
+    private static UnsupportedOperationException uoe() {
+        return new UnsupportedOperationException();
+    }
+}
diff --git a/src/mdo/java/WrapperList.java b/src/mdo/java/WrapperList.java
new file mode 100644
index 0000000..0799336
--- /dev/null
+++ b/src/mdo/java/WrapperList.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package ${package};
+
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+class WrapperList<T, U> extends AbstractList<T> {
+    private final Supplier<List<U>> getter;
+    private final Consumer<List<U>> setter;
+    private final Function<U, T> mapper;
+    private final Function<T, U> revMapper;
+
+    WrapperList(List<U> list, Function<U, T> mapper, Function<T, U> revMapper) {
+        this(() -> list, null, mapper, revMapper);
+    }
+
+    WrapperList(Supplier<List<U>> getter, Consumer<List<U>> setter, Function<U, T> mapper, Function<T, U> revMapper) {
+        this.getter = getter;
+        this.setter = setter;
+        this.mapper = mapper;
+        this.revMapper = revMapper;
+    }
+
+    @Override
+    public T get(int index) {
+        return mapper.apply(getter.get().get(index));
+    }
+
+    @Override
+    public int size() {
+        return getter.get().size();
+    }
+
+    @Override
+    public boolean add(T t) {
+        Objects.requireNonNull(t);
+        if (setter != null) {
+            List<U> list = new ArrayList<>(getter.get());
+            boolean ret = list.add(revMapper.apply(t));
+            setter.accept(list);
+            return ret;
+        } else {
+            return getter.get().add(revMapper.apply(t));
+        }
+    }
+
+    @Override
+    public T set(int index, T element) {
+        Objects.requireNonNull(element);
+        if (setter != null) {
+            List<U> list = new ArrayList<>(getter.get());
+            U ret = list.set(index, revMapper.apply(element));
+            setter.accept(list);
+            return mapper.apply(ret);
+        } else {
+            return mapper.apply(getter.get().set(index, revMapper.apply(element)));
+        }
+    }
+
+    @Override
+    public void add(int index, T element) {
+        Objects.requireNonNull(element);
+        if (setter != null) {
+            List<U> list = new ArrayList<>(getter.get());
+            list.add(index, revMapper.apply(element));
+            setter.accept(list);
+        } else {
+            getter.get().add(index, revMapper.apply(element));
+        }
+    }
+
+    @Override
+    public T remove(int index) {
+        if (setter != null) {
+            List<U> list = new ArrayList<>(getter.get());
+            U ret = list.remove(index);
+            setter.accept(list);
+            return mapper.apply(ret);
+        } else {
+            return mapper.apply(getter.get().remove(index));
+        }
+    }
+}
diff --git a/src/mdo/java/WrapperProperties.java b/src/mdo/java/WrapperProperties.java
new file mode 100644
index 0000000..46d7658
--- /dev/null
+++ b/src/mdo/java/WrapperProperties.java
@@ -0,0 +1,333 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package ${package};
+
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.InvalidPropertiesFormatException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+class WrapperProperties extends Properties {
+
+    final Supplier<Map<String, String>> getter;
+    final Consumer<Properties> setter;
+
+    WrapperProperties(Supplier<Map<String, String>> getter, Consumer<Properties> setter) {
+        this.getter = getter;
+        this.setter = setter;
+    }
+
+    @Override
+    public String getProperty(String key) {
+        return getter.get().get(key);
+    }
+
+    @Override
+    public String getProperty(String key, String defaultValue) {
+        return getter.get().getOrDefault(key, defaultValue);
+    }
+
+    @Override
+    public Enumeration<?> propertyNames() {
+        return Collections.enumeration(getter.get().keySet());
+    }
+
+    @Override
+    public Set<String> stringPropertyNames() {
+        return getter.get().keySet();
+    }
+
+    @Override
+    public void list(PrintStream out) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void list(PrintWriter out) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int size() {
+        return getter.get().size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return getter.get().isEmpty();
+    }
+
+    @Override
+    public Enumeration<Object> keys() {
+        return Collections.enumeration((Set) getter.get().keySet());
+    }
+
+    @Override
+    public Enumeration<Object> elements() {
+        return Collections.enumeration((Collection) getter.get().values());
+    }
+
+    @Override
+    public boolean contains(Object value) {
+        return getter.get().containsKey(value != null ? value.toString() : null);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return getter.get().containsValue(value);
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return getter.get().containsKey(key);
+    }
+
+    @Override
+    public Object get(Object key) {
+        return getter.get().get(key);
+    }
+
+    @Override
+    public synchronized String toString() {
+        return getter.get().toString();
+    }
+
+    @Override
+    public Set<Object> keySet() {
+        return (Set) getter.get().keySet();
+    }
+
+    @Override
+    public Collection<Object> values() {
+        return (Collection) getter.get().values();
+    }
+
+    @Override
+    public Set<Map.Entry<Object, Object>> entrySet() {
+        return (Set) getter.get().entrySet();
+    }
+
+    @Override
+    public synchronized boolean equals(Object o) {
+        if (o instanceof WrapperProperties) {
+            o = ((WrapperProperties) o).getter.get();
+        }
+        return getter.get().equals(o);
+    }
+
+    @Override
+    public synchronized int hashCode() {
+        return getter.get().hashCode();
+    }
+
+    @Override
+    public Object getOrDefault(Object key, Object defaultValue) {
+        return getter.get().getOrDefault(key, defaultValue != null ? defaultValue.toString() : null);
+    }
+
+    @Override
+    public synchronized void forEach(BiConsumer<? super Object, ? super Object> action) {
+        getter.get().forEach(action);
+    }
+
+    interface WriteOp<T> {
+        T perform(Properties props);
+    }
+
+    interface WriteOpVoid {
+        void perform(Properties props);
+    }
+
+    private <T> T writeOperation(WriteOp<T> runner) {
+        Properties props = new Properties();
+        props.putAll(getter.get());
+        T ret = runner.perform(props);
+        if (!props.equals(getter.get())) {
+            setter.accept(props);
+        }
+        return ret;
+    }
+
+    private void writeOperationVoid(WriteOpVoid runner) {
+        Properties props = new Properties();
+        props.putAll(getter.get());
+        runner.perform(props);
+        if (!props.equals(getter.get())) {
+            setter.accept(props);
+        }
+    }
+
+    @Override
+    public synchronized Object setProperty(String key, String value) {
+        return writeOperation(p -> p.setProperty(key, value));
+    }
+
+    @Override
+    public synchronized Object put(Object key, Object value) {
+        return writeOperation(p -> p.put(key, value));
+    }
+
+    @Override
+    public synchronized Object remove(Object key) {
+        return writeOperation(p -> p.remove(key));
+    }
+
+    @Override
+    public synchronized void putAll(Map<?, ?> t) {
+        writeOperationVoid(p -> p.putAll(t));
+    }
+
+    @Override
+    public synchronized void clear() {
+        writeOperationVoid(Properties::clear);
+    }
+
+    @Override
+    public synchronized void replaceAll(BiFunction<? super Object, ? super Object, ?> function) {
+        writeOperationVoid(p -> p.replaceAll(function));
+    }
+
+    @Override
+    public synchronized Object putIfAbsent(Object key, Object value) {
+        return writeOperation(p -> p.putIfAbsent(key, value));
+    }
+
+    @Override
+    public synchronized boolean remove(Object key, Object value) {
+        return writeOperation(p -> p.remove(key, value));
+    }
+
+    @Override
+    public synchronized boolean replace(Object key, Object oldValue, Object newValue) {
+        return writeOperation(p -> p.replace(key, oldValue, newValue));
+    }
+
+    @Override
+    public synchronized Object replace(Object key, Object value) {
+        return writeOperation(p -> p.replace(key, value));
+    }
+
+    @Override
+    public synchronized Object computeIfAbsent(Object key, Function<? super Object, ?> mappingFunction) {
+        return writeOperation(p -> p.computeIfAbsent(key, mappingFunction));
+    }
+
+    @Override
+    public synchronized Object computeIfPresent(
+            Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+        return writeOperation(p -> p.computeIfPresent(key, remappingFunction));
+    }
+
+    @Override
+    public synchronized Object compute(Object key, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+        return writeOperation(p -> p.compute(key, remappingFunction));
+    }
+
+    @Override
+    public synchronized Object merge(
+            Object key, Object value, BiFunction<? super Object, ? super Object, ?> remappingFunction) {
+        return writeOperation(p -> p.merge(key, value, remappingFunction));
+    }
+
+    @Override
+    public synchronized void load(Reader reader) throws IOException {
+        try {
+            writeOperationVoid(p -> {
+                try {
+                    p.load(reader);
+                } catch (IOException e) {
+                    throw new IOError(e);
+                }
+            });
+        } catch (IOError e) {
+            throw (IOException) e.getCause();
+        }
+    }
+
+    @Override
+    public synchronized void load(InputStream inStream) throws IOException {
+        try {
+            writeOperationVoid(p -> {
+                try {
+                    p.load(inStream);
+                } catch (IOException e) {
+                    throw new IOError(e);
+                }
+            });
+        } catch (IOError e) {
+            throw (IOException) e.getCause();
+        }
+    }
+
+    @Override
+    public void save(OutputStream out, String comments) {
+        Properties props = new Properties();
+        props.putAll(getter.get());
+        props.save(out, comments);
+    }
+
+    @Override
+    public void store(Writer writer, String comments) throws IOException {
+        Properties props = new Properties();
+        props.putAll(getter.get());
+        props.store(writer, comments);
+    }
+
+    @Override
+    public void store(OutputStream out, String comments) throws IOException {
+        Properties props = new Properties();
+        props.putAll(getter.get());
+        props.store(out, comments);
+    }
+
+    @Override
+    public synchronized void loadFromXML(InputStream in) throws IOException, InvalidPropertiesFormatException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void storeToXML(OutputStream os, String comment) throws IOException {
+        Properties props = new Properties();
+        props.putAll(getter.get());
+        props.storeToXML(os, comment);
+    }
+
+    @Override
+    public void storeToXML(OutputStream os, String comment, String encoding) throws IOException {
+        Properties props = new Properties();
+        props.putAll(getter.get());
+        props.storeToXML(os, comment, encoding);
+    }
+}
diff --git a/src/mdo/merger.vm b/src/mdo/merger.vm
new file mode 100644
index 0000000..ad71bf0
--- /dev/null
+++ b/src/mdo/merger.vm
@@ -0,0 +1,339 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#set ( $package = "${packageToolV4}" )
+#set ( $className = "${model.name}Merger" )
+#
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+import java.io.ObjectStreamException;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.annotations.Generated;
+import org.apache.maven.api.xml.XmlNode;
+#foreach ( $class in $model.allClasses )
+import ${packageModelV4}.${class.Name};
+#end
+
+@Generated
+public class ${className} {
+
+    private final boolean deepMerge;
+
+    public ${className}() {
+        this(true);
+    }
+
+    public ${className}(boolean deepMerge) {
+        this.deepMerge = deepMerge;
+    }
+
+    /**
+     * Merges the specified source object into the given target object.
+     *
+     * @param target The target object whose existing contents should be merged with the source, must not be
+     *            <code>null</code>.
+     * @param source The (read-only) source object that should be merged into the target object, may be
+     *            <code>null</code>.
+     * @param sourceDominant A flag indicating whether either the target object or the source object provides the
+     *            dominant data.
+     * @param hints A set of key-value pairs that customized merger implementations can use to carry domain-specific
+     *            information along, may be <code>null</code>.
+     */
+    public ${root.name} merge(${root.name} target, ${root.name} source, boolean sourceDominant, Map<?, ?> hints) {
+        Objects.requireNonNull(target, "target cannot be null");
+        if (source == null) {
+            return target;
+        }
+        Map<Object, Object> context = new HashMap<>();
+        if (hints != null) {
+            context.putAll(hints);
+        }
+        return merge${root.name}(target, source, sourceDominant, context);
+    }
+
+#foreach ( $class in $model.allClasses )
+  #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+    #set ( $ancestors = $Helper.ancestors( $class ) )
+    #set ( $allFields = [] )
+    #foreach ( $cl in $ancestors )
+      #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
+    #end
+    protected ${class.name} merge${class.name}(${class.name} target, ${class.name} source, boolean sourceDominant, Map<Object, Object> context) {
+        ${class.name}.Builder builder = ${class.name}.newBuilder(target);
+        merge${class.name}(builder, target, source, sourceDominant, context);
+        return builder.build();
+    }
+
+    protected void merge${class.name}(${class.name}.Builder builder, ${class.name} target, ${class.name} source, boolean sourceDominant, Map<Object, Object> context) {
+    #if ( $class.superClass )
+        merge${class.superClass}(builder, target, source, sourceDominant, context);
+    #end
+    #foreach ( $field in $class.getFields($version) )
+        merge${field.modelClass.name}_${Helper.capitalise($field.name)}(builder, target, source, sourceDominant, context);
+    #end
+    }
+
+    #foreach ( $field in $allFields )
+      #set ( $capField = ${Helper.capitalise($field.name)} )
+    protected void merge${class.name}_${capField}(${class.name}.Builder builder, ${class.name} target, ${class.name} source, boolean sourceDominant, Map<Object, Object> context) {
+      #if ( $field.type == "String" )
+        String src = source.get${capField}();
+        String tgt = target.get${capField}();
+        if (src != null && (sourceDominant || tgt == null)) {
+            builder.${field.name}(src);
+        #if ( $locationTracking )
+            builder.location("${field.name}", source.getLocation("${field.name}"));
+        #end
+        }
+      #elseif ( $field.type == "java.util.List" && $field.to == "String" && $field.multiplicity == "*" )
+        builder.${field.name}(merge(target.get${capField}(), source.get${capField}(), sourceDominant, e -> e));
+      #elseif ( $field.type == "java.util.Properties" && $field.to == "String" && $field.multiplicity == "*" )
+        Map<String, String> src = source.get${capField}();
+        if (!src.isEmpty()) {
+            Map<String, String> tgt = target.get${capField}();
+            if (tgt.isEmpty()) {
+                builder.${field.name}(src);
+        #if ( $locationTracking )
+                builder.location("${field.name}", source.getLocation("${field.name}"));
+        #end
+            } else {
+                Map<String, String> merged = new HashMap<>();
+                merged.putAll(sourceDominant ? target.get${capField}() : source.get${capField}());
+                merged.putAll(sourceDominant ? source.get${capField}() : target.get${capField}());
+                builder.${field.name}(merged);
+        #if ( $locationTracking )
+                builder.location("${field.name}", InputLocation.merge(target.getLocation("${field.name}"), source.getLocation("${field.name}"), sourceDominant));
+        #end
+            }
+        }
+      #elseif ( $field.to && $field.multiplicity == "1" )
+        ${field.to} src = source.get${capField}();
+        if (src != null) {
+            ${field.to} tgt = target.get${capField}();
+            if (tgt == null) {
+                tgt = ${field.to}.newInstance(false);
+            }
+            ${field.to} merged = merge${field.to}(tgt, src, sourceDominant, context);
+            builder.${field.name}(merged);
+        #if ( $locationTracking )
+            if (target.get${capField}() == null) {
+                builder.location("${field.name}", source.getLocation("${field.name}"));
+            } else if (merged != tgt) {
+                builder.location("${field.name}", new InputLocation(-1, -1));
+            }
+        #end
+        }
+      #elseif ( $field.to && $field.multiplicity == "*" )
+        if (deepMerge) {
+            builder.${field.name}(merge(target.get${capField}(), source.get${capField}(), get${field.to}Key(),
+                    (t, s) -> merge${field.to}(t, s, sourceDominant, context)));
+        } else {
+            builder.${field.name}(merge(target.get${capField}(), source.get${capField}(), sourceDominant, get${field.to}Key()));
+        }
+      #elseif ( $field.type == "DOM" )
+        XmlNode src = source.getConfiguration();
+        if (src != null) {
+            XmlNode tgt = target.getConfiguration();
+            if (tgt == null) {
+                builder.configuration(src);
+        #if ( $locationTracking )
+                builder.location("${field.name}", source.getLocation("configuration"));
+        #end
+            } else if (sourceDominant) {
+                builder.configuration(src.merge(tgt));
+        #if ( $locationTracking )
+                builder.location("${field.name}", target.getLocation("configuration"));
+        #end
+            } else {
+                builder.configuration(tgt.merge(src));
+        #if ( $locationTracking )
+                builder.location("${field.name}", null);
+        #end
+            }
+        }
+      #elseif ($field.type == "boolean")
+        if (sourceDominant) {
+            builder.${field.name}(source.is${capField}());
+        }
+      #elseif ($field.type == "int" || $field.type == "java.nio.file.Path")
+        if (sourceDominant) {
+            builder.${field.name}(source.get${capField}());
+        }
+      #else
+        // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+    }
+    #end
+
+  #end
+#end
+
+#foreach ( $class in $model.allClasses )
+  #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+    protected KeyComputer<${class.name}> get${class.name}Key() {
+        return v -> v;
+    }
+  #end
+#end
+
+    /**
+     * Use to compute keys for data structures
+     * @param <T> the data structure type
+     */
+    @FunctionalInterface
+    public interface KeyComputer<T> extends Function<T, Object> {
+    }
+
+    /**
+     * Merge two lists
+     */
+    public static <T> List<T> merge(List<T> tgt, List<T> src, boolean sourceDominant, KeyComputer<T> computer) {
+        return merge(tgt, src, computer, (t, s) -> sourceDominant ? s : t);
+    }
+
+    public static <T> List<T> merge(List<T> tgt, List<T> src, KeyComputer<T> computer, BinaryOperator<T> remapping) {
+        if (src.isEmpty()) {
+            return tgt;
+        }
+
+        MergingList<T> list;
+        if (tgt instanceof MergingList) {
+            list = (MergingList<T>) tgt;
+        } else {
+            list = new MergingList<>(computer, src.size() + tgt.size());
+            list.mergeAll(tgt, (t, s) -> s);
+        }
+
+        list.mergeAll(src, remapping);
+        return list;
+    }
+
+    /**
+     * Merging list
+     * @param <V>
+     */
+    private static class MergingList<V> extends AbstractList<V> implements java.io.Serializable {
+
+        private final KeyComputer<V> keyComputer;
+        private Map<Object, V> map;
+        private List<V> list;
+
+        MergingList(KeyComputer<V> keyComputer, int initialCapacity) {
+            this.map = new LinkedHashMap<>(initialCapacity);
+            this.keyComputer = keyComputer;
+        }
+
+        Object writeReplace() throws ObjectStreamException {
+            return new ArrayList<>(this);
+        }
+
+        @Override
+        public Iterator<V> iterator() {
+            if (map != null) {
+                return map.values().iterator();
+            } else {
+                return list.iterator();
+            }
+        }
+
+        void mergeAll(Collection<V> vs, BinaryOperator<V> remapping) {
+            if (map == null) {
+                map = list.stream().collect(Collectors.toMap(keyComputer,
+                    Function.identity(),
+                    null,
+                    LinkedHashMap::new));
+                list = null;
+            }
+
+            if (vs instanceof MergingList && ((MergingList<V>) vs).map != null) {
+                for (Map.Entry<Object, V> e : ((MergingList<V>) vs).map.entrySet()) {
+                    Object key = e.getKey();
+                    V v = e.getValue();
+                    map.merge(key, v, remapping);
+                }
+            } else {
+                for (V v : vs) {
+                    Object key = keyComputer.apply(v);
+                    map.merge(key, v, remapping);
+                }
+            }
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            if (map != null) {
+                return map.containsValue(o);
+            } else {
+                return list.contains(o);
+            }
+        }
+
+        private List<V> asList() {
+            if (list == null) {
+                list = new ArrayList<>(map.values());
+                map = null;
+            }
+            return list;
+        }
+
+        @Override
+        public void add(int index, V element) {
+            asList().add(index, element);
+        }
+
+        @Override
+        public V remove(int index) {
+            return asList().remove(index);
+        }
+
+        @Override
+        public V get(int index) {
+            return asList().get(index);
+        }
+
+        @Override
+        public int size() {
+            if (map != null) {
+                return map.size();
+            } else {
+                return list.size();
+            }
+        }
+    }
+}
diff --git a/src/mdo/model-v3.vm b/src/mdo/model-v3.vm
new file mode 100644
index 0000000..f399783
--- /dev/null
+++ b/src/mdo/model-v3.vm
@@ -0,0 +1,326 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#set ( $package = "${packageModelV3}" )
+#
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#
+#set ( $allClasses = [] )
+#foreach ( $class in $model.allClasses )
+  #if ( $class.name != "InputLocation" && $class.name != "InputSource" )
+    #set ( $dummy = $allClasses.add( $class ) )
+  #end
+#end
+#foreach ( $class in $allClasses )
+  #set ( $ancestors = $Helper.ancestors( $class ) )
+  #set ( $allFields = [] )
+  #set ( $inheritedFields = [] )
+  #foreach ( $cl in $ancestors )
+    #if ( $cl != $class )
+      #set ( $dummy = $inheritedFields.addAll( $cl.allFields ) )
+    #end
+    #set ( $dummy = $allFields.addAll( $cl.allFields ) )
+  #end
+  #set ( $className = "${class.name}" )
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/WrapperList.java
+#parse ( "java/WrapperList.java" )
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/WrapperProperties.java
+#parse ( "java/WrapperProperties.java" )
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+    #set ( $types = { } )
+    #set ( $imports = $class.getClass().forName("java.util.TreeSet").newInstance() )
+    #set ( $dummy = $imports.add( "java.io.Serializable" ) )
+    #set ( $dummy = $imports.add( "java.util.AbstractList" ) )
+    #set ( $dummy = $imports.add( "java.util.Collections" ) )
+    #set ( $dummy = $imports.add( "java.util.HashMap" ) )
+    #set ( $dummy = $imports.add( "java.util.List" ) )
+    #set ( $dummy = $imports.add( "java.util.Map" ) )
+    #set ( $dummy = $imports.add( "java.util.Objects" ) )
+    #set ( $dummy = $imports.add( "java.util.stream.Collectors" ) )
+    #set ( $dummy = $imports.add( "java.util.stream.Stream" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Generated" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Nonnull" ) )
+    #foreach ( $field in $allFields )
+      #if ( $field.type == "java.util.List" )
+          #set ( $dummy = $imports.add( "java.util.ArrayList" ) )
+          #set ( $dummy = $types.put( $field, "List<" + $field.to + ">" ) )
+      #elseif ( $field.type == "DOM" )
+          #set ( $dummy = $imports.add( "org.codehaus.plexus.util.xml.Xpp3Dom" ) )
+          #set ( $dummy = $types.put( $field, "Object" ) )
+      #else
+        #set ( $fieldType = ${types.getOrDefault($field.type,$field.type)} )
+        #set ( $idx = $fieldType.lastIndexOf('.') )
+        #if ( $idx > 0 )
+          #set ( $dummy = $imports.add( $fieldType ) )
+          #set ( $dummy = $types.put( $fieldType, $fieldType.substring( $idx + 1 ) ) )
+        #end
+      #end
+    #end
+    #set ( $eq = "" )
+    #set ( $hc = "" )
+    #foreach ( $field in $allFields )
+      #if ( $field.identifier )
+        #set ( $dummy = $imports.add( "java.util.Objects" ) )
+        #set ( $dummy = $identifiers.add( $field ) )
+        #if ( $eq == "" )
+          #set ( $eq = "Objects.equals( this.${field.name}, that.${field.name} )" )
+        #else
+          #set ( $eq = "$eq && Objects.equals( this.${field.name}, that.${field.name} )" )
+        #end
+        #if ( $hc == "" )
+          #set ( $hc = "${field.name}" )
+        #else
+          #set ( $hc = "$hc, this.${field.name}" )
+        #end
+      #end
+    #end
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+  #foreach ( $imp in $imports )
+import $imp;
+  #end
+
+@Generated
+public class ${class.name}
+    #if ( $class.superClass )
+    extends ${class.superClass}
+    implements Serializable, Cloneable
+    #else
+    extends BaseObject
+    #end
+{
+
+    public ${class.name}() {
+        this(${packageModelV4}.${class.name}.newInstance());
+    }
+
+    public ${class.name}(${packageModelV4}.${class.name} delegate) {
+        this(delegate, null);
+    }
+
+    public ${class.name}(${packageModelV4}.${class.name} delegate, BaseObject parent) {
+        super(delegate, parent);
+    }
+
+    public ${class.name} clone(){
+        return new ${class.name}(getDelegate());
+    }
+
+    #if ( $class.superClass )
+    @Override
+    #end
+    public ${packageModelV4}.${class.name} getDelegate() {
+        return (${packageModelV4}.${class.name}) super.getDelegate();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || !(o instanceof ${class.name})) {
+            return false;
+        }
+        ${class.name} that = (${class.name}) o;
+        return Objects.equals(this.delegate, that.delegate);
+    }
+
+    @Override
+    public int hashCode() {
+        return getDelegate().hashCode();
+    }
+
+    #if ( $class == $root )
+    public String getModelEncoding() {
+        return getDelegate().getModelEncoding();
+    }
+
+    #end
+    #foreach ( $field in $class.getFields($version) )
+      #set ( $cap = $Helper.capitalise( $field.name ) )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+      #if ( $type == "boolean" || $type == "Boolean" )
+        #set ( $pfx = "is" )
+      #else
+        #set ( $pfx = "get" )
+      #end
+      #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" )
+    @Nonnull
+      #end
+    public ${type} ${pfx}${cap}() {
+      #if ( $field.to != "String" && $field.type == "java.util.List" && $field.multiplicity == "*" )
+        return new WrapperList<${field.to}, ${packageModelV4}.${field.to}>(
+                    () -> getDelegate().get${cap}(), l -> update(getDelegate().with${cap}(l)),
+                    d -> new ${field.to}(d, this), ${field.to}::getDelegate);
+      #elseif ( $field.to == "String" && $field.type == "java.util.Properties" && $field.multiplicity == "*" )
+        return new WrapperProperties(() -> getDelegate().get${cap}(), this::set${cap});
+      #elseif ( $field.to == "String" && $field.type == "java.util.List" && $field.multiplicity == "*" )
+        return new WrapperList<String, ${field.to}>(() -> getDelegate().get${cap}(), this::set${cap}, s -> s, s -> s);
+      #elseif ( $field.to )
+        return getDelegate().${pfx}${cap}() != null ? new ${field.to}(getDelegate().${pfx}${cap}(), this) : null;
+      #elseif ( $field.type == "DOM" )
+        return getDelegate().${pfx}${cap}() != null ? new Xpp3Dom(getDelegate().${pfx}${cap}(), this::replace) : null;
+      #else
+        return getDelegate().${pfx}${cap}();
+      #end
+    }
+
+    public void set${cap}(${type} ${field.name}) {
+      #if ($field.type == "DOM")
+        if (${field.name} instanceof Xpp3Dom) {
+            if (!Objects.equals(((Xpp3Dom) ${field.name}).getDom(), getDelegate().${pfx}${cap}())) {
+                update(getDelegate().with${cap}(((Xpp3Dom) ${field.name}).getDom()));
+                ((Xpp3Dom) ${field.name}).setChildrenTracking(this::replace);
+            }
+        } else if (${field.name} == null) {
+            if (getDelegate().${pfx}${cap}() != null) {
+                update(getDelegate().with${cap}(null));
+            }
+        } else {
+            throw new IllegalArgumentException("Expected an Xpp3Dom object but received a " + ${field.name}.getClass() + ": " + ${field.name});
+        }
+      #elseif( $field.type == "java.util.Properties" )
+        Map<String, String> map = ${field.name}.entrySet().stream()
+                .collect(Collectors.toMap(e -> e.getKey().toString(), e -> e.getValue().toString()));
+        if (!Objects.equals(map, getDelegate().get${cap}())) {
+            update(getDelegate().with${cap}(map));
+        }
+      #elseif ( $field.to != "String" && $field.type == "java.util.List" && $field.multiplicity == "*" )
+        if (${field.name} == null) {
+            ${field.name} = Collections.emptyList();
+        }
+        if (!Objects.equals(${field.name}, ${pfx}${cap}())) {
+            update(getDelegate().with${cap}(
+                ${field.name}.stream().map(c -> c.getDelegate()).collect(Collectors.toList())));
+            ${field.name}.forEach(e -> e.childrenTracking = this::replace);
+        }
+      #elseif ( $field.to && $field.to != "String" )
+        if (!Objects.equals(${field.name}, ${pfx}${cap}())){
+            if (${field.name} != null) {
+                update(getDelegate().with${cap}(${field.name}.getDelegate()));
+                ${field.name}.childrenTracking = this::replace;
+            } else {
+                update(getDelegate().with${cap}(null));
+            }
+        }
+      #else
+        if (!Objects.equals(${field.name}, ${pfx}${cap}())) {
+            update(getDelegate().with${cap}(${field.name}));
+        }
+      #end
+    }
+
+      #if ( $field.type == "java.util.List" && $field.multiplicity == "*" )
+        #set ( $v = $Helper.singular( ${field.name} ) )
+        #set ( $scap = $Helper.capitalise( $v ) )
+    public void add${scap}(${field.to} ${v}) {
+        #if ( $field.to == "String" )
+        update(getDelegate().with${cap}(
+               Stream.concat(getDelegate().get${cap}().stream(), Stream.of(${v}))
+                        .collect(Collectors.toList())));
+        #else
+        update(getDelegate().with${cap}(
+               Stream.concat(getDelegate().get${cap}().stream(), Stream.of(${v}.getDelegate()))
+                        .collect(Collectors.toList())));
+        ${v}.childrenTracking = this::replace;
+        #end
+    }
+
+    public void remove${scap}(${field.to} ${v}) {
+        #if ( $field.to == "String" )
+        update(getDelegate().with${cap}(
+               getDelegate().get${cap}().stream()
+                        .filter(e -> !Objects.equals(e, ${v}))
+                        .collect(Collectors.toList())));
+        #else
+        update(getDelegate().with${cap}(
+               getDelegate().get${cap}().stream()
+                        .filter(e -> !Objects.equals(e, ${v}))
+                        .collect(Collectors.toList())));
+        ${v}.childrenTracking = null;
+        #end
+    }
+
+      #elseif ( $field.type == "java.util.Properties" && $field.multiplicity == "*" )
+        #set ( $v = $Helper.singular( ${field.name} ) )
+        #set ( $scap = $Helper.capitalise( $v ) )
+    public void add${scap}(String key, String value) {
+        get${cap}().put(key, value);
+    }
+
+      #end
+    #end
+    #if ( $locationTracking )
+    public InputLocation getLocation(Object key) {
+        ${packageModelV4}.InputLocation loc = getDelegate().getLocation(key);
+        return loc != null ? new InputLocation(loc) : null;
+    }
+
+    public void setLocation(Object key, InputLocation location) {
+        update(${packageModelV4}.${class.name}.newBuilder(getDelegate(), true)
+                        .location(key, location.toApiLocation()).build());
+    }
+
+    #end
+    protected boolean replace(Object oldDelegate, Object newDelegate) {
+        if (super.replace(oldDelegate, newDelegate)) {
+            return true;
+        }
+    #foreach ( $field in $class.getFields($version) )
+      #set ( $cap = $Helper.capitalise( $field.name ) )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+      #if ( $field.to && $field.multiplicity != "*" )
+        if (oldDelegate == getDelegate().get${cap}()) {
+            update(getDelegate().with${cap}((${packageModelV4}.${field.to}) newDelegate));
+            return true;
+        }
+      #elseif ($field.type == "java.util.List" && $field.to != "String")
+        if (getDelegate().get${cap}().contains(oldDelegate)) {
+            List<${packageModelV4}.${field.to}> list = new ArrayList<>(getDelegate().get${cap}());
+            list.replaceAll(d -> d == oldDelegate ? (${packageModelV4}.${field.to}) newDelegate : d);
+            update(getDelegate().with${cap}(list));
+            return true;
+        }
+      #elseif ( $field.type == "DOM" )
+        if (getDelegate().get${cap}() == oldDelegate) {
+            update(getDelegate().with${cap}((org.apache.maven.api.xml.XmlNode) newDelegate));
+        }
+      #end
+    #end
+        return false;
+    }
+
+    public static List<${packageModelV4}.${class.name}> ${Helper.uncapitalise(${class.name})}ToApiV4(List<${class.name}> list) {
+        return list != null ? new WrapperList<>(list, ${class.name}::getDelegate, ${class.name}::new) : null;
+    }
+
+    public static List<${class.name}> ${Helper.uncapitalise(${class.name})}ToApiV3(List<${packageModelV4}.${class.name}> list) {
+        return list != null ? new WrapperList<>(list, ${class.name}::new, ${class.name}::getDelegate) : null;
+    }
+
+    #foreach ( $cs in $class.getCodeSegments($version) )
+$cs.code
+    #end
+}
+#end
diff --git a/src/mdo/model-version.vm b/src/mdo/model-version.vm
new file mode 100644
index 0000000..0fcca23
--- /dev/null
+++ b/src/mdo/model-version.vm
@@ -0,0 +1,193 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#set ( $package = "${packageToolV4}" )
+#set ( $className = "${model.name}ModelVersion" )
+#
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+import java.io.ObjectStreamException;
+import java.nio.file.Path;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.annotations.Generated;
+import org.apache.maven.api.xml.XmlNode;
+#foreach ( $class in $model.allClasses )
+import ${packageModelV4}.${class.Name};
+#end
+
+@Generated
+public class ${className} {
+
+    public String getModelVersion(${root.name} model) {
+        Objects.requireNonNull(model, "model cannot be null");
+
+#set ( $String = $model.getClass().forName("java.lang.String") )
+#set ( $Comparator = $model.getClass().forName("java.util.Comparator") )
+#set ( $LinkedHashSet = $model.getClass().forName("java.util.LinkedHashSet") )
+#set ( $HashMap = $model.getClass().forName("java.util.HashMap") )
+#set ( $TreeSet = $model.getClass().forName("java.util.TreeSet") )
+#set ( $Version = $model.getClass().forName("org.codehaus.modello.model.Version") )
+#set ( $versions = $TreeSet.getConstructor( $Comparator ).newInstance( $Comparator.reverseOrder() ) )
+#foreach ( $class in $model.allClasses )
+    #set ( $dummy = $versions.add( $class.versionRange.fromVersion ) )
+    #foreach ( $field in $class.allFields )
+        #if ( ! $Helper.xmlFieldMetadata( $field ).transient )
+            #set ( $dummy = $versions.add( $field.versionRange.fromVersion ) )
+        #end
+    #end
+#end
+#if ( $minimalVersion )
+    #set ( $minimal = $Version.getConstructor( $String ).newInstance( $minimalVersion ) )
+    #set ( $versions = $versions.headSet( $minimal, false ) )
+#else
+    #set ( $dummy = $versions.remove( $Version.getConstructor( $String ).newInstance( "0.0.0" ) ) )
+#end
+#set ( $dummy = $versions.remove( $Version.getConstructor( $String ).newInstance( "32767.32767.32767" ) ) )
+#foreach ( $version in $versions )
+    #set ( $v = $version.toString().replace('.', '_') )
+        // ${version}
+        if (is_${v}(model)) {
+            return "${version}";
+        }
+#end
+#if ( $minimalVersion )
+        return "$minimalVersion";
+#else
+        return null;
+#end
+    }
+
+#foreach ( $version in $versions )
+    #set ( $v = $version.toString().replace('.', '_') )
+    #set ( $classesToCheck = $TreeSet.newInstance() )
+    #set ( $classToFields = $HashMap.newInstance() )
+    #foreach($unused in [1..10])
+        #foreach ( $class in $model.allClasses )
+            #foreach ( $field in $class.allFields )
+                #if ( ! $Helper.xmlFieldMetadata( $field ).transient )
+                    #set ( $newInVersion = $field.versionRange.fromVersion.equals($version) )
+                    #set ( $isAsso = false )
+                    #if ( $field.toClass )
+                        #set ( $ancestors = $Helper.ancestors( $field.toClass ) )
+                        #foreach ( $cl in $ancestors )
+                            #if ( $classToFields.containsKey( $cl ) )
+                                #set ( $isAsso = true )
+                            #end
+                        #end
+                    #end
+                    #if ( $newInVersion || $isAsso )
+                        #set ( $fields = $classToFields.get( $class ) )
+                        #if ( ! $fields )
+                            #set ( $fields = $LinkedHashSet.newInstance() )
+                            #set ( $dummy = $classToFields.put( $class, $fields ) )
+                        #end
+                        #set( $dummy = $fields.add($field) )
+                        #if ( $dummy )
+                        #end
+                    #end
+                #end
+            #end
+            #if ( $class.superClass )
+                #if ( $classToFields.containsKey( $model.getClass( $class.superClass, $class.versionRange ) ) )
+                    #set ( $fields = $classToFields.get( $class ) )
+                    #if ( ! $fields )
+                        #set ( $fields = $LinkedHashSet.newInstance() )
+                        #set ( $dummy = $classToFields.put( $class, $fields ) )
+                    #end
+                #end
+            #end
+        #end
+    #end
+    #foreach ( $class in $classToFields.keySet() )
+        #set ( $var = $Helper.uncapitalise( $class.name ) )
+    private boolean is_${v}(${class.name} ${var}) {
+        return ${var} != null && (
+        #set ( $pfx = "  " )
+        #if ( $class.superClass )
+            #if ( $classToFields.containsKey( $model.getClass( $class.superClass, $class.versionRange ) ) )
+            $pfx is_${v}((${class.superClass}) ${var})
+                #set ( $pfx = "||" )
+            #end
+        #end
+        #foreach ( $field in $classToFields.get( $class ) )
+            #if ( $field.isManyMultiplicity() )
+                #if ( $classToFields.containsKey( $field.toClass ) )
+            $pfx ${var}.get${Helper.capitalise($field.name)}().stream().anyMatch(this::is_${v}) // ${class.name} : ${field.name}
+                #else
+            $pfx !${var}.get${Helper.capitalise($field.name)}().isEmpty() // ${class.name} : ${field.name}
+                #end
+            #elseif ( $field.isOneMultiplicity() )
+            $pfx is_${v}(${var}.get${Helper.capitalise($field.name)}()) // ${class.name} : ${field.name}
+            #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+            $pfx has(${var}.is${Helper.capitalise($field.name)}()) // ${class.name} : ${field.name}
+            #else
+            $pfx has(${var}.get${Helper.capitalise($field.name)}()) // ${class.name} : ${field.name}
+            #end
+            #set ( $pfx = "||" )
+        #end
+        );
+    }
+    #end
+
+#end
+    private boolean has(String str) {
+        return str != null;
+    }
+
+    private boolean has(Path path) {
+        return path != null;
+    }
+
+    private boolean has(boolean bool) {
+        return bool;
+    }
+
+    private boolean has(int val) {
+        return val != 0;
+    }
+
+    private boolean has(List<?> list) {
+        return !list.isEmpty();
+    }
+
+    private boolean has(XmlNode node) {
+        return node != null;
+    }
+
+}
diff --git a/src/mdo/model.vm b/src/mdo/model.vm
new file mode 100644
index 0000000..9f790bd
--- /dev/null
+++ b/src/mdo/model.vm
@@ -0,0 +1,500 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#set ( $package = "${packageModelV4}" )
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#foreach ( $class in $model.allClasses )
+  #set ( $ancestors = $Helper.ancestors( $class ) )
+  #set ( $allFields = [] )
+  #set ( $inheritedFields = [] )
+  #foreach ( $cl in $ancestors )
+    #if ( $cl != $class )
+      #set ( $dummy = $inheritedFields.addAll( $cl.getFields($version) ) )
+    #end
+    #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
+  #end
+  #set ( $className = "${class.name}" )
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/ImmutableCollections.java
+#parse ( "java/ImmutableCollections.java" )
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+  #if ( $class.name != "InputLocation" && $class.name != "InputSource" )
+    #set ( $types = { } )
+    #set ( $imports = $class.getClass().forName("java.util.TreeSet").newInstance() )
+    #set ( $dummy = $imports.add( "java.io.Serializable" ) )
+    #set ( $dummy = $imports.add( "java.util.Collections" ) )
+    #set ( $dummy = $imports.add( "java.util.HashMap" ) )
+    #set ( $dummy = $imports.add( "java.util.Map" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Experimental" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Generated" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Immutable" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.Nonnull" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.NotThreadSafe" ) )
+    #set ( $dummy = $imports.add( "org.apache.maven.api.annotations.ThreadSafe" ) )
+    #foreach ( $field in $allFields )
+      #if ( $field.type == "java.util.List" )
+        #set ( $dummy = $imports.add( "java.util.ArrayList" ) )
+        #set ( $dummy = $imports.add( "java.util.Collection" ) )
+        #set ( $dummy = $imports.add( "java.util.List" ) )
+        #set ( $dummy = $types.put( $field, "List<" + $field.to + ">" ) )
+      #elseif ( $field.type == "java.util.Properties" )
+        #set ( $dummy = $imports.add( "java.util.Map" ) )
+        #set ( $dummy = $types.put( $field, "Map<String, String>" ) )
+      #elseif ( $field.type == "DOM" )
+        #set ( $dummy = $imports.add( "org.apache.maven.api.xml.XmlNode" ) )
+        #set ( $dummy = $types.put( $field, "XmlNode" ) )
+      #else
+        #set ( $fieldType = ${types.getOrDefault($field.type,$field.type)} )
+        #set ( $idx = $fieldType.lastIndexOf('.') )
+        #if ( $idx > 0 )
+          #set ( $dummy = $imports.add( $fieldType ) )
+          #set ( $dummy = $types.put( $fieldType, $fieldType.substring( $idx + 1 ) ) )
+        #end
+      #end
+    #end
+    #set ( $eq = "" )
+    #set ( $hc = "" )
+    #foreach ( $field in $allFields )
+      #if ( $field.identifier )
+        #set ( $dummy = $imports.add( "java.util.Objects" ) )
+        #set ( $dummy = $identifiers.add( $field ) )
+        #if ( $eq == "" )
+          #set ( $eq = "Objects.equals( this.${field.name}, that.${field.name} )" )
+        #else
+          #set ( $eq = "$eq && Objects.equals( this.${field.name}, that.${field.name} )" )
+        #end
+        #if ( $hc == "" )
+          #set ( $hc = "${field.name}" )
+        #else
+          #set ( $hc = "$hc, this.${field.name}" )
+        #end
+      #end
+    #end
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+    #foreach ( $imp in $imports )
+import $imp;
+    #end
+
+/**
+    #foreach ( $line in ${class.description.trim().split("\n")} )
+ * ${line.trim()}
+    #end
+ */
+@Experimental
+@Generated @ThreadSafe @Immutable
+public class ${class.name}
+    #if ( $class.superClass )
+    extends ${class.superClass}
+    #end
+    #if ( $locationTracking )
+    implements Serializable, InputLocationTracker
+    #else
+    implements Serializable
+    #end
+{
+    #if ( $class == $root )
+    final String namespaceUri;
+    final String modelEncoding;
+    #end
+    #foreach ( $field in $class.getFields($version) )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+    /**
+      #foreach ( $line in ${field.description.trim().split("\n")} )
+     * ${line.trim()}
+      #end
+     */
+    final ${type} $field.name;
+    #end
+    #if ( $locationTracking )
+      #if ( ! $class.superClass )
+    /** Locations */
+    final Map<Object, InputLocation> locations;
+      #end
+    #end
+
+    /**
+      * Constructor for this class, package protected.
+      * @see Builder#build()
+      */
+    ${class.name}(
+    #if ( $class == $root )
+        String namespaceUri,
+        String modelEncoding,
+    #end
+    #foreach ( $field in $allFields )
+      #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+      #if ( $type.startsWith("List<") )
+        #set ( $type = ${type.replace('List<','Collection<')} )
+      #end
+        $type $field.name${sep}
+    #end
+    #if ( $locationTracking )
+        Map<Object, InputLocation> locations
+    #end
+    ) {
+    #if ( $class.superClass )
+        super(
+      #foreach ( $field in $inheritedFields )
+        #set ( $sep = "#if(${locationTracking}||$field!=${inheritedFields[${inheritedFields.size()} - 1]}),#end" )
+            ${field.name}${sep}
+      #end
+      #if ( $locationTracking )
+            locations
+      #end
+        );
+    #end
+    #if ( $class == $root )
+        this.namespaceUri = namespaceUri;
+        this.modelEncoding = modelEncoding;
+    #end
+    #foreach ( $field in $class.getFields($version) )
+      #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" || $field.type == "java.util.Map" )
+        this.${field.name} = ImmutableCollections.copy(${field.name});
+      #else
+        this.${field.name} = ${field.name};
+      #end
+    #end
+    #if ( $locationTracking )
+      #if ( ! $class.superClass )
+        this.locations = ImmutableCollections.copy(locations);
+      #end
+    #end
+    }
+
+    #if ( ! $eq.empty )
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || !(o instanceof ${class.name})) {
+            return false;
+        }
+        ${class.name} that = (${class.name}) o;
+        return ${eq};
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(${hc});
+    }
+
+    #end
+    #if ( $class == $root )
+    public String getNamespaceUri() {
+        return namespaceUri;
+    }
+
+    public String getModelEncoding() {
+        return modelEncoding;
+    }
+
+    #end
+    #foreach ( $field in $class.getFields($version) )
+      #set ( $cap = $Helper.capitalise( $field.name ) )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+      #if ( $type == "boolean" || $type == "Boolean" )
+        #set ( $pfx = "is" )
+      #else
+        #set ( $pfx = "get" )
+      #end
+    /**
+      #set ( $desc = ${field.description.trim()} )
+      #foreach ( $line in ${desc.split("\n")} )
+     * ${line.trim()}
+      #end
+     *
+     * @return a {@code ${type}}
+     */
+      #if ( $field.type == "java.util.List" || $field.type == "java.util.Properties" )
+    @Nonnull
+      #end
+    public ${type} ${pfx}${cap}() {
+        return this.${field.name};
+    }
+
+    #end
+    #if ( $locationTracking && !$class.superClass )
+    /**
+     * Gets the location of the specified field in the input source.
+     */
+    public InputLocation getLocation(Object key) {
+        return locations != null ? locations.get(key) : null;
+    }
+
+    #end
+    /**
+     * Creates a new builder with this object as the basis.
+     *
+     * @return a {@code Builder}
+     */
+    @Nonnull
+    public Builder with() {
+        return newBuilder(this);
+    }
+    #foreach ( $field in $allFields )
+      #set ( $cap = $Helper.capitalise( $field.name ) )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+      #if ( $type.startsWith("List<") )
+        #set ( $type = ${type.replace('List<','Collection<')} )
+      #end
+    /**
+     * Creates a new {@code ${class.name}} instance using the specified ${field.name}.
+     *
+     * @param ${field.name} the new {@code $type} to use
+     * @return a {@code ${class.name}} with the specified ${field.name}
+     */
+    @Nonnull
+    public ${class.name} with${cap}($type $field.name) {
+        return newBuilder(this, true).${field.name}($field.name).build();
+    }
+    #end
+
+    /**
+     * Creates a new {@code ${class.name}} instance.
+     * Equivalent to {@code newInstance(true)}.
+     * @see #newInstance(boolean)
+     *
+     * @return a new {@code ${class.name}}
+     */
+    @Nonnull
+    public static ${class.name} newInstance() {
+        return newInstance(true);
+    }
+
+    /**
+     * Creates a new {@code ${class.name}} instance using default values or not.
+     * Equivalent to {@code newBuilder(withDefaults).build()}.
+     *
+     * @param withDefaults the boolean indicating whether default values should be used
+     * @return a new {@code ${class.name}}
+     */
+    @Nonnull
+    public static ${class.name} newInstance(boolean withDefaults) {
+        return newBuilder(withDefaults).build();
+    }
+
+    /**
+     * Creates a new {@code ${class.name}} builder instance.
+     * Equivalent to {@code newBuilder(true)}.
+     * @see #newBuilder(boolean)
+     *
+     * @return a new {@code Builder}
+     */
+    @Nonnull
+    public static Builder newBuilder() {
+        return newBuilder(true);
+    }
+
+    /**
+     * Creates a new {@code ${class.name}} builder instance using default values or not.
+     *
+     * @param withDefaults the boolean indicating whether default values should be used
+     * @return a new {@code Builder}
+     */
+    @Nonnull
+    public static Builder newBuilder(boolean withDefaults) {
+        return new Builder(withDefaults);
+    }
+
+    /**
+     * Creates a new {@code ${class.name}} builder instance using the specified object as a basis.
+     * Equivalent to {@code newBuilder(from, false)}.
+     *
+     * @param from the {@code ${class.name}} instance to use as a basis
+     * @return a new {@code Builder}
+     */
+    @Nonnull
+    public static Builder newBuilder(${class.name} from) {
+        return newBuilder(from, false);
+    }
+
+    /**
+     * Creates a new {@code ${class.name}} builder instance using the specified object as a basis.
+     *
+     * @param from the {@code ${class.name}} instance to use as a basis
+     * @param forceCopy the boolean indicating if a copy should be forced
+     * @return a new {@code Builder}
+     */
+    @Nonnull
+    public static Builder newBuilder(${class.name} from, boolean forceCopy) {
+        return new Builder(from, forceCopy);
+    }
+
+    /**
+     * Builder class used to create ${class.name} instances.
+     * @see #with()
+     * @see #newBuilder()
+     */
+    @NotThreadSafe
+    public static class Builder
+    #if ( $class.superClass )
+        extends ${class.superClass}.Builder
+    #end
+    {
+        ${class.name} base;
+    #if ( $class == $root )
+        String namespaceUri;
+        String modelEncoding;
+    #end
+    #foreach ( $field in $class.getFields($version) )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+      #if ( $type.startsWith("List<") )
+        #set ( $type = ${type.replace('List<','Collection<')} )
+      #end
+      #if ( $type == 'boolean' )
+        Boolean ${field.name};
+      #elseif ( $type == 'int' )
+        Integer ${field.name};
+      #else
+        ${type} ${field.name};
+    #end
+    #end
+    #if ( ! $class.superClass && $locationTracking )
+        Map<Object, InputLocation> locations;
+    #end
+
+        Builder(boolean withDefaults) {
+    #if ( $class.superClass )
+            super(withDefaults);
+    #end
+            if (withDefaults) {
+    #foreach ( $field in $class.getFields($version) )
+      #if ( $field.defaultValue )
+        #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+        #if ( $field.type == "String" )
+                this.${field.name} = "${field.defaultValue}";
+        #elseif ( $field.type != "java.util.List" && $field.type != "java.util.Properties" )
+                this.${field.name} = ${field.defaultValue};
+        #end
+      #end
+    #end
+            }
+        }
+
+        Builder(${class.name} base, boolean forceCopy) {
+    #if ( $class.superClass )
+            super(base, forceCopy);
+    #end
+    #if ( $class == $root )
+            this.namespaceUri = base.namespaceUri;
+            this.modelEncoding = base.modelEncoding;
+    #end
+            if (forceCopy) {
+    #foreach ( $field in $class.getFields($version) )
+                this.${field.name} = base.${field.name};
+    #end
+    #if ( $locationTracking )
+                this.locations = base.locations;
+    #end
+            } else {
+                this.base = base;
+            }
+        }
+
+    #if ( $class == $root )
+        @Nonnull
+        public Builder namespaceUri(String namespaceUri) {
+            this.namespaceUri = namespaceUri;
+            return this;
+        }
+
+        @Nonnull
+        public Builder modelEncoding(String modelEncoding) {
+            this.modelEncoding = modelEncoding;
+            return this;
+        }
+
+    #end
+    #foreach ( $field in $allFields )
+      #set ( $type = ${types.getOrDefault($field,${types.getOrDefault($field.type,$field.type)})} )
+      #if ( $type.startsWith("List<") )
+        #set ( $type = ${type.replace('List<','Collection<')} )
+      #end
+        @Nonnull
+        public Builder ${field.name}(${type} ${field.name}) {
+            this.${field.name} = ${field.name};
+            return this;
+        }
+
+    #end
+
+    #if ( $locationTracking )
+        @Nonnull
+        public Builder location(Object key, InputLocation location) {
+            if (location != null) {
+                if (!(this.locations instanceof HashMap)) {
+                    this.locations = this.locations != null ? new HashMap<>(this.locations) : new HashMap<>();
+                }
+                this.locations.put(key, location);
+            }
+            return this;
+        }
+
+    #end
+        @Nonnull
+        public ${class.name} build() {
+            if (base != null
+    #foreach ( $field in $allFields )
+                    && (${field.name} == null || ${field.name} == base.${field.name})
+    #end
+            ) {
+                return base;
+            }
+    #if ( $locationTracking )
+            Map<Object, InputLocation> newlocs = this.locations != null ? this.locations : Collections.emptyMap();
+            Map<Object, InputLocation> oldlocs = this.base != null && this.base.locations != null ? this.base.locations : Collections.emptyMap();
+            Map<Object, InputLocation> locations = new HashMap<>();
+            locations.put("", newlocs.containsKey("") ? newlocs.get("") : oldlocs.get(""));
+      #foreach ( $field in $allFields )
+            locations.put("${field.name}", newlocs.containsKey("${field.name}") ? newlocs.get("${field.name}") : oldlocs.get("${field.name}"));
+      #end
+    #end
+            return new ${class.name}(
+    #if ( $class == $root )
+                namespaceUri != null ? namespaceUri : (base != null ? base.namespaceUri : ""),
+                modelEncoding != null ? modelEncoding : (base != null ? base.modelEncoding : "UTF-8"),
+    #end
+    #foreach ( $field in $allFields )
+      #set ( $sep = "#if(${locationTracking}||$field!=${allFields[${allFields.size()} - 1]}),#end" )
+      #if ( $field.type == "boolean" || $field.type == "int" )
+                ${field.name} != null ? ${field.name} : (base != null ? base.${field.name} : ${field.defaultValue})${sep}
+      #else
+                ${field.name} != null ? ${field.name} : (base != null ? base.${field.name} : null)${sep}
+      #end
+    #end
+    #if ( $locationTracking )
+                locations
+    #end
+            );
+        }
+    }
+
+    #foreach ( $cs in $class.getCodeSegments($version) )
+$cs.code
+    #end
+}
+  #end
+#end
diff --git a/src/mdo/reader-stax.vm b/src/mdo/reader-stax.vm
new file mode 100644
index 0000000..f4b5f03
--- /dev/null
+++ b/src/mdo/reader-stax.vm
@@ -0,0 +1,973 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#set ( $package = "${packageToolV4}" )
+#set ( $className = "${model.name}StaxReader" )
+#
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#set ( $rootXml = $Helper.xmlClassMetadata( $root ) )
+#set ( $rootTag = $rootXml.tagName )
+#set ( $rootUcapName = $Helper.capitalise( $root.name ) )
+#set ( $rootLcapName = $Helper.uncapitalise( $root.name ) )
+#
+#set ( $needXmlContext = false )
+#foreach ( $class in $model.allClasses )
+  #set ( $allFields = $Helper.xmlFields( $class ) )
+  #foreach ( $field in $allFields )
+    #if ( $Helper.xmlFieldMetadata( $field ).format )
+      #set ( $needXmlContext = true )
+    #end
+  #end
+#end
+#
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.text.DateFormat;
+#if ( $needXmlContext )
+import java.util.ArrayDeque;
+#end
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+#if ( $needXmlContext )
+import java.util.Deque;
+#end
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.maven.api.annotations.Generated;
+#if ( $locationTracking )
+import ${packageModelV4}.InputSource;
+import ${packageModelV4}.InputLocation;
+#end
+#foreach ( $class in $model.allClasses )
+import ${packageModelV4}.${class.name};
+#end
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+import org.apache.maven.api.xml.XmlNode;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+
+import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
+import static javax.xml.XMLConstants.XML_NS_URI;
+
+@Generated
+public class ${className} {
+
+    private static final Map<String, String> DEFAULT_ENTITIES;
+    static {
+        Map<String, String> entities = new HashMap<>();
+        entities.put("nbsp", "\u00a0");
+        entities.put("iexcl", "\u00a1");
+        entities.put("cent", "\u00a2");
+        entities.put("pound", "\u00a3");
+        entities.put("curren", "\u00a4");
+        entities.put("yen", "\u00a5");
+        entities.put("brvbar", "\u00a6");
+        entities.put("sect", "\u00a7");
+        entities.put("uml", "\u00a8");
+        entities.put("copy", "\u00a9");
+        entities.put("ordf", "\u00aa");
+        entities.put("laquo", "\u00ab");
+        entities.put("not", "\u00ac");
+        entities.put("shy", "\u00ad");
+        entities.put("reg", "\u00ae");
+        entities.put("macr", "\u00af");
+        entities.put("deg", "\u00b0");
+        entities.put("plusmn", "\u00b1");
+        entities.put("sup2", "\u00b2");
+        entities.put("sup3", "\u00b3");
+        entities.put("acute", "\u00b4");
+        entities.put("micro", "\u00b5");
+        entities.put("para", "\u00b6");
+        entities.put("middot", "\u00b7");
+        entities.put("cedil", "\u00b8");
+        entities.put("sup1", "\u00b9");
+        entities.put("ordm", "\u00ba");
+        entities.put("raquo", "\u00bb");
+        entities.put("frac14", "\u00bc");
+        entities.put("frac12", "\u00bd");
+        entities.put("frac34", "\u00be");
+        entities.put("iquest", "\u00bf");
+        entities.put("Agrave", "\u00c0");
+        entities.put("Aacute", "\u00c1");
+        entities.put("Acirc", "\u00c2");
+        entities.put("Atilde", "\u00c3");
+        entities.put("Auml", "\u00c4");
+        entities.put("Aring", "\u00c5");
+        entities.put("AElig", "\u00c6");
+        entities.put("Ccedil", "\u00c7");
+        entities.put("Egrave", "\u00c8");
+        entities.put("Eacute", "\u00c9");
+        entities.put("Ecirc", "\u00ca");
+        entities.put("Euml", "\u00cb");
+        entities.put("Igrave", "\u00cc");
+        entities.put("Iacute", "\u00cd");
+        entities.put("Icirc", "\u00ce");
+        entities.put("Iuml", "\u00cf");
+        entities.put("ETH", "\u00d0");
+        entities.put("Ntilde", "\u00d1");
+        entities.put("Ograve", "\u00d2");
+        entities.put("Oacute", "\u00d3");
+        entities.put("Ocirc", "\u00d4");
+        entities.put("Otilde", "\u00d5");
+        entities.put("Ouml", "\u00d6");
+        entities.put("times", "\u00d7");
+        entities.put("Oslash", "\u00d8");
+        entities.put("Ugrave", "\u00d9");
+        entities.put("Uacute", "\u00da");
+        entities.put("Ucirc", "\u00db");
+        entities.put("Uuml", "\u00dc");
+        entities.put("Yacute", "\u00dd");
+        entities.put("THORN", "\u00de");
+        entities.put("szlig", "\u00df");
+        entities.put("agrave", "\u00e0");
+        entities.put("aacute", "\u00e1");
+        entities.put("acirc", "\u00e2");
+        entities.put("atilde", "\u00e3");
+        entities.put("auml", "\u00e4");
+        entities.put("aring", "\u00e5");
+        entities.put("aelig", "\u00e6");
+        entities.put("ccedil", "\u00e7");
+        entities.put("egrave", "\u00e8");
+        entities.put("eacute", "\u00e9");
+        entities.put("ecirc", "\u00ea");
+        entities.put("euml", "\u00eb");
+        entities.put("igrave", "\u00ec");
+        entities.put("iacute", "\u00ed");
+        entities.put("icirc", "\u00ee");
+        entities.put("iuml", "\u00ef");
+        entities.put("eth", "\u00f0");
+        entities.put("ntilde", "\u00f1");
+        entities.put("ograve", "\u00f2");
+        entities.put("oacute", "\u00f3");
+        entities.put("ocirc", "\u00f4");
+        entities.put("otilde", "\u00f5");
+        entities.put("ouml", "\u00f6");
+        entities.put("divide", "\u00f7");
+        entities.put("oslash", "\u00f8");
+        entities.put("ugrave", "\u00f9");
+        entities.put("uacute", "\u00fa");
+        entities.put("ucirc", "\u00fb");
+        entities.put("uuml", "\u00fc");
+        entities.put("yacute", "\u00fd");
+        entities.put("thorn", "\u00fe");
+        entities.put("yuml", "\u00ff");
+
+        // ----------------------------------------------------------------------
+        // Special entities
+        // ----------------------------------------------------------------------
+
+        entities.put("OElig", "\u0152");
+        entities.put("oelig", "\u0153");
+        entities.put("Scaron", "\u0160");
+        entities.put("scaron", "\u0161");
+        entities.put("Yuml", "\u0178");
+        entities.put("circ", "\u02c6");
+        entities.put("tilde", "\u02dc");
+        entities.put("ensp", "\u2002");
+        entities.put("emsp", "\u2003");
+        entities.put("thinsp", "\u2009");
+        entities.put("zwnj", "\u200c");
+        entities.put("zwj", "\u200d");
+        entities.put("lrm", "\u200e");
+        entities.put("rlm", "\u200f");
+        entities.put("ndash", "\u2013");
+        entities.put("mdash", "\u2014");
+        entities.put("lsquo", "\u2018");
+        entities.put("rsquo", "\u2019");
+        entities.put("sbquo", "\u201a");
+        entities.put("ldquo", "\u201c");
+        entities.put("rdquo", "\u201d");
+        entities.put("bdquo", "\u201e");
+        entities.put("dagger", "\u2020");
+        entities.put("Dagger", "\u2021");
+        entities.put("permil", "\u2030");
+        entities.put("lsaquo", "\u2039");
+        entities.put("rsaquo", "\u203a");
+        entities.put("euro", "\u20ac");
+
+        // ----------------------------------------------------------------------
+        // Symbol entities
+        // ----------------------------------------------------------------------
+
+        entities.put("fnof", "\u0192");
+        entities.put("Alpha", "\u0391");
+        entities.put("Beta", "\u0392");
+        entities.put("Gamma", "\u0393");
+        entities.put("Delta", "\u0394");
+        entities.put("Epsilon", "\u0395");
+        entities.put("Zeta", "\u0396");
+        entities.put("Eta", "\u0397");
+        entities.put("Theta", "\u0398");
+        entities.put("Iota", "\u0399");
+        entities.put("Kappa", "\u039a");
+        entities.put("Lambda", "\u039b");
+        entities.put("Mu", "\u039c");
+        entities.put("Nu", "\u039d");
+        entities.put("Xi", "\u039e");
+        entities.put("Omicron", "\u039f");
+        entities.put("Pi", "\u03a0");
+        entities.put("Rho", "\u03a1");
+        entities.put("Sigma", "\u03a3");
+        entities.put("Tau", "\u03a4");
+        entities.put("Upsilon", "\u03a5");
+        entities.put("Phi", "\u03a6");
+        entities.put("Chi", "\u03a7");
+        entities.put("Psi", "\u03a8");
+        entities.put("Omega", "\u03a9");
+        entities.put("alpha", "\u03b1");
+        entities.put("beta", "\u03b2");
+        entities.put("gamma", "\u03b3");
+        entities.put("delta", "\u03b4");
+        entities.put("epsilon", "\u03b5");
+        entities.put("zeta", "\u03b6");
+        entities.put("eta", "\u03b7");
+        entities.put("theta", "\u03b8");
+        entities.put("iota", "\u03b9");
+        entities.put("kappa", "\u03ba");
+        entities.put("lambda", "\u03bb");
+        entities.put("mu", "\u03bc");
+        entities.put("nu", "\u03bd");
+        entities.put("xi", "\u03be");
+        entities.put("omicron", "\u03bf");
+        entities.put("pi", "\u03c0");
+        entities.put("rho", "\u03c1");
+        entities.put("sigmaf", "\u03c2");
+        entities.put("sigma", "\u03c3");
+        entities.put("tau", "\u03c4");
+        entities.put("upsilon", "\u03c5");
+        entities.put("phi", "\u03c6");
+        entities.put("chi", "\u03c7");
+        entities.put("psi", "\u03c8");
+        entities.put("omega", "\u03c9");
+        entities.put("thetasym", "\u03d1");
+        entities.put("upsih", "\u03d2");
+        entities.put("piv", "\u03d6");
+        entities.put("bull", "\u2022");
+        entities.put("hellip", "\u2026");
+        entities.put("prime", "\u2032");
+        entities.put("Prime", "\u2033");
+        entities.put("oline", "\u203e");
+        entities.put("frasl", "\u2044");
+        entities.put("weierp", "\u2118");
+        entities.put("image", "\u2111");
+        entities.put("real", "\u211c");
+        entities.put("trade", "\u2122");
+        entities.put("alefsym", "\u2135");
+        entities.put("larr", "\u2190");
+        entities.put("uarr", "\u2191");
+        entities.put("rarr", "\u2192");
+        entities.put("darr", "\u2193");
+        entities.put("harr", "\u2194");
+        entities.put("crarr", "\u21b5");
+        entities.put("lArr", "\u21d0");
+        entities.put("uArr", "\u21d1");
+        entities.put("rArr", "\u21d2");
+        entities.put("dArr", "\u21d3");
+        entities.put("hArr", "\u21d4");
+        entities.put("forall", "\u2200");
+        entities.put("part", "\u2202");
+        entities.put("exist", "\u2203");
+        entities.put("empty", "\u2205");
+        entities.put("nabla", "\u2207");
+        entities.put("isin", "\u2208");
+        entities.put("notin", "\u2209");
+        entities.put("ni", "\u220b");
+        entities.put("prod", "\u220f");
+        entities.put("sum", "\u2211");
+        entities.put("minus", "\u2212");
+        entities.put("lowast", "\u2217");
+        entities.put("radic", "\u221a");
+        entities.put("prop", "\u221d");
+        entities.put("infin", "\u221e");
+        entities.put("ang", "\u2220");
+        entities.put("and", "\u2227");
+        entities.put("or", "\u2228");
+        entities.put("cap", "\u2229");
+        entities.put("cup", "\u222a");
+        entities.put("int", "\u222b");
+        entities.put("there4", "\u2234");
+        entities.put("sim", "\u223c");
+        entities.put("cong", "\u2245");
+        entities.put("asymp", "\u2248");
+        entities.put("ne", "\u2260");
+        entities.put("equiv", "\u2261");
+        entities.put("le", "\u2264");
+        entities.put("ge", "\u2265");
+        entities.put("sub", "\u2282");
+        entities.put("sup", "\u2283");
+        entities.put("nsub", "\u2284");
+        entities.put("sube", "\u2286");
+        entities.put("supe", "\u2287");
+        entities.put("oplus", "\u2295");
+        entities.put("otimes", "\u2297");
+        entities.put("perp", "\u22a5");
+        entities.put("sdot", "\u22c5");
+        entities.put("lceil", "\u2308");
+        entities.put("rceil", "\u2309");
+        entities.put("lfloor", "\u230a");
+        entities.put("rfloor", "\u230b");
+        entities.put("lang", "\u2329");
+        entities.put("rang", "\u232a");
+        entities.put("loz", "\u25ca");
+        entities.put("spades", "\u2660");
+        entities.put("clubs", "\u2663");
+        entities.put("hearts", "\u2665");
+        entities.put("diams", "\u2666");
+        DEFAULT_ENTITIES = Collections.unmodifiableMap(entities);
+    }
+
+    private boolean addDefaultEntities = true;
+#if ( $locationTracking )
+    private boolean addLocationInformation = true;
+#end
+
+    private final ContentTransformer contentTransformer;
+
+    public ${className}() {
+        this((s, f) -> s);
+    }
+
+    public ${className}(ContentTransformer contentTransformer) {
+        this.contentTransformer = contentTransformer;
+    }
+
+    /**
+     * Returns the state of the "add default entities" flag.
+     *
+     * @return boolean
+     */
+    public boolean getAddDefaultEntities() {
+        return addDefaultEntities;
+    } //-- boolean getAddDefaultEntities()
+
+    /**
+     * Sets the state of the "add default entities" flag.
+     *
+     * @param addDefaultEntities a addDefaultEntities object.
+     */
+    public void setAddDefaultEntities(boolean addDefaultEntities) {
+        this.addDefaultEntities = addDefaultEntities;
+    } //-- void setAddDefaultEntities(boolean)
+
+#if ( $locationTracking )
+    /**
+     * Returns the state of the "add location information" flag.
+     *
+     * @return boolean
+     */
+    public boolean getAddLocationInformation() {
+        return addLocationInformation;
+    } //-- boolean getAddLocationInformation()
+
+    /**
+     * Sets the state of the "add location information" flag.
+     *
+     * @param addLocationInformation a addLocationInformation object.
+     */
+    public void setAddLocationInformation(boolean addLocationInformation) {
+        this.addLocationInformation = addLocationInformation;
+    } //-- void setAddLocationInformation(boolean)
+#end
+
+    public ${root.name} read(Reader reader) throws XMLStreamException {
+#if ( $locationTracking )
+        return read(reader, true, null);
+#else
+        return read(reader, true);
+#end
+    }
+
+    /**
+     * @param reader a reader object.
+     * @param strict a strict object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+#if ( $locationTracking )
+    public ${root.name} read(Reader reader, boolean strict, InputSource source) throws XMLStreamException {
+#else
+    public ${root.name} read(Reader reader, boolean strict) throws XMLStreamException {
+#end
+        XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
+        factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+#if ( $locationTracking )
+        StreamSource streamSource = new StreamSource(reader, source != null ? source.getLocation() : null);
+#else
+        StreamSource streamSource = new StreamSource(reader);
+#end
+        XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
+#if ( $locationTracking )
+        return read(parser, strict, source);
+#else
+    return read(parser, strict);
+#end
+    } //-- ${root.name} read(Reader, boolean)
+
+    public ${root.name} read(InputStream in) throws XMLStreamException {
+#if ( $locationTracking )
+        return read(in, true, null);
+#else
+        return read(in, true);
+#end
+    }
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @param strict a strict object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+#if ( $locationTracking )
+    public ${root.name} read(InputStream in, boolean strict, InputSource source) throws XMLStreamException {
+#else
+    public ${root.name} read(InputStream in, boolean strict) throws XMLStreamException {
+#end
+        XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
+        factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+#if ( $locationTracking )
+        StreamSource streamSource = new StreamSource(in, source != null ? source.getLocation() : null);
+#else
+        StreamSource streamSource = new StreamSource(in);
+#end
+        XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
+#if ( $locationTracking )
+        return read(parser, strict, source);
+#else
+        return read(parser, strict);
+#end
+    } //-- ${root.name} read(InputStream, boolean)
+
+    /**
+     * Method read.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+#if ( $locationTracking )
+    public ${root.name} read(XMLStreamReader parser, boolean strict, InputSource source) throws XMLStreamException {
+#else
+    public ${root.name} read(XMLStreamReader parser, boolean strict) throws XMLStreamException {
+#end
+#if ( $needXmlContext )
+        Deque<Object> context = new ArrayDeque<>();
+#end
+        $rootUcapName $rootLcapName = null;
+        int eventType = parser.getEventType();
+        boolean parsed = false;
+        while (eventType != XMLStreamReader.END_DOCUMENT) {
+            if (eventType == XMLStreamReader.START_ELEMENT) {
+                if (strict && ! "${rootTag}".equals(parser.getLocalName())) {
+                    throw new XMLStreamException("Expected root element '${rootTag}' but found '" + parser.getName() + "'", parser.getLocation(), null);
+                } else if (parsed) {
+                    // fallback, already expected a XMLStreamException due to invalid XML
+                    throw new XMLStreamException("Duplicated tag: '${rootTag}'", parser.getLocation(), null);
+                }
+#if ( $locationTracking )
+                $rootLcapName = parse${rootUcapName}(parser, strict, source);
+#elseif ( $needXmlContext )
+                $rootLcapName = parse${rootUcapName}(parser, strict, context);
+#else
+                $rootLcapName = parse${rootUcapName}(parser, strict);
+#end
+                parsed = true;
+            }
+            eventType = parser.next();
+        }
+        if (parsed) {
+            return $rootLcapName;
+        }
+        throw new XMLStreamException("Expected root element '${rootTag}' but found no element at all: invalid XML document", parser.getLocation(), null);
+    } //-- ${root.name} read(XMLStreamReader, boolean)
+
+#foreach ( $class in $model.allClasses )
+ #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+  #set ( $classUcapName = $Helper.capitalise( $class.name ) )
+  #set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
+  #set ( $ancestors = $Helper.ancestors( $class ) )
+  #set ( $allFields = $Helper.xmlFields( $class ) )
+  #if ( $locationTracking )
+    private ${classUcapName} parse${classUcapName}(XMLStreamReader parser, boolean strict, InputSource source) throws XMLStreamException {
+  #elseif ( $needXmlContext )
+    private ${classUcapName} parse${classUcapName}(XMLStreamReader parser, boolean strict, Deque<Object> context) throws XMLStreamException {
+  #else
+    private ${classUcapName} parse${classUcapName}(XMLStreamReader parser, boolean strict) throws XMLStreamException {
+  #end
+        String tagName = parser.getLocalName();
+        ${classUcapName}.Builder ${classLcapName} = ${classUcapName}.newBuilder(true);
+  #if ( $locationTracking )
+        if (addLocationInformation) {
+            ${classLcapName}.location("", new InputLocation(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), source));
+        }
+  #end
+        for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
+            String name = parser.getAttributeLocalName(i);
+            String ns = parser.getAttributeNamespace(i);
+            String value = parser.getAttributeValue(i);
+            if (W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(ns) || XML_NS_URI.equals(ns)) {
+                // just ignore attributes with non-default namespace (for example: xsi and xml)
+  #if ( $class == $root )
+            } else if ("xmlns".equals(name)) {
+                // ignore xmlns attribute in root class, which is a reserved attribute name
+  #end
+  #foreach ( $field in $allFields )
+    #if ( $Helper.xmlFieldMetadata( $field ).attribute )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+            } else if ("$fieldTagName".equals(name)) {
+      #if ( $locationTracking )
+                if (addLocationInformation) {
+                    ${classLcapName}.location(name, new InputLocation(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), source));
+                }
+      #end
+      #if ( $field.type == "String" )
+                ${classLcapName}.${field.name}(interpolatedTrimmed(value, "$fieldTagName"));
+      #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+                ${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(value, "$fieldTagName"), "$fieldTagName", parser, ${field.defaultValue}));
+      #else
+                // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+    #end
+  #end
+            } else {
+                checkUnknownAttribute(parser, name, tagName, strict);
+            }
+        }
+        Set<String> parsed = new HashSet<>();
+  #foreach ( $field in $allFields )
+    #if ( $Helper.isFlatItems( $field ) )
+        List<$field.to> ${field.name} = new ArrayList<>();
+    #end
+  #end
+  #if ( $needXmlContext )
+        context.addLast( ${classLcapName} );
+  #end
+        while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
+            String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
+  #if ( $locationTracking )
+            int line = addLocationInformation ? parser.getLocation().getLineNumber() : -1;
+            int column = addLocationInformation ? parser.getLocation().getColumnNumber() : -1;
+            Map<Object, InputLocation> locations = null;
+  #end
+            switch (childName) {
+  #set( $ift = "if" )
+  #foreach ( $field in $allFields )
+    #if ( ! $Helper.xmlFieldMetadata( $field ).attribute && ! $Helper.xmlFieldMetadata( $field ).transient && ! $Helper.xmlFieldMetadata( $field ).format )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #if ( ! $fieldTagName )
+        #set ( $fieldTagName = $field.name )
+      #end
+      #if ( $Helper.isFlatItems( $field ) )
+        #set ( $fieldTagName = $Helper.singular( $fieldTagName ) )
+      #end
+      #set ( $fieldCapName = $Helper.capitalise($field.name))
+                case "${fieldTagName}": {
+      #if ( $field.type == "String" )
+                    ${classLcapName}.${field.name}(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"));
+                    break;
+      #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+                    ${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"), "${fieldTagName}", parser, ${field.defaultValue}));
+                    break;
+      #elseif ( $field.type == "int" )
+                    ${classLcapName}.${field.name}(getIntegerValue(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"), "${fieldTagName}", parser, strict, ${field.defaultValue}));
+                    break;
+      #elseif ( $field.type == "DOM" )
+        #if ( $locationTracking )
+                    ${classLcapName}.${field.name}(buildXmlNode(parser, source));
+        #else
+                    ${classLcapName}.${field.name}(buildXmlNode(parser));
+        #end
+                    break;
+      #elseif ( $field.type == "java.util.List" && $field.to == "String" && $field.multiplicity == "*" )
+                    List<String> ${field.name} = new ArrayList<>();
+        #if ( $locationTracking )
+                    locations = new HashMap<>();
+        #end
+                    while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
+                        if ("${Helper.singular($fieldTagName)}".equals(parser.getLocalName())) {
+        #if ( $locationTracking )
+                            if (addLocationInformation) {
+                                locations.put(Integer.valueOf(locations.size()), new InputLocation(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), source));
+                            }
+        #end
+                            ${field.name}.add(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"));
+                        } else {
+                            checkUnknownElement(parser, strict);
+                        }
+                    }
+                    ${classLcapName}.${field.name}(${field.name});
+                    break;
+      #elseif ( $field.type == "java.util.Properties" && $field.to == "String" && $field.multiplicity == "*" )
+                    Map<String, String> ${field.name} = new LinkedHashMap<>();
+        #if ( $locationTracking )
+                    locations = new HashMap<>();
+        #end
+                    while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
+                        String key = parser.getLocalName();
+                        String value = nextText(parser, strict).trim();
+        #if ( $locationTracking )
+                        if (addLocationInformation) {
+                            locations.put(key, new InputLocation(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), source));
+                        }
+        #end
+                        ${field.name}.put(key, value);
+                    }
+                    ${classLcapName}.${field.name}(${field.name});
+                    break;
+      #elseif ( $field.to && $field.multiplicity == "1" )
+        #if ( $locationTracking )
+                    ${classLcapName}.${field.name}(parse${field.toClass.name}(parser, strict, source));
+        #elseif ( $needXmlContext )
+                    ${classLcapName}.${field.name}(parse${field.toClass.name}(parser, strict, context));
+        #else
+                    ${classLcapName}.${field.name}(parse${field.toClass.name}(parser, strict));
+        #end
+                    break;
+      #elseif ( $field.to && $field.multiplicity == "*" && $Helper.isFlatItems( $field ) )
+                    ${field.name}.add(parse${field.toClass.name}(parser, strict));
+                    break;
+      #elseif ( $field.to && $field.multiplicity == "*" )
+                    List<$field.to> ${field.name} = new ArrayList<>();
+                    while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
+                        if ("${Helper.singular($fieldTagName)}".equals(parser.getLocalName())) {
+        #if ( $locationTracking )
+                            ${field.name}.add(parse${field.toClass.name}(parser, strict, source));
+        #elseif ( $needXmlContext )
+                            ${field.name}.add(parse${field.toClass.name}(parser, strict, context));
+        #else
+                            ${field.name}.add(parse${field.toClass.name}(parser, strict));
+        #end
+                        } else {
+                            checkUnknownElement(parser, strict);
+                        }
+                    }
+                    ${classLcapName}.${field.name}(${field.name});
+                    break;
+      #else
+                    // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+                    break;
+      #end
+                }
+      #set( $ift = "else if" )
+    #end
+  #end
+                default: {
+                    checkUnknownElement(parser, strict);
+                    break;
+                }
+            }
+  #if ( $locationTracking )
+            if (addLocationInformation) {
+                ${classLcapName}.location(childName, new InputLocation(line, column, source, locations));
+            }
+  #end
+        }
+  #if ( $needXmlContext )
+        context.removeLast();
+  #end
+  #foreach ( $field in $allFields )
+    #if ( $Helper.isFlatItems( $field ) )
+        ${classLcapName}.${field.name}(${field.name});
+    #end
+  #end
+  #foreach ( $field in $allFields )
+    #if ( $Helper.xmlFieldMetadata( $field ).format )
+        ${classLcapName}.${field.name}($Helper.xmlFieldMetadata( $field ).format);
+    #end
+  #end
+  #if ( $class == $root )
+        ${classLcapName}.namespaceUri(parser.getNamespaceURI());
+        ${classLcapName}.modelEncoding(parser.getEncoding());
+  #end
+        return ${classLcapName}.build();
+    }
+
+ #end
+#end
+
+    private String checkDuplicate(String tagName, XMLStreamReader parser, Set<String> parsed) throws XMLStreamException {
+#set( $aliases = { } )
+#set( $flats = { } )
+#foreach( $class in $model.allClasses )
+  #foreach ( $field in $class.getFields($version) )
+    #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+    #if ( ! $fieldTagName )
+      #set ( $fieldTagName = $field.name )
+    #end
+    #if ( $field.alias )
+      #set ( $dummy = $aliases.put( $field.alias, $fieldTagName ) )
+    #end
+    #if ( $Helper.isFlatItems( $field ) )
+      #set ( $fieldTagName = $Helper.singular($fieldTagName) )
+      #set ( $dummy = $flats.put( $fieldTagName, "" ) )
+    #end
+  #end
+#end
+#if ( ! ${aliases.isEmpty()} )
+        switch (tagName) {
+  #foreach( $entry in $aliases.entrySet() )
+        case "${entry.key}":
+            tagName = "${entry.value}";
+            break;
+  #end
+        }
+#end
+#if ( ! ${flats.isEmpty()} )
+        switch (tagName) {
+  #foreach( $entry in $flats.entrySet() )
+        case "${entry.key}":
+  #end
+            break;
+        default:
+            if (!parsed.add(tagName)) {
+                throw new XMLStreamException("Duplicated tag: '" + tagName + "'", parser.getLocation(), null);
+            }
+        }
+#end
+        return tagName;
+    }
+
+    /**
+     * Method checkUnknownAttribute.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @param tagName a tagName object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @throws IOException IOException if any.
+     */
+    private void checkUnknownAttribute(XMLStreamReader parser, String attribute, String tagName, boolean strict) throws XMLStreamException {
+        // strictXmlAttributes = true for model: if strict == true, not only elements are checked but attributes too
+        if (strict) {
+            throw new XMLStreamException("Unknown attribute '" + attribute + "' for tag '" + tagName + "'", parser.getLocation(), null);
+        }
+    } //-- void checkUnknownAttribute(XMLStreamReader, String, String, boolean)
+
+    /**
+     * Method checkUnknownElement.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @throws IOException IOException if any.
+     */
+    private void checkUnknownElement(XMLStreamReader parser, boolean strict) throws XMLStreamException {
+        if (strict) {
+            throw new XMLStreamException("Unrecognised tag: '" + parser.getName() + "'", parser.getLocation(), null);
+        }
+
+        for (int unrecognizedTagCount = 1; unrecognizedTagCount > 0;) {
+            int eventType = nextTag(parser);
+            if (eventType == XMLStreamReader.START_ELEMENT) {
+                unrecognizedTagCount++;
+            } else if (eventType == XMLStreamReader.END_ELEMENT) {
+                unrecognizedTagCount--;
+            }
+        }
+    } //-- void checkUnknownElement(XMLStreamReader, boolean)
+
+    /**
+     * Method getTrimmedValue.
+     *
+     * @param s a s object.
+     * @return String
+     */
+    private String getTrimmedValue(String s) {
+        if (s != null) {
+            s = s.trim();
+        }
+        return s;
+    } //-- String getTrimmedValue(String)
+
+    /**
+     * Method interpolatedTrimmed.
+     *
+     * @param value a value object.
+     * @param context a context object.
+     * @return String
+     */
+    private String interpolatedTrimmed(String value, String context) {
+        return getTrimmedValue(contentTransformer.transform(value, context));
+    } //-- String interpolatedTrimmed(String, String)
+
+    /**
+     * Method nextTag.
+     *
+     * @param parser a parser object.
+     * @throws IOException IOException if any.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return int
+     */
+    private int nextTag(XMLStreamReader parser) throws XMLStreamException {
+        while (true) {
+            int next = parser.next();
+            switch (next) {
+                case XMLStreamReader.SPACE:
+                case XMLStreamReader.COMMENT:
+                case XMLStreamReader.PROCESSING_INSTRUCTION:
+                case XMLStreamReader.CDATA:
+                case XMLStreamReader.CHARACTERS:
+                    continue;
+                case XMLStreamReader.START_ELEMENT:
+                case XMLStreamReader.END_ELEMENT:
+                    return next;
+            }
+        }
+    } //-- int nextTag(XMLStreamReader)
+
+    private String nextText(XMLStreamReader parser, boolean strict) throws XMLStreamException {
+        int eventType = parser.getEventType();
+        if (eventType != XMLStreamReader.START_ELEMENT) {
+            throw new XMLStreamException("parser must be on START_ELEMENT to read next text", parser.getLocation(), null);
+        }
+        eventType = parser.next();
+        StringBuilder result = new StringBuilder();
+        while (true) {
+            if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
+                result.append(parser.getText());
+            } else if (eventType == XMLStreamReader.ENTITY_REFERENCE) {
+                String val = null;
+                if (strict) {
+                    throw new XMLStreamException("Entities are not supported in strict mode", parser.getLocation(), null);
+                } else if (addDefaultEntities) {
+                    val = DEFAULT_ENTITIES.get(parser.getLocalName());
+                }
+                if (val != null) {
+                    result.append(val);
+                } else {
+                    result.append("&").append(parser.getLocalName()).append(";");
+                }
+            } else if (eventType != XMLStreamReader.COMMENT) {
+                break;
+            }
+            eventType = parser.next();
+        }
+        if (eventType != XMLStreamReader.END_ELEMENT) {
+            throw new XMLStreamException(
+                "TEXT must be immediately followed by END_ELEMENT and not " + eventType /*TODO: TYPES[eventType]*/, parser.getLocation(), null);
+        }
+        return result.toString();
+    }
+
+#if ( $locationTracking )
+    private XmlNode buildXmlNode(XMLStreamReader parser, InputSource source) throws XMLStreamException {
+        return XmlNodeBuilder.build(parser,
+                addLocationInformation
+                        ? p -> new InputLocation(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), source)
+                        : null);
+    }
+#else
+    private XmlNode buildXmlNode(XMLStreamReader parser) throws XMLStreamException {
+        return XmlNodeBuilder.build(parser);
+    }
+#end
+
+#foreach ( $class in $model.allClasses )
+  #foreach ( $field in $class.getFields($version) )
+    #if ( $field.type == "boolean" || $field.type == "Boolean" )
+      #set ( $hasBooleanField = true )
+    #elseif ( $field.type == "int" || $field.type == "Integer" )
+      #set ( $hasIntegerField = true )
+    #end
+  #end
+#end
+#if ( $hasBooleanField )
+    /**
+     * Method getBooleanValue.
+     *
+     * @param s a s object.
+     * @param defaultValue a defaultValue object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return boolean
+     */
+    private boolean getBooleanValue(String s, String attribute, XMLStreamReader parser, boolean defaultValue) throws XMLStreamException {
+        if (s != null && s.length() != 0) {
+            return Boolean.valueOf(s).booleanValue();
+        }
+        return defaultValue;
+    } //-- boolean getBooleanValue(String, String, XMLStreamReader, String)
+
+#end
+#if ( $hasIntegerField )
+    /**
+     * Method getIntegerValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return int
+     */
+    private int getIntegerValue(String s, String attribute, XMLStreamReader parser, boolean strict, int defaultValue) throws XMLStreamException {
+        if (s != null) {
+            try {
+                return Integer.valueOf(s).intValue();
+            } catch (NumberFormatException nfe) {
+                if (strict) {
+                    throw new XMLStreamException("Unable to parse element '" + attribute + "', must be an integer", parser.getLocation(), nfe);
+                }
+            }
+        }
+        return defaultValue;
+    } //-- int getIntegerValue(String, String, XMLStreamReader, boolean)
+
+#end
+    public static interface ContentTransformer {
+        /**
+         * Interpolate the value read from the xpp3 document
+         * @param source The source value
+         * @param fieldName A description of the field being interpolated. The implementation may use this to
+         *                           log stuff.
+         * @return The interpolated value.
+         */
+        String transform(String source, String fieldName);
+    }
+
+}
diff --git a/src/mdo/reader.vm b/src/mdo/reader.vm
new file mode 100644
index 0000000..652a78c
--- /dev/null
+++ b/src/mdo/reader.vm
@@ -0,0 +1,1102 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#if( ${packageToolV4Xpp3} )
+  #set ( $package = "${packageToolV4Xpp3}" )
+#else
+  #set ( $package = "${packageToolV4}" )
+#end
+#set ( $className = "${model.name}Xpp3Reader" )
+#
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#set ( $rootXml = $Helper.xmlClassMetadata( $root ) )
+#set ( $rootTag = $rootXml.tagName )
+#set ( $rootUcapName = $Helper.capitalise( $root.name ) )
+#set ( $rootLcapName = $Helper.uncapitalise( $root.name ) )
+#
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import org.apache.maven.api.annotations.Generated;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+#foreach ( $class in $model.allClasses )
+import ${packageModelV4}.${class.name};
+#end
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+
+@Deprecated
+@Generated
+public class ${className} {
+
+    private boolean addDefaultEntities = true;
+
+    private final ContentTransformer contentTransformer;
+
+    /**
+    * XSI namespace
+    */
+    private static final String XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance";
+
+    private static final Map<String, String> DEFAULT_ENTITIES;
+    static {
+        Map<String, String> entities = new HashMap<>();
+        entities.put("nbsp", "\u00a0");
+        entities.put("iexcl", "\u00a1");
+        entities.put("cent", "\u00a2");
+        entities.put("pound", "\u00a3");
+        entities.put("curren", "\u00a4");
+        entities.put("yen", "\u00a5");
+        entities.put("brvbar", "\u00a6");
+        entities.put("sect", "\u00a7");
+        entities.put("uml", "\u00a8");
+        entities.put("copy", "\u00a9");
+        entities.put("ordf", "\u00aa");
+        entities.put("laquo", "\u00ab");
+        entities.put("not", "\u00ac");
+        entities.put("shy", "\u00ad");
+        entities.put("reg", "\u00ae");
+        entities.put("macr", "\u00af");
+        entities.put("deg", "\u00b0");
+        entities.put("plusmn", "\u00b1");
+        entities.put("sup2", "\u00b2");
+        entities.put("sup3", "\u00b3");
+        entities.put("acute", "\u00b4");
+        entities.put("micro", "\u00b5");
+        entities.put("para", "\u00b6");
+        entities.put("middot", "\u00b7");
+        entities.put("cedil", "\u00b8");
+        entities.put("sup1", "\u00b9");
+        entities.put("ordm", "\u00ba");
+        entities.put("raquo", "\u00bb");
+        entities.put("frac14", "\u00bc");
+        entities.put("frac12", "\u00bd");
+        entities.put("frac34", "\u00be");
+        entities.put("iquest", "\u00bf");
+        entities.put("Agrave", "\u00c0");
+        entities.put("Aacute", "\u00c1");
+        entities.put("Acirc", "\u00c2");
+        entities.put("Atilde", "\u00c3");
+        entities.put("Auml", "\u00c4");
+        entities.put("Aring", "\u00c5");
+        entities.put("AElig", "\u00c6");
+        entities.put("Ccedil", "\u00c7");
+        entities.put("Egrave", "\u00c8");
+        entities.put("Eacute", "\u00c9");
+        entities.put("Ecirc", "\u00ca");
+        entities.put("Euml", "\u00cb");
+        entities.put("Igrave", "\u00cc");
+        entities.put("Iacute", "\u00cd");
+        entities.put("Icirc", "\u00ce");
+        entities.put("Iuml", "\u00cf");
+        entities.put("ETH", "\u00d0");
+        entities.put("Ntilde", "\u00d1");
+        entities.put("Ograve", "\u00d2");
+        entities.put("Oacute", "\u00d3");
+        entities.put("Ocirc", "\u00d4");
+        entities.put("Otilde", "\u00d5");
+        entities.put("Ouml", "\u00d6");
+        entities.put("times", "\u00d7");
+        entities.put("Oslash", "\u00d8");
+        entities.put("Ugrave", "\u00d9");
+        entities.put("Uacute", "\u00da");
+        entities.put("Ucirc", "\u00db");
+        entities.put("Uuml", "\u00dc");
+        entities.put("Yacute", "\u00dd");
+        entities.put("THORN", "\u00de");
+        entities.put("szlig", "\u00df");
+        entities.put("agrave", "\u00e0");
+        entities.put("aacute", "\u00e1");
+        entities.put("acirc", "\u00e2");
+        entities.put("atilde", "\u00e3");
+        entities.put("auml", "\u00e4");
+        entities.put("aring", "\u00e5");
+        entities.put("aelig", "\u00e6");
+        entities.put("ccedil", "\u00e7");
+        entities.put("egrave", "\u00e8");
+        entities.put("eacute", "\u00e9");
+        entities.put("ecirc", "\u00ea");
+        entities.put("euml", "\u00eb");
+        entities.put("igrave", "\u00ec");
+        entities.put("iacute", "\u00ed");
+        entities.put("icirc", "\u00ee");
+        entities.put("iuml", "\u00ef");
+        entities.put("eth", "\u00f0");
+        entities.put("ntilde", "\u00f1");
+        entities.put("ograve", "\u00f2");
+        entities.put("oacute", "\u00f3");
+        entities.put("ocirc", "\u00f4");
+        entities.put("otilde", "\u00f5");
+        entities.put("ouml", "\u00f6");
+        entities.put("divide", "\u00f7");
+        entities.put("oslash", "\u00f8");
+        entities.put("ugrave", "\u00f9");
+        entities.put("uacute", "\u00fa");
+        entities.put("ucirc", "\u00fb");
+        entities.put("uuml", "\u00fc");
+        entities.put("yacute", "\u00fd");
+        entities.put("thorn", "\u00fe");
+        entities.put("yuml", "\u00ff");
+
+        // ----------------------------------------------------------------------
+        // Special entities
+        // ----------------------------------------------------------------------
+
+        entities.put("OElig", "\u0152");
+        entities.put("oelig", "\u0153");
+        entities.put("Scaron", "\u0160");
+        entities.put("scaron", "\u0161");
+        entities.put("Yuml", "\u0178");
+        entities.put("circ", "\u02c6");
+        entities.put("tilde", "\u02dc");
+        entities.put("ensp", "\u2002");
+        entities.put("emsp", "\u2003");
+        entities.put("thinsp", "\u2009");
+        entities.put("zwnj", "\u200c");
+        entities.put("zwj", "\u200d");
+        entities.put("lrm", "\u200e");
+        entities.put("rlm", "\u200f");
+        entities.put("ndash", "\u2013");
+        entities.put("mdash", "\u2014");
+        entities.put("lsquo", "\u2018");
+        entities.put("rsquo", "\u2019");
+        entities.put("sbquo", "\u201a");
+        entities.put("ldquo", "\u201c");
+        entities.put("rdquo", "\u201d");
+        entities.put("bdquo", "\u201e");
+        entities.put("dagger", "\u2020");
+        entities.put("Dagger", "\u2021");
+        entities.put("permil", "\u2030");
+        entities.put("lsaquo", "\u2039");
+        entities.put("rsaquo", "\u203a");
+        entities.put("euro", "\u20ac");
+
+        // ----------------------------------------------------------------------
+        // Symbol entities
+        // ----------------------------------------------------------------------
+
+        entities.put("fnof", "\u0192");
+        entities.put("Alpha", "\u0391");
+        entities.put("Beta", "\u0392");
+        entities.put("Gamma", "\u0393");
+        entities.put("Delta", "\u0394");
+        entities.put("Epsilon", "\u0395");
+        entities.put("Zeta", "\u0396");
+        entities.put("Eta", "\u0397");
+        entities.put("Theta", "\u0398");
+        entities.put("Iota", "\u0399");
+        entities.put("Kappa", "\u039a");
+        entities.put("Lambda", "\u039b");
+        entities.put("Mu", "\u039c");
+        entities.put("Nu", "\u039d");
+        entities.put("Xi", "\u039e");
+        entities.put("Omicron", "\u039f");
+        entities.put("Pi", "\u03a0");
+        entities.put("Rho", "\u03a1");
+        entities.put("Sigma", "\u03a3");
+        entities.put("Tau", "\u03a4");
+        entities.put("Upsilon", "\u03a5");
+        entities.put("Phi", "\u03a6");
+        entities.put("Chi", "\u03a7");
+        entities.put("Psi", "\u03a8");
+        entities.put("Omega", "\u03a9");
+        entities.put("alpha", "\u03b1");
+        entities.put("beta", "\u03b2");
+        entities.put("gamma", "\u03b3");
+        entities.put("delta", "\u03b4");
+        entities.put("epsilon", "\u03b5");
+        entities.put("zeta", "\u03b6");
+        entities.put("eta", "\u03b7");
+        entities.put("theta", "\u03b8");
+        entities.put("iota", "\u03b9");
+        entities.put("kappa", "\u03ba");
+        entities.put("lambda", "\u03bb");
+        entities.put("mu", "\u03bc");
+        entities.put("nu", "\u03bd");
+        entities.put("xi", "\u03be");
+        entities.put("omicron", "\u03bf");
+        entities.put("pi", "\u03c0");
+        entities.put("rho", "\u03c1");
+        entities.put("sigmaf", "\u03c2");
+        entities.put("sigma", "\u03c3");
+        entities.put("tau", "\u03c4");
+        entities.put("upsilon", "\u03c5");
+        entities.put("phi", "\u03c6");
+        entities.put("chi", "\u03c7");
+        entities.put("psi", "\u03c8");
+        entities.put("omega", "\u03c9");
+        entities.put("thetasym", "\u03d1");
+        entities.put("upsih", "\u03d2");
+        entities.put("piv", "\u03d6");
+        entities.put("bull", "\u2022");
+        entities.put("hellip", "\u2026");
+        entities.put("prime", "\u2032");
+        entities.put("Prime", "\u2033");
+        entities.put("oline", "\u203e");
+        entities.put("frasl", "\u2044");
+        entities.put("weierp", "\u2118");
+        entities.put("image", "\u2111");
+        entities.put("real", "\u211c");
+        entities.put("trade", "\u2122");
+        entities.put("alefsym", "\u2135");
+        entities.put("larr", "\u2190");
+        entities.put("uarr", "\u2191");
+        entities.put("rarr", "\u2192");
+        entities.put("darr", "\u2193");
+        entities.put("harr", "\u2194");
+        entities.put("crarr", "\u21b5");
+        entities.put("lArr", "\u21d0");
+        entities.put("uArr", "\u21d1");
+        entities.put("rArr", "\u21d2");
+        entities.put("dArr", "\u21d3");
+        entities.put("hArr", "\u21d4");
+        entities.put("forall", "\u2200");
+        entities.put("part", "\u2202");
+        entities.put("exist", "\u2203");
+        entities.put("empty", "\u2205");
+        entities.put("nabla", "\u2207");
+        entities.put("isin", "\u2208");
+        entities.put("notin", "\u2209");
+        entities.put("ni", "\u220b");
+        entities.put("prod", "\u220f");
+        entities.put("sum", "\u2211");
+        entities.put("minus", "\u2212");
+        entities.put("lowast", "\u2217");
+        entities.put("radic", "\u221a");
+        entities.put("prop", "\u221d");
+        entities.put("infin", "\u221e");
+        entities.put("ang", "\u2220");
+        entities.put("and", "\u2227");
+        entities.put("or", "\u2228");
+        entities.put("cap", "\u2229");
+        entities.put("cup", "\u222a");
+        entities.put("int", "\u222b");
+        entities.put("there4", "\u2234");
+        entities.put("sim", "\u223c");
+        entities.put("cong", "\u2245");
+        entities.put("asymp", "\u2248");
+        entities.put("ne", "\u2260");
+        entities.put("equiv", "\u2261");
+        entities.put("le", "\u2264");
+        entities.put("ge", "\u2265");
+        entities.put("sub", "\u2282");
+        entities.put("sup", "\u2283");
+        entities.put("nsub", "\u2284");
+        entities.put("sube", "\u2286");
+        entities.put("supe", "\u2287");
+        entities.put("oplus", "\u2295");
+        entities.put("otimes", "\u2297");
+        entities.put("perp", "\u22a5");
+        entities.put("sdot", "\u22c5");
+        entities.put("lceil", "\u2308");
+        entities.put("rceil", "\u2309");
+        entities.put("lfloor", "\u230a");
+        entities.put("rfloor", "\u230b");
+        entities.put("lang", "\u2329");
+        entities.put("rang", "\u232a");
+        entities.put("loz", "\u25ca");
+        entities.put("spades", "\u2660");
+        entities.put("clubs", "\u2663");
+        entities.put("hearts", "\u2665");
+        entities.put("diams", "\u2666");
+        DEFAULT_ENTITIES = Collections.unmodifiableMap(entities);
+    }
+
+
+    public ${className}() {
+        this((s, f) -> s);
+    }
+
+    public ${className}(ContentTransformer contentTransformer) {
+        this.contentTransformer = contentTransformer;
+    }
+
+    /**
+     *
+     * @param reader a reader object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+    public ${root.name} read(Reader reader, boolean strict) throws IOException, XMLStreamException {
+        XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
+        factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+        XMLStreamReader parser = null;
+        try {
+            parser = factory.createXMLStreamReader(reader);
+        } catch (XMLStreamException e) {
+            throw new RuntimeException(e);
+        }
+        return read(parser, strict);
+    } //-- ${root.name} read(Reader, boolean)
+
+    /**
+     *
+     * @param reader a reader object.
+     * @throws IOException IOException if any.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+    public ${root.name} read(Reader reader) throws IOException, XMLStreamException {
+        return read(reader, true);
+    } //-- ${root.name} read(Reader)
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+    public ${root.name} read(InputStream in, boolean strict) throws IOException, XMLStreamException {
+        XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
+        factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+        StreamSource streamSource = new StreamSource(in, null);
+        XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
+        return read(parser, strict);
+    } //-- ${root.name} read(InputStream, boolean)
+
+    /**
+     * Method read.
+     *
+     * @param in a in object.
+     * @throws IOException IOException if any.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+    public ${root.name} read(InputStream in) throws IOException, XMLStreamException {
+        XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
+        factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
+        StreamSource streamSource = new StreamSource(in, null);
+        XMLStreamReader parser = factory.createXMLStreamReader(streamSource);
+        return read(parser,true);
+    } //-- ${root.name} read(InputStream)
+
+    /**
+     * Method read.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @throws IOException IOException if any.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return ${root.name}
+     */
+    public ${root.name} read(XMLStreamReader parser, boolean strict) throws IOException, XMLStreamException {
+        $rootUcapName $rootLcapName = null;
+        int eventType = parser.getEventType();
+        boolean parsed = false;
+        while (eventType != XMLStreamReader.END_DOCUMENT) {
+            if (eventType == XMLStreamReader.START_ELEMENT) {
+                if (strict && ! "${rootTag}".equals(parser.getLocalName())) {
+                    throw new XMLStreamException("Expected root element '${rootTag}' but found '" + parser.getLocalName() + "'", parser.getLocation(), null);
+                } else if (parsed) {
+                    // fallback, already expected a XMLStreamException due to invalid XML
+                    throw new XMLStreamException("Duplicated tag: '${rootTag}'", parser.getLocation(), null);
+                }
+                $rootLcapName = parse${rootUcapName}(parser, strict);
+                parsed = true;
+            }
+            eventType = parser.next();
+        }
+        if (parsed) {
+            return $rootLcapName;
+        }
+        throw new XMLStreamException("Expected root element '${rootTag}' but found no element at all: invalid XML document", parser.getLocation(), null);
+    } //-- ${root.name} read(XMLStreamReader, boolean)
+
+#foreach ( $class in $model.allClasses )
+ #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+  #set ( $classUcapName = $Helper.capitalise( $class.name ) )
+  #set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
+  #set ( $ancestors = $Helper.ancestors( $class ) )
+  #set ( $allFields = [] )
+  #foreach ( $cl in $ancestors )
+    #set ( $dummy = $allFields.addAll( $cl.getFields($version) ) )
+  #end
+    private ${classUcapName} parse${classUcapName}(XMLStreamReader parser, boolean strict)
+            throws IOException, XMLStreamException {
+        String tagName = parser.getLocalName();
+        ${classUcapName}.Builder ${classLcapName} = ${classUcapName}.newBuilder(true);
+        for (int i = parser.getAttributeCount() - 1; i >= 0; i--) {
+            String name = parser.getAttributeLocalName(i);
+            String ns = parser.getAttributeNamespace(i);
+            String value = parser.getAttributeValue(i);
+            if (XSI_NAMESPACE.equals(ns)) {
+                // just ignore attributes with non-default namespace (for example: xmlns:xsi)
+     #if ( $class == $root )
+            }  else if ("xmlns".equals(name)) {
+                // ignore xmlns attribute in root class, which is a reserved attribute name
+  #end
+            }
+  #foreach ( $field in $allFields )
+    #if ( $Helper.xmlFieldMetadata( $field ).attribute )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+            else if ("$fieldTagName".equals(name)) {
+      #if ( $field.type == "String" )
+                ${classLcapName}.${field.name}(interpolatedTrimmed(value, "$fieldTagName"));
+      #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+                ${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(value, "$fieldTagName"), "$fieldTagName", parser, ${field.defaultValue}));
+      #else
+                // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+            }
+    #end
+  #end
+            else {
+                checkUnknownAttribute(parser, name, tagName, strict);
+            }
+        }
+        Set<String> parsed = new HashSet<>();
+  #foreach ( $field in $allFields )
+    #if ( $Helper.isFlatItems( $field ) )
+        List<$field.to> ${field.name} = new ArrayList<>();
+    #end
+  #end
+        while ((strict ? parser.nextTag() : nextTag(parser)) == XMLStreamReader.START_ELEMENT) {
+            String childName = checkDuplicate(parser.getLocalName(), parser, parsed);
+            switch (childName) {
+  #set( $ift = "if" )
+  #foreach ( $field in $allFields )
+    #if ( ! $Helper.xmlFieldMetadata( $field ).attribute && ! $Helper.xmlFieldMetadata( $field ).transient )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #if ( ! $fieldTagName )
+        #set ( $fieldTagName = $field.name )
+      #end
+      #if ( $Helper.isFlatItems( $field ) )
+        #set ( $fieldTagName = $Helper.singular( $fieldTagName ) )
+      #end
+      #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+                case "${fieldTagName}": {
+      #if ( $field.type == "String" )
+                    ${classLcapName}.${field.name}(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"));
+                    break;
+      #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+                    ${classLcapName}.${field.name}(getBooleanValue(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"), "${fieldTagName}", parser, ${field.defaultValue}));
+                    break;
+      #elseif ( $field.type == "int" )
+                    ${classLcapName}.${field.name}(getIntegerValue(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"), "${fieldTagName}", parser, strict, ${field.defaultValue}));
+                    break;
+      #elseif ( $field.type == "DOM" )
+                    ${classLcapName}.${field.name}(XmlNodeBuilder.build(parser));
+                    break;
+      #elseif ( $field.type == "java.util.List" && $field.to == "String" && $field.multiplicity == "*" )
+                    List<String> ${field.name} = new ArrayList<>();
+                    while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
+                        if ("${Helper.singular($fieldTagName)}".equals(parser.getLocalName())) {
+                            ${field.name}.add(interpolatedTrimmed(nextText(parser, strict), "${fieldTagName}"));
+                        } else {
+                            checkUnknownElement(parser, strict);
+                        }
+                    }
+                    ${classLcapName}.${field.name}(${field.name});
+                    break;
+      #elseif ( $field.type == "java.util.Properties" && $field.to == "String" && $field.multiplicity == "*" )
+                    Map<String, String> ${field.name} = new LinkedHashMap<>();
+                    while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
+                        String key = parser.getLocalName();
+                        String value = nextText(parser, strict).trim();
+                        ${field.name}.put(key, value);
+                    }
+                    ${classLcapName}.${field.name}(${field.name});
+                    break;
+      #elseif ( $field.to && $field.multiplicity == "1" )
+                    ${classLcapName}.${field.name}(parse${field.toClass.name}(parser, strict));
+                    break;
+      #elseif ( $field.to && $field.multiplicity == "*" && $Helper.isFlatItems( $field ) )
+                    ${field.name}.add(parse${field.toClass.name}(parser, strict));
+                    break;
+      #elseif ( $field.to && $field.multiplicity == "*" )
+                    List<$field.to> ${field.name} = new ArrayList<>();
+                    while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
+                        if ("${Helper.singular($fieldTagName)}".equals(parser.getLocalName())) {
+                            ${field.name}.add(parse${field.toClass.name}(parser, strict));
+                        } else {
+                            checkUnknownElement(parser, strict);
+                        }
+                    }
+                    ${classLcapName}.${field.name}(${field.name});
+                    break;
+      #else
+                    // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+                    break;
+      #end
+                }
+      #set( $ift = "else if" )
+    #end
+  #end
+                default: {
+                    checkUnknownElement(parser, strict);
+                    break;
+                }
+            }
+        }
+  #foreach ( $field in $allFields )
+    #if ( $Helper.isFlatItems( $field ) )
+        ${classLcapName}.${field.name}(${field.name});
+    #end
+  #end
+  #if ( $class == $root )
+        ${classLcapName}.modelEncoding(parser.getEncoding());
+  #end
+        return ${classLcapName}.build();
+    }
+
+ #end
+#end
+
+    private String checkDuplicate(String tagName, XMLStreamReader parser, Set<String> parsed) throws XMLStreamException {
+#set( $aliases = { } )
+#set( $flats = { } )
+#foreach( $class in $model.allClasses )
+  #foreach ( $field in $class.getFields($version) )
+    #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+    #if ( ! $fieldTagName )
+      #set ( $fieldTagName = $field.name )
+    #end
+    #if ( $field.alias )
+      #set ( $dummy = $aliases.put( $field.alias, $fieldTagName ) )
+    #end
+    #if ( $Helper.isFlatItems( $field ) )
+      #set ( $fieldTagName = $Helper.singular($fieldTagName) )
+      #set ( $dummy = $flats.put( $fieldTagName, "" ) )
+    #end
+  #end
+#end
+#if ( ! ${aliases.isEmpty()} )
+        switch (tagName) {
+  #foreach( $entry in $aliases.entrySet() )
+            case "${entry.key}":
+                tagName = "${entry.value}";
+  #end
+        }
+#end
+#if ( ! ${flats.isEmpty()} )
+        switch (tagName) {
+  #foreach( $entry in $flats.entrySet() )
+            case "${entry.key}":
+  #end
+                break;
+            default:
+                if (!parsed.add(tagName)) {
+                    throw new XMLStreamException("Duplicated tag: '" + tagName + "'", parser.getLocation(), null);
+                }
+        }
+#end
+        return tagName;
+    }
+
+    /**
+     * Sets the state of the "add default entities" flag.
+     *
+     * @param addDefaultEntities a addDefaultEntities object.
+     */
+    public void setAddDefaultEntities(boolean addDefaultEntities) {
+        this.addDefaultEntities = addDefaultEntities;
+    } //-- void setAddDefaultEntities(boolean)
+
+    public static interface ContentTransformer {
+        /**
+         * Interpolate the value read from the xpp3 document
+         * @param source The source value
+         * @param fieldName A description of the field being interpolated. The implementation may use this to
+         *                           log stuff.
+         * @return The interpolated value.
+         */
+        String transform(String source, String fieldName);
+    }
+
+    /**
+     * Method checkFieldWithDuplicate.
+     *
+     * @param parser a parser object.
+     * @param parsed a parsed object.
+     * @param alias a alias object.
+     * @param tagName a tagName object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return boolean
+     */
+    private boolean checkFieldWithDuplicate(XMLStreamReader parser, String tagName, String alias, Set<String> parsed)
+        throws XMLStreamException {
+        if (!(parser.getLocalName().equals(tagName) || parser.getLocalName().equals(alias))) {
+            return false;
+        }
+        if (!parsed.add(tagName)) {
+            throw new XMLStreamException("Duplicated tag: '" + tagName + "'", parser.getLocation(), null);
+        }
+        return true;
+    } //-- boolean checkFieldWithDuplicate(XMLStreamReader, String, String, Set<String>)
+
+    /**
+     * Method checkUnknownAttribute.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @param tagName a tagName object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @throws IOException IOException if any.
+     */
+    private void checkUnknownAttribute(XMLStreamReader parser, String attribute, String tagName, boolean strict)
+        throws XMLStreamException, IOException {
+        // strictXmlAttributes = true for model: if strict == true, not only elements are checked but attributes too
+        if (strict) {
+            throw new XMLStreamException("Unknown attribute '" + attribute + "' for tag '" + tagName + "'", parser.getLocation(), null);
+        }
+    } //-- void checkUnknownAttribute(XMLStreamReader, String, String, boolean)
+
+    /**
+     * Method checkUnknownElement.
+     *
+     * @param parser a parser object.
+     * @param strict a strict object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @throws IOException IOException if any.
+     */
+    private void checkUnknownElement(XMLStreamReader parser, boolean strict)
+        throws XMLStreamException, IOException {
+        if (strict) {
+            throw new XMLStreamException("Unrecognised tag: '" + parser.getLocalName() + "'", parser.getLocation(), null);
+        }
+
+        for (int unrecognizedTagCount = 1; unrecognizedTagCount > 0;) {
+            int eventType = parser.next();
+            if (eventType == XMLStreamReader.START_ELEMENT) {
+                unrecognizedTagCount++;
+            } else if (eventType == XMLStreamReader.END_ELEMENT) {
+                unrecognizedTagCount--;
+            }
+        }
+    } //-- void checkUnknownElement(XMLStreamReader, boolean)
+
+    /**
+     * Returns the state of the "add default entities" flag.
+     *
+     * @return boolean
+     */
+    public boolean getAddDefaultEntities() {
+        return addDefaultEntities;
+    } //-- boolean getAddDefaultEntities()
+
+    /**
+     * Method getBooleanValue.
+     *
+     * @param s a s object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return boolean
+     */
+    private boolean getBooleanValue(String s, String attribute, XMLStreamReader parser)
+        throws XMLStreamException {
+        return getBooleanValue(s, attribute, parser, false);
+    } //-- boolean getBooleanValue(String, String, XMLStreamReader)
+
+    /**
+     * Method getBooleanValue.
+     *
+     * @param s a s object.
+     * @param defaultValue a defaultValue object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return boolean
+     */
+    private boolean getBooleanValue(String s, String attribute, XMLStreamReader parser, boolean defaultValue)
+        throws XMLStreamException {
+        if (s != null && s.length() != 0) {
+            return Boolean.valueOf(s).booleanValue();
+        }
+        return defaultValue;
+    } //-- boolean getBooleanValue(String, String, XMLStreamReader, String)
+
+    /**
+     * Method getByteValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return byte
+     */
+    private byte getByteValue(String s, String attribute, XMLStreamReader parser, boolean strict)
+        throws XMLStreamException {
+        if (s != null) {
+            try {
+                return Byte.valueOf(s).byteValue();
+            } catch (NumberFormatException nfe) {
+                if (strict) {
+                    throw new XMLStreamException("Unable to parse element '" + attribute + "', must be a byte", parser.getLocation(), nfe);
+                }
+            }
+        }
+        return 0;
+    } //-- byte getByteValue(String, String, XMLStreamReader, boolean)
+
+    /**
+     * Method getCharacterValue.
+     *
+     * @param s a s object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return char
+     */
+    private char getCharacterValue(String s, String attribute, XMLStreamReader parser)
+        throws XMLStreamException {
+        if (s != null) {
+            return s.charAt(0);
+        }
+        return 0;
+    } //-- char getCharacterValue(String, String, XMLStreamReader)
+
+    /**
+     * Method getDateValue.
+     *
+     * @param s a s object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return Date
+     */
+    private Date getDateValue(String s, String attribute, XMLStreamReader parser)
+        throws XMLStreamException {
+        return getDateValue(s, attribute, null, parser);
+    } //-- Date getDateValue(String, String, XMLStreamReader)
+
+    /**
+     * Method getDateValue.
+     *
+     * @param s a s object.
+     * @param parser a parser object.
+     * @param dateFormat a dateFormat object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return Date
+     */
+    private Date getDateValue(String s, String attribute, String dateFormat, XMLStreamReader parser)
+        throws XMLStreamException {
+        if (s != null) {
+            String effectiveDateFormat = dateFormat;
+            if (dateFormat == null) {
+                effectiveDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS";
+            }
+            if ("long".equals(effectiveDateFormat)) {
+                try {
+                    return new java.util.Date(Long.parseLong(s));
+                } catch (NumberFormatException e) {
+                    throw new XMLStreamException(e.getMessage(), parser.getLocation(), e);
+                }
+            } else {
+                try {
+                    DateFormat dateParser = new java.text.SimpleDateFormat(effectiveDateFormat, java.util.Locale.US);
+                    return dateParser.parse(s);
+                } catch (java.text.ParseException e) {
+                    throw new XMLStreamException(e.getMessage(), parser.getLocation(), e);
+                }
+            }
+        }
+        return null;
+    } //-- Date getDateValue(String, String, String, XMLStreamReader)
+
+    /**
+     * Method getDoubleValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return double
+     */
+    private double getDoubleValue(String s, String attribute, XMLStreamReader parser, boolean strict)
+        throws XMLStreamException {
+        if (s != null) {
+            try {
+                return Double.valueOf(s).doubleValue();
+            } catch (NumberFormatException nfe) {
+                if (strict) {
+                    throw new XMLStreamException("Unable to parse element '" + attribute + "', must be a floating point number", parser.getLocation(), nfe);
+                }
+            }
+        }
+        return 0;
+    } //-- double getDoubleValue(String, String, XMLStreamReader, boolean)
+
+    /**
+     * Method getFloatValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return float
+     */
+    private float getFloatValue(String s, String attribute, XMLStreamReader parser, boolean strict)
+        throws XMLStreamException {
+        if (s != null) {
+            try {
+                return Float.valueOf(s).floatValue();
+            } catch (NumberFormatException nfe) {
+                if (strict) {
+                    throw new XMLStreamException("Unable to parse element '" + attribute + "', must be a floating point number", parser.getLocation(), nfe);
+                }
+            }
+        }
+        return 0;
+    } //-- float getFloatValue(String, String, XMLStreamReader, boolean)
+
+    /**
+     * Method getIntegerValue.
+     *
+     * @param s a s object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return int
+     */
+    private int getIntegerValue(String s, String attribute, XMLStreamReader parser, boolean strict)
+        throws XMLStreamException {
+        return getIntegerValue(s, attribute, parser, strict, 0);
+    } //-- int getBooleanValue(String, String, XMLStreamReader)
+
+    /**
+     * Method getIntegerValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return int
+     */
+    private int getIntegerValue(String s, String attribute, XMLStreamReader parser, boolean strict, int defaultValue)
+        throws XMLStreamException {
+        if (s != null) {
+            try {
+                return Integer.valueOf(s).intValue();
+            } catch (NumberFormatException nfe) {
+                if (strict) {
+                    throw new XMLStreamException("Unable to parse element '" + attribute + "', must be an integer", parser.getLocation(), nfe);
+                }
+            }
+        }
+        return defaultValue;
+    } //-- int getIntegerValue(String, String, XMLStreamReader, boolean, int)
+
+    /**
+     * Method getLongValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return long
+     */
+    private long getLongValue(String s, String attribute, XMLStreamReader parser, boolean strict)
+            throws XMLStreamException {
+        if (s != null) {
+            try {
+                return Long.valueOf(s).longValue();
+            } catch (NumberFormatException nfe) {
+                if (strict) {
+                    throw new XMLStreamException("Unable to parse element '" + attribute + "', must be a long integer", parser.getLocation(), nfe);
+                }
+            }
+        }
+        return 0;
+    } //-- long getLongValue(String, String, XMLStreamReader, boolean)
+
+    /**
+     * Method getRequiredAttributeValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return String
+     */
+    private String getRequiredAttributeValue(String s, String attribute, XMLStreamReader parser, boolean strict)
+            throws XMLStreamException {
+        if (s == null) {
+            if (strict) {
+                throw new XMLStreamException("Missing required value for attribute '" + attribute + "'", parser.getLocation(), null);
+            }
+        }
+        return s;
+    } //-- String getRequiredAttributeValue(String, String, XMLStreamReader, boolean)
+
+    /**
+     * Method getShortValue.
+     *
+     * @param s a s object.
+     * @param strict a strict object.
+     * @param parser a parser object.
+     * @param attribute a attribute object.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return short
+     */
+    private short getShortValue(String s, String attribute, XMLStreamReader parser, boolean strict)
+            throws XMLStreamException {
+        if (s != null) {
+            try {
+                return Short.valueOf(s).shortValue();
+            } catch (NumberFormatException nfe) {
+                if (strict) {
+                    throw new XMLStreamException("Unable to parse element '" + attribute + "', must be a short integer", parser.getLocation(), nfe);
+                }
+            }
+        }
+        return 0;
+    } //-- short getShortValue(String, String, XMLStreamReader, boolean)
+
+    /**
+     * Method getTrimmedValue.
+     *
+     * @param s a s object.
+     * @return String
+     */
+    private String getTrimmedValue(String s) {
+        if (s != null) {
+            s = s.trim();
+        }
+        return s;
+    } //-- String getTrimmedValue(String)
+
+    /**
+     * Method interpolatedTrimmed.
+     *
+     * @param value a value object.
+     * @param context a context object.
+     * @return String
+     */
+    private String interpolatedTrimmed(String value, String context) {
+        return getTrimmedValue(contentTransformer.transform(value, context));
+    } //-- String interpolatedTrimmed(String, String)
+
+    /**
+     * Method nextTag.
+     *
+     * @param parser a parser object.
+     * @throws IOException IOException if any.
+     * @throws XMLStreamException XMLStreamException if
+     * any.
+     * @return int
+     */
+    private int nextTag(XMLStreamReader parser) throws IOException, XMLStreamException {
+        while (true) {
+            int next = parser.next();
+            switch (next) {
+                case XMLStreamReader.SPACE:
+                case XMLStreamReader.COMMENT:
+                case XMLStreamReader.PROCESSING_INSTRUCTION:
+                case XMLStreamReader.CDATA:
+                case XMLStreamReader.CHARACTERS:
+                    continue;
+                case XMLStreamReader.START_ELEMENT:
+                case XMLStreamReader.END_ELEMENT:
+                    return next;
+            }
+        }
+    } //-- int nextTag(XMLStreamReader)
+
+    private String nextText(XMLStreamReader parser, boolean strict) throws XMLStreamException {
+        int eventType = parser.getEventType();
+        if (eventType != XMLStreamReader.START_ELEMENT) {
+            throw new XMLStreamException("parser must be on START_ELEMENT to read next text", parser.getLocation(), null);
+        }
+        eventType = parser.next();
+        StringBuilder result = new StringBuilder();
+        while (true) {
+            if (eventType == XMLStreamReader.CHARACTERS || eventType == XMLStreamReader.CDATA) {
+                result.append(parser.getText());
+            } else if (eventType == XMLStreamReader.ENTITY_REFERENCE) {
+                String val = null;
+                if (strict) {
+                    throw new XMLStreamException("Entities are not supported in strict mode", parser.getLocation(), null);
+                } else if (addDefaultEntities) {
+                    val = DEFAULT_ENTITIES.get(parser.getLocalName());
+                }
+                if (val != null) {
+                    result.append(val);
+                } else {
+                    result.append("&").append(parser.getLocalName()).append(";");
+                }
+            } else if (eventType != XMLStreamReader.COMMENT) {
+                break;
+            }
+            eventType = parser.next();
+        }
+        if (eventType != XMLStreamReader.END_ELEMENT) {
+            throw new XMLStreamException(
+                    "TEXT must be immediately followed by END_ELEMENT and not " + eventType /*TODO: TYPES[eventType]*/, parser.getLocation(), null);
+        }
+        return result.toString();
+    }
+
+}
diff --git a/src/mdo/transformer.vm b/src/mdo/transformer.vm
new file mode 100644
index 0000000..8eaac49
--- /dev/null
+++ b/src/mdo/transformer.vm
@@ -0,0 +1,178 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#set ( $package = "${packageToolV4}" )
+#set ( $className = "${model.name}Transformer" )
+#
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+import java.io.ObjectStreamException;
+import java.util.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Objects;
+import java.util.function.BinaryOperator;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import org.apache.maven.api.annotations.Generated;
+import org.apache.maven.api.xml.XmlNode;
+#foreach ( $class in $model.allClasses )
+import ${packageModelV4}.${class.name};
+#end
+import org.codehaus.plexus.util.xml.Xpp3Dom;
+
+@Generated
+public class ${className} {
+
+    private final Function<String, String> transformer;
+
+    public ${className}(Function<String, String> transformer) {
+        this.transformer = transformer;
+    }
+
+    /**
+     * Transforms the given model
+     */
+    public ${root.name} visit(${root.name} target) {
+        Objects.requireNonNull(target, "target cannot be null");
+        return transform${root.name}(target);
+    }
+
+    /**
+     * The transformation function.
+     */
+    protected String transform(String value) {
+        return transformer.apply(value);
+    }
+
+#foreach ( $class in $model.allClasses )
+  #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+    #set ( $ancestors = $Helper.ancestors( $class ) )
+    #set ( $allFields = $Helper.xmlFields( $class ) )
+    protected ${class.name} transform${class.name}(${class.name} target) {
+        if (target == null) {
+            return null;
+        }
+        ${class.name}.Builder builder = ${class.name}.newBuilder(target);
+    #foreach ( $field in $allFields )
+        transform${field.modelClass.name}_${Helper.capitalise($field.name)}(builder, target);
+    #end
+        return builder.build();
+    }
+
+    #foreach ( $field in $allFields )
+      #set ( $capField = ${Helper.capitalise($field.name)} )
+    protected void transform${class.name}_${capField}(${class.name}.Builder builder, ${class.name} target) {
+      #if ( $field.type == "String" )
+        String newVal = transform(target.get${capField}());
+        builder.${field.name}(newVal != target.get${capField}() ? newVal : null);
+      #elseif ( $field.type == "java.util.List" && $field.to == "String" && $field.multiplicity == "*" )
+        builder.${field.name}(transform(target.get${capField}(), this::transform));
+      #elseif ( $field.type == "java.util.Properties" && $field.to == "String" && $field.multiplicity == "*" )
+        Map<String, String> props = target.get${capField}();
+        Map<String, String> newProps = null;
+        for (Map.Entry<String, String> entry : props.entrySet()) {
+            String newVal = transform(entry.getValue());
+            if (newVal != null && newVal != entry.getValue()) {
+                if (newProps == null) {
+                    newProps = new HashMap<>();
+                    newProps.putAll(props);
+                    builder.${field.name}(newProps);
+                }
+                newProps.put(entry.getKey(), newVal);
+            }
+        }
+      #elseif ( $field.to && $field.multiplicity == "1" )
+        ${field.to} newVal = transform${field.to}(target.get${capField}());
+        builder.${field.name}(newVal != target.get${capField}() ? newVal : null);
+      #elseif ( $field.to && $field.multiplicity == "*" )
+        builder.${field.name}(transform(target.get${capField}(), this::transform${field.to}));
+      #elseif ( $field.type == "DOM" )
+        XmlNode newVal = transform(target.get${capField}());
+        builder.${field.name}(newVal != target.get${capField}() ? newVal : null);
+      #elseif ( $field.type == "boolean" || $field.type == "int" || $field.type == "java.nio.file.Path" )
+        // nothing to do, the transformer only handles strings
+      #else
+        // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+    }
+    #end
+
+  #end
+#end
+    protected <T> List<T> transform(List<T> list, Function<T, T> transformer) {
+        List<T> newList = null;
+        for (int i = 0; i < list.size(); i++) {
+            T newVal = transformer.apply(list.get(i));
+            if (newVal != list.get(i)) {
+                if (newList == null) {
+                    newList = new ArrayList<>(list);
+                }
+                newList.set(i, newVal);
+            }
+        }
+        return newList;
+    }
+
+    protected XmlNode transform(XmlNode node) {
+        if (node != null) {
+            Xpp3Dom xpp = new Xpp3Dom(node);
+            transform(xpp);
+            return xpp.getDom();
+        }
+        return node;
+    }
+
+    protected void transform(Xpp3Dom dom) {
+        if (dom != null) {
+            String org, val;
+            // Content
+            org = dom.getValue();
+            val = transform(org);
+            if (org != val) {
+                dom.setValue(val);
+            }
+            // Attributes
+            for (String attr : dom.getAttributeNames()) {
+                org = dom.getAttribute(attr);
+                val = transform(org);
+                if (org != val) {
+                    dom.setAttribute(attr, val);
+                }
+            }
+            // Children
+            for (int i = 0, l = dom.getChildCount(); i < l; i++) {
+                transform(dom.getChild(i));
+            }
+        }
+    }
+}
diff --git a/src/mdo/writer-stax.vm b/src/mdo/writer-stax.vm
new file mode 100644
index 0000000..dc30f61
--- /dev/null
+++ b/src/mdo/writer-stax.vm
@@ -0,0 +1,516 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#set ( $package = "${packageToolV4}" )
+#set ( $className = "${model.name}StaxWriter" )
+#
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#set ( $xmlModelMetadata = $model.getMetadata( "org.codehaus.modello.plugins.xml.metadata.XmlModelMetadata" ) )
+#if ( $forcedIOModelVersion )
+  #set ( $Version = $model.class.classLoader.loadClass( "org.codehaus.modello.model.Version" ) )
+  #set ( $ioVersion = $Version.getConstructor( $package.class ).newInstance( $forcedIOModelVersion ) )
+#else
+  #set ( $ioVersion = $version )
+#end
+#set ( $namespace = $xmlModelMetadata.getNamespace($ioVersion) )
+#set ( $schemaLocation = $xmlModelMetadata.getSchemaLocation($ioVersion) )
+#set ( $rootXml = $Helper.xmlClassMetadata( $root ) )
+#set ( $rootTag = $rootXml.tagName )
+#set ( $rootUcapName = $Helper.capitalise( $root.name ) )
+#set ( $rootLcapName = $Helper.uncapitalise( $root.name ) )
+#
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
+import org.apache.maven.api.annotations.Generated;
+#if ( $locationTracking )
+import ${packageModelV4}.InputLocation;
+import ${packageModelV4}.InputLocationTracker;
+#end
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+#foreach ( $class in $model.allClasses )
+  #if ( $class.name != "InputLocation" )
+import ${packageModelV4}.${class.name};
+  #end
+#end
+import org.codehaus.stax2.util.StreamWriterDelegate;
+
+import static javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI;
+
+@Generated
+public class ${className} {
+
+      //--------------------------/
+     //- Class/Member Variables -/
+    //--------------------------/
+
+    /**
+     * Default namespace.
+     */
+    private static final String NAMESPACE = "${namespace}";
+
+    /**
+     * Default schemaLocation.
+     */
+    private static final String SCHEMA_LOCATION = "${schemaLocation}";
+
+    /**
+     * Field namespace.
+     */
+    private String namespace = NAMESPACE;
+
+    /**
+     * Field schemaLocation.
+     */
+    private String schemaLocation = SCHEMA_LOCATION;
+
+    /**
+     * Field fileComment.
+     */
+    private String fileComment = null;
+
+#if ( $locationTracking )
+    private boolean addLocationInformation = true;
+
+    /**
+     * Field stringFormatter.
+     */
+    protected InputLocation.StringFormatter stringFormatter;
+
+#end
+      //-----------/
+     //- Methods -/
+    //-----------/
+
+    /**
+     * Method setNamespace.
+     *
+     * @param namespace the namespace to use.
+     */
+    public void setNamespace(String namespace) {
+        this.namespace = Objects.requireNonNull(namespace);
+    } //-- void setNamespace(String)
+
+    /**
+     * Method setSchemaLocation.
+     *
+     * @param schemaLocation the schema location to use.
+     */
+    public void setSchemaLocation(String schemaLocation) {
+        this.schemaLocation = Objects.requireNonNull(schemaLocation);
+        } //-- void setSchemaLocation(String)
+
+    /**
+     * Method setFileComment.
+     *
+     * @param fileComment a fileComment object.
+     */
+    public void setFileComment(String fileComment) {
+        this.fileComment = fileComment;
+    } //-- void setFileComment(String)
+
+#if ( $locationTracking )
+    /**
+     * Method setAddLocationInformation.
+     */
+    public void setAddLocationInformation(boolean addLocationInformation) {
+        this.addLocationInformation = addLocationInformation;
+    } //-- void setAddLocationInformation(String)
+
+    /**
+     * Method setStringFormatter.
+     *
+     * @param stringFormatter
+     */
+    public void setStringFormatter(InputLocation.StringFormatter stringFormatter) {
+        this.stringFormatter = stringFormatter;
+    } //-- void setStringFormatter(InputLocation.StringFormatter)
+
+#end
+    /**
+     * Method write.
+     *
+     * @param writer a writer object
+     * @param ${rootLcapName} a ${root.name} object
+     * @throws IOException IOException if any
+     */
+    public void write(Writer writer, ${root.name} ${rootLcapName}) throws IOException, XMLStreamException {
+        XMLOutputFactory factory = new com.ctc.wstx.stax.WstxOutputFactory();
+        factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
+        factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
+        factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_ADD_SPACE_AFTER_EMPTY_ELEM, true);
+        XMLStreamWriter serializer = new IndentingXMLStreamWriter(factory.createXMLStreamWriter(writer));
+        serializer.writeStartDocument(${rootLcapName}.getModelEncoding(), null);
+        write${root.name}("$rootTag", ${rootLcapName}, serializer);
+        serializer.writeEndDocument();
+    } //-- void write(Writer, ${root.name})
+
+    /**
+     * Method write.
+     *
+     * @param stream a stream object
+     * @param ${rootLcapName} a ${root.name} object
+     * @throws IOException IOException if any
+     */
+    public void write(OutputStream stream, ${root.name} ${rootLcapName}) throws IOException, XMLStreamException {
+        XMLOutputFactory factory = new com.ctc.wstx.stax.WstxOutputFactory();
+        factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, false);
+        factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_USE_DOUBLE_QUOTES_IN_XML_DECL, true);
+        factory.setProperty(com.ctc.wstx.api.WstxOutputProperties.P_ADD_SPACE_AFTER_EMPTY_ELEM, true);
+        XMLStreamWriter serializer = new IndentingXMLStreamWriter(factory.createXMLStreamWriter(stream, ${rootLcapName}.getModelEncoding()));
+        serializer.writeStartDocument(${rootLcapName}.getModelEncoding(), null);
+        write${root.name}("$rootTag", ${rootLcapName}, serializer);
+        serializer.writeEndDocument();
+    } //-- void write(OutputStream, ${root.name})
+
+#foreach ( $class in $model.allClasses )
+ #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+  #set ( $classUcapName = $Helper.capitalise( $class.name ) )
+  #set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
+  #set ( $allFields = $Helper.xmlFields( $class ) )
+    private void write${classUcapName}(String tagName, ${classUcapName} ${classLcapName}, XMLStreamWriter serializer)
+        throws IOException, XMLStreamException {
+        if (${classLcapName} != null) {
+  #if ( $class == $root )
+            if (this.fileComment != null) {
+                serializer.writeCharacters("\n");
+                serializer.writeComment(this.fileComment);
+                serializer.writeCharacters("\n");
+            }
+            serializer.writeStartElement("", tagName, namespace);
+            serializer.writeNamespace("", namespace);
+            serializer.writeNamespace("xsi", W3C_XML_SCHEMA_INSTANCE_NS_URI);
+            serializer.writeAttribute(W3C_XML_SCHEMA_INSTANCE_NS_URI, "schemaLocation", namespace + " " + schemaLocation);
+  #else
+            serializer.writeStartElement(namespace, tagName);
+  #end
+  #foreach ( $field in $allFields )
+    #if ( $Helper.xmlFieldMetadata( $field ).attribute && ! $Helper.xmlFieldMetadata( $field ).format )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+      #if ( $field.type == "String" )
+            writeAttr("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer);
+      #elseif ( $field.type == "boolean" )
+        #set ( $def = ${field.defaultValue} )
+        #if ( ${def} == "true" )
+            writeAttr("$fieldTagName", ${classLcapName}.is${fieldCapName}() ? null : "false", serializer);
+        #else
+            writeAttr("$fieldTagName", ${classLcapName}.is${fieldCapName}() ? "true" : null, serializer);
+        #end
+      #else
+            // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+    #end
+  #end
+  #foreach ( $field in $allFields )
+    #if ( ! $Helper.xmlFieldMetadata( $field ).attribute && ! $Helper.xmlFieldMetadata( $field ).transient
+                 && ! $Helper.xmlFieldMetadata( $field ).format )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #if ( ! $fieldTagName )
+        #set ( $fieldTagName = $field.name )
+      #end
+      #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+      #set ( $def = ${field.defaultValue} )
+      #if ( $locationTracking )
+        #set ( $loctrac = ", ${classLcapName}" )
+        #set ( $loctracnull = ", null" )
+      #else
+        #set ( $loctrac = "" )
+        #set ( $loctracnull = "" )
+      #end
+      #if ( $field.type == "String" )
+        #if ( ! $def )
+            writeTag("$fieldTagName", null, ${classLcapName}.get${fieldCapName}(), serializer${loctrac});
+        #else
+            writeTag("$fieldTagName", "${def}", ${classLcapName}.get${fieldCapName}(), serializer${loctrac});
+        #end
+      #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+        #if ( ${def} == "true" )
+            writeTag("$fieldTagName", "${def}", ${classLcapName}.is${fieldCapName}() ? null : "false", serializer${loctrac});
+        #else
+            writeTag("$fieldTagName", "${def}", ${classLcapName}.is${fieldCapName}() ? "true" : null, serializer${loctrac});
+        #end
+      #elseif ( $field.type == "int" )
+            writeTag("$fieldTagName", "${def}", Integer.toString(${classLcapName}.get${fieldCapName}()), serializer${loctrac});
+      #elseif ( $field.type == "DOM" )
+            writeDom(${classLcapName}.get${fieldCapName}(), serializer);
+      #elseif ( $field.type == "java.util.List" && $field.to == "String" && $field.multiplicity == "*" )
+        #set( $singularField = ${Helper.singular($fieldTagName)} )
+            writeList("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer${loctrac},
+                    t -> writeTag("$singularField", null, t, serializer${loctracnull}));
+      #elseif ( $field.type == "java.util.Properties" && $field.to == "String" && $field.multiplicity == "*" )
+            writeProperties("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer${loctrac});
+      #elseif ( $field.to && $field.multiplicity == "1" )
+            write${field.to}("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer);
+      #elseif ( $field.to && $field.multiplicity == "*" )
+        #set( $singularField = ${Helper.singular($fieldTagName)} )
+            writeList("$fieldTagName", $Helper.isFlatItems($field), ${classLcapName}.get${fieldCapName}(), serializer${loctrac},
+                    t -> write${field.to}("$singularField", t, serializer));
+      #else
+            // TODO: name=${field.name} type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+    #end
+  #end
+            serializer.writeEndElement();
+        }
+    }
+
+ #end
+#end
+    @FunctionalInterface
+    private interface ElementWriter<T> {
+        public void write(T t) throws IOException, XMLStreamException;
+    }
+
+#if ( $locationTracking )
+    private <T> void writeList(String tagName, List<T> list, XMLStreamWriter serializer, InputLocationTracker locationTracker, ElementWriter<T> writer) throws IOException, XMLStreamException {
+        writeList(tagName, false, list, serializer, locationTracker, writer);
+#else
+    private <T> void writeList(String tagName, List<T> list, XMLStreamWriter serializer, ElementWriter<T> writer) throws IOException, XMLStreamException {
+        writeList(tagName, false, list, serializer, writer);
+#end
+    }
+
+#if ( $locationTracking )
+    private <T> void writeList(String tagName, boolean flat, List<T> list, XMLStreamWriter serializer, InputLocationTracker locationTracker, ElementWriter<T> writer) throws IOException, XMLStreamException {
+#else
+    private <T> void writeList(String tagName, boolean flat, List<T> list, XMLStreamWriter serializer, ElementWriter<T> writer) throws IOException, XMLStreamException {
+#end
+        if (list != null && !list.isEmpty()) {
+            if (!flat) {
+                serializer.writeStartElement(namespace, tagName);
+            }
+            int index = 0;
+#if ( $locationTracking )
+            InputLocation location = locationTracker != null ? locationTracker.getLocation(tagName) : null;
+#end
+            for (T t : list) {
+                writer.write(t);
+#if ( $locationTracking )
+                writeLocationTracking(location, Integer.valueOf(index++), serializer);
+#end
+            }
+            if (!flat) {
+                serializer.writeEndElement();
+            }
+        }
+    }
+
+#if ( $locationTracking )
+    private <T> void writeProperties(String tagName, Map<String, String> props, XMLStreamWriter serializer, InputLocationTracker locationTracker) throws IOException, XMLStreamException {
+#else
+    private <T> void writeProperties(String tagName, Map<String, String> props, XMLStreamWriter serializer) throws IOException, XMLStreamException {
+#end
+        if (props != null && !props.isEmpty()) {
+            serializer.writeStartElement(namespace, tagName);
+#if ( $locationTracking )
+            InputLocation location = locationTracker != null ? locationTracker.getLocation(tagName) : null;
+#end
+            for (Map.Entry<String, String> entry : props.entrySet()) {
+                String key = entry.getKey();
+#if ( $locationTracking )
+                writeTag(key, null, entry.getValue(), serializer, null);
+                writeLocationTracking(location, key, serializer);
+#else
+                writeTag(key, null, entry.getValue(), serializer);
+#end
+            }
+            serializer.writeEndElement();
+        }
+    }
+
+    private void writeDom(XmlNode dom, XMLStreamWriter serializer) throws IOException, XMLStreamException {
+        if (dom != null) {
+            serializer.writeStartElement(namespace, dom.getName());
+            for (Map.Entry<String, String> attr : dom.getAttributes().entrySet()) {
+                if (attr.getKey().startsWith("xml:")) {
+                    serializer.writeAttribute("http://www.w3.org/XML/1998/namespace",
+                    attr.getKey().substring(4), attr.getValue());
+                } else {
+                    serializer.writeAttribute(attr.getKey(), attr.getValue());
+                }
+            }
+            for (XmlNode child : dom.getChildren()) {
+                writeDom(child, serializer);
+            }
+            String value = dom.getValue();
+            if (value != null) {
+                serializer.writeCharacters(value);
+            }
+            serializer.writeEndElement();
+#if ( $locationTracking )
+            if (addLocationInformation && dom.getInputLocation() instanceof InputLocation && dom.getChildren().isEmpty()) {
+                serializer.writeComment(toString((InputLocation) dom.getInputLocation()));
+            }
+#end
+        }
+    }
+
+#if ( $locationTracking )
+    private void writeTag(String tagName, String defaultValue, String value, XMLStreamWriter serializer, InputLocationTracker locationTracker) throws IOException, XMLStreamException {
+#else
+    private void writeTag(String tagName, String defaultValue, String value, XMLStreamWriter serializer) throws IOException, XMLStreamException {
+#end
+        if (value != null && !Objects.equals(defaultValue, value)) {
+            serializer.writeStartElement(namespace, tagName);
+            serializer.writeCharacters(value);
+            serializer.writeEndElement();
+#if ( $locationTracking )
+            writeLocationTracking(locationTracker, tagName, serializer);
+#end
+        }
+    }
+
+    private void writeAttr(String attrName, String value, XMLStreamWriter serializer) throws IOException, XMLStreamException {
+        if (value != null) {
+            serializer.writeAttribute(attrName, value);
+        }
+    }
+#if ( $locationTracking )
+
+    /**
+     * Method writeLocationTracking.
+     *
+     * @param locationTracker
+     * @param serializer
+     * @param key
+     * @throws IOException
+     */
+    protected void writeLocationTracking(InputLocationTracker locationTracker, Object key, XMLStreamWriter serializer) throws IOException, XMLStreamException {
+        if (addLocationInformation) {
+            InputLocation location = (locationTracker == null) ? null : locationTracker.getLocation(key);
+            if (location != null) {
+                serializer.writeComment(toString(location));
+            }
+        }
+    } //-- void writeLocationTracking(InputLocationTracker, Object, XMLStreamWriter)
+
+    /**
+     * Method toString.
+     *
+     * @param location
+     * @return String
+     */
+    protected String toString(InputLocation location) {
+        if (stringFormatter != null) {
+            return stringFormatter.toString(location);
+        }
+        if (location.getSource() != null) {
+            return ' ' + location.getSource().toString() + ':' + location.getLineNumber() + ' ';
+        } else {
+            return " " + location.getLineNumber() + " ";
+        }
+    } //-- String toString(InputLocation)
+#end
+
+    static class IndentingXMLStreamWriter extends StreamWriterDelegate {
+
+        int depth = 0;
+        boolean hasChildren = false;
+
+        public IndentingXMLStreamWriter(XMLStreamWriter parent) {
+            super(parent);
+        }
+
+        @Override
+        public void writeEmptyElement(String localName) throws XMLStreamException {
+            indent();
+            super.writeEmptyElement(localName);
+            hasChildren = true;
+        }
+
+        @Override
+        public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
+            indent();
+            super.writeEmptyElement(namespaceURI, localName);
+            hasChildren = true;
+        }
+
+        @Override
+        public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+            indent();
+            super.writeEmptyElement(prefix, localName, namespaceURI);
+            hasChildren = true;
+        }
+
+        @Override
+        public void writeStartElement(String localName) throws XMLStreamException {
+            indent();
+            super.writeStartElement(localName);
+            depth++;
+            hasChildren = false;
+        }
+
+        @Override
+        public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
+            indent();
+            super.writeStartElement(namespaceURI, localName);
+            depth++;
+            hasChildren = false;
+        }
+
+        @Override
+        public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
+            indent();
+            super.writeStartElement(prefix, localName, namespaceURI);
+            depth++;
+            hasChildren = false;
+        }
+
+        @Override
+        public void writeEndElement() throws XMLStreamException {
+            depth--;
+            if (hasChildren) {
+                indent();
+            }
+            super.writeEndElement();
+            hasChildren = true;
+        }
+
+        private void indent() throws XMLStreamException {
+            super.writeCharacters("\n");
+            for (int i = 0; i < depth; i++) {
+                super.writeCharacters("  ");
+            }
+        }
+    }
+}
diff --git a/src/mdo/writer.vm b/src/mdo/writer.vm
new file mode 100644
index 0000000..33a3689
--- /dev/null
+++ b/src/mdo/writer.vm
@@ -0,0 +1,277 @@
+#*
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+*#
+#parse ( "common.vm" )
+#
+#if( ${packageToolV4Xpp3} )
+  #set ( $package = "${packageToolV4Xpp3}" )
+#else
+  #set ( $package = "${packageToolV4}" )
+#end
+#set ( $className = "${model.name}Xpp3Writer" )
+#
+#set ( $root = $model.getClass( $model.getRoot($version), $version ) )
+#set ( $rootXml = $Helper.xmlClassMetadata( $root ) )
+#set ( $rootTag = $rootXml.tagName )
+#set ( $rootUcapName = $Helper.capitalise( $root.name ) )
+#set ( $rootLcapName = $Helper.uncapitalise( $root.name ) )
+#
+#MODELLO-VELOCITY#SAVE-OUTPUT-TO ${package.replace('.','/')}/${className}.java
+// =================== DO NOT EDIT THIS FILE ====================
+//  Generated by Modello Velocity from ${template}
+//  template, any modifications will be overwritten.
+// ==============================================================
+package ${package};
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import org.apache.maven.api.annotations.Generated;
+import org.apache.maven.api.xml.XmlNode;
+import org.apache.maven.internal.xml.XmlNodeBuilder;
+#foreach ( $class in $model.allClasses )
+import ${packageModelV4}.${class.name};
+#end
+import org.codehaus.plexus.util.xml.pull.EntityReplacementMap;
+import org.codehaus.plexus.util.xml.pull.MXParser;
+import org.codehaus.plexus.util.xml.pull.MXSerializer;
+import org.codehaus.plexus.util.xml.pull.XmlPullParser;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.codehaus.plexus.util.xml.pull.XmlSerializer;
+
+@Deprecated
+@Generated
+public class ${className} {
+
+      //--------------------------/
+     //- Class/Member Variables -/
+    //--------------------------/
+
+    /**
+     * Field NAMESPACE.
+     */
+    private static final String NAMESPACE = null;
+
+    /**
+     * Field fileComment.
+     */
+    private String fileComment = null;
+
+
+      //-----------/
+     //- Methods -/
+    //-----------/
+
+    /**
+     * Method setFileComment.
+     *
+     * @param fileComment a fileComment object.
+     */
+    public void setFileComment(String fileComment) {
+        this.fileComment = fileComment;
+    } //-- void setFileComment(String)
+
+    /**
+     * Method write.
+     *
+     * @param writer a writer object
+     * @param ${rootLcapName} a ${root.name} object
+     * @throws java.io.IOException java.io.IOException if any
+     */
+    public void write(Writer writer, ${root.name} ${rootLcapName}) throws java.io.IOException {
+        XmlSerializer serializer = new MXSerializer();
+        serializer.setProperty("http://xmlpull.org/v1/doc/properties.html#serializer-indentation", "  ");
+        serializer.setProperty("http://xmlpull.org/v1/doc/properties.html#serializer-line-separator", "\n");
+        serializer.setOutput(writer);
+        serializer.startDocument(${rootLcapName}.getModelEncoding(), null);
+        write${root.name}("$rootTag", ${rootLcapName}, serializer);
+        serializer.endDocument();
+    } //-- void write(Writer, ${root.name})
+
+    /**
+     * Method write.
+     *
+     * @param stream a stream object
+     * @param ${rootLcapName} a ${root.name} object
+     * @throws java.io.IOException java.io.IOException if any
+     */
+    public void write(OutputStream stream, ${root.name} ${rootLcapName}) throws java.io.IOException {
+        XmlSerializer serializer = new MXSerializer();
+        serializer.setProperty("http://xmlpull.org/v1/doc/properties.html#serializer-indentation", "  ");
+        serializer.setProperty("http://xmlpull.org/v1/doc/properties.html#serializer-line-separator", "\n");
+        serializer.setOutput(stream, ${rootLcapName}.getModelEncoding());
+        serializer.startDocument(${rootLcapName}.getModelEncoding(), null);
+        write${root.name}("$rootTag", ${rootLcapName}, serializer);
+        serializer.endDocument();
+    } //-- void write(OutputStream, ${root.name})
+
+#foreach ( $class in $model.allClasses )
+ #if ( $class.name != "InputSource" && $class.name != "InputLocation" )
+  #set ( $classUcapName = $Helper.capitalise( $class.name ) )
+  #set ( $classLcapName = $Helper.uncapitalise( $class.name ) )
+  #set ( $allFields = $Helper.xmlFields( $class ) )
+    private void write${classUcapName}(String tagName, ${classUcapName} ${classLcapName}, XmlSerializer serializer) throws IOException {
+        if (${classLcapName} != null) {
+  #if ( $class == $root )
+            if (this.fileComment != null) {
+                serializer.comment(this.fileComment);
+            }
+            serializer.setPrefix("", "http://maven.apache.org/POM/4.0.0");
+            serializer.setPrefix("xsi", "http://www.w3.org/2001/XMLSchema-instance");
+            serializer.startTag(NAMESPACE, tagName);
+            serializer.attribute("", "xsi:schemaLocation", "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd");
+  #else
+            serializer.startTag(NAMESPACE, tagName);
+  #end
+  #foreach ( $field in $allFields )
+    #if ( $Helper.xmlFieldMetadata( $field ).attribute )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+      #if ( $field.type == "String" )
+            writeAttr("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer);
+      #elseif ( $field.type == "boolean" )
+        #set ( $def = ${field.defaultValue} )
+        #if ( ${def} == "true" )
+            writeAttr("$fieldTagName", ${classLcapName}.is${fieldCapName}() ? null : "false", serializer);
+        #else
+            writeAttr("$fieldTagName", ${classLcapName}.is${fieldCapName}() ? "true" : null, serializer);
+        #end
+      #else
+            // TODO: type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+    #end
+  #end
+  #foreach ( $field in $allFields )
+    #if ( ! $Helper.xmlFieldMetadata( $field ).attribute && ! $Helper.xmlFieldMetadata( $field ).transient )
+      #set ( $fieldTagName = $Helper.xmlFieldMetadata( $field ).tagName )
+      #if ( ! $fieldTagName )
+        #set ( $fieldTagName = $field.name )
+      #end
+      #set ( $fieldCapName = $Helper.capitalise( $field.name ) )
+      #set ( $def = ${field.defaultValue} )
+      #if ( $field.type == "String" )
+        #if ( ! $def )
+            writeTag("$fieldTagName", null, ${classLcapName}.get${fieldCapName}(), serializer);
+        #else
+            writeTag("$fieldTagName", "${def}", ${classLcapName}.get${fieldCapName}(), serializer);
+        #end
+      #elseif ( $field.type == "boolean" || $field.type == "Boolean" )
+        #if ( ${def} == "true" )
+            writeTag("$fieldTagName", "${def}", ${classLcapName}.is${fieldCapName}() ? null : "false", serializer);
+        #else
+            writeTag("$fieldTagName", "${def}", ${classLcapName}.is${fieldCapName}() ? "true" : null, serializer);
+        #end
+      #elseif ( $field.type == "int" )
+            writeTag("$fieldTagName", "${def}", Integer.toString(${classLcapName}.get${fieldCapName}()), serializer);
+      #elseif ( $field.type == "DOM" )
+            writeDom(${classLcapName}.get${fieldCapName}(), serializer);
+      #elseif ( $field.type == "java.util.List" && $field.to == "String" && $field.multiplicity == "*" )
+        #set( $singularField = ${Helper.singular($fieldTagName)} )
+            writeList("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer, t -> writeTag("$singularField", "${def}", t, serializer));
+      #elseif ( $field.type == "java.util.Properties" && $field.to == "String" && $field.multiplicity == "*" )
+            writeProperties("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer);
+      #elseif ( $field.to && $field.multiplicity == "1" )
+            write${field.to}("$fieldTagName", ${classLcapName}.get${fieldCapName}(), serializer);
+      #elseif ( $field.to && $field.multiplicity == "*" )
+        #set( $singularField = ${Helper.singular($fieldTagName)} )
+            writeList("$fieldTagName", $Helper.isFlatItems($field), ${classLcapName}.get${fieldCapName}(), serializer, t -> write${field.to}("$singularField", t, serializer));
+      #else
+            // TODO: name=${field.name} type=${field.type} to=${field.to} multiplicity=${field.multiplicity}
+      #end
+    #end
+  #end
+            serializer.endTag(NAMESPACE, tagName);
+        }
+    }
+
+ #end
+#end
+    @FunctionalInterface
+    private interface ElementWriter<T> {
+        public void write(T t) throws IOException;
+    }
+
+    private <T> void writeList(String tagName, List<T> list, XmlSerializer serializer, ElementWriter<T> writer) throws IOException {
+        writeList(tagName, false, list, serializer, writer);
+    }
+
+    private <T> void writeList(String tagName, boolean flat, List<T> list, XmlSerializer serializer, ElementWriter<T> writer) throws IOException {
+        if (list != null && !list.isEmpty()) {
+            if (!flat) {
+                serializer.startTag(NAMESPACE, tagName);
+            }
+            for (T t : list) {
+                writer.write(t);
+            }
+            if (!flat) {
+                serializer.endTag(NAMESPACE, tagName);
+            }
+        }
+    }
+
+    private <T> void writeProperties(String tagName, Map<String, String> props, XmlSerializer serializer) throws IOException {
+        if (props != null && !props.isEmpty()) {
+            serializer.startTag(NAMESPACE, tagName);
+            for (Map.Entry<String, String> entry : props.entrySet()) {
+                writeTag(entry.getKey(), null, entry.getValue(), serializer);
+            }
+            serializer.endTag(NAMESPACE, tagName);
+        }
+    }
+
+    private void writeDom(XmlNode dom, XmlSerializer serializer) throws IOException {
+        if (dom != null) {
+            serializer.startTag(NAMESPACE, dom.getName());
+            for (Map.Entry<String, String> attr : dom.getAttributes().entrySet()) {
+                serializer.attribute(NAMESPACE, attr.getKey(), attr.getValue());
+            }
+            for (XmlNode child : dom.getChildren()) {
+                writeDom(child, serializer);
+            }
+            String value = dom.getValue();
+            if (value != null) {
+                serializer.text(value);
+            }
+            serializer.endTag(NAMESPACE, dom.getName());
+        }
+    }
+
+    private void writeTag(String tagName, String defaultValue, String value, XmlSerializer serializer) throws IOException {
+        if (value != null && !Objects.equals(defaultValue, value)) {
+            serializer.startTag(NAMESPACE, tagName).text(value).endTag(NAMESPACE, tagName);
+        }
+    }
+
+    private void writeAttr(String attrName, String value, XmlSerializer serializer) throws IOException {
+        if (value != null) {
+            serializer.attribute(NAMESPACE, attrName, value);
+        }
+    }
+
+}
diff --git a/src/site/site.xml b/src/site/site.xml
index 83da6d7..3ba52bd 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -39,7 +39,7 @@
 
     <menu name="Overview">
       <item name="Introduction" href="index.html"/>
-      <item name="JavaDocs" href="apidocs/index.html"/>
+      <item name="Javadocs" href="apidocs/index.html"/>
       <item name="Source Xref" href="xref/index.html"/>
       <!--item name="FAQ" href="faq.html"/-->
       <item name="License" href="http://www.apache.org/licenses/"/>
diff --git a/src/site/xdoc/index.xml b/src/site/xdoc/index.xml
index 73a43f2..21521eb 100644
--- a/src/site/xdoc/index.xml
+++ b/src/site/xdoc/index.xml
@@ -57,15 +57,14 @@
           <area shape="rect" coords="244,381,406,421"  alt="maven-settings-builder" href="maven-settings-builder/" />
           <area shape="rect" coords="278,447,371,486"  alt="maven-settings" href="maven-settings/" />
           <area shape="rect" coords="387,512,540,553"  alt="maven-model-builder" href="maven-model-builder/" />
-          <area shape="rect" coords="304,578,485,619"  alt="maven-model-transform" href="maven-model-transform/" />
           <area shape="rect" coords="492,577,594,619"  alt="maven-model" href="maven-model/" />
           <area shape="rect" coords="71,0,222,41"      alt="maven-slf4j-provider" href="maven-slf4j-provider/" />
           <area shape="rect" coords="73,66,220,108"    alt="maven-slf4j-wrapper" href="maven-slf4j-wrapper/" />
           <area shape="rect" coords="1,517,192,680"    alt="maven-resolver" href="https://maven.apache.org/resolver/" />
-          <area shape="rect" coords="87,132,204,172"   alt="slf4j-api" href="http://www.slf4j.org/manual.html" />
-          <area shape="rect" coords="679,66,827,106"   alt="commons-cli" href="http://commons.apache.org/cli/" />
+          <area shape="rect" coords="87,132,204,172"   alt="slf4j-api" href="https://www.slf4j.org/manual.html" />
+          <area shape="rect" coords="679,66,827,106"   alt="commons-cli" href="https://commons.apache.org/cli/" />
           <area shape="rect" coords="82,197,216,237"   alt="maven-shared-utils" href="https://maven.apache.org/shared/maven-shared-utils/" />
-          <area shape="rect" coords="109,263,189,304"  alt="jansi" href="http://fusesource.github.io/jansi/" />
+          <area shape="rect" coords="109,263,189,304"  alt="jansi" href="https://fusesource.github.io/jansi/" />
           <area shape="rect" coords="679,132,892,171"  alt="wagon-provider-api" href="https://maven.apache.org/wagon/wagon-provider-api/" />
           <area shape="rect" coords="674,437,831,477"  alt="plexus-sec-dispatcher" href="https://github.com/codehaus-plexus/plexus-sec-dispatcher" />
           <area shape="rect" coords="859,436,949,479"  alt="plexus-cipher" href="https://github.com/codehaus-plexus/plexus-cipher" />
@@ -74,7 +73,7 @@
           <area shape="rect" coords="868,324,951,366"  alt="plexus-utils" href="https://codehaus-plexus.github.io/plexus-utils" />
           <area shape="rect" coords="660,310,965,520"  alt="plexus" href="https://codehaus-plexus.github.io/" />
           <area shape="rect" coords="679,183,910,281"  alt="sisu" href="https://projects.eclipse.org/projects/technology.sisu" />
-          <area shape="rect" coords="921,195,1004,239" alt="guice" href="http://code.google.com/p/google-guice/" />
+          <area shape="rect" coords="921,195,1004,239" alt="guice" href="https://github.com/google/guice" />
         </map>
       </p>
     </section>